+{include file=$PF_FOOTER}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/changepassword.form.tpl b/modules/registration/tpl/default/html/changepassword.form.tpl
new file mode 100755
index 0000000..43fb539
--- /dev/null
+++ b/modules/registration/tpl/default/html/changepassword.form.tpl
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/changepassword.tpl b/modules/registration/tpl/default/html/changepassword.tpl
new file mode 100755
index 0000000..e4c6ae5
--- /dev/null
+++ b/modules/registration/tpl/default/html/changepassword.tpl
@@ -0,0 +1,9 @@
+{include file=$PF_HEADER}
+
+
+
Enter a new password
+
+ {$FORM_ELEMENTS}
+
+
+{include file=$PF_FOOTER}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/edit-member.tpl b/modules/registration/tpl/default/html/edit-member.tpl
new file mode 100644
index 0000000..3c075bc
--- /dev/null
+++ b/modules/registration/tpl/default/html/edit-member.tpl
@@ -0,0 +1,262 @@
+
+
+
+
+
+
+
+ {$user->getParty()->getFullName()|default:'None'}
+ Edit Name
+
+
+
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/email-accountcreateion-html.tpl b/modules/registration/tpl/default/html/email-accountcreateion-html.tpl
new file mode 100644
index 0000000..faf86b8
--- /dev/null
+++ b/modules/registration/tpl/default/html/email-accountcreateion-html.tpl
@@ -0,0 +1,21 @@
+Whats cookin good lookin?!
+
+Congratulations! With your new MSQC account youve officially been inducted into an elite squadron of quilting ninjas. Your training and preparation in the art of quilting have clearly paid off! Here is your login info:
+
+Login:
+Password:
+
+Remember though, not everyone gets one of these accounts, and with great power comes great responsibility.
+
+With this account, you have been entrusted with a sacred duty, namely to ALWAYS login when you come to our site. Why? This is why:
+
+1) The only way to earn and spend Quilters Cash is to be logged in If you dont youre basically throwing away free money (to learn more about Quilters Cash, click here)
+2) You can check out with lightning speed (and the stealth and grace of a true quilting ninja)
+3) When logged in, you have access to our awesome Quilting Forums, QuiltsByMe.com, and Quilting Tutorials.
+
+Oh ya, one more duty we forgot to mention you must check the daily deal every day and talk yourself into buying it, then out of buying it because you have way too much fabric, then back into buying again.
+
+With this solemn commitment to the art of ninja quilting, we now knight you Sir/Siress ____
+
+Respectfully,
+The Board of Quilting Ninjas at the Missouri Star Quilting Company.
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/email-resetpassword-html.tpl b/modules/registration/tpl/default/html/email-resetpassword-html.tpl
new file mode 100755
index 0000000..2d611c7
--- /dev/null
+++ b/modules/registration/tpl/default/html/email-resetpassword-html.tpl
@@ -0,0 +1,12 @@
+Hello!
+
+A password reset request has been made for your account at {$smarty.const.PF_SITE_NAME}
+
+If you requested your password to be reset, please click on the link below to complete your request.
+
+{$smarty.const.PF_URL}/registration/resetpassword?key={$key}
+
+If you did not request for your password to be reset, you can safely ignore this message.
+
+Thank you!
+{$smarty.const.PF_SITE_NAME}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/email-resetpassword-txt.tpl b/modules/registration/tpl/default/html/email-resetpassword-txt.tpl
new file mode 100755
index 0000000..2d611c7
--- /dev/null
+++ b/modules/registration/tpl/default/html/email-resetpassword-txt.tpl
@@ -0,0 +1,12 @@
+Hello!
+
+A password reset request has been made for your account at {$smarty.const.PF_SITE_NAME}
+
+If you requested your password to be reset, please click on the link below to complete your request.
+
+{$smarty.const.PF_URL}/registration/resetpassword?key={$key}
+
+If you did not request for your password to be reset, you can safely ignore this message.
+
+Thank you!
+{$smarty.const.PF_SITE_NAME}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/forgot.form.tpl b/modules/registration/tpl/default/html/forgot.form.tpl
new file mode 100755
index 0000000..07e0015
--- /dev/null
+++ b/modules/registration/tpl/default/html/forgot.form.tpl
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/forgot.tpl b/modules/registration/tpl/default/html/forgot.tpl
new file mode 100755
index 0000000..ad52347
--- /dev/null
+++ b/modules/registration/tpl/default/html/forgot.tpl
@@ -0,0 +1,12 @@
+{include file=$PF_HEADER}
+
+
+
Forgot your password?
+
+ No problem! Just give us the email address you used to set up your account, and we will reset your password right away!
+
+
+ {$FORM_ELEMENTS}
+
+
+{include file=$PF_FOOTER}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/login-box.tpl b/modules/registration/tpl/default/html/login-box.tpl
new file mode 100644
index 0000000..5461893
--- /dev/null
+++ b/modules/registration/tpl/default/html/login-box.tpl
@@ -0,0 +1,3 @@
+
+ {$LOGIN_FORM_ELEMENTS}
+
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/login.form.tpl b/modules/registration/tpl/default/html/login.form.tpl
new file mode 100755
index 0000000..33e5efe
--- /dev/null
+++ b/modules/registration/tpl/default/html/login.form.tpl
@@ -0,0 +1,14 @@
+
+
+
+
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/login.tpl b/modules/registration/tpl/default/html/login.tpl
new file mode 100755
index 0000000..52695ce
--- /dev/null
+++ b/modules/registration/tpl/default/html/login.tpl
@@ -0,0 +1,16 @@
+{include file=$PF_HEADER}
+
+
+
Sign In
+
+
Sign in
+ {$LOGIN_FORM_ELEMENTS}
+
+
+
+
New users, create an account and join us!
+ {$CREATE_FORM_ELEMENTS}
+
+
+
+{include file=$PF_FOOTER}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/passwordreset.tpl b/modules/registration/tpl/default/html/passwordreset.tpl
new file mode 100644
index 0000000..1f616e2
--- /dev/null
+++ b/modules/registration/tpl/default/html/passwordreset.tpl
@@ -0,0 +1,14 @@
+{include file=$PF_HEADER}
+
+
+
+
+
Your Password has been Changed
+
+
+ Your password has been successfully updated, and you're now logged in too. Enjoy!
+
+
+
+
+{include file=$PF_FOOTER}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/passwordresetsent.tpl b/modules/registration/tpl/default/html/passwordresetsent.tpl
new file mode 100755
index 0000000..918af5c
--- /dev/null
+++ b/modules/registration/tpl/default/html/passwordresetsent.tpl
@@ -0,0 +1,14 @@
+{include file=$PF_HEADER}
+
+
+
+
+
Your Password has been Reset
+
+
+ Please check your e-mail for a link to enter a new password.
+
+
+
+
+{include file=$PF_FOOTER}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/resetpassword.form.tpl b/modules/registration/tpl/default/html/resetpassword.form.tpl
new file mode 100755
index 0000000..43fb539
--- /dev/null
+++ b/modules/registration/tpl/default/html/resetpassword.form.tpl
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/registration/tpl/default/html/resetpassword.tpl b/modules/registration/tpl/default/html/resetpassword.tpl
new file mode 100755
index 0000000..2f5588a
--- /dev/null
+++ b/modules/registration/tpl/default/html/resetpassword.tpl
@@ -0,0 +1,11 @@
+{include file=$PF_HEADER}
+
+
Enter a new password
+
+ Please choose a new password below, and you'll be all set.
+
+
+ {$FORM_ELEMENTS}
+
+
+{include file=$PF_FOOTER}
\ No newline at end of file
diff --git a/modules/registration/tpl/default/images/.placeholder b/modules/registration/tpl/default/images/.placeholder
new file mode 100755
index 0000000..e69de29
diff --git a/modules/registration/tpl/default/js/.placeholder b/modules/registration/tpl/default/js/.placeholder
new file mode 100755
index 0000000..e69de29
diff --git a/modules/thirdparty/elastica/LICENSE.txt b/modules/thirdparty/elastica/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/thirdparty/elastica/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/modules/thirdparty/elastica/README.markdown b/modules/thirdparty/elastica/README.markdown
new file mode 100755
index 0000000..1db2fc4
--- /dev/null
+++ b/modules/thirdparty/elastica/README.markdown
@@ -0,0 +1,40 @@
+Elastica: elasticsearch PHP Client
+==================================
+
+[](http://travis-ci.org/ruflin/Elastica)
+
+Documentation
+---------------------
+Check out the [Elastica documentation](http://ruflin.github.com/Elastica/) to find out how Elastica works. If you have questions, don't hesitate to ask them in the [Elastica google group](https://groups.google.com/group/elastica-php-client). Issues should go to the [issue tracker from github](https://github.com/ruflin/Elastica/issues).
+
+About
+---------------------
+PHP client for the distributed search engine [elasticsearch](http://www.elasticsearch.com/) which is
+based on [Lucene](http://lucene.apache.org/java/docs/index.html) and can be an alternative to [solr](http://lucene.apache.org/solr/).
+The client naming and structure is consistent with [Zend Framework](http://framework.zend.com/)
+and other PHP frameworks. This makes it easy to use the client in combination with Zend Framework.
+
+Changes
+-------
+For changes in the API please check the file [changes.txt](https://github.com/ruflin/Elastica/blob/master/changes.txt)
+
+Versions
+--------
+The version numbers are consistent with elasticsearch. The version number 0.16.0.0 means it is the first release for elasticsearch version 0.16.0. The next release is called 0.16.0.1. As soon as the elasticsearch is updated and the client is updated, also the next version is called 0.16.1.0. Like this it should be always clear to which versions the Elastica client is compatible.
+
+Compatibility
+-------------
+At the moment the client should be backward compatible to PHP 5.2. That's the reason why
+the client was not directly built with namespaces and other nice PHP 5.3 features.
+
+File indexing
+-------------
+File upload is supported but the mapper attachement plugin has to be installed
+
+ ./bin/plugin install mapper-attachments
+
+Contributing
+------------
+Help is very welcomed, but code contributions must be done in respect of [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md).
+
+See [Coding guidelines](https://github.com/ruflin/Elastica/wiki/Coding-guidelines) for tips on how to do so.
\ No newline at end of file
diff --git a/modules/thirdparty/elastica/Vagrantfile b/modules/thirdparty/elastica/Vagrantfile
new file mode 100644
index 0000000..af49b02
--- /dev/null
+++ b/modules/thirdparty/elastica/Vagrantfile
@@ -0,0 +1,14 @@
+# Elastica debian image
+#
+# All passwords and username (db, ...) are root / root
+#
+# The image has 2GB of memory and a size of 10GB
+
+Vagrant::Config.run do |config|
+
+ config.vm.box = "debian-6.0.3-64-elastica-20120115"
+ config.vm.box_url = "http://ruflin.com/files/vagrant/debian-6.0.3-64-elastica-20120528.box"
+ config.vm.network :hostonly, "10.10.10.10"
+
+ config.vm.share_folder "project", "/project", "."
+end
diff --git a/modules/thirdparty/elastica/build.xml b/modules/thirdparty/elastica/build.xml
new file mode 100755
index 0000000..7b2ce3f
--- /dev/null
+++ b/modules/thirdparty/elastica/build.xml
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/thirdparty/elastica/changes.txt b/modules/thirdparty/elastica/changes.txt
new file mode 100644
index 0000000..c07db9b
--- /dev/null
+++ b/modules/thirdparty/elastica/changes.txt
@@ -0,0 +1,262 @@
+CHANGES
+
+2012-07-26
+- Change Elastica_Filter_GeoDistance::__construct(), accepts geohash parameter (BC break, before: ($key, $latitude, $longitude, $distance), after: ($key, $location, $distance) where $location is array('lat' => $latitude, 'lon' => $longitude) or a geohash)
+
+2012-07-17
+- Changed naming for several methods to camelCase
+- Enforced PSR1 code style, as per https://github.com/pmjones/fig-standards/blob/psr-1-style-guide/proposed/PSR-1-basic.md
+- Added Elastica_Script::toArray
+- Added Elastica_ScriptFields
+- Elastica_Query::setScriptFields now takes Elastica_ScriptFields or associative array as argument, the old implementation was bogus.
+
+2012-06-24
+- Simplify Elastica_Type::search and Elastica_Index::search by using Elastica_Search
+- Implement Elastica_Filter_Abstract::setCache and Elastica_Filter_Abstract::setCacheKey
+- Add Elastica_Param::hasParam
+- Remove unsupported use of minimum number should match for Boolean Filter
+- Remove old style path creation through params in Elastica_Index::create and Elastica_Search::search
+
+2012-06-22
+- Add Elastica_Filter_Limit
+- Add getters+setters for Index Setting blocks 'read', 'write' and 'metadata'
+- Add Elastica_Filter_MatchAll
+
+2012-06-20
+- Facet scope added
+
+2012-06-09
+- Change $_parent to null to also support 0 for an id
+- Fix Elasitca_Document->toArray()
+
+2012-05-01
+- Release v0.19.3.0
+- MoreLikeThis Query in Elastica_Document
+- Add query param for request (allows GET params)
+
+2012-03-04
+- Node info call update. The receive os info and more, param is needed. By default, only basics are returned
+- Release v0.19.0.0 which is compatible with ES 0.19.0 http://www.elasticsearch.org/blog/2012/03/01/0.19.0-released.html
+
+2012-02-21
+- Allow percolate queries in bulk requests
+- Fix memory leak in curl requests
+
+2012-01-23
+- Packagist added http://packagist.org/
+
+2012-01-15
+- Vagrantfile for vagrant environment with elasticsearch added. Run: vagrant up
+
+2012-01-08
+- Allow to set curl params over client config #106 #107
+- Add the possiblity to add path or url in config for a request #120
+
+2012-01-04
+- Elastica_Index::exists() and Elastica_Cluster::getIndexNames() added
+
+2012-01-01
+- Elastica_Cluster_Settings added
+- Read only feature for cluster and index added. This feature is elasticsearch >0.19.0 only. ES 0.19.0 release is not out yet
+
+2011-12-29
+- Elastica_Type::deleteByQuery implemented
+
+2011-12-20
+- Release v0.18.6.0
+
+2011-12-19
+- Percolator for Type and Documents added
+
+2011-12-06
+- Elastica_Percolator added. See tests for more details
+
+2011-12-02
+- Rename Elastica_Type::getType() to Elastica_Type::getName(), getType() is now deprecated
+
+2011-12-01
+- Elastica_Filter_Term::addTerm renamed to setTerm, Elastica_Filter_Term::setTerm renamed to setRawTerm
+- Elastica_Query_Term::addTerm renamed to setTerm, Elastica_Query_Term::setTerm renamed to setRawTerm
+
+2011-11-30
+- Release v0.18.5.0
+
+2011-11-28
+- Elastica_Filter_Nested added
+
+2011-11-26
+- Elastica_Search::addIndices(), Elastica_Search::addTypes() added
+
+2011-11-20
+- Release v0.18.4.1
+- Elastica_Log added for logging. Has to be passed as client config to enable
+- Elastica blogging introduced: http://ruflin.com/en/elastica
+
+2011-11-17
+- Release v0.18.4.0
+- Support for Travis CI added: http://travis-ci.org/ruflin/Elastica
+
+2011-11-07
+- Elastica_Index_Stats added
+
+2011-11-05
+- Elastica_Query_Nested added
+
+2011-10-29
+- TTL for document and mapping added
+
+2011-10-28
+- Refactored Elastica_Query_CustomScore::addCSParam to ::addParams
+- Rename Elastica_Query_CustomScore::addParam to ::addCSParam
+- Release v0.18.1.0
+
+2011-10-20
+- Release v0.17.9.0
+- Elastica_Filter_Type added
+
+2011-10-19
+- Elastica_Query_CustomFilterScore added
+
+2011-10-15
+- API Documentation changed to DocBlox
+
+2011-10-10
+- Bug fixing
+- Release v0.17.8.0 added
+
+2011-09-19
+- Release v0.17.7.0 added
+- Release v0.17.6.1 added
+
+2011-09-18
+- Elastica_Exception_ExpectedFieldNotFound renamed to Elastica_Exception_NotFound
+
+2011-08-25
+- Https transport layer added
+
+2011-08-22
+- Typo in Terms query fixed (issue #74)
+
+2011-08-15
+- Refactoring HTTP connection to keep alive connection -> speed improvement during using the same client
+- Release v0.17.6.0 added
+
+2011-08-09
+- Automatic creation of id for documents added. This was more a bug
+- Release v0.17.4.0 added
+
+2011-08-08
+- Elastica_Query_Text added
+- Params (constructor) of Elastica_Filter_GeoBoundingBox changed (array instead of single params)
+
+2011-08-07
+- Elastica_Query_MoreLikeThis added by @juneym. Still work under progress
+- Refactoring Queries and Filters to use Elastica_Param. Adding tests
+
+2011-08-05
+- Elastica_Filter_Abstract enhanced for more general usage (set/get/addParam(s)) added
+
+2011-08-04
+- Release v0.17.3.0 added
+- Elastica_Index_Settings::set/get response updated. get('...') does not require 'index.' in front anymore
+- Nodes and Cluster shutdown added
+- Elastica_Node::getIp() and getPort() added
+
+2011-07-30
+- Readd merge_factor to settings. Now working as expected. Index has to be closed first.
+
+2011-07-29
+- Release tag v0.17.2.0 added. Elastica is compatible with elasticsearch 0.17.2
+
+2011-07-22
+- Elastica_Index_Settings::getMergePolicyMergeFactor and set removed because of enhanced merge policy implementation in ES 0.17.0 https://github.com/elasticsearch/elasticsearch/issues/998
+- Release tav v0.17.1.0 added
+
+2011-07-21
+- Elastica_Query_HasChild and _parent feature added by fabian
+- Elastica_Filter_GeoBoundingBox added by fabian
+
+2011-07-20
+- Elastica_Query_Builder added by chrisdegrim
+
+2011-07-19
+- Release tag v0.17.0.0 added. Elastica is compatible with elasticsearch 0.17.0
+
+2011-07-18
+- ResultSet::hasFacets added
+- QueryString useDisMax added
+
+2011-07-15
+- Facet/DateHistogram and Facet/Historgram added
+- Documentation pages added unter http://ruflin.github.com/Elastica
+- Release tag v0.16.4.0 added
+
+2011-06-19
+- Add support for multiple servers to Elastica_Client (issue #39)
+
+2011-06-16
+- Support for multiple index, type queries and _all queries added through Elastica_Search object
+- Elastica_Index::clearCache added to clean cache
+- Elastica_Index::flush added
+
+2011-06-07
+- Elastica_Index::setNumberOfShards removed as not supported after creating index
+
+2011-05-11
+- Refactor client constructor. Elastica_Client::__construct(array $config) now takes a config array instead of host and port
+
+2011-05-08
+- Elastica_Query_QueryString::escapeTerm move to Elastica_Util::escapeTerm
+
+2011-04-29
+- Added getParam to Elastica_Result that more values can be retrieved from the hit array
+- Elastica_Filter_Ids added http://www.elasticsearch.org/guide/reference/query-dsl/ids-filter.html
+- getMergePolicyMergeFactor and getRefreshInterval to Elastica_Type_Settings added. If no value is set, default values are returned
+
+2011-04-28
+- Release of version 0.16.0.0 (see new version naming structure in README)
+
+2011-04-27
+- Refactoring of Elastica_Type::setMapping. No source parameter anymore.
+- Elastica_Type_Mapping object introduced to set more fine grained mapping
+
+2011-04-17
+- Elastica_Filter_Exists added
+
+2011-04-14
+- Elastica_Type getCount replace by count()
+- Count has now optional query parametere
+
+2011-04-01
+- Renaming of functions in Elastica_Query_Terms and Ela-stica_Query_Filter to fit new naming convention. setTerms, addTerm have different API now!
+
+2011-03-31
+- Deprecated code removed
+- Break backward compatibility to 0.15.1 (versions introduced by wlp1979)
+
+2011-03-30
+- Filtered query introduced
+- setRawArguments in Elastica_Query is now setParam
+- open / close for index added
+- Remove Elastica_Filter and Elastica_Facets because not needed anymore
+
+2011-03-29
+- Renaming Elastica_Filter->addQuery, addFilter to setQuery, setFilter
+- Add parts of Facets API
+- Add facet Terms
+- Renaming Elastica_Query->addFilter to setFilter
+
+2011-03-24
+- Renaming of Elastica_Status_Index to Elastica_Index_Status => API Change!
+- IndexSettings added for improved bulk updating http://www.elasticsearch.org/blog/2011/03/23/update-settings.html
+
+2011-03-21
+- Node object added
+- Node_Info and Node_Stats added
+- Refactoring of Cluster object
+
+2011-03-13
+- changes.txt introduced
+- getResponse in Elastica_Response renamed to getData. getResponse now deprecated
+- Index status objects added
+- getIndexName in Elastica_Index renamed to getName. getIndexName is deprecated
\ No newline at end of file
diff --git a/modules/thirdparty/elastica/composer.json b/modules/thirdparty/elastica/composer.json
new file mode 100644
index 0000000..e994d99
--- /dev/null
+++ b/modules/thirdparty/elastica/composer.json
@@ -0,0 +1,20 @@
+{
+ "name": "ruflin/Elastica",
+ "description": "Elasticsearch Client",
+ "keywords": ["search","client"],
+ "homepage": "http://ruflin.github.com/Elastica/",
+ "type": "library",
+ "license": "Apache 2.0",
+ "authors": [
+ {
+ "name": "Nicolas Ruflin",
+ "homepage": "http://ruflin.com/"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "autoload": {
+ "psr-0": {"Elastica": "lib/"}
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Client.php b/modules/thirdparty/elastica/lib/Elastica/Client.php
new file mode 100755
index 0000000..351a878
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Client.php
@@ -0,0 +1,413 @@
+
+ */
+class Elastica_Client
+{
+ /**
+ * Default elastic search port
+ */
+ const DEFAULT_PORT = 9200;
+
+ /**
+ * Default host
+ */
+ const DEFAULT_HOST = 'localhost';
+
+ /**
+ * Default transport
+ *
+ * @var string
+ */
+ const DEFAULT_TRANSPORT = 'Http';
+
+ /**
+ * Number of seconds after a timeout occurs for every request
+ * If using indexing of file large value necessary.
+ */
+ const TIMEOUT = 300;
+
+ /**
+ * Config with defaults
+ *
+ * @var array
+ */
+ protected $_config = array(
+ 'host' => self::DEFAULT_HOST,
+ 'port' => self::DEFAULT_PORT,
+ 'path' => '',
+ 'url' => null,
+ 'transport' => self::DEFAULT_TRANSPORT,
+ 'persistent' => true,
+ 'timeout' => self::TIMEOUT,
+ 'headers' => array(),
+ 'servers' => array(),
+ 'curl' => array(),
+ 'roundRobin' => false,
+ 'log' => false,
+ 'retryOnConflict' => 0,
+ );
+
+ /**
+ * Creates a new Elastica client
+ *
+ * @param array $config OPTIONAL Additional config options
+ */
+ public function __construct(array $config = array())
+ {
+ $this->setConfig($config);
+ }
+
+ /**
+ * Sets specific config values (updates and keeps default values)
+ *
+ * @param array $config Params
+ */
+ public function setConfig(array $config)
+ {
+ foreach ($config as $key => $value) {
+ $this->_config[$key] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns a specific config key or the whole
+ * config array if not set
+ *
+ * @param string $key Config key
+ * @return array|string Config value
+ */
+ public function getConfig($key = '')
+ {
+ if (empty($key)) {
+ return $this->_config;
+ }
+
+ if (!array_key_exists($key, $this->_config)) {
+ throw new Elastica_Exception_Invalid('Config key is not set: ' . $key);
+ }
+
+ return $this->_config[$key];
+ }
+
+ /**
+ * Sets / overwrites a specific config value
+ *
+ * @param string $key Key to set
+ * @param mixed $value Value
+ * @return Elastica_Client Client object
+ */
+ public function setConfigValue($key, $value)
+ {
+ return $this->setConfig(array($key => $value));
+ }
+
+ /**
+ * Returns the index for the given connection
+ *
+ * @param string $name Index name to create connection to
+ * @return Elastica_Index Index for the given name
+ */
+ public function getIndex($name)
+ {
+ return new Elastica_Index($this, $name);
+ }
+
+ /**
+ * Returns host the client connects to
+ *
+ * @return string Host
+ */
+ public function getHost()
+ {
+ return $this->getConfig('host');
+ }
+
+ /**
+ * Returns connection port of this client
+ *
+ * @return int Connection port
+ */
+ public function getPort()
+ {
+ return (int) $this->getConfig('port');
+ }
+
+ /**
+ * Returns transport type to user
+ *
+ * @return string Transport type
+ */
+ public function getTransport()
+ {
+ return $this->getConfig('transport');
+ }
+
+ /**
+ * Adds a HTTP Header
+ *
+ * @param string $header The HTTP Header
+ * @param string $headerValue The HTTP Header Value
+ * @throws Elastica_Exception_Invalid If $header or $headerValue is not a string
+ */
+ public function addHeader($header, $headerValue)
+ {
+ if (is_string($header) && is_string($headerValue)) {
+ $this->_config['headers'][$header] = $headerValue;
+ } else {
+ throw new Elastica_Exception_Invalid('Header must be a string');
+ }
+ }
+
+ /**
+ * Remove a HTTP Header
+ *
+ * @param string $header The HTTP Header to remove
+ * @throws Elastica_Exception_Invalid IF $header is not a string
+ */
+ public function removeHeader($header)
+ {
+ if (is_string($header)) {
+ if (array_key_exists($header, $this->_config['headers'])) {
+ unset($this->_config['headers'][$header]);
+ }
+ } else {
+ throw new Elastica_Exception_Invalid('Header must be a string');
+ }
+ }
+
+ /**
+ * Uses _bulk to send documents to the server
+ *
+ * Array of Elastica_Document as input. Index and type has to be
+ * set inside the document, because for bulk settings documents,
+ * documents can belong to any type and index
+ *
+ * @param array $docs Array of Elastica_Document
+ * @return Elastica_Response Response object
+ * @throws Elastica_Exception_Invalid If docs is empty
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/
+ */
+ public function addDocuments(array $docs)
+ {
+ if (empty($docs)) {
+ throw new Elastica_Exception_Invalid('Array has to consist of at least one element');
+ }
+ $params = array();
+
+ foreach ($docs as $doc) {
+
+ $indexInfo = array(
+ '_index' => $doc->getIndex(),
+ '_type' => $doc->getType(),
+ '_id' => $doc->getId()
+ );
+
+ $version = $doc->getVersion();
+ if (!empty($version)) {
+ $indexInfo['_version'] = $version;
+ }
+
+ $parent = $doc->getParent();
+ if (!is_null($parent)) {
+ $indexInfo['_parent'] = $parent;
+ }
+
+ $percolate = $doc->getPercolate();
+ if (!empty($percolate)) {
+ $indexInfo['percolate'] = $percolate;
+ }
+
+ $params[] = array('index' => $indexInfo);
+ $params[] = $doc->getData();
+ }
+
+ return $this->bulk($params);
+ }
+
+ /**
+ * Update document, using update script. Requires elasticsearch >= 0.19.0
+ *
+ * @param int $id document id
+ * @param Elastica_Script $script script to use for update
+ * @param string $index index to update
+ * @param string $type type of index to update
+ * @param array $options array of query params to use for query. For possible options check es api
+ * @return Elastica_Response
+ * @link http://www.elasticsearch.org/guide/reference/api/update.html
+ */
+ public function updateDocument($id, Elastica_Script $script, $index, $type, array $options = array())
+ {
+ $path = $index . '/' . $type . '/' . $id . '/_update';
+ if (!isset($options['retry_on_conflict'])) {
+ $retryOnConflict = $this->getConfig("retryOnConflict");
+ $options['retry_on_conflict'] = $retryOnConflict;
+ }
+
+ $data = array(
+ 'script' => $script->getScript(),
+ );
+ if ($script->getLang() != null) {
+ $data['lang'] = $script->getLang();
+ }
+ if ($script->getParams() != null) {
+ $data['params'] = $script->getParams();
+ }
+
+ return $this->request($path, Elastica_Request::POST, $data, $options);
+ }
+
+ /**
+ * Bulk deletes documents (not implemented yet)
+ *
+ * @param array $docs Docs
+ * @throws Elastica_Exception
+ */
+ public function deleteDocuments(array $docs)
+ {
+ // TODO: similar to delete ids but with type and index inside files
+ throw new Elastica_Exception_NotImplemented('not implemented yet');
+ }
+
+ /**
+ * Returns the status object for all indices
+ *
+ * @return Elastica_Status Status object
+ */
+ public function getStatus()
+ {
+ return new Elastica_Status($this);
+ }
+
+ /**
+ * Returns the current cluster
+ *
+ * @return Elastica_Cluster Cluster object
+ */
+ public function getCluster()
+ {
+ return new Elastica_Cluster($this);
+ }
+
+ /**
+ * Deletes documents with the given ids, index, type from the index
+ *
+ * @param array $ids Document ids
+ * @param string|Elastica_Index $index Index name
+ * @param string|Elastica_Type $type Type of documents
+ * @return Elastica_Response Response object
+ * @throws Elastica_Exception If ids is empty
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/
+ */
+ public function deleteIds(array $ids, $index, $type)
+ {
+ if (empty($ids)) {
+ throw new Elastica_Exception_Invalid('Array has to consist of at least one id');
+ }
+
+ if ($index instanceof Elastica_Index) {
+ $index = $index->getName();
+ }
+
+ if ($type instanceof Elastica_Type) {
+ $type = $type->getName();
+ }
+
+ $params = array();
+ foreach ($ids as $id) {
+ $action = array(
+ 'delete' => array(
+ '_index' => $index,
+ '_type' => $type,
+ '_id' => $id,
+ )
+ );
+
+ $params[] = $action;
+ }
+
+ return $this->bulk($params);
+ }
+
+ /**
+ * Bulk operation
+ *
+ * Every entry in the params array has to exactly on array
+ * of the bulk operation. An example param array would be:
+ *
+ * array(
+ * array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
+ * array('user' => array('name' => 'hans')),
+ * array('delete' => array('_index' => 'test', '_type' => 'user', '_id' => '2'))
+ * );
+ *
+ * @param array $params Parameter array
+ * @return Elastica_Response Reponse object
+ * @todo Test
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/
+ */
+ public function bulk(array $params)
+ {
+ if (empty($params)) {
+ throw new Elastica_Exception_Invalid('Array has to consist of at least one param');
+ }
+
+ $path = '_bulk';
+
+ $queryString = '';
+ foreach ($params as $index => $baseArray) {
+ // Always newline needed
+ $queryString .= json_encode($baseArray) . PHP_EOL;
+ }
+
+ $response = $this->request($path, Elastica_Request::PUT, $queryString);
+ $data = $response->getData();
+
+ if (isset($data['items'])) {
+ foreach ($data['items'] as $item) {
+ $params = reset($item);
+ if (isset($params['error'])) {
+ throw new Elastica_Exception_BulkResponse($response);
+ }
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Makes calls to the elasticsearch server based on this index
+ *
+ * It's possible to make any REST query directly over this method
+ *
+ * @param string $path Path to call
+ * @param string $method Rest method to use (GET, POST, DELETE, PUT)
+ * @param array $data OPTIONAL Arguments as array
+ * @param array $query OPTIONAL Query params
+ * @return Elastica_Response Response object
+ */
+ public function request($path, $method, $data = array(), array $query = array())
+ {
+ $request = new Elastica_Request($this, $path, $method, $data, $query);
+
+ return $request->send();
+ }
+
+ /**
+ * Optimizes all search indices
+ *
+ * @param array $args OPTIONAL Optional arguments
+ * @return Elastica_Response Response object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/optimize/
+ */
+ public function optimizeAll($args = array())
+ {
+ return $this->request('_optimize', Elastica_Request::POST, $args);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Cluster.php b/modules/thirdparty/elastica/lib/Elastica/Cluster.php
new file mode 100755
index 0000000..a7aa915
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Cluster.php
@@ -0,0 +1,160 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/cluster
+ */
+class Elastica_Cluster
+{
+ /**
+ * Client
+ *
+ * @var Elastica_Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Creates a cluster object
+ *
+ * @param Elastica_Client $client Connection client object
+ */
+ public function __construct(Elastica_Client $client)
+ {
+ $this->_client = $client;
+ $this->refresh();
+ }
+
+ /**
+ * Refreshs all cluster information (state)
+ */
+ public function refresh()
+ {
+ $path = '_cluster/state';
+ $this->_response = $this->_client->request($path, Elastica_Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+
+ /**
+ * Returns the response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Return list of index names
+ *
+ * @return array List of index names
+ */
+ public function getIndexNames()
+ {
+ $metaData = $this->_data['metadata']['indices'];
+
+ $indices = array();
+ foreach ($metaData as $key => $value) {
+ $indices[] = $key;
+ }
+
+ return $indices;
+ }
+
+ /**
+ * Returns the full state of the cluster
+ *
+ * @return array State array
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-state.html
+ */
+ public function getState()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns a list of existing node names
+ *
+ * @return array List of node names
+ */
+ public function getNodeNames()
+ {
+ $data = $this->getState();
+
+ return array_keys($data['routing_nodes']['nodes']);
+ }
+
+ /**
+ * Returns all nodes of the cluster
+ *
+ * @return array List of Elastica_Node objects
+ */
+ public function getNodes()
+ {
+ $nodes = array();
+ foreach ($this->getNodeNames() as $name) {
+ $nodes[] = new Elastica_Node($name, $this->getClient());
+ }
+
+ return $nodes;
+ }
+
+ /**
+ * Returns the client object
+ *
+ * @return Elastica_Client Client object
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Returns the cluster information (not implemented yet)
+ *
+ * @param array $args Additional arguemtns
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/cluster/nodes_info/
+ */
+ public function getInfo(array $args)
+ {
+ throw new Exception('not implemented yet');
+ }
+
+ /**
+ * Return Cluster health
+ *
+ * @param array $args OPTIONAL
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/cluster/health/
+ */
+ public function getHealth($args = array())
+ {
+ throw new Exception('not implemented yet');
+ }
+
+ /**
+ * Return Cluster settings
+ *
+ * @return Elastica_Cluster_Settings
+ */
+ public function getSettings()
+ {
+ return new Elastica_Cluster_Settings($this->getClient());
+ }
+
+ /**
+ * Shuts down the complete cluster
+ *
+ * @param string $delay OPTIONAL Seconds to shutdown cluster after (default = 1s)
+ * @return Elastica_Response
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown.html
+ */
+ public function shutdown($delay = '1s')
+ {
+ $path = '_shutdown?delay=' . $delay;
+
+ return $this->_client->request($path, Elastica_Request::POST);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Cluster/Settings.php b/modules/thirdparty/elastica/lib/Elastica/Cluster/Settings.php
new file mode 100644
index 0000000..927bbe0
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Cluster/Settings.php
@@ -0,0 +1,179 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-update-settings.html
+ */
+class Elastica_Cluster_Settings
+{
+ /**
+ * Client
+ *
+ * @var Elastica_Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Creates a cluster object
+ *
+ * @param Elastica_Client $client Connection client object
+ */
+ public function __construct(Elastica_Client $client)
+ {
+ $this->_client = $client;
+ }
+
+ /**
+ * Returns settings data
+ *
+ * @return array Settings data (persistent and transient)
+ */
+ public function get()
+ {
+ return $this->request()->getData();
+ }
+
+ /**
+ * Returns the current persistent settings of the cluster
+ *
+ * If param is set, only specified setting is return.
+ *
+ * @param string $setting OPTIONAL Setting name to return
+ * @return array|string|null Settings data
+ */
+ public function getPersistent($setting = '')
+ {
+ $data = $this->get();
+ $settings = $data['persistent'];
+
+ if (!empty($setting)) {
+ if (isset($settings[ $setting])) {
+ return $settings[$setting];
+ } else {
+ return null;
+ }
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Returns the current transient settings of the cluster
+ *
+ * If param is set, only specified setting is return.
+ *
+ * @param string $setting OPTIONAL Setting name to return
+ * @return array|string|null Settings data
+ */
+ public function getTransient($setting = '')
+ {
+ $data = $this->get();
+ $settings = $data['transient'];
+
+ if (!empty($setting)) {
+ if (isset($settings[ $setting])) {
+ return $settings[$setting];
+ } else {
+ return null;
+ }
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Sets persistent setting
+ *
+ * @param string $key
+ * @param string $value
+ * @return Elastica_Response
+ */
+ public function setPersistent($key, $value)
+ {
+ return $this->set(
+ array(
+ 'persistent' => array(
+ $key => $value
+ )
+ )
+ );
+ }
+
+ /**
+ * Sets transient settings
+ *
+ * @param string $key
+ * @param string $value
+ * @return Elastica_Response
+ */
+ public function setTransient($key, $value)
+ {
+ return $this->set(
+ array(
+ 'transient' => array(
+ $key => $value
+ )
+ )
+ );
+ }
+
+ /**
+ * Sets the cluster to read only
+ *
+ * Second param can be used to set it persistent
+ *
+ * @param bool $readOnly
+ * @param bool $persistent
+ * @return Elastica_Response $response
+ */
+ public function setReadOnly($readOnly = true, $persistent = false)
+ {
+ $key = 'cluster.blocks.read_only';
+
+ if ($persistent) {
+ $response = $this->setPersistent($key, $readOnly);
+ } else {
+ $response = $this->setTransient($key, $readOnly);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Set settings for cluster
+ *
+ * @param array $settings Raw settings (including persistent or transient)
+ * @return Elastica_Response
+ */
+ public function set(array $settings)
+ {
+ return $this->request($settings, Elastica_Request::PUT);
+ }
+
+ /**
+ * Get the client
+ *
+ * @return Elastica_Client
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Sends settings request
+ *
+ * @param array $data OPTIONAL Data array
+ * @param string $method OPTIONAL Transfer method (default = Elastica_Request::GET)
+ * @return Elastica_Response Response object
+ */
+ public function request(array $data = array(), $method = Elastica_Request::GET)
+ {
+ $path = '_cluster/settings';
+
+ return $this->getClient()->request($path, $method, $data);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Document.php b/modules/thirdparty/elastica/lib/Elastica/Document.php
new file mode 100644
index 0000000..2bb13ae
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Document.php
@@ -0,0 +1,390 @@
+
+ */
+class Elastica_Document
+{
+ /**
+ * Document id
+ *
+ * @var string|int Document id
+ */
+ protected $_id = '';
+
+ /**
+ * Document data
+ *
+ * @var array Document data
+ */
+ protected $_data = array();
+
+ /**
+ * Document type name
+ *
+ * @var string Document type name
+ */
+ protected $_type = null;
+
+ /**
+ * Document index name
+ *
+ * @var string Document index name
+ */
+ protected $_index = null;
+
+ /**
+ * Document version
+ *
+ * @var string Document version
+ */
+ protected $_version = '';
+
+ /**
+ * Parent document id
+ *
+ * @var string|int Parent document id
+ */
+ protected $_parent = null;
+
+ /**
+ * Optype
+ *
+ * @var string Optype
+ */
+ protected $_optype = '';
+
+ /**
+ * Percolate
+ *
+ * @var string Percolate
+ */
+ protected $_percolate = '';
+
+ /**
+ * Creates a new document
+ *
+ * @param int $id OPTIONAL $id Id is create if empty
+ * @param array $data OPTIONAL Data array
+ * @param string $type OPTIONAL Type name
+ * @param string $index OPTIONAL Index name
+ */
+ public function __construct($id = '', array $data = array(), $type = '', $index = '')
+ {
+ $this->_id = $id;
+ $this->setData($data);
+ $this->setType($type);
+ $this->setIndex($index);
+ }
+
+ /**
+ * Returns document id
+ *
+ * @return string|int Document id
+ */
+ public function getId()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * Adds the given key/value pair to the document
+ *
+ * @param string $key Document entry key
+ * @param mixed $value Document entry value
+ * @return Elastica_Document
+ */
+ public function add($key, $value)
+ {
+ $this->_data[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Adds a file to the index
+ *
+ * To use this feature you have to call the following command in the
+ * elasticsearch directory:
+ *
+ * ./bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/1.2.0
+ *
+ * This installs the tika file analysis plugin. More infos about supported formats
+ * can be found here: {@link http://tika.apache.org/0.7/formats.html}
+ *
+ * @param string $key Key to add the file to
+ * @param string $filepath Path to add the file
+ * @param string $mimeType OPTIONAL Header mime type
+ * @return Elastica_Document
+ */
+ public function addFile($key, $filepath, $mimeType = '')
+ {
+ $value = base64_encode(file_get_contents($filepath));
+
+ if (!empty($mimeType)) {
+ $value = array('_content_type' => $mimeType, '_name' => $filepath, 'content' => $value,);
+ }
+
+ $this->add($key, $value);
+
+ return $this;
+ }
+
+ /**
+ * Add file content
+ *
+ * @param string $key Document key
+ * @param string $content Raw file content
+ * @return Elastica_Document
+ */
+ public function addFileContent($key, $content)
+ {
+ return $this->add($key, base64_encode($content));
+ }
+
+ /**
+ * Adds a geopoint to the document
+ *
+ * Geohashes re not yet supported
+ *
+ * @param string $key Field key
+ * @param float $latitude Latitud value
+ * @param float $longitude Longitude value
+ * @link http://www.elasticsearch.com/docs/elasticsearch/mapping/geo_point/
+ * @return Elastica_Document
+ */
+ public function addGeoPoint($key, $latitude, $longitude)
+ {
+ $value = array('lat' => $latitude, 'lon' => $longitude,);
+
+ $this->add($key, $value);
+
+ return $this;
+ }
+
+ /**
+ * Overwrites the curent document data with the given data
+ *
+ * @param array $data Data array
+ * @return Elastica_Document
+ */
+ public function setData(array $data)
+ {
+ $this->_data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Sets lifetime of document
+ *
+ * @param string $ttl
+ * @return Elastica_Document
+ */
+ public function setTtl($ttl)
+ {
+ return $this->add('_ttl', $ttl);
+ }
+
+ /**
+ * Returns the document data
+ *
+ * @return array Document data
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Sets the document type name
+ *
+ * @param string $type Type name
+ * @return Elastica_Document Current object
+ */
+ public function setType($type)
+ {
+ $this->_type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Return document type name
+ *
+ * @return string Document type name
+ * @throws Elastica_Exception_Invalid
+ */
+ public function getType()
+ {
+ $type = $this->_type;
+
+ if (is_null($type)) {
+ throw new Elastica_Exception_Invalid('Type not set');
+ }
+
+ return $type;
+ }
+
+ /**
+ * Sets the document index name
+ *
+ * @param string $index Index name
+ * @return Elastica_Document Current object
+ */
+ public function setIndex($index)
+ {
+ $this->_index = $index;
+
+ return $this;
+ }
+
+ /**
+ * Get the document index name
+ *
+ * @return string Index name
+ * @throws Elastica_Exception_Invalid
+ */
+ public function getIndex()
+ {
+ $index = $this->_index;
+
+ if (is_null($index)) {
+ throw new Elastica_Exception_Invalid('Index not set');
+ }
+
+ return $index;
+ }
+
+ /**
+ * Sets the version of a document for use with optimistic concurrency control
+ *
+ * @param int $version Document version
+ * @return Elastica_Document Current object
+ * @link http://www.elasticsearch.org/blog/2011/02/08/versioning.html
+ */
+ public function setVersion($version)
+ {
+ if ($version !== '') {
+ $this->_version = (int) $version;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns document version
+ *
+ * @return string|int Document version
+ */
+ public function getVersion()
+ {
+ return $this->_version;
+ }
+
+ /**
+ * Sets parent document id
+ *
+ * @param string|int $parent Parent document id
+ * @return Elastica_Document Current object
+ * @link http://www.elasticsearch.org/guide/reference/mapping/parent-field.html
+ */
+ public function setParent($parent)
+ {
+ $this->_parent = $parent;
+
+ return $this;
+ }
+
+ /**
+ * Returns the parent document id
+ *
+ * @return string|int Parent document id
+ */
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+
+ /**
+ * Set operation type
+ *
+ * @param string $optype Only accept create
+ * @return Elastica_Document Current object
+ */
+ public function setOpType($optype)
+ {
+ $this->_optype = $optype;
+
+ return $this;
+ }
+
+ /**
+ * Get operation type
+ */
+ public function getOpType()
+ {
+ return $this->_optype;
+ }
+
+ /**
+ * Set percolate query param
+ *
+ * @param string $value percolator filter
+ * @return Elastica_Document
+ */
+ public function setPercolate($value = '*')
+ {
+ $this->_percolate = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get percolate parameter
+ *
+ * @return string
+ */
+ public function getPercolate()
+ {
+ return $this->_percolate;
+ }
+
+ /**
+ * Returns the document as an array
+ * @return array
+ */
+ public function toArray()
+ {
+ $doc = array();
+
+ if (!is_null($this->_index)) {
+ $doc['_index'] = $this->_index;
+ }
+
+ if (!is_null($this->_type)) {
+ $doc['_type'] = $this->_type;
+ }
+
+ if (!is_null($this->_index)) {
+ $doc['_id'] = $this->getId();
+ }
+
+ $version = $this->getVersion();
+ if (!empty($version)) {
+ $doc['_version'] = $version;
+ }
+
+ $parent = $this->getParent();
+ if (!is_null($parent)) {
+ $doc['_parent'] = $parent;
+ }
+
+ $doc['_source'] = $this->getData();
+
+ return $doc;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Abstract.php
new file mode 100755
index 0000000..08d28eb
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Abstract.php
@@ -0,0 +1,11 @@
+
+ */
+abstract class Elastica_Exception_Abstract extends Exception
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/BulkResponse.php b/modules/thirdparty/elastica/lib/Elastica/Exception/BulkResponse.php
new file mode 100644
index 0000000..873cca1
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Exception/BulkResponse.php
@@ -0,0 +1,66 @@
+_response = $response;
+ parent::__construct('Error in one or more bulk request actions');
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Returns array of failed actions
+ *
+ * @return array Array of failed actions
+ */
+ public function getFailures()
+ {
+ $data = $this->_response->getData();
+ $errors = array();
+
+ foreach ($data['items'] as $item) {
+ $meta = reset($item);
+ $action = key($item);
+ if (isset($meta['error'])) {
+ $error = array(
+ 'action' => $action,
+ );
+ foreach ($meta as $key => $value) {
+ $key = ltrim($key, '_');
+ $error[$key] = $value;
+ }
+
+ $errors[] = $error;
+ }
+ }
+
+ return $errors;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Client.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Client.php
new file mode 100755
index 0000000..e8e2480
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Client.php
@@ -0,0 +1,117 @@
+
+ */
+class Elastica_Exception_Client extends Elastica_Exception_Abstract
+{
+ /**
+ * Error code / message
+ *
+ * @var string Error code / message
+ */
+ protected $_error = 0;
+
+ /**
+ * Request
+ *
+ * @var Elastica_Request Request object
+ */
+ protected $_request = null;
+
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Construct Exception
+ *
+ * @param string $error Error
+ * @param Elastica_Request $request
+ * @param Elastica_Response $response
+ */
+ public function __construct($error, Elastica_Request $request = null, Elastica_Response $response = null)
+ {
+ $this->_error = $error;
+ $this->_request = $request;
+ $this->_response = $response;
+
+ $message = $this->getErrorMessage($this->getError());
+ parent::__construct($message);
+ }
+
+ /**
+ * Returns the error message corresponding to the error code
+ * cUrl error code reference can be found here {@link http://curl.haxx.se/libcurl/c/libcurl-errors.html}
+ *
+ * @param string $error Error code
+ * @return string Error message
+ */
+ public function getErrorMessage($error)
+ {
+ switch ($error) {
+ case CURLE_UNSUPPORTED_PROTOCOL:
+ $error = "Unsupported protocol";
+ break;
+ case CURLE_FAILED_INIT:
+ $error = "Internal cUrl error?";
+ break;
+ case CURLE_URL_MALFORMAT:
+ $error = "Malformed URL";
+ break;
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ $error = "Couldnt resolve proxy";
+ break;
+ case CURLE_COULDNT_RESOLVE_HOST:
+ $error = "Couldnt resolve host";
+ break;
+ case CURLE_COULDNT_CONNECT:
+ $error = "Couldnt connect to host, ElasticSearch down?";
+ break;
+ case 28:
+ $error = "Operation timed out";
+ break;
+ default:
+ $error = "Unknown error:" . $error;
+ break;
+ }
+
+ return $error;
+ }
+
+ /**
+ * Return Error code / message
+ *
+ * @return string Error code / message
+ */
+ public function getError()
+ {
+ return $this->_error;
+ }
+
+ /**
+ * Returns request object
+ *
+ * @return Elastica_Transport_Abstract Request object
+ */
+ public function getRequest()
+ {
+ return $this->_request;
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Invalid.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Invalid.php
new file mode 100755
index 0000000..eefb3fe
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Invalid.php
@@ -0,0 +1,11 @@
+
+ */
+class Elastica_Exception_Invalid extends Elastica_Exception_Abstract
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/NotFound.php b/modules/thirdparty/elastica/lib/Elastica/Exception/NotFound.php
new file mode 100644
index 0000000..91152c2
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Exception/NotFound.php
@@ -0,0 +1,11 @@
+
+ */
+class Elastica_Exception_NotFound extends Elastica_Exception_Abstract
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/NotImplemented.php b/modules/thirdparty/elastica/lib/Elastica/Exception/NotImplemented.php
new file mode 100755
index 0000000..680f6e4
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Exception/NotImplemented.php
@@ -0,0 +1,13 @@
+
+ */
+class Elastica_Exception_NotImplemented extends Elastica_Exception_Abstract
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Response.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Response.php
new file mode 100755
index 0000000..c2677a1
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Response.php
@@ -0,0 +1,38 @@
+
+ */
+class Elastica_Exception_Response extends Elastica_Exception_Abstract
+{
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Construct Exception
+ *
+ * @param Elastica_Response $response
+ */
+ public function __construct(Elastica_Response $response)
+ {
+ $this->_response = $response;
+ parent::__construct($response->getError());
+ }
+
+ /**
+ * Returns reponsce object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Abstract.php
new file mode 100644
index 0000000..8317eee
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Abstract.php
@@ -0,0 +1,134 @@
+
+ * @author Jasper van Wanrooy
+ */
+abstract class Elastica_Facet_Abstract extends Elastica_Param
+{
+ /**
+ * Holds the name of the facet.
+ * @var string
+ */
+ protected $_name = '';
+
+ /**
+ * Holds all facet parameters.
+ * @var array
+ */
+ protected $_facet = array();
+
+ /**
+ * Constructs a Facet object.
+ *
+ * @param string $name The name of the facet.
+ */
+ public function __construct($name)
+ {
+ $this->setName($name);
+ }
+
+ /**
+ * Sets the name of the facet. It is automatically set by
+ * the constructor.
+ *
+ * @param string $name The name of the facet.
+ * @throws Elastica_Exception_Invalid
+ * @return Elastica_Facet_Abstract
+ */
+ public function setName($name)
+ {
+ if (empty($name)) {
+ throw new Elastica_Exception_Invalid('Facet name has to be set');
+ }
+ $this->_name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Gets the name of the facet.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Sets a filter for this facet.
+ *
+ * @param Elastica_Filter_Abstract $filter A filter to apply on the facet.
+ * @return Elastica_Facet_Abstract
+ */
+ public function setFilter(Elastica_Filter_Abstract $filter)
+ {
+ return $this->_setFacetParam('facet_filter', $filter->toArray());
+ }
+
+ /**
+ * Sets the flag to either run the facet globally or bound to the
+ * current search query. When not set, it defaults to the
+ * ElasticSearch default value.
+ *
+ * @param bool $global Flag to either run the facet globally.
+ * @return Elastica_Facet_Abstract
+ */
+ public function setGlobal($global = true)
+ {
+ return $this->_setFacetParam('global', (bool) $global);
+ }
+
+ /**
+ * Sets the path to the nested document
+ *
+ * @param string $nestedPath Nested path
+ * @return Elastica_Facet_Abstract
+ */
+ public function setNested($nestedPath)
+ {
+ return $this->_setFacetParam('nested', $nestedPath);
+ }
+
+ /**
+ * Sets the scope
+ *
+ * @param string $scope Scope
+ * @return Elastica_Facet_Abstract
+ */
+ public function setScope($scope)
+ {
+ return $this->_setFacetParam('scope', $scope);
+ }
+
+ /**
+ * Basic definition of all specs of the facet. Each implementation
+ * should override this function in order to set it's specific
+ * settings.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->_facet;
+ }
+
+ /**
+ * Sets a param for the facet. Each facet implementation needs to take
+ * care of handling their own params.
+ *
+ * @param string $key The key of the param to set.
+ * @param mixed $value The value of the param.
+ * @return Elastica_Facet_Abstract
+ */
+ protected function _setFacetParam($key, $value)
+ {
+ $this->_facet[$key] = $value;
+
+ return $this;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/DateHistogram.php b/modules/thirdparty/elastica/lib/Elastica/Facet/DateHistogram.php
new file mode 100644
index 0000000..c9856b5
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/DateHistogram.php
@@ -0,0 +1,41 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/search/facets/date-histogram-facet.html
+ * @link https://github.com/elasticsearch/elasticsearch/issues/591
+ */
+class Elastica_Facet_DateHistogram extends Elastica_Facet_Histogram
+{
+ /**
+ * Set the time_zone parameter
+ *
+ * @param string $tzOffset
+ * @return void
+ */
+ public function setTimezone($tzOffset)
+ {
+ return $this->setParam('time_zone', $tzOffset);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see Elastica_Facet_Abstract::toArray()
+ * @throws Elastica_Exception_Invalid When the right fields haven't been set.
+ * @return array
+ */
+ public function toArray()
+ {
+ /**
+ * Set the range in the abstract as param.
+ */
+ $this->_setFacetParam('date_histogram', $this->_params);
+
+ return $this->_facet;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Filter.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Filter.php
new file mode 100644
index 0000000..65356fa
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Filter.php
@@ -0,0 +1,22 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/search/facets/filter-facet.html
+ */
+class Elastica_Facet_Filter extends Elastica_Facet_Abstract
+{
+ /**
+ * Set the filter for the facet.
+ *
+ * @param Elastica_Filter_Abstract $filter
+ * @return Elastica_Facet_Filter
+ */
+ public function setFilter(Elastica_Filter_Abstract $filter)
+ {
+ return $this->_setFacetParam('filter', $filter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/GeoDistance.php b/modules/thirdparty/elastica/lib/Elastica/Facet/GeoDistance.php
new file mode 100644
index 0000000..ec4288a
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/GeoDistance.php
@@ -0,0 +1,63 @@
+
+ * @linkhttp://www.elasticsearch.org/guide/reference/api/search/facets/geo-distance-facet.html
+ */
+class Elastica_Facet_GeoDistance extends Elastica_Facet_Abstract
+{
+ /**
+ * Sets the ranges for the facet all at once.
+ * Sample ranges:
+ * array (
+ * array('to' => 50),
+ * array('from' => 20, 'to' => 70),
+ * array('from' => 70, 'to' => 120),
+ * array('from' => 150)
+ * )
+ *
+ * @param array $ranges Numerical array with range definitions.
+ * @return Elastica_Facet_GeoDistance
+ */
+ public function setRanges(array $ranges)
+ {
+ return $this->setParam ( 'ranges', $ranges );
+ }
+
+ /**
+ * Set the relative GeoPoint for the facet.
+ *
+ * @param string $typeField index type and field e.g foo.bar
+ * @param float $latitude
+ * @param float $longitude
+ * @return Elastica_Facet_GeoDistance
+ */
+ public function setGeoPoint($typeField, $latitude, $longitude)
+ {
+ return $this->setParam ( $typeField, array (
+ "lat" => $latitude,
+ "lon" => $longitude
+ ) );
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see Elastica_Facet_Abstract::toArray()
+ * @throws Elastica_Exception_Invalid When the right fields haven't been set.
+ * @return array
+ */
+ public function toArray()
+ {
+ /**
+ * Set the geo_distance in the abstract as param.
+ */
+ $this->_setFacetParam ( 'geo_distance', $this->_params );
+
+ return parent::toArray ();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Histogram.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Histogram.php
new file mode 100644
index 0000000..b721353
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Histogram.php
@@ -0,0 +1,86 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/search/facets/histogram-facet.html
+ */
+class Elastica_Facet_Histogram extends Elastica_Facet_Abstract
+{
+ /**
+ * Sets the field for histogram
+ *
+ * @param string $field The name of the field for the historgram
+ * @return Elastica_Facet_Histogram
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Set the value for interval
+ *
+ * @param string $interval
+ * @return Elastica_Facet_Range
+ */
+ public function setInterval($interval)
+ {
+ return $this->setParam('interval', $interval);
+ }
+
+ /**
+ * Set the fields for key_field and value_field
+ *
+ * @param string $keyField Key field
+ * @param string $valueField Value field
+ * @return Elastica_Facet_Range
+ */
+ public function setKeyValueFields($keyField, $valueField)
+ {
+ return $this->setParam('key_field', $keyField)->setParam('value_field', $valueField);
+ }
+
+ /**
+ * Sets the key and value for this facet by script.
+ *
+ * @param string $keyScript Script to check whether it falls into the range.
+ * @param string $valueScript Script to use for statistical calculations.
+ */
+ public function setKeyValueScripts($keyScript, $valueScript)
+ {
+ return $this->setParam('key_script', $keyScript)
+ ->setParam('value_script', $valueScript);
+ }
+
+ /**
+ * Set the "params" essential to the a script
+ *
+ * @param array $params Associative array (key/value pair)
+ * @return Elastica_Facet_Histogram Facet object
+ */
+ public function setScriptParams(array $params)
+ {
+ return $this->setParam('params', $params);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see Elastica_Facet_Abstract::toArray()
+ * @throws Elastica_Exception_Invalid When the right fields haven't been set.
+ * @return array
+ */
+ public function toArray()
+ {
+ /**
+ * Set the range in the abstract as param.
+ */
+ $this->_setFacetParam('histogram', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Query.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Query.php
new file mode 100644
index 0000000..4e49bdc
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Query.php
@@ -0,0 +1,22 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/search/facets/query-facet.html
+ */
+class Elastica_Facet_Query extends Elastica_Facet_Abstract
+{
+ /**
+ * Set the query for the facet.
+ *
+ * @param Elastica_Query_Abstract $query
+ * @return Elastica_Facet_Query
+ */
+ public function setQuery(Elastica_Query_Abstract $query)
+ {
+ return $this->_setFacetParam('query', $query->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Range.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Range.php
new file mode 100644
index 0000000..6d7a5b1
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Range.php
@@ -0,0 +1,124 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/search/facets/range-facet.html
+ */
+class Elastica_Facet_Range extends Elastica_Facet_Abstract
+{
+ /**
+ * Sets the field for the range.
+ *
+ * @param string $field The name of the field for range.
+ * @return Elastica_Facet_Range
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Sets the fields by their separate key and value fields.
+ *
+ * @param string $keyField The key_field param for the range.
+ * @param string $valueField The key_value param for the range.
+ * @return Elastica_Facet_Range
+ */
+ public function setKeyValueFields($keyField, $valueField)
+ {
+ return $this->setParam('key_field', $keyField)
+ ->setParam('value_field', $valueField);
+ }
+
+ /**
+ * Sets the key and value for this facet by script.
+ *
+ * @param string $keyScript Script to check whether it falls into the range.
+ * @param string $valueScript Script to use for statistical calculations.
+ */
+ public function setKeyValueScripts($keyScript, $valueScript)
+ {
+ return $this->setParam('key_script', $keyScript)
+ ->setParam('value_script', $valueScript);
+ }
+
+ /**
+ * Sets the ranges for the facet all at once. Sample ranges:
+ * array (
+ * array('to' => 50),
+ * array('from' => 20, 'to' 70),
+ * array('from' => 70, 'to' => 120),
+ * array('from' => 150)
+ * )
+ *
+ * @param array $ranges Numerical array with range definitions.
+ * @return Elastica_Facet_Range
+ */
+ public function setRanges(array $ranges)
+ {
+ return $this->setParam('ranges', $ranges);
+ }
+
+ /**
+ * Adds a range to the range facet.
+ *
+ * @param mixed $from The from for the range.
+ * @param mixed $to The to for the range.
+ * @return Elastica_Facet_Range
+ */
+ public function addRange($from = null, $to = null)
+ {
+ if (!isset($this->_params['ranges']) || !is_array($this->_params['ranges'])) {
+ $this->_params['ranges'] = array();
+ }
+
+ $this->_params['ranges'][] = array('from' => $from, 'to' => $to);
+
+ return $this;
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see Elastica_Facet_Abstract::toArray()
+ * @throws Elastica_Exception_Invalid When the right fields haven't been set.
+ * @return array
+ */
+ public function toArray()
+ {
+ /**
+ * Check the facet for validity.
+ * There are three ways to set the key and value field for the range:
+ * - a single field for both key and value; or
+ * - separate fields for key and value; or
+ * - separate scripts for key and value.
+ */
+ $fieldTypesSet = 0;
+ if (isset($this->_params['field'])) {
+ $fieldTypesSet++;
+ }
+ if (isset($this->_params['key_field'])) {
+ $fieldTypesSet++;
+ }
+ if (isset($this->_params['key_script'])) {
+ $fieldTypesSet++;
+ }
+
+ if ($fieldTypesSet === 0) {
+ throw new Elastica_Exception_Invalid('Neither field, key_field nor key_script is set.');
+ } elseif ($fieldTypesSet > 1) {
+ throw new Elastica_Exception_Invalid('Either field, key_field and key_value or key_script and value_script should be set.');
+ }
+
+ /**
+ * Set the range in the abstract as param.
+ */
+ $this->_setFacetParam('range', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Statistical.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Statistical.php
new file mode 100644
index 0000000..b0c2787
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Statistical.php
@@ -0,0 +1,58 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/search/facets/statistical-facet.html
+ */
+class Elastica_Facet_Statistical extends Elastica_Facet_Abstract
+{
+ /**
+ * Sets the field for the statistical query.
+ *
+ * @param string $field The field name for the statistical query.
+ * @return Elastica_Facet_Statistical
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Sets multiple fields for the statistical query.
+ *
+ * @param array $fields Numerical array with the fields for the statistical query.
+ * @return Elastica_Facet_Statistical
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Sets a script to calculate statistical information
+ *
+ * @param string $script The script to do calculations on the statistical values
+ * @return Elastica_Facet_Statistical
+ */
+ public function setScript($script)
+ {
+ return $this->setParam('script', $script);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see Elastica_Facet_Abstract::toArray()
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->_setFacetParam('statistical', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Terms.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Terms.php
new file mode 100644
index 0000000..d76d429
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Terms.php
@@ -0,0 +1,107 @@
+
+ * @author Jasper van Wanrooy
+ * @link http://www.elasticsearch.org/guide/reference/api/search/facets/terms-facet.html
+ */
+class Elastica_Facet_Terms extends Elastica_Facet_Abstract
+{
+ /**
+ * Holds the types of ordering which are allowed
+ * by ElasticSearch.
+ *
+ * @var array
+ */
+ protected $_orderTypes = array('count', 'term', 'reverse_count', 'reverse_term');
+
+ /**
+ * Sets the field for the terms.
+ *
+ * @param string $field The field name for the terms.
+ * @return Elastica_Facet_Terms
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Sets multiple fields for the terms.
+ *
+ * @param array $fields Numerical array with the fields for the terms.
+ * @return Elastica_Facet_Terms
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Sets the flag to return all available terms. When they
+ * don't have a hit, they have a count of zero.
+ *
+ * @param bool $allTerms Flag to fetch all terms.
+ * @return Elastica_Facet_Terms
+ */
+ public function setAllTerms($allTerms)
+ {
+ return $this->setParam('all_terms', (bool) $allTerms);
+ }
+
+ /**
+ * Sets the ordering type for this facet. ElasticSearch
+ * internal default is count.
+ *
+ * @param string $type The order type to set use for sorting of the terms.
+ * @throws Elastica_Exception_Invalid When an invalid order type was set.
+ * @return Elastica_Facet_Terms
+ */
+ public function setOrder($type)
+ {
+ if (!in_array($type, $this->_orderTypes)) {
+ throw new Elastica_Exception_Invalid('Invalid order type: ' . $type);
+ }
+
+ return $this->setParam('order', $type);
+ }
+
+ /**
+ * Set an array with terms which are omitted in the search.
+ *
+ * @param array $exclude Numerical array which includes all terms which needs to be ignored.
+ * @return Elastica_Facet_Terms
+ */
+ public function setExclude(array $exclude)
+ {
+ return $this->setParam('exclude', $exclude);
+ }
+
+ /**
+ * Sets the amount of terms to be returned.
+ *
+ * @param int $size The amount of terms to be returned.
+ * @return Elastica_Facet_Terms
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', (int) $size);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see Elastica_Facet_Abstract::toArray()
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->_setFacetParam('terms', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/TermsStats.php b/modules/thirdparty/elastica/lib/Elastica/Facet/TermsStats.php
new file mode 100644
index 0000000..7b4f2c4
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Facet/TermsStats.php
@@ -0,0 +1,60 @@
+
+ */
+class Elastica_Facet_TermsStats extends Elastica_Facet_Abstract
+{
+
+ /**
+ * Sets the key field for the query.
+ *
+ * @param string $keyField The key field name for the query.
+ * @return Elastica_Facet_TermsStats
+ */
+ public function setKeyField( $keyField )
+ {
+ return $this->setParam( 'key_field', $keyField );
+ }
+
+ /**
+ * Sets a script to calculate statistical information on a per term basis
+ *
+ * @param string $valueScript The script to do calculations on the statistical values
+ * @return Elastica_Facet_TermsStats
+ */
+ public function setValueScript( $valueScript )
+ {
+ return $this->setParam( 'value_script', $valueScript );
+ }
+
+ /**
+ * Sets a field to compute basic statistical results on
+ *
+ * @param string $valueField The field to compute statistical values for
+ * @return Elastica_Facet_TermsStats
+ */
+ public function setValueField( $valueField )
+ {
+ return $this->setParam( 'value_field', $valueField );
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see Elastica_Facet_Abstract::toArray()
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->_setFacetParam( 'terms_stats', $this->_params );
+
+ return parent::toArray();
+ }
+
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract.php
new file mode 100755
index 0000000..1c736b9
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract.php
@@ -0,0 +1,50 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/
+ */
+abstract class Elastica_Filter_Abstract extends Elastica_Param
+{
+ /**
+ * Sets the filter cache
+ *
+ * @param boolean $cached Cached
+ * @return Elastica_Filter_Abstract
+ */
+ public function setCached($cached = true)
+ {
+ return $this->setParam('_cache', (bool) $cached);
+ }
+
+ /**
+ * Sets the filter cache key
+ *
+ * @param string $cacheKey Cache key
+ * @return Elastica_Filter_Abstract
+ */
+ public function setCacheKey($cacheKey)
+ {
+ $cacheKey = (string) $cacheKey;
+
+ if (empty($cacheKey)) {
+ throw new Elastica_Exception_Invalid('Invalid parameter. Has to be a non empty string');
+ }
+
+ return $this->setParam('_cache_key', (string) $cacheKey);
+ }
+
+ /**
+ * Sets the filter name
+ *
+ * @param string $name Name
+ * @return Elastica_Filter_Abstract
+ */
+ public function setName($name)
+ {
+ return $this->setParam('_name', $name);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract/Multi.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract/Multi.php
new file mode 100644
index 0000000..30fb74a
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract/Multi.php
@@ -0,0 +1,67 @@
+
+ */
+abstract class Elastica_Filter_Abstract_Multi extends Elastica_Filter_Abstract
+{
+ /**
+ * Filters
+ * @var array
+ */
+ protected $_filters = array();
+
+ /**
+ * Add filter
+ *
+ * @param Elastica_Filter_Abstract $filter
+ * @return Elastica_Filter_Abstract_Multi
+ */
+ public function addFilter(Elastica_Filter_Abstract $filter)
+ {
+ $this->_filters[] = $filter->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Set filters
+ *
+ * @param array $filters
+ * @return Elastica_Filter_Abstract_Multi
+ */
+ public function setFilters(array $filters)
+ {
+ $this->_filters = array();
+
+ foreach ($filters as $filter) {
+ $this->addFilter($filter);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @see Elastica_Param::toArray()
+ */
+ public function toArray()
+ {
+ $data = parent::toArray();
+ $name = $this->_getBaseName();
+ $filterData = $data[$name];
+
+ if (empty($filterData)) {
+ $filterData = $this->_filters;
+ } else {
+ $filterData['filters'] = $this->_filters;
+ }
+
+ $data[$name] = $filterData;
+
+ return $data;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/And.php b/modules/thirdparty/elastica/lib/Elastica/Filter/And.php
new file mode 100644
index 0000000..ab226f8
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/And.php
@@ -0,0 +1,13 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/and-filter.html
+ */
+class Elastica_Filter_And extends Elastica_Filter_Abstract_Multi
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Bool.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Bool.php
new file mode 100755
index 0000000..8909a33
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Bool.php
@@ -0,0 +1,147 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/bool_query/
+ */
+class Elastica_Filter_Bool extends Elastica_Filter_Abstract
+{
+ /**
+ * minimum number of matches
+ *
+ * @var int minimum number of matches
+ */
+ protected $_minimumNumberShouldMatch = 1;
+
+ /**
+ * Must
+ *
+ * @var array
+ */
+ protected $_must = array();
+
+ /**
+ * Should
+ *
+ * @var array
+ */
+ protected $_should = array();
+
+ /**
+ * Must not
+ *
+ * @var array
+ */
+ protected $_mustNot = array();
+
+ /**
+ * Adds should filter
+ *
+ * @param array|Elastica_Filter_Abstract $args Filter data
+ * @return Elastica_Filter_Bool Current object
+ */
+ public function addShould($args)
+ {
+ return $this->_addFilter('should', $args);
+ }
+
+ /**
+ * Adds must filter
+ *
+ * @param array|Elastica_Filter_Abstract $args Filter data
+ * @return Elastica_Filter_Bool Current object
+ */
+ public function addMust($args)
+ {
+ return $this->_addFilter('must', $args);
+ }
+
+ /**
+ * Adds mustNot filter
+ *
+ * @param array|Elastica_Filter_Abstract $args Filter data
+ * @return Elastica_Filter_Bool Current object
+ */
+ public function addMustNot($args)
+ {
+ return $this->_addFilter('mustNot', $args);
+ }
+
+ /**
+ * Adds general filter based on type
+ *
+ * @param string $type Filter type
+ * @param array|Elastica_Filter_Abstract $args Filter data
+ * @return Elastica_Filter_Bool Current object
+ */
+ protected function _addFilter($type, $args)
+ {
+ if ($args instanceof Elastica_Filter_Abstract) {
+ $args = $args->toArray();
+ }
+
+ if (!is_array($args)) {
+ throw new Elastica_Exception_Invalid('Invalid parameter. Has to be array or instance of Elastica_Filter');
+ }
+
+ $varName = '_' . $type;
+ $this->{$varName}[] = $args;
+
+ return $this;
+ }
+
+ /**
+ * Converts bool filter to array
+ *
+ * @see Elastica_Filter_Abstract::toArray()
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ $args = array();
+
+ if (!empty($this->_must)) {
+ $args['must'] = $this->_must;
+ }
+
+ if (!empty($this->_should)) {
+ $args['should'] = $this->_should;
+ }
+
+ if (!empty($this->_mustNot)) {
+ $args['must_not'] = $this->_mustNot;
+ }
+
+ return array('bool' => $args);
+ }
+
+ /**
+ * Sets the boost value for this filter
+ *
+ * @param float $boost Boost
+ * @return Elastica_Filter_Bool Current object
+ */
+ public function setBoost($boost)
+ {
+ $this->_boost = $boost;
+
+ return $this;
+ }
+
+ /**
+ * Sets the minimum number that should filter have to match
+ *
+ * @param int $minimumNumberShouldMatch Number of matches
+ * @return Elastica_Filter_Bool Current object
+ */
+ public function setMinimumNumberShouldMatch($minimumNumberShouldMatch)
+ {
+ $this->_minimumNumberShouldMatch = intval($minimumNumberShouldMatch);
+
+ return $this;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Exists.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Exists.php
new file mode 100644
index 0000000..12006f2
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Exists.php
@@ -0,0 +1,33 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/exists-filter.html
+ */
+class Elastica_Filter_Exists extends Elastica_Filter_Abstract
+{
+ /**
+ * Construct exists filter
+ *
+ * @param string $field
+ */
+ public function __construct($field)
+ {
+ $this->setField($field);
+ }
+
+ /**
+ * Set field
+ *
+ * @param string $field
+ * @return Elastica_Filter_Exists
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/GeoBoundingBox.php b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoBoundingBox.php
new file mode 100755
index 0000000..9958572
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoBoundingBox.php
@@ -0,0 +1,46 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/geo_bounding_box_filter/
+ */
+class Elastica_Filter_GeoBoundingBox extends Elastica_Filter_Abstract
+{
+ /**
+ * Construct GeoBoundingBox filter
+ *
+ * @param string $key Key
+ * @param array $coordinates Array with top left coordinate as first and bottom right coordinate as second element
+ */
+ public function __construct($key, array $coordinates)
+ {
+ $this->addCoordinates($key, $coordinates);
+ }
+
+ /**
+ * Add coordinates
+ *
+ * @param string $key Key
+ * @param array $coordinates Array with top left coordinate as first and bottom right coordinate as second element
+ * @throws Elastica_Exception_Invalid If $coordinates doesn't have two elements
+ * @return Elastica_Filter_GeoBoundingBox Current object
+ */
+ public function addCoordinates($key, array $coordinates)
+ {
+ if (!isset($coordinates[0]) || !isset($coordinates[1])) {
+ throw new Elastica_Exception_Invalid('expected $coordinates to be an array with two elements');
+ }
+
+ $this->setParam($key, array(
+ 'top_left' => $coordinates[0],
+ 'bottom_right' => $coordinates[1]
+ ));
+
+ return $this;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/GeoDistance.php b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoDistance.php
new file mode 100755
index 0000000..fa2ac39
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoDistance.php
@@ -0,0 +1,242 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/geo-distance-filter.html
+ */
+class Elastica_Filter_GeoDistance extends Elastica_Filter_Abstract
+{
+ const DISTANCE_TYPE_ARC = 'arc';
+ const DISTANCE_TYPE_PLANE = 'plane';
+
+ const OPTIMIZE_BBOX_MEMORY = 'memory';
+ const OPTIMIZE_BBOX_INDEXED = 'indexed';
+ const OPTIMIZE_BBOX_NONE = 'none';
+
+ /**
+ * Location type
+ *
+ * Decides if this filter uses latitude/longitude or geohash for the location.
+ * Values are "latlon" or "geohash".
+ *
+ * @var string
+ */
+ private $_locationType = null;
+
+ /**
+ * Key
+ *
+ * @var string
+ */
+ private $_key = null;
+
+ /**
+ * Latitude
+ *
+ * @var float
+ */
+ private $_latitude = null;
+
+ /**
+ * Longitude
+ *
+ * @var float
+ */
+ private $_longitude = null;
+
+ /**
+ * Geohash
+ *
+ * @var string
+ */
+ private $_geohash = null;
+
+ /**
+ * Create GeoDistance object
+ *
+ * @param string $key Key
+ * @param array|string $location Location as array or geohash: array('lat' => 48.86, 'lon' => 2.35) OR 'drm3btev3e86'
+ * @param string $distance Distance
+ * @throws Elastica_Exception_Invalid
+ */
+ public function __construct($key, $location, $distance)
+ {
+ // Fix old constructor. Remove it when the old constructor is not supported anymore
+ if (func_num_args() === 4) {
+ extract($this->_oldConstruct(func_get_args()));
+ }
+
+ // Key
+ $this->setKey($key);
+
+ // Location
+ if (is_array($location)) { // Latitude/Longitude
+ // Latitude
+ if (isset($location['lat'])) {
+ $this->setLatitude($location['lat']);
+ } else {
+ throw new Elastica_Exception_Invalid('$location[\'lat\'] has to be set');
+ }
+
+ // Longitude
+ if (isset($location['lon'])) {
+ $this->setLongitude($location['lon']);
+ } else {
+ throw new Elastica_Exception_Invalid('$location[\'lon\'] has to be set');
+ }
+ } elseif (is_string($location)) { // Geohash
+ $this->setGeohash($location);
+ } else { // Invalid location
+ throw new Elastica_Exception_Invalid('$location has to be an array (latitude/longitude) or a string (geohash)');
+ }
+
+ //Distance
+ $this->setDistance($distance);
+ }
+
+ /**
+ * Convert old constructor signature to the new one
+ * Remove it when the old constructor is not supported
+ *
+ * @deprecated
+ * @param array $args old arguments
+ * @return array new arguments
+ */
+ private function _oldConstruct(array $args)
+ {
+ return array(
+ 'key' => $args[0],
+ 'location' => array(
+ 'lat' => $args[1],
+ 'lon' => $args[2]
+ ),
+ 'distance' => $args[3]
+ );
+ }
+
+ /**
+ * @param string $key
+ * @return Elastica_Filter_GeoDistance current filter
+ */
+ public function setKey($key)
+ {
+ $this->_key = $key;
+
+ return $this;
+ }
+
+ /**
+ * @param float $latitude
+ * @return Elastica_Filter_GeoDistance current filter
+ */
+ public function setLatitude($latitude)
+ {
+ $this->_latitude = (float) $latitude;
+ $this->_locationType = 'latlon';
+
+ return $this;
+ }
+
+ /**
+ * @param float $longitude
+ * @return Elastica_Filter_GeoDistance current filter
+ */
+ public function setLongitude($longitude)
+ {
+ $this->_longitude = (float) $longitude;
+ $this->_locationType = 'latlon';
+
+ return $this;
+ }
+
+ /**
+ * @param string $geohash
+ * @return Elastica_Filter_GeoDistance current filter
+ */
+ public function setGeohash($geohash)
+ {
+ $this->_geohash = $geohash;
+ $this->_locationType = 'geohash';
+
+ return $this;
+ }
+
+ /**
+ * @param string $distance
+ * @return Elastica_Filter_GeoDistance current filter
+ */
+ public function setDistance($distance)
+ {
+ $this->setParam('distance', $distance);
+
+ return $this;
+ }
+
+ /**
+ * See DISTANCE_TYPE_* constants
+ *
+ * @param string $distanceType
+ * @return Elastica_Filter_GeoDistance current filter
+ */
+ public function setDistanceType($distanceType)
+ {
+ $this->setParam('distance_type', $distanceType);
+
+ return $this;
+ }
+
+ /**
+ * See OPTIMIZE_BBOX_* constants
+ *
+ * @param string $optimizeBbox
+ * @return Elastica_Filter_GeoDistance current filter
+ */
+ public function setOptimizeBbox($optimizeBbox)
+ {
+ $this->setParam('optimize_bbox', $optimizeBbox);
+
+ return $this;
+ }
+
+ /**
+ * @see Elastica_Param::toArray()
+ * @throws Elastica_Exception_Invalid
+ */
+ public function toArray()
+ {
+ $data = parent::toArray();
+
+ // Add location to data array
+ $filterName = $this->_getBaseName();
+ $filterData = $data[$filterName];
+
+ if ($this->_locationType === 'latlon') { // Latitude/longitude
+ $location = array();
+
+ if (isset($this->_latitude)) { // Latitude
+ $location['lat'] = $this->_latitude;
+ } else {
+ throw new Elastica_Exception_Invalid('Latitude has to be set');
+ }
+
+ if (isset($this->_longitude)) { // Geohash
+ $location['lon'] = $this->_longitude;
+ } else {
+ throw new Elastica_Exception_Invalid('Longitude has to be set');
+ }
+ } elseif ($this->_locationType === 'geohash') { // Geohash
+ $location = $this->_geohash;
+ } else { // Invalid location type
+ throw new Elastica_Exception_Invalid('Invalid location type');
+ }
+
+ $filterData[$this->_key] = $location;
+
+ $data[$filterName] = $filterData;
+
+ return $data;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/GeoPolygon.php b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoPolygon.php
new file mode 100755
index 0000000..7a05560
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoPolygon.php
@@ -0,0 +1,56 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/geo_bounding_box_filter/
+ */
+class Elastica_Filter_GeoPolygon extends Elastica_Filter_Abstract
+{
+ /**
+ * Key
+ *
+ * @var string Key
+ */
+ protected $_key = '';
+
+ /**
+ * Points making up polygon
+ *
+ * @var array Points making up polygon
+ */
+ protected $_points = array();
+
+ /**
+ * Construct polygon filter
+ *
+ * @param string $key Key
+ * @param array $points Points making up polygon
+ */
+ public function __construct($key, array $points)
+ {
+ $this->_key = $key;
+ $this->_points = $points;
+ }
+
+ /**
+ * Converts filter to array
+ *
+ * @see Elastica_Filter_Abstract::toArray()
+ * @return array
+ */
+ public function toArray()
+ {
+ return array(
+ 'geo_polygon' => array(
+ $this->_key => array(
+ 'points' => $this->_points
+ ),
+ )
+ );
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/HasChild.php b/modules/thirdparty/elastica/lib/Elastica/Filter/HasChild.php
new file mode 100644
index 0000000..5a10e6c
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/HasChild.php
@@ -0,0 +1,50 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/has-child-filter.html
+ */
+class Elastica_Filter_HasChild extends Elastica_Filter_Abstract
+{
+ /**
+ * Construct HasChild filter
+ *
+ * @param string|Elastica_Query $query Query string or a Elastica_Query object
+ * @param string $type Parent document type
+ */
+ public function __construct($query, $type = null)
+ {
+ $this->setQuery($query);
+ $this->setType($type);
+ }
+
+ /**
+ * Sets query object
+ *
+ * @param string|Elastica_Query|Elastica_Query_Abstract $query
+ * @return Elastica_Filter_HasChild Current object
+ */
+ public function setQuery($query)
+ {
+ $query = Elastica_Query::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Set type of the parent document
+ *
+ * @param string $type Parent document type
+ * @return Elastica_Filter_HasChild Current object
+ */
+ public function setType($type)
+ {
+ return $this->setParam('type', $type);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Ids.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Ids.php
new file mode 100644
index 0000000..8cb511e
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Ids.php
@@ -0,0 +1,88 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/ids-filter.html
+ */
+class Elastica_Filter_Ids extends Elastica_Filter_Abstract
+{
+ /**
+ * Creates filter object
+ *
+ * @param string|Elastica_Type $type Type to filter on
+ * @param array $ids List of ids
+ */
+ public function __construct($type = null, array $ids = array())
+ {
+ $this->setType($type);
+ $this->setIds($ids);
+ }
+
+ /**
+ * Adds one more filter to the and filter
+ *
+ * @param string $id Adds id to filter
+ * @return Elastica_Filter_Ids Current object
+ */
+ public function addId($id)
+ {
+ return $this->addParam('values', $id);
+ }
+
+ /**
+ * Adds one more type to query
+ *
+ * @param string $type Adds type to query
+ * @return Elastica_Filter_Ids Current object
+ */
+ public function addType($type)
+ {
+ if ($type instanceof Elastica_Type) {
+ $type = $type->getType();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // TODO: Shouldn't this throw an exception?
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ return $this->addParam('type', $type);
+ }
+
+ /**
+ * Set type
+ *
+ * @param string|Elastica_Type $type Type name or object
+ * @return Elastica_Filter_Ids Current object
+ */
+ public function setType($type)
+ {
+ if ($type instanceof Elastica_Type) {
+ $type = $type->getType();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // TODO: Shouldn't this throw an exception or let handling of invalid params to ES?
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ return $this->setParam('type', $type);
+ }
+
+ /**
+ * Sets the ids to filter
+ *
+ * @param array|string $ids List of ids
+ * @return Elastica_Filter_Ids Current object
+ */
+ public function setIds($ids)
+ {
+ if (!is_array($ids)) {
+ $ids = array($ids);
+ }
+
+ return $this->setParam('values', $ids);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Limit.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Limit.php
new file mode 100644
index 0000000..66c1100
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Limit.php
@@ -0,0 +1,34 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/limit-filter.html
+ */
+class Elastica_Filter_Limit extends Elastica_Filter_Abstract
+{
+ /**
+ * Construct limit filter
+ *
+ * @param int $limit Limit
+ * @return Elastica_Filter_Limit
+ */
+ public function __construct($limit)
+ {
+ $this->setLimit($limit);
+ }
+
+ /**
+ * Set the limit
+ *
+ * @param int $limit Limit
+ * @return Elastica_Filter_Limit
+ */
+ public function setLimit($limit)
+ {
+ return $this->setParam('value', (int) $limit);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/MatchAll.php b/modules/thirdparty/elastica/lib/Elastica/Filter/MatchAll.php
new file mode 100755
index 0000000..6e3f357
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/MatchAll.php
@@ -0,0 +1,19 @@
+
+ */
+class Elastica_Filter_MatchAll extends Elastica_Filter_Abstract
+{
+ /**
+ * Creates match all filter
+ */
+ public function __construct()
+ {
+ $this->_params = new stdClass();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Missing.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Missing.php
new file mode 100644
index 0000000..dfc8a11
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Missing.php
@@ -0,0 +1,35 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/missing-filter.html
+ */
+class Elastica_Filter_Missing extends Elastica_Filter_Abstract
+{
+ /**
+ * Construct missing filter
+ *
+ * @param string $field OPTIONAL
+ */
+ public function __construct($field = '')
+ {
+ if (strlen($field)) {
+ $this->setField($field);
+ }
+ }
+
+ /**
+ * Set field
+ *
+ * @param string $field
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', (string) $field);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Nested.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Nested.php
new file mode 100644
index 0000000..0ea060f
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Nested.php
@@ -0,0 +1,45 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/nested-filter.html
+ */
+class Elastica_Filter_Nested extends Elastica_Filter_Abstract
+{
+ /**
+ * Adds field to mlt filter
+ *
+ * @param string $path Nested object path
+ * @return Elastica_Filter_Nested
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+
+ /**
+ * Sets nested query
+ *
+ * @param Elastica_Query_Abstract $query
+ * @return Elastica_Filter_Nested
+ */
+ public function setQuery(Elastica_Query_Abstract $query)
+ {
+ return $this->setParam('query', $query->toArray());
+ }
+
+ /**
+ * Set score mode
+ *
+ * @param string $scoreMode Options: avg, total, max and none.
+ * @return Elastica_Filter_Nested
+ */
+ public function setScoreMode($scoreMode)
+ {
+ return $this->setParam('score_mode', $scoreMode);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Not.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Not.php
new file mode 100644
index 0000000..edbcb7a
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Not.php
@@ -0,0 +1,33 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/not-filter.html
+ */
+class Elastica_Filter_Not extends Elastica_Filter_Abstract
+{
+ /**
+ * Creates Not filter query
+ *
+ * @param Elastica_Filter_Abstract $filter Filter object
+ */
+ public function __construct(Elastica_Filter_Abstract $filter)
+ {
+ $this->setFilter($filter);
+ }
+
+ /**
+ * Set filter
+ *
+ * @param Elastica_Filter_Abstract $filter
+ * @return Elastica_Filter_Not
+ */
+ public function setFilter(Elastica_Filter_Abstract $filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/NumericRange.php b/modules/thirdparty/elastica/lib/Elastica/Filter/NumericRange.php
new file mode 100644
index 0000000..4c024ac
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/NumericRange.php
@@ -0,0 +1,13 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/numeric-range-filter.html
+ */
+class Elastica_Filter_NumericRange extends Elastica_Filter_Range
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Or.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Or.php
new file mode 100755
index 0000000..bf4b98b
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Or.php
@@ -0,0 +1,13 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/or_filter/
+ */
+class Elastica_Filter_Or extends Elastica_Filter_Abstract_Multi
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Prefix.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Prefix.php
new file mode 100644
index 0000000..9df7260
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Prefix.php
@@ -0,0 +1,75 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/prefix-filter.html
+ */
+class Elastica_Filter_Prefix extends Elastica_Filter_Abstract
+{
+ /**
+ * Holds the name of the field for the prefix.
+ *
+ * @var string
+ */
+ protected $_field = '';
+
+ /**
+ * Holds the prefix string.
+ *
+ * @var string
+ */
+ protected $_prefix = '';
+
+ /**
+ * Creates prefix filter
+ *
+ * @param string $field Field name
+ * @param string $prefix Prefix string
+ */
+ public function __construct($field = '', $prefix = '')
+ {
+ $this->setField($field);
+ $this->setPrefix($prefix);
+ }
+
+ /**
+ * Sets the name of the prefix field.
+ *
+ * @param string $field Field name
+ */
+ public function setField($field)
+ {
+ $this->_field = $field;
+
+ return $this;
+ }
+
+ /**
+ * Sets the prefix string.
+ *
+ * @param string $prefix Prefix string
+ */
+ public function setPrefix($prefix)
+ {
+ $this->_prefix = $prefix;
+
+ return $this;
+ }
+
+ /**
+ * Convers object to an arrray
+ *
+ * @see Elastica_Filter_Abstract::toArray()
+ * @return array data array
+ */
+ public function toArray()
+ {
+ $this->setParam($this->_field, $this->_prefix);
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Query.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Query.php
new file mode 100644
index 0000000..a723aa1
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Query.php
@@ -0,0 +1,85 @@
+
+ */
+class Elastica_Filter_Query extends Elastica_Filter_Abstract
+{
+ /**
+ * Query
+ * @var array
+ */
+ protected $_query;
+
+ /**
+ * Construct query filter
+ *
+ * @param array|Elastica_Query_Abstract $query
+ */
+ public function __construct($query = null)
+ {
+ if (!is_null($query)) {
+ $this->setQuery($query);
+ }
+ }
+
+ /**
+ * Set query
+ *
+ * @param array|Elastica_Query_Abstract $query
+ * @return Elastca_Filter_Query Query object
+ * @throws Elastica_Exception_Invalid Invalid param
+ */
+ public function setQuery($query)
+ {
+ if (!$query instanceof Elastica_Query_Abstract && ! is_array($query)) {
+ throw new Elastica_Exception_Invalid('expected an array or instance of Elastica_Query_Abstract');
+ }
+
+ if ($query instanceof Elastica_Query_Abstract) {
+ $query = $query->toArray();
+ }
+
+ $this->_query = $query;
+
+ return $this;
+ }
+
+ /**
+ * @see Elastica_Param::_getBaseName()
+ */
+ protected function _getBaseName()
+ {
+ if (empty($this->_params)) {
+ return parent::_getBaseName();
+ } else {
+ return 'fquery';
+ }
+ }
+
+ /**
+ * @see Elastica_Param::toArray()
+ */
+ public function toArray()
+ {
+ $data = parent::toArray();
+
+ $name = $this->_getBaseName();
+ $filterData = $data[$name];
+
+ if (empty($filterData)) {
+ $filterData = $this->_query;
+ } else {
+ $filterData['query'] = $this->_query;
+ }
+
+ $data[$name] = $filterData;
+
+ return $data;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Range.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Range.php
new file mode 100755
index 0000000..b368b05
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Range.php
@@ -0,0 +1,60 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/range-filter.html
+ */
+class Elastica_Filter_Range extends Elastica_Filter_Abstract
+{
+ /**
+ * Fields
+ *
+ * @var array Fields
+ */
+ protected $_fields = array();
+
+ /**
+ * Construct range filter
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ * @return Elastica_Filter_Range
+ */
+ public function __construct($fieldName = false, array $args = array())
+ {
+ if ($fieldName) {
+ $this->addField($fieldName, $args);
+ }
+ }
+
+ /**
+ * Ads a field with arguments to the range query
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ * @return Elastica_Filter_Range
+ */
+ public function addField($fieldName, array $args)
+ {
+ $this->_fields[$fieldName] = $args;
+
+ return $this;
+ }
+
+ /**
+ * Convers object to array
+ *
+ * @see Elastica_Filter_Abstract::toArray()
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ $this->setParams($this->_fields);
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Script.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Script.php
new file mode 100644
index 0000000..d16a453
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Script.php
@@ -0,0 +1,70 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/script-filter.html
+ */
+class Elastica_Filter_Script extends Elastica_Filter_Abstract
+{
+ /**
+ * Query object
+ *
+ * @var array|Elastica_Query_Abstract
+ */
+ protected $_query = null;
+
+ /**
+ * Construct script filter
+ *
+ * @param array|Elastica_Query_Abstract $query OPTIONAL Query object
+ */
+ public function __construct($query = null)
+ {
+ if (!is_null($query)) {
+ $this->setQuery($query);
+ }
+ }
+
+ /**
+ * Sets query object
+ *
+ * @param array|Elastica_Query_Abstract $query
+ * @return Elastica_Filter_Script
+ * @throws Elastica_Exception_Invalid Invalid argument type
+ */
+ public function setQuery($query)
+ {
+ // TODO: check if should be renamed to setScript?
+ if (!$query instanceof Elastica_Query_Abstract && !is_array($query)) {
+ throw new Elastica_Exception_Invalid('expected an array or instance of Elastica_Query_Abstract');
+ }
+
+ if ($query instanceof Elastica_Query_Abstract) {
+ $this->_query = $query->toArray();
+ } else {
+ $this->_query = $query;
+ }
+
+ return $this;
+ }
+
+ /**
+ * ToArray
+ *
+ * @return array Script filter
+ * @see Elastica_Filter_Abstract::toArray()
+ */
+ public function toArray()
+ {
+ return array(
+ 'script' => (
+ $this->_query
+ ),
+ );
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Term.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Term.php
new file mode 100755
index 0000000..16adb5b
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Term.php
@@ -0,0 +1,45 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/term_query/
+ */
+class Elastica_Filter_Term extends Elastica_Filter_Abstract
+{
+ /**
+ * Construct term filter
+ *
+ * @param array $term Term array
+ */
+ public function __construct(array $term = array())
+ {
+ $this->setRawTerm($term);
+ }
+
+ /**
+ * Sets/overwrites key and term directly
+ *
+ * @param array $term Key value pair
+ * @return Elastica_Filter_Term Filter object
+ */
+ public function setRawTerm(array $term)
+ {
+ return $this->setParams($term);
+ }
+
+ /**
+ * Adds a term to the term query
+ *
+ * @param string $key Key to query
+ * @param string|array $value Values(s) for the query. Boost can be set with array
+ * @return Elastica_Filter_Term Filter object
+ */
+ public function setTerm($key, $value)
+ {
+ return $this->setRawTerm(array($key => $value));
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Terms.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Terms.php
new file mode 100755
index 0000000..f1a294d
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Terms.php
@@ -0,0 +1,87 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/terms-filter.html
+ */
+class Elastica_Filter_Terms extends Elastica_Filter_Abstract
+{
+ /**
+ * Terms
+ *
+ * @var array Terms
+ */
+ protected $_terms = array();
+
+ /**
+ * Params
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Terms key
+ *
+ * @var string Terms key
+ */
+ protected $_key = '';
+
+ /**
+ * Creates terms filter
+ *
+ * @param string $key Terms key
+ * @param array $terms Terms values
+ */
+ public function __construct($key = '', array $terms = array())
+ {
+ $this->setTerms($key, $terms);
+ }
+
+ /**
+ * Sets key and terms for the filter
+ *
+ * @param string $key Terms key
+ * @param array $terms Terms for the query.
+ */
+ public function setTerms($key, array $terms)
+ {
+ $this->_key = $key;
+ $this->_terms = array_values($terms);
+
+ return $this;
+ }
+
+ /**
+ * Adds an additional term to the query
+ *
+ * @param string $term Filter term
+ * @return Elastica_Filter_Abstract Filter object
+ */
+ public function addTerm($term)
+ {
+ $this->_terms[] = $term;
+
+ return $this;
+ }
+
+ /**
+ * Convers object to an arrray
+ *
+ * @see Elastica_Filter_Abstract::toArray()
+ * @return array data array
+ */
+ public function toArray()
+ {
+ if (empty($this->_key)) {
+ throw new Elastica_Exception_Invalid('Terms key has to be set');
+ }
+ $this->_params[$this->_key] = $this->_terms;
+
+ return array('terms' => $this->_params);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Type.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Type.php
new file mode 100755
index 0000000..49fb459
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Type.php
@@ -0,0 +1,58 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/type-filter.html
+ */
+class Elastica_Filter_Type extends Elastica_Filter_Abstract
+{
+ /**
+ * Type
+ *
+ * @var Elastica_Type Type object
+ */
+ protected $_type = null;
+
+ /**
+ * Construct Type Filter
+ *
+ * @param string $typeName Type name
+ * @return Elastica_Filter_Type
+ */
+ public function __construct($typeName = null)
+ {
+ if ($typeName) {
+ $this->setType($typeName);
+ }
+ }
+
+ /**
+ * Ads a field with arguments to the range query
+ *
+ * @param string $typeName Type name
+ * @return Elastica_Filter_Type current object
+ */
+ public function setType($typeName)
+ {
+ $this->_type = $typeName;
+
+ return $this;
+ }
+
+ /**
+ * Convert object to array
+ *
+ * @see Elastica_Filter_Abstract::toArray()
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ return array(
+ 'type' => array('value' => $this->_type)
+ );
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Index.php b/modules/thirdparty/elastica/lib/Elastica/Index.php
new file mode 100755
index 0000000..187aa24
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Index.php
@@ -0,0 +1,400 @@
+
+ */
+class Elastica_Index implements Elastica_Searchable
+{
+ /**
+ * Index name
+ *
+ * @var string Index name
+ */
+ protected $_name = '';
+
+ /**
+ * Client object
+ *
+ * @var Elastica_Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Creates a new index object
+ *
+ * All the communication to and from an index goes of this object
+ *
+ * @param Elastica_Client $client Client object
+ * @param string $name Index name
+ */
+ public function __construct(Elastica_Client $client, $name)
+ {
+ $this->_client = $client;
+
+ if (!is_string($name)) {
+ throw new Elastica_Exception_Invalid('Index name should be of type string');
+ }
+ $this->_name = $name;
+ }
+
+ /**
+ * Returns a type object for the current index with the given name
+ *
+ * @param string $type Type name
+ * @return Elastica_Type Type object
+ */
+ public function getType($type)
+ {
+ return new Elastica_Type($this, $type);
+ }
+
+ /**
+ * Returns the current status of the index
+ *
+ * @return Elastica_Index_Status Index status
+ */
+ public function getStatus()
+ {
+ return new Elastica_Index_Status($this);
+ }
+
+ /**
+ * Return Index Stats
+ *
+ * @return ELastica_Index_Stats
+ */
+ public function getStats()
+ {
+ return new Elastica_Index_Stats($this);
+ }
+
+ /**
+ * Gets all the type mappings for an index.
+ *
+ * @return array
+ */
+ public function getMapping()
+ {
+ $path = '_mapping';
+
+ $response = $this->request($path, Elastica_Request::GET);
+
+ return $response->getData();
+ }
+
+ /**
+ * Returns the index settings object
+ *
+ * @return Elastica_Index_Settings Settings object
+ */
+ public function getSettings()
+ {
+ return new Elastica_Index_Settings($this);
+ }
+
+ /**
+ * Uses _bulk to send documents to the server
+ *
+ * @param array $docs Array of Elastica_Document
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/
+ */
+ public function addDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setIndex($this->getName());
+ }
+
+ return $this->getClient()->addDocuments($docs);
+ }
+
+ /**
+ * Update document, using update script. Requires elasticsearch >= 0.19.0
+ *
+ * @param string $id document id
+ * @param Elastica_Script $script script to use for update
+ * @param string $type index type
+ * @param array $options options for query
+ * @return Elastica_Response
+ * @link http://www.elasticsearch.org/guide/reference/api/update.html
+ * @see Elastica_Client::updateDocument()
+ */
+ public function updateDocument($id, Elastica_Script $script, $type, array $options = array())
+ {
+ return $this->getClient()->updateDocument($id, $script, $this->getName(), $type, $options);
+ }
+
+ /**
+ * Deletes the index
+ *
+ * @return Elastica_Response Response object
+ */
+ public function delete()
+ {
+ $response = $this->request('', Elastica_Request::DELETE);
+
+ return $response;
+ }
+
+ /**
+ * Optimizes search index
+ *
+ * Detailed arguments can be found here in the link
+ *
+ * @param array $args OPTIONAL Additional arguments
+ * @return array Server response
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/optimize/
+ */
+ public function optimize($args = array())
+ {
+ // TODO: doesn't seem to work?
+ $this->request('_optimize', Elastica_Request::POST, $args);
+ }
+
+ /**
+ * Refreshs the index
+ *
+ * @return Elastica_Response Response object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/refresh/
+ */
+ public function refresh()
+ {
+ return $this->request('_refresh', Elastica_Request::POST, array());
+ }
+
+ /**
+ * Creates a new index with the given arguments
+ *
+ * @param array $args OPTIONAL Arguments to use
+ * @param bool|array $options OPTIONAL
+ * bool=> Deletes index first if already exists (default = false).
+ * array => Associative array of options (option=>value)
+ * @return array Server response
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/create_index/
+ */
+ public function create(array $args = array(), $options = null)
+ {
+ $path = '';
+ $query = array();
+
+ if (is_bool($options)) {
+ if ($options) {
+ try {
+ $this->delete();
+ } catch (Elastica_Exception_Response $e) {
+ // Table can't be deleted, because doesn't exist
+ }
+ }
+ } else {
+ if (is_array($options)) {
+ foreach ($options as $key => $value) {
+ switch ($key) {
+ case 'recreate' :
+ try {
+ $this->delete();
+ } catch (Elastica_Exception_Response $e) {
+ // Table can't be deleted, because doesn't exist
+ }
+ break;
+ case 'routing' :
+ $query = array('routing' => $value);
+ break;
+ default:
+ throw new Elastica_Exception_Invalid('Invalid option ' . $key);
+ break;
+ }
+ }
+ }
+ }
+
+ return $this->request($path, Elastica_Request::PUT, $args, $query);
+ }
+
+ /**
+ * Checks if the given index is already created
+ *
+ * @return bool True if index exists
+ */
+ public function exists()
+ {
+ $cluster = new Elastica_Cluster($this->getClient());
+
+ return in_array($this->getName(), $cluster->getIndexNames());
+ }
+
+ /**
+ * Searchs in this index
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
+ * @return Elastica_ResultSet ResultSet with all results inside
+ * @see Elastica_Searchable::search
+ */
+ public function search($query, $options = null)
+ {
+ $search = new Elastica_Search($this->getClient());
+ $search->addIndex($this);
+
+ return $search->search($query, $options);
+ }
+
+ /**
+ * Counts results of query
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @return int number of documents matching the query
+ * @see Elastica_Searchable::count
+ */
+ public function count($query = '')
+ {
+ $query = Elastica_Query::create($query);
+ $path = '_search';
+
+ $response = $this->request($path, Elastica_Request::GET, $query->toArray(), array('search_type' => 'count'));
+ $resultSet = new Elastica_ResultSet($response);
+
+ return $resultSet->getTotalHits();
+ }
+
+ /**
+ * Opens an index
+ *
+ * @return Elastica_Response Response object
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close.html
+ */
+ public function open()
+ {
+ $this->request('_open', Elastica_Request::POST);
+ }
+
+ /**
+ * Closes the index
+ *
+ * @return Elastica_Response Response object
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close.html
+ */
+ public function close()
+ {
+ return $this->request('_close', Elastica_Request::POST);
+ }
+
+ /**
+ * Returns the index name
+ *
+ * @return string Index name
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Returns index client
+ *
+ * @return Elastica_Client Index client object
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Adds an alias to the current index
+ *
+ * @param string $name Alias name
+ * @param bool $replace OPTIONAL If set, an existing alias will be replaced
+ * @return Elastica_Response Response
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases.html
+ */
+ public function addAlias($name, $replace = false)
+ {
+ $path = '_aliases';
+
+ if ($replace) {
+ $status = new Elastica_Status($this->getClient());
+
+ foreach ($status->getIndicesWithAlias($name) as $index) {
+ $index->removeAlias($name);
+ }
+ }
+
+ $data = array('actions' => array(array('add' => array('index' => $this->getName(), 'alias' => $name))));
+
+ return $this->getClient()->request($path, Elastica_Request::POST, $data);
+ }
+
+ /**
+ * Removes an alias pointing to the current index
+ *
+ * @param string $name Alias name
+ * @return Elastica_Response Response
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases.html
+ */
+ public function removeAlias($name)
+ {
+ $path = '_aliases';
+
+ $data = array('actions' => array(array('remove' => array('index' => $this->getName(), 'alias' => $name))));
+
+ return $this->getClient()->request($path, Elastica_Request::POST, $data);
+ }
+
+ /**
+ * Clears the cache of an index
+ *
+ * @return Elastica_Response Reponse object
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-clearcache.html
+ */
+ public function clearCache()
+ {
+ $path = '_cache/clear';
+ // TODO: add additional cache clean arguments
+ return $this->request($path, Elastica_Request::POST);
+ }
+
+ /**
+ * Flushs the index to storage
+ *
+ * @return Elastica_Response Reponse object
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-flush.html
+ */
+ public function flush()
+ {
+ $path = '_flush';
+ // TODO: Add option for refresh
+ return $this->request($path, Elastica_Request::POST);
+ }
+
+ /**
+ * Can be used to change settings during runtime. One example is to use
+ * if for bulk updating {@link http://www.elasticsearch.org/blog/2011/03/23/update-settings.html}
+ *
+ * @param array $data Data array
+ * @return Elastica_Response Response object
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings.html
+ */
+ public function setSettings(array $data)
+ {
+ return $this->request('_settings', Elastica_Request::PUT, $data);
+ }
+
+ /**
+ * Makes calls to the elasticsearch server based on this index
+ *
+ * @param string $path Path to call
+ * @param string $method Rest method to use (GET, POST, DELETE, PUT)
+ * @param array $data OPTIONAL Arguments as array
+ * @param array $query OPTIONAL Query params
+ * @return Elastica_Response Response object
+ */
+ public function request($path, $method, $data = array(), array $query = array())
+ {
+ $path = $this->getName() . '/' . $path;
+
+ return $this->getClient()->request($path, $method, $data, $query);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Index/Settings.php b/modules/thirdparty/elastica/lib/Elastica/Index/Settings.php
new file mode 100644
index 0000000..d46d103
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Index/Settings.php
@@ -0,0 +1,294 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings.html
+ * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html
+ */
+class Elastica_Index_Settings
+{
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats info
+ *
+ * @var array Stats info
+ */
+ protected $_data = array();
+
+ /**
+ * Index
+ *
+ * @var Elastica_Index Index object
+ */
+ protected $_index = null;
+
+ const DEFAULT_REFRESH_INTERVAL = '1s';
+
+ /**
+ * Construct
+ *
+ * @param Elastica_Index $index Index object
+ */
+ public function __construct(Elastica_Index $index)
+ {
+ $this->_index = $index;
+ }
+
+ /**
+ * Returns the current settings of the index
+ *
+ * If param is set, only specified setting is return.
+ * 'index.' is added in front of $setting.
+ *
+ * @param string $setting OPTIONAL Setting name to return
+ * @return array|string|null Settings data
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings.html
+ */
+ public function get($setting = '')
+ {
+ $data = $this->request()->getData();
+ $settings = $data[$this->_index->getName()]['settings'];
+
+ if (!empty($setting)) {
+ if (isset($settings['index.' . $setting])) {
+ return $settings['index.' . $setting];
+ } else {
+ return null;
+ }
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Sets the number of replicas
+ *
+ * @param int $replicas Number of replicas
+ * @return Elastica_Response Response object
+ */
+ public function setNumberOfReplicas($replicas)
+ {
+ $replicas = (int) $replicas;
+
+ $data = array('number_of_replicas' => $replicas);
+
+ return $this->set($data);
+ }
+
+ /**
+ * Sets the index to read only
+ *
+ * @param bool $readOnly (default = true)
+ * @return Elastica_Response
+ */
+ public function setReadOnly($readOnly = true)
+ {
+ return $this->set(array('blocks.read_only' => $readOnly));
+ }
+
+ /**
+ * @return bool
+ */
+ public function getBlocksRead()
+ {
+ return (bool) $this->get('blocks.read');
+ }
+
+ /**
+ * @param bool $state OPTIONAL (default = true)
+ * @return Elastica_Response
+ */
+ public function setBlocksRead($state = true)
+ {
+ $state = $state ? 1 : 0;
+
+ return $this->set(array('blocks.read' => $state));
+ }
+
+ /**
+ * @return bool
+ */
+ public function getBlocksWrite()
+ {
+ return (bool) $this->get('blocks.write');
+ }
+
+ /**
+ * @param bool $state OPTIONAL (default = true)
+ * @return Elastica_Response
+ */
+ public function setBlocksWrite($state = true)
+ {
+ $state = $state ? 1 : 0;
+
+ return $this->set(array('blocks.write' => (int) $state));
+ }
+
+ /**
+ * @return bool
+ */
+ public function getBlocksMetadata()
+ {
+ return (bool) $this->get('blocks.metadata');
+ }
+
+ /**
+ * @param bool $state OPTIONAL (default = true)
+ * @return Elastica_Response
+ */
+ public function setBlocksMetadata($state = true)
+ {
+ $state = $state ? 1 : 0;
+
+ return $this->set(array('blocks.metadata' => (int) $state));
+ }
+
+ /**
+ * Sets the index refresh interval
+ *
+ * Value can be for example 3s for 3 seconds or
+ * 5m for 5 minutes. -1 refreshing is disabled.
+ *
+ * @param int $interval Number of seconds
+ * @return Elastica_Response Response object
+ */
+ public function setRefreshInterval($interval)
+ {
+ return $this->set(array('refresh_interval' => $interval));
+ }
+
+ /**
+ * Returns the refresh interval
+ *
+ * If no interval is set, the default interval is returned
+ *
+ * @return string Refresh interval
+ */
+ public function getRefreshInterval()
+ {
+ $interval = $this->get('refresh_interval');
+
+ if (empty($interval)) {
+ $interval = self::DEFAULT_REFRESH_INTERVAL;
+ }
+
+ return $interval;
+ }
+
+ /**
+ * Return merge policy
+ *
+ * @return string Merge policy type
+ */
+ public function getMergePolicyType()
+ {
+ return $this->get('merge.policy.type');
+ }
+
+ /**
+ * Sets merge policy
+ *
+ * @param string $type Merge policy type
+ * @return Elastica_Response Response object
+ * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html
+ */
+ public function setMergePolicyType($type)
+ {
+ $this->getIndex()->close();
+ $response = $this->set(array('merge.policy.type' => $type));
+ $this->getIndex()->open();
+
+ return $response;
+ }
+
+ /**
+ * Sets the specific merge policies
+ *
+ * To have this changes made the index has to be closed and reopened
+ *
+ * @param string $key Merge policy key (for ex. expunge_deletes_allowed)
+ * @param string $value
+ * @return Elastica_Response
+ * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html
+ */
+ public function setMergePolicy($key, $value)
+ {
+ $this->getIndex()->close();
+ $response = $this->set(array('merge.policy.' . $key => $value));
+ $this->getIndex()->open();
+
+ return $response;
+ }
+
+ /**
+ * Returns the specific merge policy value
+ *
+ * @param string $key Merge policy key (for ex. expunge_deletes_allowed)
+ * @return string Refresh interval
+ * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html
+ */
+ public function getMergePolicy($key)
+ {
+ return $this->get('merge.policy.' . $key);
+ }
+
+ /**
+ * Can be used to set/update settings
+ *
+ * @param array $data Arguments
+ * @return Elastica_Response Response object
+ */
+ public function set(array $data)
+ {
+ return $this->request($data, Elastica_Request::PUT);
+ }
+
+ /**
+ * Returns the index object
+ *
+ * @return Elastica_Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Updates the given settings for the index
+ *
+ * With elasticsearch 0.16 the following settings are supported
+ * - index.term_index_interval
+ * - index.term_index_divisor
+ * - index.translog.flush_threshold_ops
+ * - index.translog.flush_threshold_size
+ * - index.translog.flush_threshold_period
+ * - index.refresh_interval
+ * - index.merge.policy
+ * - index.auto_expand_replicas
+ *
+ * @param array $data OPTIONAL Data array
+ * @param string $method OPTIONAL Transfer method (default = Elastica_Request::GET)
+ * @return Elastica_Response Response object
+ */
+ public function request(array $data = array(), $method = Elastica_Request::GET)
+ {
+ $path = '_settings';
+
+ $data = array('index' => $data);
+
+ return $this->getIndex()->request($path, $method, $data);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Index/Stats.php b/modules/thirdparty/elastica/lib/Elastica/Index/Stats.php
new file mode 100644
index 0000000..34741be
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Index/Stats.php
@@ -0,0 +1,104 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-stats.html
+ */
+class Elastica_Index_Stats
+{
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats info
+ *
+ * @var array Stats info
+ */
+ protected $_data = array();
+
+ /**
+ * Index
+ *
+ * @var Elastica_Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Construct
+ *
+ * @param Elastica_Index $index Index object
+ */
+ public function __construct(Elastica_Index $index)
+ {
+ $this->_index = $index;
+ $this->refresh();
+ }
+
+ /**
+ * Returns the raw stats info
+ *
+ * @return array Stats info
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns the entry in the data array based on the params.
+ * Various params possible.
+ *
+ * @return mixed Data array entry or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return null;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns the index object
+ *
+ * @return Elastica_Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all status data of this object
+ */
+ public function refresh()
+ {
+ $path = '_stats';
+ $this->_response = $this->getIndex()->request($path, Elastica_Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Index/Status.php b/modules/thirdparty/elastica/lib/Elastica/Index/Status.php
new file mode 100644
index 0000000..7be19d9
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Index/Status.php
@@ -0,0 +1,143 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html
+ */
+class Elastica_Index_Status
+{
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats info
+ *
+ * @var array Stats info
+ */
+ protected $_data = array();
+
+ /**
+ * Index
+ *
+ * @var Elastica_Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Construct
+ *
+ * @param Elastica_Index $index Index object
+ */
+ public function __construct(Elastica_Index $index)
+ {
+ $this->_index = $index;
+ $this->refresh();
+ }
+
+ /**
+ * Returns all status info
+ *
+ * @return array Status info
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns the entry in the data array based on the params.
+ * Various params possible.
+ *
+ * @return mixed Data array entry or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+ $data = $data['indices'][$this->getIndex()->getName()];
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return null;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns all index aliases
+ *
+ * @return array Aliases
+ */
+ public function getAliases()
+ {
+ // TODO Update as soon as new API is implmented
+ $cluster = new Elastica_Cluster($this->_index->getClient());
+ $state = $cluster->getState();
+
+ return $state['metadata']['indices'][$this->_index->getName()]['aliases'];
+ }
+
+ /**
+ * Returns all index settings
+ *
+ * @return array Index settings
+ */
+ public function getSettings()
+ {
+ // TODO Update as soon as new API is implmented
+ $cluster = new Elastica_Cluster($this->_index->getClient());
+ $state = $cluster->getState();
+
+ return $state['metadata']['indices'][$this->_index->getName()]['settings'];
+ }
+
+ /**
+ * Checks if the index has the given alias
+ *
+ * @param string $name Alias name
+ */
+ public function hasAlias($name)
+ {
+ return in_array($name, $this->getAliases());
+ }
+
+ /**
+ * Returns the index object
+ *
+ * @return Elastica_Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all status data of this object
+ */
+ public function refresh()
+ {
+ $path = '_status';
+ $this->_response = $this->getIndex()->request($path, Elastica_Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Log.php b/modules/thirdparty/elastica/lib/Elastica/Log.php
new file mode 100644
index 0000000..10fc99d
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Log.php
@@ -0,0 +1,109 @@
+
+ */
+class Elastica_Log
+{
+ /**
+ * Log path or true if enabled
+ *
+ * @var string|bool
+ */
+ protected $_log = false;
+
+ /**
+ * Last logged message
+ *
+ * @var string Last logged message
+ */
+ protected $_lastMessage = '';
+
+ /**
+ * Inits log object. Checks if logging is enabled for the given client
+ *
+ * @param Elastica_Client $client
+ */
+ public function __construct(Elastica_Client $client)
+ {
+ $this->setLog($client->getConfig('log'));
+ }
+
+ /**
+ * Log a message
+ *
+ * @param string|Elastica_Request $message
+ */
+ public function log($message)
+ {
+ if (!$this->_log) {
+ return;
+ }
+
+ if ($message instanceof Elastica_Request) {
+ $message = $this->_convertRequest($message);
+ }
+
+ $this->_lastMessage = $message;
+
+ if (is_string($this->_log)) {
+ error_log($message . PHP_EOL, 3, $this->_log);
+ } else {
+ error_log($message);
+ }
+
+ }
+
+ /**
+ * Enable/disable log or set log path
+ *
+ * @param bool|string $log Enables log or sets log path
+ * @return Elastica_Log
+ */
+ public function setLog($log)
+ {
+ $this->_log = $log;
+
+ return $this;
+ }
+
+ /**
+ * Converts a request to a log message
+ *
+ * @param Elastica_Request $request
+ * @return string Request log message
+ */
+ protected function _convertRequest(Elastica_Request $request)
+ {
+ $message = 'curl -X' . strtoupper($request->getMethod()) . ' ';
+ $message .= '\'http://' . $request->getClient()->getHost() . ':' . $request->getClient()->getPort() . '/';
+ $message .= $request->getPath();
+
+ $query = $request->getQuery();
+ if (!empty($query)) {
+ $message .= '?' . http_build_query($query);
+ }
+
+ $message .= '\'';
+
+ $data = $request->getData();
+ if (!empty($data)) {
+ $message .= ' -d \'' . json_encode($data) . '\'';
+ }
+
+ return $message;
+ }
+
+ /**
+ * Return last logged message
+ *
+ * @return string Last logged message
+ */
+ public function getLastMessage()
+ {
+ return $this->_lastMessage;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Node.php b/modules/thirdparty/elastica/lib/Elastica/Node.php
new file mode 100644
index 0000000..ff7ef92
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Node.php
@@ -0,0 +1,118 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html
+ */
+class Elastica_Node
+{
+ /**
+ * Node name
+ *
+ * @var string Node name
+ */
+ protected $_name = '';
+
+ /**
+ * Node stats
+ *
+ * @var Elastica_Node_Stats Node Stats
+ */
+ protected $_stats = null;
+
+ /**
+ * Node info
+ *
+ * @var Elastica_Node_Info Node info
+ */
+ protected $_info = null;
+
+ /**
+ * Create a new node object
+ *
+ * @param string $name Node name
+ * @param Elastica_Client $client Node object
+ */
+ public function __construct($name, Elastica_Client $client)
+ {
+ $this->_name = $name;
+ $this->_client = $client;
+ $this->refresh();
+ }
+
+ /**
+ * Get the name of the node
+ *
+ * @return string Node name
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Returns the current client object
+ *
+ * @return Elastica_Client Client
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Return stats object of the current node
+ *
+ * @return Elastica_Node_Stats Node stats
+ */
+ public function getStats()
+ {
+ if (!$this->_stats) {
+ $this->_stats = new Elastica_Node_Stats($this);
+ }
+
+ return $this->_stats;
+ }
+
+ /**
+ * Return info object of the current node
+ *
+ * @return Elastica_Node_Info Node info object
+ */
+ public function getInfo()
+ {
+ if (!$this->_info) {
+ $this->_info = new Elastica_Node_Info($this);
+ }
+
+ return $this->_info;
+ }
+
+ /**
+ * Refreshs all node information
+ *
+ * This should be called after upating a node to refresh all information
+ */
+ public function refresh()
+ {
+ $this->_stats = null;
+ $this->_info = null;
+ }
+
+ /**
+ * Shuts this node down
+ *
+ * @param string $delay OPTIONAL Delay after which node is shut down (defualt = 1s)
+ * @return Elastica_Response
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown.html
+ */
+ public function shutdown($delay = '1s')
+ {
+ $path = '_cluster/nodes/' . $this->getName() . '/_shutdown?delay=' . $delay;
+
+ return $this->_client->request($path, Elastica_Request::POST);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Node/Info.php b/modules/thirdparty/elastica/lib/Elastica/Node/Info.php
new file mode 100644
index 0000000..734f0a2
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Node/Info.php
@@ -0,0 +1,151 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html
+ */
+class Elastica_Node_Info
+{
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats data
+ *
+ * @var array stats data
+ */
+ protected $_data = array();
+
+ /**
+ * Node
+ *
+ * @var Elastica_Node Node object
+ */
+ protected $_node = null;
+
+ /**
+ * Create new info object for node
+ *
+ * @param Elastica_Node $node Node object
+ * @param array $params List of params to return. Can be: settings, os, process, jvm, thread_pool, network, transport, http
+ */
+ public function __construct(Elastica_Node $node, array $params = array())
+ {
+ $this->_node = $node;
+ $this->refresh($params);
+ }
+
+ /**
+ * Returns the entry in the data array based on the params.
+ * Several params possible.
+ *
+ * Example 1: get('os', 'mem', 'total') returns total memory of the system the
+ * node is running on
+ * Example 2: get('os', 'mem') returns an array with all mem infos
+ *
+ * @return mixed Data array entry or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return null;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Return port of the node
+ *
+ * @return string Returns Node port
+ */
+ public function getPort()
+ {
+ // Returns string in format: inet[/192.168.1.115:9201]
+ $data = $this->get('http_address');
+ $data = substr($data, 6, strlen($data) - 7);
+ $data = explode(':', $data);
+
+ return $data[1];
+ }
+
+ /**
+ * Return IP of the node
+ *
+ * @return string Returns Node ip address
+ */
+ public function getIp()
+ {
+ // Returns string in format: inet[/192.168.1.115:9201]
+ $data = $this->get('http_address');
+ $data = substr($data, 6, strlen($data) - 7);
+ $data = explode(':', $data);
+
+ return $data[0];
+ }
+
+ /**
+ * Return all info data
+ *
+ * @return array Data array
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Return node object
+ *
+ * @return Elastica_Node Node object
+ */
+ public function getNode()
+ {
+ return $this->_node;
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all nodes information. Has to be called if informations changed
+ *
+ * @param array $params Params to return (default none). Possible options: settings, os, process, jvm, thread_pool, network, transport, http
+ * @return Elastica_Response Response object
+ */
+ public function refresh(array $params = array())
+ {
+ $path = '_cluster/nodes/' . $this->getNode()->getName();
+
+ if (!empty($params)) {
+ $path .= '?';
+ foreach ($params as $param) {
+ $path .= $param . '=true&';
+ }
+ }
+
+ $this->_response = $this->getNode()->getClient()->request($path, Elastica_Request::GET);
+ $data = $this->getResponse()->getData();
+ $this->_data = reset($data['nodes']);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Node/Stats.php b/modules/thirdparty/elastica/lib/Elastica/Node/Stats.php
new file mode 100644
index 0000000..3223642
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Node/Stats.php
@@ -0,0 +1,109 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html
+ */
+class Elastica_Node_Stats
+{
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats data
+ *
+ * @var array stats data
+ */
+ protected $_data = array();
+
+ /**
+ * Node
+ *
+ * @var Elastica_Node Node object
+ */
+ protected $_node = null;
+
+ /**
+ * Create new stats for node
+ *
+ * @param Elastica_Node $node Elastica node object
+ */
+ public function __construct(Elastica_Node $node)
+ {
+ $this->_node = $node;
+ $this->refresh();
+ }
+
+ /**
+ * Returns all node stats as array based on the arguments
+ *
+ * Several arguments can be use
+ * get('index', 'test', 'example')
+ *
+ * @return array Node stats for the given field or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return null;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns all stats data
+ *
+ * @return array Data array
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns node object
+ *
+ * @return Elastica_Node Node object
+ */
+ public function getNode()
+ {
+ return $this->_node;
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all nodes information. Has to be called if informations changed
+ *
+ * @return Elastica_Response Response object
+ */
+ public function refresh()
+ {
+ $path = '_cluster/nodes/' . $this->getNode()->getName() . '/stats';
+ $this->_response = $this->getNode()->getClient()->request($path, Elastica_Request::GET);
+ $data = $this->getResponse()->getData();
+ $this->_data = reset($data['nodes']);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Param.php b/modules/thirdparty/elastica/lib/Elastica/Param.php
new file mode 100644
index 0000000..8a6099f
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Param.php
@@ -0,0 +1,156 @@
+
+ */
+class Elastica_Param
+{
+ /**
+ * Params
+ *
+ * @var array
+ */
+ protected $_params = array();
+
+ /**
+ * Raw Params
+ *
+ * @var array
+ */
+ protected $_rawParams = array();
+
+ /**
+ * Converts the params to an array. A default implementation exist to create
+ * the an array out of the class name (last part of the class name)
+ * and the params
+ *
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ $data = array($this->_getBaseName() => $this->getParams());
+
+ if (!empty($this->_rawParams)) {
+ $data = array_merge($data, $this->_rawParams);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Param's name
+ * Picks the last part of the class name and makes it snake_case
+ * You can override this method if you want to change the name
+ *
+ * @return string name
+ */
+ protected function _getBaseName()
+ {
+ $classNameParts = explode('_', get_class($this));
+ $name = Elastica_Util::toSnakeCase(array_pop($classNameParts));
+
+ return $name;
+ }
+
+ /**
+ * Sets params not inside params array
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return Elastica_Param
+ */
+ protected function _setRawParam($key, $value)
+ {
+ $this->_rawParams[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets (overwrites) the value at the given key
+ *
+ * @param string $key Key to set
+ * @param mixed $value Key Value
+ */
+ public function setParam($key, $value)
+ {
+ $this->_params[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets (overwrites) all params of this object
+ *
+ * @param array $params Parameter list
+ * @return Elastica_Param
+ */
+ public function setParams(array $params)
+ {
+ $this->_params = $params;
+
+ return $this;
+ }
+
+ /**
+ * Adds a param to the list
+ *
+ * This function can be used to add an array of params
+ *
+ * @param string $key Param key
+ * @param mixed $value Value to set
+ * @return Elastica_Param
+ */
+ public function addParam($key, $value)
+ {
+ if (!isset($this->_params[$key])) {
+ $this->_params[$key] = array();
+ }
+
+ $this->_params[$key][] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Returns a specific param
+ *
+ * @param string $key Key to return
+ * @return mixed Key value
+ * @throws Elastica_Exception_Invalid If requested key is not set
+ */
+ public function getParam($key)
+ {
+ if (!isset($this->_params[$key])) {
+ throw new Elastica_Exception_Invalid('Param ' . $key . ' does not exist');
+ }
+
+ return $this->_params[$key];
+ }
+
+ /**
+ * Test if a param is set
+ *
+ * @param string $key Key to test
+ * @return boolean True if the param is set, false otherwise
+ */
+ public function hasParam($key)
+ {
+ return isset($this->_params[$key]);
+ }
+
+ /**
+ * Returns the params array
+ *
+ * @return array Params
+ */
+ public function getParams()
+ {
+ return $this->_params;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Percolator.php b/modules/thirdparty/elastica/lib/Elastica/Percolator.php
new file mode 100644
index 0000000..e0a4420
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Percolator.php
@@ -0,0 +1,83 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/percolate.html
+ */
+class Elastica_Percolator
+{
+ /**
+ * Index object
+ *
+ * @var Elastica_Index
+ */
+ protected $_index = null;
+
+ /**
+ * Construct new perlocator
+ *
+ * @param Elastica_Index $index
+ */
+ public function __construct(Elastica_Index $index)
+ {
+ $this->_index = $index;
+ }
+
+ /**
+ * Registers a percolator query
+ *
+ * @param string $name Query name
+ * @param string|Elastica_Query|Elastica_Query_Abstract $query Query to add
+ * @return Elastica_Response
+ */
+ public function registerQuery($name, $query)
+ {
+ $path = '_percolator/' . $this->_index->getName() . '/' . $name;
+ $query = Elastica_Query::create($query);
+
+ return $this->_index->getClient()->request($path, Elastica_Request::PUT, $query->toArray());
+ }
+
+ /**
+ * Removes a percolator query
+ * @param string $name query name
+ * @return Elastica_Response
+ */
+ public function unregisterQuery($name)
+ {
+ $path = '_percolator/' . $this->_index->getName() . '/' . $name;
+
+ return $this->_index->getClient()->request($path, Elastica_Request::DELETE);
+ }
+
+ /**
+ * Match a document to percolator queries
+ *
+ * @param Elastica_Document $doc
+ * @param string|Elastica_Query|Elastica_Query_Abstract $query Not implemented yet
+ * @return Elastica_Response
+ */
+ public function matchDoc(Elastica_Document $doc, $query = null)
+ {
+ $path = $this->_index->getName() . '/type/_percolate';
+ $data = array('doc' => $doc->getData());
+
+ $response = $this->getIndex()->getClient()->request($path, Elastica_Request::GET, $data);
+ $data = $response->getData();
+
+ return $data['matches'];
+ }
+
+ /**
+ * Return index object
+ *
+ * @return Elastica_Index
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query.php b/modules/thirdparty/elastica/lib/Elastica/Query.php
new file mode 100755
index 0000000..462b5a2
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query.php
@@ -0,0 +1,319 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/
+ */
+class Elastica_Query extends Elastica_Param
+{
+ /**
+ * Params
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Creates a query object
+ *
+ * @param array|Elastica_Query_Abstract $query OPTIONAL Query object (default = null)
+ */
+ public function __construct($query = null)
+ {
+ if (is_array($query)) {
+ $this->setRawQuery($query);
+ } elseif ($query instanceof Elastica_Query_Abstract) {
+ $this->setQuery($query);
+ }
+ }
+
+ /**
+ * Transforms a string or an array to a query object
+ *
+ * If query is empty,
+ *
+ * @param mixed $query
+ * @return Elastica_Query
+ **/
+ public static function create($query)
+ {
+ switch (true) {
+ case $query instanceof Elastica_Query:
+ return $query;
+ case $query instanceof Elastica_Query_Abstract:
+ return new self($query);
+ case $query instanceof Elastica_Filter_Abstract:
+ $newQuery = new Elastica_Query();
+ $newQuery->setFilter($query);
+
+ return $newQuery;
+ case empty($query):
+ return new self(new Elastica_Query_MatchAll());
+ case is_string($query):
+ return new self(new Elastica_Query_QueryString($query));
+
+ }
+
+ // TODO: Implement queries without
+ throw new Elastica_Exception_NotImplemented();
+ }
+
+ /**
+ * Sets query as raw array. Will overwrite all already set arguments
+ *
+ * @param array $query Query array
+ * @return Elastica_Query Query object
+ */
+ public function setRawQuery(array $query)
+ {
+ $this->_params = $query;
+
+ return $this;
+ }
+
+ /**
+ * Sets the query
+ *
+ * @param Elastica_Query_Abstract $query Query object
+ * @return Elastica_Query Query object
+ */
+ public function setQuery(Elastica_Query_Abstract $query)
+ {
+ return $this->setParam('query', $query->toArray());
+ }
+
+ /**
+ * Gets the query array
+ *
+ * @return array
+ **/
+ public function getQuery()
+ {
+ return $this->getParam('query');
+ }
+
+ /**
+ * Set Filter
+ *
+ * @param Elastica_Filter_Abstract $filter Filter object
+ * @return Elastica_Query Current object
+ */
+ public function setFilter(Elastica_Filter_Abstract $filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * Sets the start from which the search results should be returned
+ *
+ * @param int $from
+ * @return Elastica_Query Query object
+ */
+ public function setFrom($from)
+ {
+ return $this->setParam('from', $from);
+ }
+
+ /**
+ * Sets sort arguments for the query
+ * Replaces existing values
+ *
+ * @param array $sortArgs Sorting arguments
+ * @return Elastica_Query Query object
+ * @link http://www.elasticsearch.org/guide/reference/api/search/sort.html
+ */
+ public function setSort(array $sortArgs)
+ {
+ return $this->setParam('sort', $sortArgs);
+ }
+
+ /**
+ * Adds a sort param to the query
+ *
+ * @param mixed $sort Sort parameter
+ * @return Elastica_Query Query object
+ * @link http://www.elasticsearch.org/guide/reference/api/search/sort.html
+ */
+ public function addSort($sort)
+ {
+ return $this->addParam('sort', $sort);
+ }
+
+ /**
+ * Sets highlight arguments for the query
+ *
+ * @param array $highlightArgs Set all highlight arguments
+ * @return Elastica_Query Query object
+ * @link http://www.elasticsearch.org/guide/reference/api/search/highlighting.html
+ */
+ public function setHighlight(array $highlightArgs)
+ {
+ return $this->setParam('highlight', $highlightArgs);
+ }
+
+ /**
+ * Adds a highlight argument
+ *
+ * @param mixed $highlight Add highlight argument
+ * @return Elastica_Query Query object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/highlighting/
+ */
+ public function addHighlight($highlight)
+ {
+ return $this->addParam('highlight', $highlight);
+ }
+
+ /**
+ * Alias for setLimit
+ *
+ * @param int $limit OPTIONAL Maximal number of results for query (default = 10)
+ * @return Elastica_Query Query object
+ */
+ public function setSize($limit = 10)
+ {
+ return $this->setLimit($limit);
+ }
+
+ /**
+ * Sets maximum number of results for this query
+ *
+ * Setting the limit to 0, means no limit
+ *
+ * @param int $limit OPTIONAL Maximal number of results for query (default = 10)
+ * @return Elastica_Query Query object
+ */
+ public function setLimit($limit = 10)
+ {
+ return $this->setParam('size', $limit);
+ }
+
+ /**
+ * Enables explain on the query
+ *
+ * @param bool $explain OPTIONAL Enabled or disable explain (default = true)
+ * @return Elastica_Query Current object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/explain/
+ */
+ public function setExplain($explain = true)
+ {
+ return $this->setParam('explain', $explain);
+ }
+
+ /**
+ * Enables version on the query
+ *
+ * @param bool $version OPTIONAL Enabled or disable version (default = true)
+ * @return Elastica_Query Current object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/version/
+ */
+ public function setVersion($version = true)
+ {
+ return $this->setParam('version', $version);
+ }
+
+ /**
+ * Sets the fields to be returned by the search
+ *
+ * @param array $fields Fields to be returne
+ * @return Elastica_Query Current object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/fields/
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Set script fields
+ *
+ * @param array|Elastica_ScriptFields $scriptFields Script fields
+ * @return Elastica_Query Current object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/script_fields/
+ */
+ public function setScriptFields($scriptFields)
+ {
+ if (is_array($scriptFields)) {
+ $scriptFields = new Elastica_ScriptFields($scriptFields);
+ }
+
+ return $this->setParam('script_fields', $scriptFields->toArray());
+ }
+
+ /**
+ * Adds a Script to the query
+ *
+ * @param Elastica_Script $script Script object
+ * @return Elastica_Query Query object
+ */
+ public function addScriptField($name, Elastica_Script $script)
+ {
+ $this->_params['script_fields'][$name] = $script->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Sets all facets for this query object. Replaces existing facets
+ *
+ * @param array $facets List of facet objects
+ * @return Elastica_Query Query object
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/facets
+ */
+ public function setFacets(array $facets)
+ {
+ $this->_params['facets'] = array();
+ foreach ($facets as $facet) {
+ $this->addFacet($facet);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds a Facet to the query
+ *
+ * @param Elastica_Facet_Abstract $facet Facet object
+ * @return Elastica_Query Query object
+ */
+ public function addFacet(Elastica_Facet_Abstract $facet)
+ {
+ $this->_params['facets'][$facet->getName()] = $facet->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Converts all query params to an array
+ *
+ * @return array Query array
+ */
+ public function toArray()
+ {
+ // If no query is set, all query is chosen by default
+ if (!isset($this->_params['query'])) {
+ $this->setQuery(new Elastica_Query_MatchAll());
+ }
+
+ return $this->_params;
+ }
+
+ /**
+ * Allows filtering of documents based on a minimum score
+ *
+ * @param int|double $minScore Minimum score to filter documents by
+ * @return Elastica_Query Query object
+ */
+ public function setMinScore($minScore)
+ {
+ if (!is_numeric($minScore)) {
+ throw new Elastica_Exception_Invalid('has to be numeric param');
+ }
+
+ return $this->setParam('min_score', $minScore);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Query/Abstract.php
new file mode 100755
index 0000000..760f7bf
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Abstract.php
@@ -0,0 +1,11 @@
+
+ */
+abstract class Elastica_Query_Abstract extends Elastica_Param
+{
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Array.php b/modules/thirdparty/elastica/lib/Elastica/Query/Array.php
new file mode 100755
index 0000000..d71d296
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Array.php
@@ -0,0 +1,53 @@
+
+ */
+class Elastica_Query_Array extends Elastica_Query_Abstract
+{
+ /**
+ * Query
+ *
+ * @var array Query
+ */
+ protected $_query = array();
+
+ /**
+ * Constructs a query based on an array
+ *
+ * @param array $query Query array
+ */
+ public function __construct(array $query)
+ {
+ $this->setQuery($query);
+ }
+
+ /**
+ * Sets new query array
+ *
+ * @param array $query Query array
+ * @return Elastica_Query_Array Current object
+ */
+ public function setQuery(array $query)
+ {
+ $this->_query = $query;
+
+ return $this;
+ }
+
+ /**
+ * Converts query to array
+ *
+ * @return array Query array
+ * @see Elastica_Query_Abstract::toArray()
+ */
+ public function toArray()
+ {
+ return $this->_query;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Bool.php b/modules/thirdparty/elastica/lib/Elastica/Query/Bool.php
new file mode 100755
index 0000000..9c7562c
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Bool.php
@@ -0,0 +1,87 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/bool_query/
+ */
+class Elastica_Query_Bool extends Elastica_Query_Abstract
+{
+ /**
+ * Add should part to query
+ *
+ * @param Elastica_Query_Abstract|array $args Should query
+ * @return Elastica_Query_Bool Current object
+ */
+ public function addShould($args)
+ {
+ return $this->_addQuery('should', $args);
+ }
+
+ /**
+ * Add must part to query
+ *
+ * @param Elastica_Query_Abstract|array $args Must query
+ * @return Elastica_Query_Bool Current object
+ */
+ public function addMust($args)
+ {
+ return $this->_addQuery('must', $args);
+ }
+
+ /**
+ * Add must not part to query
+ *
+ * @param Elastica_Query_Abstract|array $args Must not query
+ * @return Elastica_Query_Bool Current object
+ */
+ public function addMustNot($args)
+ {
+ return $this->_addQuery('must_not', $args);
+ }
+
+ /**
+ * Adds a query to the current object
+ *
+ * @param string $type Query type
+ * @param Elastica_Query_Abstract|array $args Query
+ * @throws Elastica_Exception_Invalid If not valid query
+ */
+ protected function _addQuery($type, $args)
+ {
+ if ($args instanceof Elastica_Query_Abstract) {
+ $args = $args->toArray();
+ }
+
+ if (!is_array($args)) {
+ throw new Elastica_Exception_Invalid('Invalid parameter. Has to be array or instance of Elastica_Query');
+ }
+
+ return $this->addParam($type, $args);
+ }
+
+ /**
+ * Sets boost value of this query
+ *
+ * @param float $boost Boost value
+ * @return Elastica_Query_Bool Current object
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', $boost);
+ }
+
+ /**
+ * Set the minimum number of of should match
+ *
+ * @param int $minimumNumberShouldMatch Should match minimum
+ * @return Elastica_Query_Bool Current object
+ */
+ public function setMinimumNumberShouldMatch($minimumNumberShouldMatch)
+ {
+ return $this->setParam('minimum_number_should_match', $minimumNumberShouldMatch);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Builder.php b/modules/thirdparty/elastica/lib/Elastica/Query/Builder.php
new file mode 100644
index 0000000..ddb6957
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Builder.php
@@ -0,0 +1,947 @@
+
+ * @link http://www.elasticsearch.com/
+ **/
+class Elastica_Query_Builder extends Elastica_Query_Abstract
+{
+ /**
+ * Query string.
+ *
+ * @var string
+ */
+ private $_string = '{';
+
+ /**
+ * Factory method.
+ *
+ * @param string $string JSON encoded string to use as query.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public static function factory($string = null)
+ {
+ return new Elastica_Query_Builder($string);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param string $string JSON encoded string to use as query.
+ */
+ public function __construct($string = null)
+ {
+ if (! $string == null) {
+ $this->_string .= substr($string, 1, -1);
+ }
+ }
+
+ /**
+ * Output the query string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return rtrim($this->_string, ',').'}';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toArray()
+ {
+ $array = json_decode($this->__toString(), true);
+
+ if (is_null($array)) {
+ throw new Elastica_Exception_Invalid('The query produced is invalid');
+ }
+
+ return $array;
+ }
+
+ /**
+ * Allow widcards (*, ?) as the first character in a query.
+ *
+ * @param boolean $bool Defaults to true.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function allowLeadingWildcard($bool = true)
+ {
+ return $this->field('allow_leading_wildcard', (bool) $bool);
+ }
+
+ /**
+ * Enable best effort analysis of wildcard terms.
+ *
+ * @param boolean $bool Defaults to true.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function analyzeWildcard($bool = true)
+ {
+ return $this->field('analyze_wildcard', (bool) $bool);
+ }
+
+ /**
+ * Set the analyzer name used to analyze the query string.
+ *
+ * @param string $analyzer Analyzer to use.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function analyzer($analyzer)
+ {
+ return $this->field('analyzer', $analyzer);
+ }
+
+ /**
+ * Auitogenerate phrase queries.
+ *
+ * @param boolean $bool Defaults to true.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function autoGeneratePhraseQueries($bool = true)
+ {
+ return $this->field('auto_generate_phrase_queries', (bool) $bool);
+ }
+
+ /**
+ * Bool Query.
+ *
+ * A query that matches documents matching boolean combinations of other queries.
+ *
+ * The bool query maps to Lucene BooleanQuery.
+ *
+ * It is built using one or more boolean clauses, each clause with a typed
+ * occurrence.
+ *
+ * The occurrence types are: must, should, must_not.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function bool()
+ {
+ return $this->fieldOpen('bool');
+ }
+
+ /**
+ * Close a 'bool' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function boolClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Sets the boost value of the query.
+ *
+ * @param float $boost Defaults to 1.0.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function boost($boost = 1.0)
+ {
+ return $this->field('boost', (float) $boost);
+ }
+
+ /**
+ * Close a previously opened brace.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function close()
+ {
+ $this->_string = rtrim($this->_string, ' ,').'},';
+
+ return $this;
+ }
+
+ /**
+ * Constant Score Query.
+ *
+ * A query that wraps a filter or another query and simply returns a constant
+ * score equal to the query boost for every document in the filter.
+ *
+ * Maps to Lucene ConstantScoreQuery.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function constantScore()
+ {
+ return $this->fieldOpen('constant_score');
+ }
+
+ /**
+ * Close a 'constant_score' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function constantScoreClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * The default field for query terms if no prefix field is specified.
+ *
+ * @param string $field Defaults to _all.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function defaultField($field = '_all')
+ {
+ return $this->field('default_field', $field);
+ }
+
+ /**
+ * The default operator used if no explicit operator is specified.
+ *
+ * For example, with a default operator of OR, the query "capital of Hungary"
+ * is translated to "capital OR of OR Hungary", and with default operator of
+ * AND, the same query is translated to "capital AND of AND Hungary".
+ *
+ * @param string $operator Defaults to OR.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function defaultOperator($operator = 'OR')
+ {
+ return $this->field('default_operator', $operator);
+ }
+
+ /**
+ * Dis Max Query.
+ *
+ * A query that generates the union of documents produced by its subqueries,
+ * and that scores each document with the maximum score for that document as
+ * produced by any subquery, plus a tie breaking increment for any additional
+ * matching subqueries.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function disMax()
+ {
+ return $this->fieldOpen('dis_max');
+ }
+
+ /**
+ * Close a 'dis_max' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function disMaxClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Enable position increments in result queries.
+ *
+ * @param boolean $bool Defaults to true.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function enablePositionIncrements($bool = true)
+ {
+ return $this->field('enable_position_increments', (bool) $bool);
+ }
+
+ /**
+ * Enables explanation for each hit on how its score was computed.
+ *
+ * @param boolean $value Turn on / off explain.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function explain($value = true)
+ {
+ return $this->field('explain', $value);
+ }
+
+ /**
+ * Open 'facets' block.
+ *
+ * Facets provide aggregated data based on a search query.
+ *
+ * In the simple case, a facet can return facet counts for various facet
+ * values for a specific field.
+ *
+ * ElasticSearch supports more advanced facet implementations, such as
+ * statistical or date histogram facets.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function facets()
+ {
+ return $this->fieldOpen('facets');
+ }
+
+ /**
+ * Close a facets block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function facetsClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Add a specific field / value entry.
+ *
+ * @param string $name Field to add.
+ * @param mixed $value Value to set.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function field($name, $value)
+ {
+ if (is_bool($value)) {
+ $value = '"'. var_export($value, true) . '"';
+ } elseif (is_array($value)) {
+ $value = '["'.implode('","', $value).'"]';
+ } else {
+ $value = '"'.$value.'"';
+ }
+
+ $this->_string .= '"'.$name.'":'.$value.',';
+
+ return $this;
+ }
+
+ /**
+ * Close a field block.
+ *
+ * Alias of close() for ease of reading in source.
+ * Passed parameters will be ignored, however they can be useful in source for
+ * seeing which field is being closed.
+ *
+ * Elastica_Query_Builder::factory()
+ * ->query()
+ * ->range()
+ * ->fieldOpen('created')
+ * ->gte('2011-07-18 00:00:00')
+ * ->lt('2011-07-19 00:00:00')
+ * ->fieldClose('created')
+ * ->rangeClose()
+ * ->queryClose();
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function fieldClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Open a node for the specified name.
+ *
+ * @param string $name Field name.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function fieldOpen($name)
+ {
+ $this->_string .= '"'.$name.'":';
+ $this->open();
+
+ return $this;
+ }
+
+ /**
+ * Explicitly define fields to return.
+ *
+ * @param array $fields Array of fields to return.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function fields(array $fields)
+ {
+ $this->_string .= '"fields":[';
+
+ foreach ($fields as $field) {
+ $this->_string .= '"'.$field.'",';
+ }
+
+ $this->_string = rtrim($this->_string, ',').'],';
+
+ return $this;
+ }
+
+ /**
+ * Open a 'filter' block.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function filter()
+ {
+ return $this->fieldOpen('filter');
+ }
+
+ /**
+ * Close a filter block.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function filterClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Query.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function filteredQuery()
+ {
+ return $this->fieldOpen('filtered');
+ }
+
+ /**
+ * Close a 'filtered_query' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function filteredQueryClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Set the from parameter (offset).
+ *
+ * @param integer $value Result number to start from.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function from($value = 0)
+ {
+ return $this->field('from', $value);
+ }
+
+ /**
+ * Set the minimum similarity for fuzzy queries.
+ *
+ * @param float $value Defaults to 0.5.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function fuzzyMinSim($value = 0.5)
+ {
+ return $this->field('fuzzy_min_sim', (float) $value);
+ }
+
+ /**
+ * Set the prefix length for fuzzy queries.
+ *
+ * @param integer $value Defaults to 0.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function fuzzyPrefixLength($value = 0)
+ {
+ return $this->field('fuzzy_prefix_length', (int) $value);
+ }
+
+ /**
+ * Add a greater than (gt) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be gt.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function gt($value)
+ {
+ return $this->field('gt', $value);
+ }
+
+ /**
+ * Add a greater than or equal to (lt) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be gte to.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function gte($value)
+ {
+ return $this->field('gte', $value);
+ }
+
+ /**
+ * Automatically lower-case terms of wildcard, prefix, fuzzy, and range queries.
+ *
+ * @param boolean $bool Defaults to true.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function lowercaseExpandedTerms($bool = true)
+ {
+ return $this->field('lowercase_expanded_terms', (bool) $bool);
+ }
+
+ /**
+ * Add a less than (lt) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be lt.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function lt($value)
+ {
+ return $this->field('lt', $value);
+ }
+
+ /**
+ * Add a less than or equal to (lte) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be lte to.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function lte($value)
+ {
+ return $this->field('lte', $value);
+ }
+
+ /**
+ * Match All Query.
+ *
+ * A query that matches all documents.
+ *
+ * Maps to Lucene MatchAllDocsQuery.
+ *
+ * @param float $boost Boost to use.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function matchAll($boost = null)
+ {
+ $this->fieldOpen('match_all');
+
+ if ( ! $boost == null && is_numeric($boost)) {
+ $this->field('boost', (float) $boost);
+ }
+
+ return $this->close();
+ }
+
+ /**
+ * The minimum number of should clauses to match.
+ *
+ * @param integer $minimum Minimum number that should match.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function minimumNumberShouldMatch($minimum)
+ {
+ return $this->field('minimum_number_should_match', (int) $minimum);
+ }
+
+ /**
+ * @see minimumNumberShouldMatch()
+ * @deprecated
+ */
+ public function minimumShouldMatch($minimum)
+ {
+ return $this->minimumNumberShouldMatch($minimum);
+ }
+
+ /**
+ * The clause (query) must appear in matching documents.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function must()
+ {
+ return $this->fieldOpen('must');
+ }
+
+ /**
+ * Close a 'must' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function mustClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * The clause (query) must not appear in the matching documents.
+ *
+ * Note that it is not possible to search on documents that only consists of
+ * a must_not clauses.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function mustNot()
+ {
+ return $this->fieldOpen('must_not');
+ }
+
+ /**
+ * Close a 'must_not' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function mustNotClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Add an opening brace.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function open()
+ {
+ $this->_string .= '{';
+
+ return $this;
+ }
+
+ /**
+ * Sets the default slop for phrases.
+ *
+ * If zero, then exact phrase matches are required.
+ *
+ * @param integer $value Defaults to 0.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function phraseSlop($value = 0)
+ {
+ return $this->field('phrase_slop', (int) $value);
+ }
+
+ /**
+ * Query.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function prefix()
+ {
+ return $this->fieldOpen('prefix');
+ }
+
+ /**
+ * Close a 'prefix' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function prefixClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Queries to run within a dis_max query.
+ *
+ * @param array $queries Array of queries.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function queries(array $queries)
+ {
+ $this->_string .= '"queries":[';
+
+ foreach ($queries as $query) {
+ $this->_string .= $query.',';
+ }
+
+ $this->_string = rtrim($this->_string, ' ,').'],';
+
+ return $this;
+ }
+
+ /**
+ * Open a query block.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function query()
+ {
+ return $this->fieldOpen('query');
+ }
+
+ /**
+ * Close a query block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function queryClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Query String Query.
+ *
+ * A query that uses a query parser in order to parse its content
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function queryString()
+ {
+ return $this->fieldOpen('query_string');
+ }
+
+ /**
+ * Close a 'query_string' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function queryStringClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Open a range block.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function range()
+ {
+ return $this->fieldOpen('range');
+ }
+
+ /**
+ * Close a range block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function rangeClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * The clause (query) should appear in the matching document.
+ *
+ * A boolean query with no must clauses, one or more should clauses must
+ * match a document.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function should()
+ {
+ return $this->fieldOpen('should');
+ }
+
+ /**
+ * Close a 'should' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function shouldClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Set the size parameter (number of records to return).
+ *
+ * @param integer $value Number of records to return.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function size($value = 10)
+ {
+ return $this->field('size', $value);
+ }
+
+ /**
+ * Allows to add one or more sort on specific fields.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function sort()
+ {
+ return $this->fieldOpen('sort');
+ }
+
+ /**
+ * Close a sort block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function sortClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Add a field to sort on.
+ *
+ * @param string $name Field to sort.
+ * @param boolean $reverse Reverse direction.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function sortField($name, $reverse = false)
+ {
+ return $this
+ ->fieldOpen('sort')
+ ->fieldOpen($name)
+ ->field('reverse', $reverse)
+ ->close()
+ ->close();
+ }
+
+ /**
+ * Sort on multiple fields
+ *
+ * @param array $fields Associative array where the keys are field names to sort on, and the
+ * values are the sort order: "asc" or "desc"
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function sortFields(array $fields)
+ {
+ $this->_string .= '"sort":[';
+
+ foreach ($fields as $fieldName => $order) {
+ $this->_string .= '{"'.$fieldName.'":"'.$order.'"},';
+ }
+
+ $this->_string = rtrim($this->_string, ',') . '],';
+
+ return $this;
+ }
+
+ /**
+ * Term Query.
+ *
+ * Matches documents that have fields that contain a term (not analyzed).
+ *
+ * The term query maps to Lucene TermQuery.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function term()
+ {
+ return $this->fieldOpen('term');
+ }
+
+ /**
+ * Close a 'term' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function termClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Open a 'text_phrase' block.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function textPhrase()
+ {
+ return $this->fieldOpen('text_phrase');
+ }
+
+ /**
+ * Close a 'text_phrase' block.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function textPhraseClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * When using dis_max, the disjunction max tie breaker.
+ *
+ * @param float $multiplier Multiplier to use.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function tieBreakerMultiplier($multiplier)
+ {
+ return $this->field('tie_breaker_multiplier', (float) $multiplier);
+ }
+
+ /**
+ * @see tieBreakerMultiplier
+ * @deprecated
+ */
+ public function tieBreaker($multiplier)
+ {
+ return $this->tieBreakerMultiplier($multiplier);
+ }
+
+ /**
+ * Query.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function wildcard()
+ {
+ return $this->fieldOpen('wildcard');
+ }
+
+ /**
+ * Close a 'wildcard' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return Elastica_Query_Builder
+ */
+ public function wildcardClose()
+ {
+ return $this->fieldClose();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/ConstantScore.php b/modules/thirdparty/elastica/lib/Elastica/Query/ConstantScore.php
new file mode 100644
index 0000000..b819006
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/ConstantScore.php
@@ -0,0 +1,51 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/constant-score-query.html
+ */
+class Elastica_Query_ConstantScore extends Elastica_Query_Abstract
+{
+ /**
+ * Construct constant score query
+ *
+ * @param null|Elastica_Filter_Abstract|array $filter
+ */
+ public function __construct($filter = null)
+ {
+ if (!is_null($filter)) {
+ $this->setFilter($filter);
+ }
+ }
+
+ /**
+ * Set filter
+ *
+ * @param array|Elastica_Filter_Abstract $filter
+ * @return Elastica_Query_ConstantScore Query object
+ */
+ public function setFilter($filter)
+ {
+ if ($filter instanceof Elastica_Filter_Abstract) {
+ $filter = $filter->toArray();
+ }
+
+ return $this->setParam('filter', $filter);
+ }
+
+ /**
+ * Set boost
+ *
+ * @param float $boost
+ * @return Elastica_Query_ConstantScore
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', $boost);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/CustomFiltersScore.php b/modules/thirdparty/elastica/lib/Elastica/Query/CustomFiltersScore.php
new file mode 100644
index 0000000..267035d
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/CustomFiltersScore.php
@@ -0,0 +1,55 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/custom-filters-score-query.html
+ */
+class Elastica_Query_CustomFiltersScore extends Elastica_Query_Abstract
+{
+ /**
+ * Sets a query
+ *
+ * @param Elastica_Query_Abstract $query Query object
+ * @return Elastica_Query_CustomFiltersScore Current object
+ */
+ public function setQuery(Elastica_Query_Abstract $query)
+ {
+ $this->setParam('query', $query->toArray());
+
+ return $this;
+ }
+
+ /**
+ * Add a filter with boost
+ *
+ * @param Elastica_Filter_Abstract $filter Filter object
+ * @param float $boost Boost for the filter
+ * @return Elastica_Query_CustomFiltersScore Current object
+ */
+ public function addFilter(Elastica_Filter_Abstract $filter, $boost)
+ {
+ $filterParam = array('filter' => $filter->toArray(), 'boost' => $boost);
+ $this->addParam('filters', $filterParam);
+
+ return $this;
+ }
+
+ /**
+ * Add a filter with a script to calculate the score
+ *
+ * @param Elastica_Filter_Abstract $filter Filter object
+ * @param Elastica_Script $script Script for calculating the score
+ * @return Elastica_Query_CustomFiltersScore Current object
+ */
+ public function addFilterScript(Elastica_Filter_Abstract $filter, Elastica_Script $script)
+ {
+ $filterParam = array('filter' => $filter->toArray(), 'script' => $script->getScript());
+ $this->addParam('filters', $filterParam);
+
+ return $this;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/CustomScore.php b/modules/thirdparty/elastica/lib/Elastica/Query/CustomScore.php
new file mode 100644
index 0000000..e05a7ea
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/CustomScore.php
@@ -0,0 +1,51 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/custom-score-query.html
+ */
+class Elastica_Query_CustomScore extends Elastica_Query_Abstract
+{
+ /**
+ * Sets query object
+ *
+ * @param string|Elastica_Query|Elastica_Query_Abstract $query
+ * @return Elastica_Query_CustomScore
+ */
+ public function setQuery($query)
+ {
+ $query = Elastica_Query::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Set script
+ *
+ * @param string $script
+ * @return Elastica_Query_CustomScore
+ */
+ public function setScript($script)
+ {
+ return $this->setParam('script', $script);
+ }
+
+ /**
+ * Add params
+ *
+ * @param array $params
+ * @return Elastica_Query_CustomScore
+ */
+ public function addParams(array $params)
+ {
+ $this->setParam('params', $params);
+
+ return $this;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Field.php b/modules/thirdparty/elastica/lib/Elastica/Query/Field.php
new file mode 100755
index 0000000..818b931
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Field.php
@@ -0,0 +1,81 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/field_query/
+ */
+class Elastica_Query_Field extends Elastica_Query_Abstract
+{
+ /**
+ * Field for object
+ *
+ * @var string Field for object
+ */
+ protected $_field = '';
+
+ /**
+ * Query string
+ *
+ * @var string Query string
+ */
+ protected $_queryString = '';
+
+ /**
+ * Creates field query object. Calls setField and setQuery with argument
+ *
+ * @param string $field OPTIONAL field for object
+ * @param string $queryString OPTIONAL Query string for object
+ */
+ public function __construct($field = '', $queryString = '')
+ {
+ $this->setField($field);
+ $this->setQueryString($queryString);
+ }
+
+ /**
+ * Sets the field
+ *
+ * @param string $field Field
+ * @return Elastica_Query_Field Current object
+ */
+ public function setField($field)
+ {
+ $this->_field = $field;
+
+ return $this;
+ }
+
+ /**
+ * Sets a new query string for the object
+ *
+ * @param string $queryString Query string
+ * @return Elastica_Query_Field Current object
+ */
+ public function setQueryString($queryString)
+ {
+ if (!is_string($queryString)) {
+ throw new Elastica_Exception_Invalid('Parameter has to be a string');
+ }
+
+ $this->_queryString = $queryString;
+
+ return $this;
+ }
+
+ /**
+ * Converts query to array
+ *
+ * @return array Query array
+ * @see Elastica_Query_Abstract::toArray()
+ */
+ public function toArray()
+ {
+ $this->setParam($this->_field, array('query' => $this->_queryString));
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Filtered.php b/modules/thirdparty/elastica/lib/Elastica/Query/Filtered.php
new file mode 100644
index 0000000..3d8a15b
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Filtered.php
@@ -0,0 +1,78 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/fuzzy_query/
+ */
+class Elastica_Query_Filtered extends Elastica_Query_Abstract
+{
+ /**
+ * Query
+ *
+ * @var Elastica_Query_Abstract Query object
+ */
+ protected $_query = null;
+
+ /**
+ * Filter
+ *
+ * @var Elastica_Filter_Abstract Filter object
+ */
+ protected $_filter = null;
+
+ /**
+ * Constructs a filtered query
+ *
+ * @param Elastica_Query_Abstract $query Query object
+ * @param Elastica_Filter_Abstract $filter Filter object
+ */
+ public function __construct(Elastica_Query_Abstract $query, Elastica_Filter_Abstract $filter)
+ {
+ $this->setQuery($query);
+ $this->setFilter($filter);
+ }
+
+ /**
+ * Sets a query
+ *
+ * @param Elastica_Query_Abstract $query Query object
+ * @return Elastica_Query_Filtered Current object
+ */
+ public function setQuery(Elastica_Query_Abstract $query)
+ {
+ $this->_query = $query;
+
+ return $this;
+ }
+
+ /**
+ * Sets the filter
+ *
+ * @param Elastica_Filter_Abstract $filter Filter object
+ * @return Elastica_Query_Filtered Current object
+ */
+ public function setFilter(Elastica_Filter_Abstract $filter)
+ {
+ $this->_filter = $filter;
+
+ return $this;
+ }
+
+ /**
+ * Converts query to array
+ *
+ * @return array Query array
+ * @see Elastica_Query_Abstract::toArray()
+ */
+ public function toArray()
+ {
+ return array('filtered' => array(
+ 'query' => $this->_query->toArray(),
+ 'filter' => $this->_filter->toArray()
+ ));
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Fuzzy.php b/modules/thirdparty/elastica/lib/Elastica/Query/Fuzzy.php
new file mode 100755
index 0000000..a751e0e
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Fuzzy.php
@@ -0,0 +1,24 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/fuzzy_query/
+ */
+class Elastica_Query_Fuzzy extends Elastica_Query_Abstract
+{
+ /**
+ * Adds field to fuzzy query
+ *
+ * @param string $fieldName Field name
+ * @param array $args Data array
+ * @return Elastica_Query_Fuzzy Current object
+ */
+ public function addField($fieldName, array $args)
+ {
+ return $this->setParam($fieldName, $args);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/FuzzyLikeThis.php b/modules/thirdparty/elastica/lib/Elastica/Query/FuzzyLikeThis.php
new file mode 100644
index 0000000..99fe1ae
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/FuzzyLikeThis.php
@@ -0,0 +1,162 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html
+ */
+class Elastica_Query_FuzzyLikeThis extends Elastica_Query_Abstract
+{
+ /**
+ * Field names
+ *
+ * @var array Field names
+ */
+ protected $_fields = array();
+
+ /**
+ * Like text
+ *
+ * @var string Like text
+ */
+ protected $_likeText = '';
+
+ /**
+ * Max query terms value
+ *
+ * @var int Max query terms value
+ */
+ protected $_maxQueryTerms = 25;
+
+ /**
+ * minimum similarity
+ *
+ * @var int minimum similarity
+ */
+ protected $_minSimilarity = 0.5;
+
+ /**
+ * Prefix Length
+ *
+ * @var int Prefix Length
+ */
+ protected $_prefixLength = 0;
+
+ /**
+ * Boost
+ *
+ * @var float Boost
+ */
+ protected $_boost = 1.0;
+
+ /**
+ * Adds field to flt query
+ *
+ * @param array $fields Field names
+ * @return Elastica_Query_FuzzyLikeThis Current object
+ */
+ public function addFields(array $fields)
+ {
+ $this->_fields = $fields;
+
+ return $this;
+ }
+
+ /**
+ * Set the "like_text" value
+ *
+ * @param string $text
+ * @return Elastica_Query_FuzzyLikeThis This current object
+ */
+ public function setLikeText($text)
+ {
+ $text = trim($text);
+ $this->_likeText = $text;
+
+ return $this;
+ }
+
+ /**
+ * Set the minimum similarity
+ *
+ * @param int $value
+ * @return Elastica_Query_FuzzyLikeThis This current object
+ */
+ public function setMinSimilarity($value)
+ {
+ $value = (float) $value;
+ $this->_minSimilarity = $value;
+
+ return $this;
+ }
+
+ /**
+ * Set boost
+ *
+ * @param float $value Boost value
+ * @return Elastica_Query_FuzzyLikeThis Query object
+ */
+ public function setBoost($value)
+ {
+ $this->_boost = (float) $value;
+
+ return $this;
+ }
+
+ /**
+ * Set Prefix Length
+ *
+ * @param int $value Prefix length
+ * @return Elastica_Query_FuzzyLikeThis
+ */
+ public function setPrefixLength($value)
+ {
+ $this->_prefixLength = (int) $value;
+
+ return $this;
+ }
+
+ /**
+ * Set max_query_terms
+ *
+ * @param int $value Max query terms value
+ * @return Elastica_Query_FuzzyLikeThis
+ */
+ public function setMaxQueryTerms($value)
+ {
+ $this->_maxQueryTerms = (int) $value;
+
+ return $this;
+ }
+
+ /**
+ * Converts fuzzy like this query to array
+ *
+ * @return array Query array
+ * @see Elastica_Query_Abstract::toArray()
+ */
+ public function toArray()
+ {
+ if (!empty($this->_fields)) {
+ $args['fields'] = $this->_fields;
+ }
+
+ if (!empty($this->_boost)) {
+ $args['boost'] = $this->_boost;
+ }
+
+ if (!empty($this->_likeText)) {
+ $args['like_text'] = $this->_likeText;
+ }
+
+ $args['min_similarity'] = ($this->_minSimilarity > 0) ? $this->_minSimilarity : 0;
+
+ $args['prefix_length'] = $this->_prefixLength;
+ $args['max_query_terms'] = $this->_maxQueryTerms;
+
+ return array('fuzzy_like_this' => $args);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/HasChild.php b/modules/thirdparty/elastica/lib/Elastica/Query/HasChild.php
new file mode 100644
index 0000000..6bd625f
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/HasChild.php
@@ -0,0 +1,50 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/has-child-query.html
+ */
+class Elastica_Query_HasChild extends Elastica_Query_Abstract
+{
+ /**
+ * Construct HasChild Query
+ *
+ * @param string|Elastica_Query $query Query string or a Elastica_Query object
+ * @param string $type Parent document type
+ */
+ public function __construct($query, $type = null)
+ {
+ $this->setQuery($query);
+ $this->setType($type);
+ }
+
+ /**
+ * Sets query object
+ *
+ * @param string|Elastica_Query|Elastica_Query_Abstract $query
+ * @return Elastica_Query_HasChild
+ */
+ public function setQuery($query)
+ {
+ $query = Elastica_Query::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Set type of the parent document
+ *
+ * @param string $type Parent document type
+ * @return Elastica_Query_HasChild Current object
+ */
+ public function setType($type)
+ {
+ return $this->setParam('type', $type);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Ids.php b/modules/thirdparty/elastica/lib/Elastica/Query/Ids.php
new file mode 100644
index 0000000..d6186f8
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Ids.php
@@ -0,0 +1,114 @@
+
+ * @author Tim Rupp
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/ids-query.html
+ */
+class Elastica_Query_Ids extends Elastica_Query_Abstract
+{
+ /**
+ * Params
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Creates filter object
+ *
+ * @param string|Elastica_Type $type Type to filter on
+ * @param array $ids List of ids
+ */
+ public function __construct($type = null, array $ids = array())
+ {
+ $this->setType($type);
+ $this->setIds($ids);
+ }
+
+ /**
+ * Adds one more filter to the and filter
+ *
+ * @param string $id Adds id to filter
+ * @return Elastica_Query_Ids Current object
+ */
+ public function addId($id)
+ {
+ $this->_params['values'][] = $id;
+
+ return $this;
+ }
+
+ /**
+ * Adds one more type to query
+ *
+ * @param string $type Adds type to query
+ * @return Elastica_Query_Ids Current object
+ */
+ public function addType($type)
+ {
+ if ($type instanceof Elastica_Type) {
+ $type = $type->getType();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ $this->_params['type'][] = $type;
+
+ return $this;
+ }
+
+ /**
+ * Set type
+ *
+ * @param string|Elastica_Type $type Type name or object
+ * @return Elastica_Query_Ids Current object
+ */
+ public function setType($type)
+ {
+ if ($type instanceof Elastica_Type) {
+ $type = $type->getType();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ $this->_params['type'] = $type;
+
+ return $this;
+ }
+
+ /**
+ * Sets the ids to filter
+ *
+ * @param array|string $ids List of ids
+ * @return Elastica_Query_Ids Current object
+ */
+ public function setIds($ids)
+ {
+ if (is_array($ids)) {
+ $this->_params['values'] = $ids;
+ } else {
+ $this->_params['values'] = array($ids);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Converts filter to array
+ *
+ * @see Elastica_Query_Abstract::toArray()
+ * @return array Query array
+ */
+ public function toArray()
+ {
+ return array('ids' => $this->_params);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/MatchAll.php b/modules/thirdparty/elastica/lib/Elastica/Query/MatchAll.php
new file mode 100755
index 0000000..ee88468
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/MatchAll.php
@@ -0,0 +1,19 @@
+
+ */
+class Elastica_Query_MatchAll extends Elastica_Query_Abstract
+{
+ /**
+ * Creates match all query
+ */
+ public function __construct()
+ {
+ $this->_params = new stdClass();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/MoreLikeThis.php b/modules/thirdparty/elastica/lib/Elastica/Query/MoreLikeThis.php
new file mode 100644
index 0000000..19d289c
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/MoreLikeThis.php
@@ -0,0 +1,160 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/mlt-query.html
+ */
+class Elastica_Query_MoreLikeThis extends Elastica_Query_Abstract
+{
+ /**
+ * Adds field to mlt query
+ *
+ * @param array $fields Field names
+ * @return Elastica_Query_MoreLikeThis Current object
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Set the "like_text" value
+ *
+ * @param string $likeText
+ * @return Elastica_Query_MoreLikeThis This current object
+ */
+ public function setLikeText($likeText)
+ {
+ $likeText = trim($likeText);
+
+ return $this->setParam('like_text', $likeText);
+ }
+
+ /**
+ * Set boost
+ *
+ * @param float $boost Boost value
+ * @return Elastica_Query_MoreLikeThis Query object
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', (float) $boost);
+ }
+
+ /**
+ * Set max_query_terms
+ *
+ * @param int $maxQueryTerms Max query terms value
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setMaxQueryTerms($maxQueryTerms)
+ {
+ return $this->setParam('max_query_terms', (int) $maxQueryTerms);
+ }
+
+ /**
+ * Set percent terms to match
+ *
+ * @param float $percentTermsToMatch Percentage
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setPercentTermsToMatch($percentTermsToMatch)
+ {
+ return $this->setParam('percent_terms_to_match', (float) $percentTermsToMatch);
+ }
+
+ /**
+ * Set min term frequency
+ *
+ * @param int $minTermFreq
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setMinTermFrequency($minTermFreq)
+ {
+ return $this->setParam('min_term_freq', (int) $minTermFreq);
+ }
+
+ /**
+ * set min document frequency
+ *
+ * @param int $minDocFreq
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setMinDocFrequency($minDocFreq)
+ {
+ return $this->setParam('min_doc_freq', (int) $minDocFreq);
+ }
+
+ /**
+ * set max document frequency
+ *
+ * @param int $maxDocFreq
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setMaxDocFrequency($maxDocFreq)
+ {
+ return $this->setParam('max_doc_freq', (int) $maxDocFreq);
+ }
+
+ /**
+ * Set min word length
+ *
+ * @param int $minWordLength
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setMinWordLength($minWordLength)
+ {
+ return $this->setParam('min_word_length', (int) $minWordLength);
+ }
+
+ /**
+ * Set max word length
+ *
+ * @param int $maxWordLength
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setMaxWordLength($maxWordLength)
+ {
+ return $this->setParam('max_word_length', (int) $maxWordLength);
+ }
+
+ /**
+ * Set boost terms
+ *
+ * @param bool $boostTerms
+ * @return Elastica_Query_MoreLikeThis
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/mlt-query.html
+ */
+ public function setBoostTerms($boostTerms)
+ {
+ return $this->setParam('boost_terms', (bool) $boostTerms);
+ }
+
+ /**
+ * Set analyzer
+ *
+ * @param string $analyzer
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setAnalyzer($analyzer)
+ {
+ $analyzer = trim($analyzer);
+
+ return $this->setParam('analyzer', $analyzer);
+ }
+
+ /**
+ * Set stopwords
+ *
+ * @param array $stopWords
+ * @return Elastica_Query_MoreLikeThis
+ */
+ public function setStopWords(array $stopWords)
+ {
+ return $this->setParam('stop_words', $stopWords);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Nested.php b/modules/thirdparty/elastica/lib/Elastica/Query/Nested.php
new file mode 100644
index 0000000..9f517a3
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Nested.php
@@ -0,0 +1,45 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/nested-query.html
+ */
+class Elastica_Query_Nested extends Elastica_Query_Abstract
+{
+ /**
+ * Adds field to mlt query
+ *
+ * @param string $path Nested object path
+ * @return Elastica_Query_Nested
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+
+ /**
+ * Sets nested query
+ *
+ * @param Elastica_Query_Abstract $query
+ * @return Elastica_Query_Nested
+ */
+ public function setQuery(Elastica_Query_Abstract $query)
+ {
+ return $this->setParam('query', $query->toArray());
+ }
+
+ /**
+ * Set score method
+ *
+ * @param string $scoreMode Options: avg, total, max and none.
+ * @return Elastica_Query_Nested
+ */
+ public function setScoreMode($scoreMode)
+ {
+ return $this->setParam('score_mode', $scoreMode);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/QueryString.php b/modules/thirdparty/elastica/lib/Elastica/Query/QueryString.php
new file mode 100755
index 0000000..f8229e5
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/QueryString.php
@@ -0,0 +1,276 @@
+, Jasper van Wanrooy
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/query-string-query.html
+ */
+class Elastica_Query_QueryString extends Elastica_Query_Abstract
+{
+ /**
+ * Query string
+ *
+ * @var string Query string
+ */
+ protected $_queryString = '';
+
+ /**
+ * Creates query string object. Calls setQuery with argument
+ *
+ * @param string $queryString OPTIONAL Query string for object
+ */
+ public function __construct($queryString = '')
+ {
+ $this->setQuery($queryString);
+ }
+
+ /**
+ * Sets a new query string for the object
+ *
+ * @param string $query Query string
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setQuery($query = '')
+ {
+ if (!is_string($query)) {
+ throw new Elastica_Exception_Invalid('Parameter has to be a string');
+ }
+
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * Sets the default operator AND or OR
+ *
+ * If no operator is set, OR is chosen
+ *
+ * @param string $queryString Query string
+ * @return Elastica_Query_QueryString Current object
+ * @deprecated Please use setQuery instead
+ */
+ public function setQueryString($queryString)
+ {
+ return $this->setQuery($queryString);
+ }
+
+ /**
+ * Sets the default field
+ *
+ * If no field is set, _all is chosen
+ *
+ * @param string $field Field
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setDefaultField($field)
+ {
+ return $this->setParam('default_field', $field);
+ }
+
+ /**
+ * Sets the default operator AND or OR
+ *
+ * If no operator is set, OR is chosen
+ *
+ * @param string $operator Operator
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setDefaultOperator($operator)
+ {
+ return $this->setParam('default_operator', $operator);
+ }
+
+ /**
+ * Sets the analyzer to analyze the query with.
+ *
+ * @param string $analyzer Analyser to use
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setAnalyzer($analyzer)
+ {
+ return $this->setParam('analyzer', $analyzer);
+ }
+
+ /**
+ * Sets the parameter to allow * and ? as first characters.
+ *
+ * If not set, defaults to true.
+ *
+ * @param bool $allow
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setAllowLeadingWildcard($allow = true)
+ {
+ return $this->setParam('allow_leading_wildcard', (bool) $allow);
+ }
+
+ /**
+ * Sets the parameter to auto-lowercase terms of some queries.
+ *
+ * If not set, defaults to true.
+ *
+ * @param bool $lowercase
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setLowercaseExpandedTerms($lowercase = true)
+ {
+ return $this->setParam('lowercase_expanded_terms', (bool) $lowercase);
+ }
+
+ /**
+ * Sets the paramater to enable the position increments in result queries.
+ *
+ * If not set, defaults to true.
+ *
+ * @param bool $enabled
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setEnablePositionIncrements($enabled = true)
+ {
+ return $this->setParam('enable_position_increments', (bool) $enabled);
+ }
+
+ /**
+ * Sets the fuzzy prefix length parameter.
+ *
+ * If not set, defaults to 0.
+ *
+ * @param int $length
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setFuzzyPrefixLength($length = 0)
+ {
+ return $this->setParam('fuzzy_prefix_length', (int) $length);
+ }
+
+ /**
+ * Sets the fuzzy minimal similarity parameter.
+ *
+ * If not set, defaults to 0.5
+ *
+ * @param float $minSim
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setFuzzyMinSim($minSim = 0.5)
+ {
+ return $this->setParam('fuzzy_min_sim', (float) $minSim);
+ }
+
+ /**
+ * Sets the phrase slop.
+ *
+ * If zero, exact phrases are required.
+ * If not set, defaults to zero.
+ *
+ * @param int $phraseSlop
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setPhraseSlop($phraseSlop = 0)
+ {
+ return $this->setParam('phrase_slop', (int) $phraseSlop);
+ }
+
+ /**
+ * Sets the boost value of the query.
+ *
+ * If not set, defaults to 1.0.
+ *
+ * @param float $boost
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setBoost($boost = 1.0)
+ {
+ return $this->setParam('boost', (float) $boost);
+ }
+
+ /**
+ * Allows analyzing of wildcard terms.
+ *
+ * If not set, defaults to false
+ *
+ * @param bool $analyze
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setAnalyzeWildcard($analyze = true)
+ {
+ return $this->setParam('analyze_wildcard', (bool) $analyze);
+ }
+
+ /**
+ * Sets the param to automatically generate phrase queries.
+ *
+ * If not set, defaults to false.
+ *
+ * @param bool $autoGenerate
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setAutoGeneratePhraseQueries($autoGenerate = true)
+ {
+ return $this->setParam('auto_generate_phrase_queries', (bool) $autoGenerate);
+ }
+
+ /**
+ * Sets the fields
+ *
+ * If no fields are set, _all is chosen
+ *
+ * @param array $fields Fields
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setFields(array $fields)
+ {
+ if (!is_array($fields)) {
+ throw new Elastica_Exception_Invalid('Parameter has to be an array');
+ }
+
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Whether to use bool or dis_max quueries to internally combine results for multi field search.
+ *
+ * @param bool $value Determines whether to use
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setUseDisMax($value = true)
+ {
+ return $this->setParam('use_dis_max', (bool) $value);
+ }
+
+ /**
+ * When using dis_max, the disjunction max tie breaker.
+ *
+ * If not set, defaults to 0.
+ *
+ * @param int $tieBreaker
+ * @return Elastica_Query_QueryString Current object
+ */
+ public function setTieBraker($tieBreaker = 0)
+ {
+ return $this->setParam('tie_breaker', (int) $tieBreaker);
+ }
+
+ /**
+ * Set a re-write condition. See https://github.com/elasticsearch/elasticsearch/issues/1186 for additional information
+ *
+ * @param string $rewrite
+ * @return Elastica_Param
+ */
+ public function setRewrite($rewrite = "")
+ {
+ return $this->setParam('rewrite', $rewrite);
+ }
+
+ /**
+ * Converts query to array
+ *
+ * @see Elastica_Param::toArray()
+ * @return array Query array
+ */
+ public function toArray()
+ {
+ return array('query_string' => array_merge(array('query' => $this->_queryString), $this->getParams()),);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Range.php b/modules/thirdparty/elastica/lib/Elastica/Query/Range.php
new file mode 100755
index 0000000..1e5f674
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Range.php
@@ -0,0 +1,25 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/range_query/
+ */
+class Elastica_Query_Range extends Elastica_Query_Abstract
+{
+ /**
+ * Adds a range field to the query
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ * @return Elastica_Query_Range Current object
+ */
+ public function addField($fieldName, array $args)
+ {
+ return $this->setParam($fieldName, $args);
+
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Term.php b/modules/thirdparty/elastica/lib/Elastica/Query/Term.php
new file mode 100755
index 0000000..772418a
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Term.php
@@ -0,0 +1,47 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/term_query/
+ */
+class Elastica_Query_Term extends Elastica_Query_Abstract
+{
+ /**
+ * Constructs the Term query object
+ *
+ * @param array $term OPTIONAL Calls setTerm with the given $term array
+ */
+ public function __construct(array $term = array())
+ {
+ $this->setRawTerm($term);
+ }
+
+ /**
+ * Set term can be used instead of addTerm if some more special
+ * values for a term have to be set.
+ *
+ * @param array $term Term array
+ * @return Elastica_Query_Term Current object
+ */
+ public function setRawTerm(array $term)
+ {
+ return $this->setParams($term);
+ }
+
+ /**
+ * Adds a term to the term query
+ *
+ * @param string $key Key to query
+ * @param string|array $value Values(s) for the query. Boost can be set with array
+ * @param float $boost OPTIONAL Boost value (default = 1.0)
+ * @return Elastica_Query_Term Current object
+ */
+ public function setTerm($key, $value, $boost = 1.0)
+ {
+ return $this->setRawTerm(array($key => array('value' => $value, 'boost' => $boost)));
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Terms.php b/modules/thirdparty/elastica/lib/Elastica/Query/Terms.php
new file mode 100755
index 0000000..4577f21
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Terms.php
@@ -0,0 +1,96 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/terms-query.html
+ */
+class Elastica_Query_Terms extends Elastica_Query_Abstract
+{
+ /**
+ * Terms
+ *
+ * @var array Terms
+ */
+ protected $_terms = array();
+
+ /**
+ * Params
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Terms key
+ *
+ * @var string Terms key
+ */
+ protected $_key = '';
+
+ /**
+ * Construct terms query
+ *
+ * @param string $key OPTIONAL Terms key
+ * @param array $terms OPTIONAL Terms list
+ */
+ public function __construct($key = '', array $terms = array())
+ {
+ $this->setTerms($key, $terms);
+ }
+
+ /**
+ * Sets key and terms for the query
+ *
+ * @param string $key Terms key
+ * @param array $terms Terms for the query.
+ */
+ public function setTerms($key, array $terms)
+ {
+ $this->_key = $key;
+ $this->_terms = array_values($terms);
+
+ return $this;
+ }
+
+ /**
+ * Adds a single term to the list
+ *
+ * @param string $term Term
+ */
+ public function addTerm($term)
+ {
+ $this->_terms[] = $term;
+
+ return $this;
+ }
+
+ /**
+ * Sets the minimum matching values
+ *
+ * @param int $minimum Minimum value
+ */
+ public function setMinimumMatch($minimum)
+ {
+ return $this->setParam('minimum_match', (int) $minimum);
+ }
+
+ /**
+ * Converts the terms object to an array
+ *
+ * @return array Query array
+ * @see Elastica_Query_Abstract::toArray()
+ */
+ public function toArray()
+ {
+ if (empty($this->_key)) {
+ throw new Elastica_Exception_Invalid('Terms key has to be set');
+ }
+ $this->setParam($this->_key, $this->_terms);
+
+ return parent::toArray();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Text.php b/modules/thirdparty/elastica/lib/Elastica/Query/Text.php
new file mode 100644
index 0000000..a0bdc8e
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Text.php
@@ -0,0 +1,79 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/text-query.html
+ */
+class Elastica_Query_Text extends Elastica_Query_Abstract
+{
+ /**
+ * Sets a param for the message array
+ *
+ * @param string $field
+ * @param mixed $values
+ * @return Elastica_Query_Text
+ */
+ public function setField($field, $values)
+ {
+ return $this->setParam($field, $values);
+ }
+
+ /**
+ * Sets a param for the given field
+ *
+ * @param string $field
+ * @param string $key
+ * @param string $value
+ * @return Elastica_Query_Text
+ */
+ public function setFieldParam($field, $key, $value)
+ {
+ if (!isset($this->_params[$field])) {
+ $this->_params[$field] = array();
+ }
+
+ $this->_params[$field][$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets the query string
+ *
+ * @param string $field
+ * @param string $query
+ * @return Elastica_Query_Text
+ */
+ public function setFieldQuery($field, $query)
+ {
+ return $this->setFieldParam($field, 'query', $query);
+ }
+
+ /**
+ * Set field type
+ *
+ * @param string $field
+ * @param string $type Text query type
+ * @return Elastica_Query_Text
+ */
+ public function setFieldType($field, $type)
+ {
+ return $this->setFieldParam($field, 'type', $type);
+ }
+
+ /**
+ * Set field max expansions
+ *
+ * @param string $field
+ * @param int $maxExpansions
+ * @return Elastica_Query_Text
+ */
+ public function setFieldMaxExpansions($field, $maxExpansions)
+ {
+ return $this->setFieldParam($field, 'max_expansions', $maxExpansions);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/TopChildren.php b/modules/thirdparty/elastica/lib/Elastica/Query/TopChildren.php
new file mode 100644
index 0000000..f412064
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/TopChildren.php
@@ -0,0 +1,50 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/query-dsl/top-children-query.html
+ */
+class Elastica_Query_TopChildren extends Elastica_Query_Abstract
+{
+ /**
+ * Construct topChildren query
+ *
+ * @param string|Elastica_Query $query Query string or a Elastica_Query object
+ * @param string $type Parent document type
+ */
+ public function __construct($query, $type = null)
+ {
+ $this->setQuery($query);
+ $this->setType($type);
+ }
+
+ /**
+ * Sets query object
+ *
+ * @param string|Elastica_Query|Elastica_Query_Abstract $query
+ * @return Elastica_Query_TopChildren
+ */
+ public function setQuery($query)
+ {
+ $query = Elastica_Query::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Set type of the parent document
+ *
+ * @param string $type Parent document type
+ * @return Elastica_Query_TopChildren Current object
+ */
+ public function setType($type)
+ {
+ return $this->setParam('type', $type);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Wildcard.php b/modules/thirdparty/elastica/lib/Elastica/Query/Wildcard.php
new file mode 100755
index 0000000..c385577
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Query/Wildcard.php
@@ -0,0 +1,38 @@
+
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/wildcard_query
+ */
+class Elastica_Query_Wildcard extends Elastica_Query_Abstract
+{
+ /**
+ * Construct wildcard query
+ *
+ * @param string $key OPTIONAL Wildcard key
+ * @param string $value OPTIONAL Wildcard value
+ * @param float $boost OPTIONAL Boost value (default = 1)
+ */
+ public function __construct($key = '', $value = null, $boost = 1.0)
+ {
+ if (!empty($key)) {
+ $this->setValue($key, $value, $boost);
+ }
+ }
+
+ /**
+ * Sets the query expression for a key with its boost value
+ *
+ * @param string $key
+ * @param string $value
+ * @param float $boost
+ */
+ public function setValue($key, $value, $boost = 1.0)
+ {
+ $this->setParam($key, array('value' => $value, 'boost' => $boost));
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Request.php b/modules/thirdparty/elastica/lib/Elastica/Request.php
new file mode 100755
index 0000000..b654d39
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Request.php
@@ -0,0 +1,244 @@
+
+ */
+class Elastica_Request
+{
+ const POST = 'POST';
+ const PUT = 'PUT';
+ const GET = 'GET';
+ const DELETE = 'DELETE';
+
+ /**
+ * Client
+ *
+ * @var Elastica_Client Client object
+ */
+ protected $_client;
+
+ /**
+ * Request path
+ *
+ * @var string Request path
+ */
+ protected $_path;
+
+ /**
+ * Request method (use const's)
+ *
+ * @var string Request method (use const's)
+ */
+ protected $_method;
+
+ /**
+ * Data array
+ *
+ * @var array Data array
+ */
+ protected $_data;
+
+ /**
+ * Query params
+ *
+ * @var array Query params
+ */
+ protected $_query;
+
+ /**
+ * Internal id of last used server. This is used for round robin
+ *
+ * @var int Last server id
+ */
+ protected static $_serverId = null;
+
+ /**
+ * Construct
+ *
+ * @param Elastica_Client $client
+ * @param string $path Request path
+ * @param string $method Request method (use const's)
+ * @param array $data OPTIONAL Data array
+ * @param array $query OPTIONLA Query params
+ */
+ public function __construct(Elastica_Client $client, $path, $method, $data = array(), array $query = array())
+ {
+ $this->_client = $client;
+ $this->_path = $path;
+ $this->_method = $method;
+ $this->_data = $data;
+ $this->_query = $query;
+ }
+
+ /**
+ * Sets the request method. Use one of the for consts
+ *
+ * @param string $method Request method
+ * @return Elastica_Request Current object
+ */
+ public function setMethod($method)
+ {
+ $this->_method = $method;
+
+ return $this;
+ }
+
+ /**
+ * Get request method
+ *
+ * @return string Request method
+ */
+ public function getMethod()
+ {
+ return $this->_method;
+ }
+
+ /**
+ * Sets the request data
+ *
+ * @param array $data Request data
+ */
+ public function setData($data)
+ {
+ $this->_data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Return request data
+ *
+ * @return array Request data
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Sets the request path
+ *
+ * @param string $path Request path
+ * @return Elastica_Request Current object
+ */
+ public function setPath($path)
+ {
+ $this->_path = $path;
+
+ return $this;
+ }
+
+ /**
+ * Return request path
+ *
+ * @return string Request path
+ */
+ public function getPath()
+ {
+ return $this->_path;
+ }
+
+ /**
+ * Return query params
+ *
+ * @return array Query params
+ */
+ public function getQuery()
+ {
+ return $this->_query;
+ }
+
+ /**
+ * Return Client Object
+ *
+ * @return Elastica_Client
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Returns a specific config key or the whole
+ * config array if not set
+ *
+ * @param string $key Config key
+ * @return array|string Config value
+ */
+ public function getConfig($key = '')
+ {
+ return $this->getClient()->getConfig($key);
+ }
+
+ /**
+ * Returns an instance of the transport type
+ *
+ * @return Elastica_Transport_Abstract Transport object
+ * @throws Elastica_Exception_Invalid If invalid transport type
+ */
+ public function getTransport()
+ {
+ $className = 'Elastica_Transport_' . $this->_client->getConfig('transport');
+ if (!class_exists($className)) {
+ throw new Elastica_Exception_Invalid('Invalid transport');
+ }
+
+ return new $className($this);
+ }
+
+ /**
+ * Sends request to server
+ *
+ * @return Elastica_Response Response object
+ */
+ public function send()
+ {
+ $log = new Elastica_Log($this->getClient());
+ $log->log($this);
+
+ $transport = $this->getTransport();
+
+ $servers = $this->getClient()->getConfig('servers');
+
+ /*
+
+ // Integration of temp file
+ $dir = sys_get_temp_dir();
+ $name = 'elasticaServers.json';
+ $file = $dir . DIRECTORY_SEPARATOR . $name;
+
+ if (!file_exists($file)) {
+ file_put_contents($file, 'hh');
+ error_log(print_r($this->getClient()->getCluster(), true));
+ }
+
+ */
+
+ if (empty($servers)) {
+ $params = array(
+ 'url' => $this->getClient()->getConfig('url'),
+ 'host' => $this->getClient()->getHost(),
+ 'port' => $this->getClient()->getPort(),
+ 'path' => $this->getClient()->getConfig('path'),
+ );
+ $response = $transport->exec($params);
+ } else {
+
+ // Set server id for first request (round robin by default)
+ if (is_null(self::$_serverId)) {
+ self::$_serverId = rand(0, count($servers) - 1);
+ } else {
+ self::$_serverId = (self::$_serverId + 1) % count($servers);
+ }
+
+ $server = $servers[self::$_serverId];
+
+ $response = $transport->exec($server);
+ }
+
+ return $response;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Response.php b/modules/thirdparty/elastica/lib/Elastica/Response.php
new file mode 100755
index 0000000..80071d9
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Response.php
@@ -0,0 +1,215 @@
+ is given to resultset, returned by ...
+ *
+ * @category Xodoa
+ * @package Elastica
+ * @author Nicolas Ruflin
+ */
+class Elastica_Response
+{
+ /**
+ * Query time
+ *
+ * @var float Query time
+ */
+ protected $_queryTime = null;
+
+ /**
+ * Response string (json)
+ *
+ * @var string Response
+ */
+ protected $_responseString = '';
+
+ /**
+ * Error
+ *
+ * @var boolean Error
+ */
+ protected $_error = false;
+
+ /**
+ * Transfer info
+ *
+ * @var array transfer info
+ */
+ protected $_transferInfo = array();
+
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Construct
+ *
+ * @param string $responseString Response string (json)
+ */
+ public function __construct($responseString)
+ {
+ $this->_responseString = $responseString;
+ }
+
+ /**
+ * Error message
+ *
+ * @return string Error message
+ */
+ public function getError()
+ {
+ $message = '';
+ $response = $this->getData();
+
+ if (isset($response['error'])) {
+ $message = $response['error'];
+ }
+
+ return $message;
+ }
+
+ /**
+ * True if response has error
+ *
+ * @return bool True if response has error
+ */
+ public function hasError()
+ {
+ $response = $this->getData();
+
+ if (isset($response['error'])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if the query returned ok
+ *
+ * @return bool True if ok
+ */
+ public function isOk()
+ {
+ $data = $this->getData();
+
+ return (isset($data['ok']) && $data['ok']);
+ }
+
+ /**
+ * Response data array
+ *
+ * @return array Response data array
+ */
+ public function getData()
+ {
+ if ($this->_response == null) {
+ $response = $this->_responseString;
+ if ($response === false) {
+ $this->_error = true;
+ } else {
+
+ $tempResponse = json_decode($response, true);
+ // If error is returned, json_decod makes empty string of string
+ if (!empty($tempResponse)) {
+ $response = $tempResponse;
+ }
+ }
+
+ if (empty($response)) {
+ $response = array();
+ }
+
+ if (is_string($response)) {
+ $response = array('message' => $response);
+ }
+
+ $this->_response = $response;
+ }
+
+ return $this->_response;
+ }
+
+ /**
+ * Gets the transfer information if in DEBUG mode.
+ *
+ * @return array Information about the curl request.
+ */
+ public function getTransferInfo()
+ {
+ return $this->_transferInfo;
+ }
+
+ /**
+ * Sets the transfer info of the curl request. This function is called
+ * from the Elastica_Client::_callService only in debug mode.
+ *
+ * @param array $transferInfo The curl transfer information.
+ * @return Elastica_Response Current object
+ */
+ public function setTransferInfo(array $transferInfo)
+ {
+ $this->_transferInfo = $transferInfo;
+
+ return $this;
+ }
+
+ /**
+ * This is only available if DEBUG constant is set to true
+ *
+ * @return float Query time
+ */
+ public function getQueryTime()
+ {
+ return $this->_queryTime;
+ }
+
+ /**
+ * Sets the query time
+ *
+ * @param float $queryTime Query time
+ * @return Elastica_Response Current object
+ */
+ public function setQueryTime($queryTime)
+ {
+ $this->_queryTime = $queryTime;
+
+ return $this;
+ }
+
+ /**
+ * Time request took
+ *
+ * @return int Time request took
+ */
+ public function getEngineTime()
+ {
+ $data = $this->getData();
+
+ if (!isset($data['took'])) {
+ throw new Elastica_Exception_NotFound("Unable to find the field [took]from the response");
+ }
+
+ return $data['took'];
+ }
+
+ /**
+ * Get the _shard statistics for the response
+ *
+ * @return array
+ */
+ public function getShardsStatistics()
+ {
+ $data = $this->getData();
+
+ if (!isset($data['_shards'])) {
+ throw new Elastica_Exception_NotFound("Unable to find the field [_shards] from the response");
+ }
+
+ return $data['_shards'];
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Result.php b/modules/thirdparty/elastica/lib/Elastica/Result.php
new file mode 100644
index 0000000..12cf4ca
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Result.php
@@ -0,0 +1,179 @@
+
+ */
+class Elastica_Result
+{
+ /**
+ * Hit array
+ *
+ * @var array Hit array
+ */
+ protected $_hit = array();
+
+ /**
+ * Constructs a single results object
+ *
+ * @param array $hit Hit data
+ */
+ public function __construct(array $hit)
+ {
+ $this->_hit = $hit;
+ }
+
+ /**
+ * Returns a param from the result hit array
+ *
+ * This function can be used to retrieve all data for which a specific
+ * function doesn't exist.
+ * If the param does not exist, an empty array is retured
+ *
+ * @param string $name Param name
+ * @return array Result data
+ */
+ public function getParam($name)
+ {
+ if (isset($this->_hit[$name])) {
+ return $this->_hit[$name];
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Returns the hit id
+ *
+ * @return string Hit id
+ */
+ public function getId()
+ {
+ return $this->getParam('_id');
+ }
+
+ /**
+ * Returns the type of the result
+ *
+ * @return string Result type
+ */
+ public function getType()
+ {
+ return $this->getParam('_type');
+ }
+
+ /**
+ * Returns list of fields
+ *
+ * @return array Fields list
+ */
+ public function getFields()
+ {
+ return $this->getParam('fields');
+ }
+
+ /**
+ * Returns the index name of the result
+ *
+ * @return string Index name
+ */
+ public function getIndex()
+ {
+ return $this->getParam('_index');
+ }
+
+ /**
+ * Returns the score of the result
+ *
+ * @return float Result score
+ */
+ public function getScore()
+ {
+ return $this->getParam('_score');
+ }
+
+ /**
+ * Returns the raw hit array
+ *
+ * @return array Hit array
+ */
+ public function getHit()
+ {
+ return $this->_hit;
+ }
+
+ /**
+ * Returns the version information from the hit
+ *
+ * @return string|int Document version
+ */
+ public function getVersion()
+ {
+ return $this->getParam('_version');
+ }
+
+ /**
+ * Returns result data
+ *
+ * Checks for partial result data with getFields, falls back to getSource
+ *
+ * @return array Result data array
+ */
+ public function getData()
+ {
+ if (isset($this->_hit['fields']) && !isset($this->_hit['_source'])) {
+ return $this->getFields();
+ } else {
+ return $this->getSource();
+ }
+ }
+
+ /**
+ * Returns the result source
+ *
+ * @return array Source data array
+ */
+ public function getSource()
+ {
+ return $this->getParam('_source');
+ }
+
+ /**
+ * Returns result data
+ *
+ * @return array Result data array
+ */
+ public function getHighlights()
+ {
+ return $this->getParam('highlight');
+ }
+
+ /**
+ * Returns explanation on how its score was computed.
+ *
+ * @return array explanations
+ */
+ public function getExplanation()
+ {
+ return $this->getParam('_explanation');
+ }
+
+ /**
+ * Magic function to directly access keys inside the result
+ *
+ * Returns null if key does not exist
+ *
+ * @param string $key Key name
+ * @return mixed Key value
+ */
+ public function __get($key)
+ {
+ $source = $this->getData();
+
+ return array_key_exists($key, $source) ? $source[$key] : null;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/ResultSet.php b/modules/thirdparty/elastica/lib/Elastica/ResultSet.php
new file mode 100755
index 0000000..873beb3
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/ResultSet.php
@@ -0,0 +1,189 @@
+
+ */
+class Elastica_ResultSet implements Iterator, Countable
+{
+ /**
+ * Results
+ *
+ * @var array Results
+ */
+ protected $_results = array();
+
+ /**
+ * Current position
+ *
+ * @var int Current position
+ */
+ protected $_position = 0;
+
+ /**
+ * Response
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+ protected $_took = 0;
+ /**
+ * Constructs ResultSet object
+ *
+ * @param Elastica_Response $response Response object
+ */
+ public function __construct(Elastica_Response $response)
+ {
+ $this->rewind();
+ $this->_init($response);
+ }
+
+ /**
+ * Loads all data into the results object (initalisation)
+ *
+ * @param Elastica_Response $response Response object
+ */
+ protected function _init(Elastica_Response $response)
+ {
+ $this->_response = $response;
+ $result = $response->getData();
+ $this->_totalHits = $result['hits']['total'];
+ $this->_took = isset($result['took']) ? $result['took'] : 0;
+ if (isset($result['hits']['hits'])) {
+ foreach ($result['hits']['hits'] as $hit) {
+ $this->_results[] = new Elastica_Result($hit);
+ }
+ }
+ }
+
+ /**
+ * Returns all results
+ *
+ * @return array Results
+ */
+ public function getResults()
+ {
+ return $this->_results;
+ }
+
+ /**
+ * Returns whether facets exist
+ *
+ * @return boolean Facet existence
+ */
+ public function hasFacets()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['facets']);
+ }
+
+ /**
+ * Returns all facets results
+ *
+ * @return array Facet results
+ */
+ public function getFacets()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['facets']) ? $data['facets'] : array();
+ }
+
+ /**
+ * Returns the total number of found hits
+ *
+ * @return int Total hits
+ */
+ public function getTotalHits()
+ {
+ return (int) $this->_totalHits;
+ }
+
+ /**
+ * Returns the total number of ms for this search to complete
+ *
+ * @return int Total time
+ */
+ public function getTotalTime()
+ {
+ return (int) $this->_took;
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Returns size of current set
+ *
+ * @return int Size of set
+ */
+ public function count()
+ {
+ return sizeof($this->_results);
+ }
+
+ /**
+ * Returns the current object of the set
+ *
+ * @return Elastica_Result|bool Set object or false if not valid (no more entries)
+ */
+ public function current()
+ {
+ if ($this->valid()) {
+ return $this->_results[$this->key()];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Sets pointer (current) to the next item of the set
+ */
+ public function next()
+ {
+ $this->_position++;
+
+ return $this->current();
+ }
+
+ /**
+ * Returns the position of the current entry
+ *
+ * @return int Current position
+ */
+ public function key()
+ {
+ return $this->_position;
+ }
+
+ /**
+ * Check if an object exists at the current position
+ *
+ * @return bool True if object exists
+ */
+ public function valid()
+ {
+ return isset($this->_results[$this->key()]);
+ }
+
+ /**
+ * Resets position to 0, restarts iterator
+ */
+ public function rewind()
+ {
+ $this->_position = 0;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Script.php b/modules/thirdparty/elastica/lib/Elastica/Script.php
new file mode 100644
index 0000000..21d9c7f
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Script.php
@@ -0,0 +1,99 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/modules/scripting.html
+ */
+class Elastica_Script
+{
+ /**
+ * @var string
+ */
+ private $_script;
+ /**
+ * @var string
+ */
+ private $_lang;
+ /**
+ * @var array
+ */
+ private $_params;
+
+ /**
+ * @param string $script
+ * @param array|null $params
+ * @param string|null $lang
+ */
+ public function __construct($script, array $params = null, $lang = null)
+ {
+ $this->_script = $script;
+ $this->_params = $params;
+ $this->_lang = $lang;
+ }
+
+ /**
+ * @param string $lang
+ */
+ public function setLang($lang)
+ {
+ $this->_lang = $lang;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLang()
+ {
+ return $this->_lang;
+ }
+
+ /**
+ * @param array $params
+ */
+ public function setParams($params)
+ {
+ $this->_params = $params;
+ }
+
+ /**
+ * @return array
+ */
+ public function getParams()
+ {
+ return $this->_params;
+ }
+
+ /**
+ * @param string $script
+ */
+ public function setScript($script)
+ {
+ $this->_script = $script;
+ }
+
+ /**
+ * @return string
+ */
+ public function getScript()
+ {
+ return $this->_script;
+ }
+
+ public function toArray()
+ {
+ $array = array(
+ 'script' => $this->_script,
+ );
+ if ($this->_params) {
+ $array['params'] = $this->_params;
+ }
+ if ($this->_lang) {
+ $array['lang'] = $this->_lang;
+ }
+
+ return $array;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/ScriptFields.php b/modules/thirdparty/elastica/lib/Elastica/ScriptFields.php
new file mode 100644
index 0000000..87ba224
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/ScriptFields.php
@@ -0,0 +1,55 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/search/script-fields.html
+ */
+class Elastica_ScriptFields extends Elastica_Param
+{
+ /**
+ * @param array $scripts OPTIONAL
+ */
+ public function __construct(array $scripts = array())
+ {
+ if ($scripts) {
+ $this->setScripts($scripts);
+ }
+ }
+
+ /**
+ * @param string $name Name of the Script field
+ * @param Elastica_Script $script
+ * @return Elastica_ScriptFields
+ */
+ public function addScript($name, Elastica_Script $script)
+ {
+ if (!is_string($name) || !strlen($name)) {
+ throw new Elastica_Exception_Invalid('The name of a Script is required and must be a string');
+ }
+ $this->setParam($name, $script->toArray());
+
+ return $this;
+ }
+
+ /**
+ * @param array $script Associative array of string => Elastica_Script
+ * @return Elastica_ScriptFields
+ */
+ public function setScripts(array $scripts)
+ {
+ $this->_params = array();
+ foreach ($scripts as $name => $script) {
+ $this->addScript($name, $script);
+ }
+
+ return $this;
+ }
+
+ public function toArray()
+ {
+ return $this->_params;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Search.php b/modules/thirdparty/elastica/lib/Elastica/Search.php
new file mode 100644
index 0000000..3721ef9
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Search.php
@@ -0,0 +1,225 @@
+
+ */
+class Elastica_Search
+{
+ /**
+ * Array of indices
+ *
+ * @var array
+ */
+ protected $_indices = array();
+
+ /**
+ * Array of types
+ *
+ * @var array
+ */
+ protected $_types = array();
+
+ /**
+ * Client object
+ *
+ * @var Elastica_Client
+ */
+ protected $_client;
+
+ /**
+ * Constructs search object
+ *
+ * @param Elastica_Client $client Client object
+ */
+ public function __construct(Elastica_Client $client)
+ {
+ $this->_client = $client;
+ }
+
+ /**
+ * Adds a index to the list
+ *
+ * @param Elastica_Index|string $index Index object or string
+ * @return Elastica_Search Current object
+ */
+ public function addIndex($index)
+ {
+ if ($index instanceof Elastica_Index) {
+ $index = $index->getName();
+ }
+
+ if (!is_string($index)) {
+ throw new Elastica_Exception_Invalid('Invalid param type');
+ }
+
+ $this->_indices[] = $index;
+
+ return $this;
+ }
+
+ /**
+ * Add array of indices at once
+ *
+ * @param array $indices
+ * @return Elastica_Search
+ */
+ public function addIndices(array $indices = array())
+ {
+ foreach ($indices as $index) {
+ $this->addIndex($index);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds a type to the current search
+ *
+ * @param Elastica_Type|string $type Type name or object
+ * @return Elastica_Search Search object
+ * @throws Elastica_Exception_Invalid
+ */
+ public function addType($type)
+ {
+ if ($type instanceof Elastica_Type) {
+ $type = $type->getName();
+ }
+
+ if (!is_string($type)) {
+ throw new Elastica_Exception_Invalid('Invalid type type');
+ }
+
+ $this->_types[] = $type;
+
+ return $this;
+ }
+
+ /**
+ * Add array of types
+ *
+ * @param array $types
+ * @return Elastica_Search
+ */
+ public function addTypes(array $types = array())
+ {
+ foreach ($types as $type) {
+ $this->addType($type);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Return client object
+ *
+ * @return Elastica_Client Client object
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Return array of indices
+ *
+ * @return array List of index names
+ */
+ public function getIndices()
+ {
+ return $this->_indices;
+ }
+
+ /**
+ * Return array of types
+ *
+ * @return array List of types
+ */
+ public function getTypes()
+ {
+ return $this->_types;
+ }
+
+ /**
+ * Creates new search object
+ *
+ * @param Elastica_Searchable $searchObject
+ */
+ public static function create(Elastica_Searchable $searchObject)
+ {
+ throw new Elastica_Exception_NotImplemented();
+ // Set index
+ // set type
+ // set client
+ }
+
+ /**
+ * Combines indices and types to the search request path
+ *
+ * @return string Search path
+ */
+ public function getPath()
+ {
+ $indices = $this->getIndices();
+
+ $path = '';
+
+ if (empty($indices)) {
+ $path .= '_all';
+ } else {
+ $path .= implode(',', $indices);
+ }
+
+ $types = $this->getTypes();
+
+ if (!empty($types)) {
+ $path .= '/' . implode(',', $types);
+ }
+
+ // Add full path based on indices and types -> could be all
+ return $path . '/_search';
+ }
+
+ /**
+ * Search in the set indices, types
+ *
+ * @param mixed $query
+ * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
+ * @return Elastica_ResultSet
+ */
+ public function search($query, $options = null)
+ {
+ $query = Elastica_Query::create($query);
+ $path = $this->getPath();
+ $params = array();
+
+ if (is_int($options)) {
+ $query->setLimit($options);
+ } else {
+ if (is_array($options)) {
+ foreach ($options as $key => $value) {
+ switch ($key) {
+ case 'limit' :
+ $query->setLimit($value);
+ break;
+ case 'routing' :
+ $params['routing'] = $value;
+ break;
+ case 'search_type':
+ $params['search_type'] = $value;
+ break;
+ default:
+ throw new Elastica_Exception_Invalid('Invalid option ' . $key);
+ break;
+ }
+ }
+ }
+ }
+
+ $response = $this->getClient()->request($path, Elastica_Request::GET, $query->toArray(), $params);
+
+ return new Elastica_ResultSet($response);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Searchable.php b/modules/thirdparty/elastica/lib/Elastica/Searchable.php
new file mode 100644
index 0000000..65eee4e
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Searchable.php
@@ -0,0 +1,43 @@
+
+ */
+interface Elastica_Searchable
+{
+ /**
+ * Searches results for a query
+ *
+ * TODO: Improve sample code
+ * {
+ * "from" : 0,
+ * "size" : 10,
+ * "sort" : {
+ * "postDate" : {"reverse" : true},
+ * "user" : { },
+ * "_score" : { }
+ * },
+ * "query" : {
+ * "term" : { "user" : "kimchy" }
+ * }
+ * }
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @return Elastica_ResultSet ResultSet with all results inside
+ */
+ public function search($query);
+
+ /**
+ * Counts results for a query
+ *
+ * If no query is set, matchall query is created
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @return int number of documents matching the query
+ */
+ public function count($query = '');
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Status.php b/modules/thirdparty/elastica/lib/Elastica/Status.php
new file mode 100644
index 0000000..c4d9dca
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Status.php
@@ -0,0 +1,171 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html
+ */
+class Elastica_Status
+{
+ /**
+ * Contains all status infos
+ *
+ * @var Elastica_Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Data
+ *
+ * @var array Data
+ */
+ protected $_data = array();
+
+ /**
+ * Client object
+ *
+ * @var Elastica_Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Constructs Status object
+ *
+ * @param Elastica_Client $client Client object
+ */
+ public function __construct(Elastica_Client $client)
+ {
+ $this->_client = $client;
+ $this->refresh();
+ }
+
+ /**
+ * Returns status data
+ *
+ * @return array Status data
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns status objects of all indices
+ *
+ * @return array List of Elastica_Client_Index objects
+ */
+ public function getIndexStatuses()
+ {
+ $statuses = array();
+ foreach ($this->getIndexNames() as $name) {
+ $index = new Elastica_Index($this->_client, $name);
+ $statuses[] = new Elastica_Index_Status($index);
+ }
+
+ return $statuses;
+ }
+
+ /**
+ * Returns a list of the existing index names
+ *
+ * @return array Index names list
+ */
+ public function getIndexNames()
+ {
+ $names = array();
+ foreach ($this->_data['indices'] as $name => $data) {
+ $names[] = $name;
+ }
+
+ return $names;
+ }
+
+ /**
+ * Checks if the given index exists
+ *
+ * @param string $name Index name to check
+ * @return bool True if index exists
+ */
+ public function indexExists($name)
+ {
+ return in_array($name, $this->getIndexNames());
+ }
+
+ /**
+ * Checks if the given alias exists
+ *
+ * @param string $name Alias name
+ * @return bool True if alias exists
+ */
+ public function aliasExists($name)
+ {
+ foreach ($this->getIndexStatuses() as $status) {
+ if ($status->hasAlias($name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an array with all indices that the given alias name points to
+ *
+ * @param string $name Alias name
+ * @return array List of Elastica_Index
+ */
+ public function getIndicesWithAlias($name)
+ {
+ $indices = array();
+ foreach ($this->getIndexStatuses() as $status) {
+ if ($status->hasAlias($name)) {
+ $indices[] = $status->getIndex();
+ }
+ }
+
+ return $indices;
+ }
+
+ /**
+ * Returns response object
+ *
+ * @return Elastica_Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Return shards info
+ *
+ * @return array Shards info
+ */
+ public function getShards()
+ {
+ return $this->_data['shards'];
+ }
+
+ /**
+ * Refresh status object
+ */
+ public function refresh()
+ {
+ $path = '_status';
+ $this->_response = $this->_client->request($path, Elastica_Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+
+ /**
+ * Refresh serverStatus object
+ */
+ public function getServerStatus()
+ {
+ $path = '';
+ $response = $this->_client->request($path, Elastica_Request::GET);
+
+ return $response->getData();
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Abstract.php
new file mode 100644
index 0000000..fece61c
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Abstract.php
@@ -0,0 +1,67 @@
+
+ */
+abstract class Elastica_Transport_Abstract
+{
+ /**
+ * Path
+ *
+ * @var string path
+ */
+ protected $_path;
+
+ /**
+ * Method
+ *
+ * @var string method
+ * @todo set default method?
+ */
+ protected $_method;
+
+ /**
+ * Data
+ *
+ * @var array Data
+ */
+ protected $_data;
+
+ /**
+ * Config
+ *
+ * @var array config
+ */
+ protected $_config;
+
+ /**
+ * Construc transport
+ *
+ * @param Elastica_Request $request Request object
+ */
+ public function __construct(Elastica_Request $request)
+ {
+ $this->_request = $request;
+ }
+
+ /**
+ * Returns the request object
+ *
+ * @return Elastica_Request Request object
+ */
+ public function getRequest()
+ {
+ return $this->_request;
+ }
+
+ /**
+ * Executes the transport request
+ *
+ * @param array $params Hostname, port, path, ...
+ * @return Elastica_Response Response object
+ */
+ abstract public function exec(array $params);
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Http.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Http.php
new file mode 100644
index 0000000..737bd82
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Http.php
@@ -0,0 +1,149 @@
+
+ */
+class Elastica_Transport_Http extends Elastica_Transport_Abstract
+{
+ /**
+ * Http scheme
+ *
+ * @var string Http scheme
+ */
+ protected $_scheme = 'http';
+
+ /**
+ * Curl resource to reuse
+ *
+ * @var resource Curl resource to reuse
+ */
+ protected static $_connection = null;
+
+ /**
+ * Makes calls to the elasticsearch server
+ *
+ * All calls that are made to the server are done through this function
+ *
+ * @param array $params Host, Port, ...
+ * @return Elastica_Response Response object
+ */
+ public function exec(array $params)
+ {
+ $request = $this->getRequest();
+
+ $conn = $this->_getConnection($request->getConfig('persistent'));
+
+ // If url is set, url is taken. Otherwise port, host and path
+ if (!empty($params['url'])) {
+ $baseUri = $params['url'];
+ } else {
+ if (!isset($params['host']) || !isset($params['port'])) {
+ throw new Elastica_Exception_Invalid('host and port have to be set');
+ }
+
+ $path = isset($params['path']) ? $params['path'] : '';
+
+ $baseUri = $this->_scheme . '://' . $params['host'] . ':' . $params['port'] . '/' . $path;
+ }
+
+ $baseUri .= $request->getPath();
+
+ $query = $request->getQuery();
+
+ if (!empty($query)) {
+ $baseUri .= '?' . http_build_query($query);
+ }
+
+ curl_setopt($conn, CURLOPT_URL, $baseUri);
+ curl_setopt($conn, CURLOPT_TIMEOUT, $request->getConfig('timeout'));
+ curl_setopt($conn, CURLOPT_CUSTOMREQUEST, $request->getMethod());
+ curl_setopt($conn, CURLOPT_FORBID_REUSE, 0);
+
+ $this->_setupCurl($conn);
+
+ $headersConfig = $request->getConfig('headers');
+ if (!empty($headersConfig)) {
+ $headers = array();
+ while (list($header, $headerValue) = each($headersConfig)) {
+ array_push($headers, $header . ': ' . $headerValue);
+ }
+
+ curl_setopt($conn, CURLOPT_HTTPHEADER, $headers);
+ }
+
+ // TODO: REFACTOR
+ $data = $request->getData();
+
+ if (isset($data) && !empty($data)) {
+ if (is_array($data)) {
+ $content = json_encode($data);
+ } else {
+ $content = $data;
+ }
+
+ // Escaping of / not necessary. Causes problems in base64 encoding of files
+ $content = str_replace('\/', '/', $content);
+
+ curl_setopt($conn, CURLOPT_POSTFIELDS, $content);
+ }
+
+ $start = microtime(true);
+
+ // cURL opt returntransfer leaks memory, therefore OB instead.
+ ob_start();
+ curl_exec($conn);
+ $responseString = ob_get_clean();
+
+ $end = microtime(true);
+
+ // Checks if error exists
+ $errorNumber = curl_errno($conn);
+
+ $response = new Elastica_Response($responseString);
+
+ if (defined('DEBUG') && DEBUG) {
+ $response->setQueryTime($end - $start);
+ $response->setTransferInfo(curl_getinfo($conn));
+ }
+
+ if ($response->hasError()) {
+ throw new Elastica_Exception_Response($response);
+ }
+
+ if ($errorNumber > 0) {
+ throw new Elastica_Exception_Client($errorNumber, $request, $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Called to add additional curl params
+ *
+ * @param resource $connection Curl connection
+ */
+ protected function _setupCurl($connection)
+ {
+ foreach ($this->_request->getClient()->getConfig('curl') as $key => $param) {
+ curl_setopt($connection, $key, $param);
+ }
+ }
+
+ /**
+ * Return Curl ressource
+ *
+ * @param bool $persistent False if not persistent connection
+ * @return resource Connection resource
+ */
+ protected function _getConnection($persistent = true)
+ {
+ if (!$persistent || !self::$_connection) {
+ self::$_connection = curl_init();
+ }
+
+ return self::$_connection;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Https.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Https.php
new file mode 100644
index 0000000..83070dd
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Https.php
@@ -0,0 +1,27 @@
+
+ */
+class Elastica_Transport_Https extends Elastica_Transport_Http
+{
+ /**
+ * Https scheme
+ *
+ * @var string https scheme
+ */
+ protected $_scheme = 'https';
+
+ /**
+ * Overloads setupCurl to set SSL params
+ *
+ * @param resource $connection Curl connection resource
+ */
+ protected function _setupCurl($connection)
+ {
+ parent::_setupCurl($connection);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Memcache.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Memcache.php
new file mode 100644
index 0000000..03e9fdb
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Memcache.php
@@ -0,0 +1,73 @@
+
+ */
+class Elastica_Transport_Memcache extends Elastica_Transport_Abstract
+{
+ /**
+ * Makes calls to the elasticsearch server
+ *
+ * @param array $params Host, Port, ...
+ * @return Elastica_Response Response object
+ */
+ public function exec(array $params)
+ {
+ $request = $this->getRequest();
+
+ $memcache = new Memcache();
+ $memcache->connect($params['host'], $params['port']);
+
+ // Finds right function name
+ $function = strtolower($request->getMethod());
+
+ $data = $request->getData();
+
+ $content = '';
+
+ if (!empty($data)) {
+ if (is_array($data)) {
+ $content = json_encode($data);
+ } else {
+ $content = $data;
+ }
+
+ // Escaping of / not necessary. Causes problems in base64 encoding of files
+ $content = str_replace('\/', '/', $content);
+ }
+
+ $responseString = '';
+
+ switch ($function) {
+ case 'post':
+ case 'put':
+ $memcache->set($request->getPath(), $content);
+ break;
+ case 'get':
+ $responseString = $memcache->get($request->getPath() . '?source=' . $content);
+ echo $responseString . PHP_EOL;
+ break;
+ case 'delete':
+ break;
+ default:
+ throw new Elastica_Exception_Invalid('Method ' . $function . ' is not supported in memcache transport');
+
+ }
+
+ $response = new Elastica_Response($responseString);
+
+ if (defined('DEBUG') && DEBUG) {
+ $response->setQueryTime($end - $start);
+ $response->setTransferInfo(curl_getinfo($conn));
+ }
+
+ if ($response->hasError()) {
+ throw new Elastica_Exception_Response($response);
+ }
+
+ return $response;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Type.php b/modules/thirdparty/elastica/lib/Elastica/Type.php
new file mode 100644
index 0000000..093a612
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Type.php
@@ -0,0 +1,320 @@
+ index -> type -> document
+ *
+ * Search over different indices and types is not supported yet {@link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/indices_types/}
+ *
+ * @category Xodoa
+ * @package Elastica
+ * @author Nicolas Ruflin
+ */
+class Elastica_Type implements Elastica_Searchable
+{
+ /**
+ * Index
+ *
+ * @var Elastica_Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Type name
+ *
+ * @var string Type name
+ */
+ protected $_name = '';
+
+ /**
+ * Creates a new type object inside the given index
+ *
+ * @param Elastica_Index $index Index Object
+ * @param string $name Type name
+ */
+ public function __construct(Elastica_Index $index, $name)
+ {
+ $this->_index = $index;
+ $this->_name = $name;
+ }
+
+ /**
+ * Adds the given document to the search index
+ *
+ * @param Elastica_Document $doc Document with data
+ * @return Elastica_Response
+ */
+ public function addDocument(Elastica_Document $doc)
+ {
+ $path = $doc->getId();
+
+ $query = array();
+
+ if ($doc->getVersion() > 0) {
+ $query['version'] = $doc->getVersion();
+ }
+
+ if (!is_null($doc->getParent())) {
+ $query['parent'] = $doc->getParent();
+ }
+
+ if ($doc->getOpType()) {
+ $query['op_type'] = $doc->getOpType();
+ }
+
+ if ($doc->getPercolate()) {
+ $query['percolate'] = $doc->getPercolate();
+ }
+
+ $type = Elastica_Request::PUT;
+
+ // If id is empty, POST has to be used to automatically create id
+ if (empty($path)) {
+ $type = Elastica_Request::POST;
+ }
+
+ return $this->request($path, $type, $doc->getData(), $query);
+ }
+
+ /**
+ * Update document, using update script. Requires elasticsearch >= 0.19.0
+ *
+ * @param string $id Document id
+ * @param Elastica_Script $script script to use for update
+ * @param array $options options for query
+ * @return Elastica_Response
+ * @see Elastica_Client::updateDocument()
+ * @link http://www.elasticsearch.org/guide/reference/api/update.html
+ */
+ public function updateDocument($id, Elastica_Script $script, array $options = array())
+ {
+ return $this->getIndex()->updateDocument($id, $script, $this->getName(), $options);
+ }
+
+ /**
+ * Uses _bulk to send documents to the server
+ *
+ * @param array $docs Array of Elastica_Document
+ * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/
+ */
+ public function addDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setType($this->getName());
+ }
+
+ return $this->getIndex()->addDocuments($docs);
+ }
+
+ /**
+ * Get the document from search index
+ *
+ * @param string $id Document id
+ * @return Elastica_Document
+ */
+ public function getDocument($id)
+ {
+ $path = $id;
+
+ try {
+ $result = $this->request($path, Elastica_Request::GET)->getData();
+ } catch (Elastica_Exception_Response $e) {
+ throw new Elastica_Exception_NotFound('doc id ' . $id . ' not found');
+ }
+
+ if (empty($result['exists'])) {
+ throw new Elastica_Exception_NotFound('doc id ' . $id . ' not found');
+ }
+
+ $data = isset($result['_source']) ? $result['_source'] : array();
+ $document = new Elastica_Document($id, $data, $this->getName(), $this->getIndex());
+ $document->setVersion($result['_version']);
+
+ return $document;
+ }
+
+ /**
+ * Returns the type name
+ *
+ * @return string Type
+ * @deprecated Use getName instead
+ */
+ public function getType()
+ {
+ return $this->getName();
+ }
+
+ /**
+ * Returns the type name
+ *
+ * @return string Type name
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Sets value type mapping for this type
+ *
+ * @param Elastica_Type_Mapping|array $mapping Elastica_Type_Mapping object or property array with all mappings
+ */
+ public function setMapping($mapping)
+ {
+ $mapping = Elastica_Type_Mapping::create($mapping);
+ $mapping->setType($this);
+
+ return $mapping->send();
+ }
+
+ /**
+ * Returns current mapping for the given type
+ *
+ * @return array Current mapping
+ */
+ public function getMapping()
+ {
+ $path = '_mapping';
+
+ $response = $this->request($path, Elastica_Request::GET);
+
+ return $response->getData();
+ }
+
+ /**
+ * Do a search on this type
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
+ * @return Elastica_ResultSet ResultSet with all results inside
+ * @see Elastica_Searchable::search
+ */
+ public function search($query, $options = null)
+ {
+ $search = new Elastica_Search($this->getIndex()->getClient());
+ $search->addIndex($this->getIndex());
+ $search->addType($this);
+
+ return $search->search($query, $options);
+ }
+
+ /**
+ * Count docs by query
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @return int number of documents matching the query
+ * @see Elastica_Searchable::count
+ */
+ public function count($query = '')
+ {
+ $query = Elastica_Query::create($query);
+ $path = '_search';
+
+ $response = $this->request($path, Elastica_Request::GET, $query->toArray(), array('search_type' => 'count'));
+ $resultSet = new Elastica_ResultSet($response);
+
+ return $resultSet->getTotalHits();
+ }
+
+ /**
+ * Returns index client
+ *
+ * @return Elastica_Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Deletes an entry by its unique identifier
+ *
+ * @param int|string $id Document id
+ * @return Elastica_Response Response object
+ * @link http://www.elasticsearch.org/guide/reference/api/delete.html
+ */
+ public function deleteById($id)
+ {
+ if (empty($id) || !trim($id)) {
+ throw new InvalidArgumentException();
+ }
+
+ return $this->request($id, Elastica_Request::DELETE);
+ }
+
+ /**
+ * Deletes the given list of ids from this type
+ *
+ * @param array $ids
+ * @return Elastica_Response Response object
+ */
+ public function deleteIds(array $ids)
+ {
+ return $this->getIndex()->getClient()->deleteIds($ids, $this->getIndex(), $this);
+ }
+
+ /**
+ * Deletes entries in the db based on a query
+ *
+ * @param Elastica_Query|string $query Query object
+ * @link http://www.elasticsearch.org/guide/reference/api/delete-by-query.html
+ */
+ public function deleteByQuery($query)
+ {
+ $query = Elastica_Query::create($query);
+
+ return $this->request('_query', Elastica_Request::DELETE, $query->getQuery());
+ }
+
+ /**
+ * Deletes the index type.
+ *
+ * @return Elastica_Response
+ */
+ public function delete()
+ {
+ $response = $this->request('', Elastica_Request::DELETE);
+
+ return $response;
+ }
+
+ /**
+ * More like this query based on the given object
+ *
+ * The id in the given object has to be set
+ *
+ * @param Elastica_Document $doc Document to query for similar objects
+ * @param array $params OPTIONAL Additional arguments for the query
+ * @param Elastica_Query $query OPTIONAL Query to filter the moreLikeThis results
+ * @return Elastica_ResultSet ResultSet with all results inside
+ * @link http://www.elasticsearch.org/guide/reference/api/more-like-this.html
+ */
+ public function moreLikeThis(Elastica_Document $doc, $params = array(), $query = array())
+ {
+ $path = $doc->getId() . '/_mlt';
+
+ $query = Elastica_Query::create($query);
+
+ $response = $this->request($path, Elastica_Request::GET, $query->toArray(), $params);
+
+ return new Elastica_ResultSet($response);
+ }
+
+ /**
+ * Makes calls to the elasticsearch server based on this type
+ *
+ * @param string $path Path to call
+ * @param string $method Rest method to use (GET, POST, DELETE, PUT)
+ * @param array $data OPTIONAL Arguments as array
+ * @param array $query OPTIONAL Query params
+ * @return Elastica_Response Response object
+ */
+ public function request($path, $method, $data = array(), array $query = array())
+ {
+ $path = $this->getName() . '/' . $path;
+
+ return $this->getIndex()->request($path, $method, $data, $query);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Type/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Type/Abstract.php
new file mode 100755
index 0000000..f8e5798
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Type/Abstract.php
@@ -0,0 +1,179 @@
+
+ */
+abstract class Elastica_Type_Abstract implements Elastica_Searchable
+{
+ const MAX_DOCS_PER_REQUEST = 1000;
+
+ /**
+ * Index name
+ *
+ * @var string Index name
+ */
+ protected $_indexName = '';
+
+ /**
+ * Index name
+ *
+ * @var string Index name
+ */
+ protected $_typeName = '';
+
+ /**
+ * Client
+ *
+ * @var Elastica_Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Index
+ *
+ * @var Elastica_Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Type
+ *
+ * @var Elastica_Type Type object
+ */
+ protected $_type = null;
+
+ /**
+ * Mapping
+ *
+ * @var array Mapping
+ */
+ protected $_mapping = array();
+
+ /**
+ * Index params
+ *
+ * @var array Index params
+ */
+ protected $_indexParams = array();
+
+ /**
+ * Source
+ *
+ * @var boolean Source
+ */
+ protected $_source = true;
+
+ /**
+ * Creates index object with client connection
+ *
+ * Reads index and type name from protected vars _indexName and _typeName.
+ * Has to be set in child class
+ *
+ * @param Elastica_Client $client OPTIONAL Client object
+ */
+ public function __construct(Elastica_Client $client = null)
+ {
+ if (!$client) {
+ $client = new Elastica_Client();
+ }
+
+ if (empty($this->_indexName)) {
+ throw new Elastica_Exception_Invalid('Index name has to be set');
+ }
+
+ if (empty($this->_typeName)) {
+ throw new Elastica_Exception_Invalid('Type name has to be set');
+ }
+
+ $this->_client = $client;
+ $this->_index = new Elastica_Index($this->_client, $this->_indexName);
+ $this->_type = new Elastica_Type($this->_index, $this->_typeName);
+ }
+
+ /**
+ * Creates the index and sets the mapping for this type
+ *
+ * @param bool $recreate OPTIONAL Recreates the index if true (default = false)
+ */
+ public function create($recreate = false)
+ {
+ $this->getIndex()->create($this->_indexParams, $recreate);
+
+ $mapping = new Elastica_Type_Mapping($this->getType());
+ $mapping->setProperties($this->_mapping);
+ $mapping->setSource(array('enabled' => $this->_source));
+ $mapping->send();
+ }
+
+ /**
+ * Search on the type
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @return Elastica_ResultSet ResultSet with all results inside
+ * @see Elastica_Searchable::search
+ */
+ public function search($query)
+ {
+ return $this->getType()->search($query);
+ }
+
+ /**
+ * Count docs in the type based on query
+ *
+ * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object
+ * @return int number of documents matching the query
+ * @see Elastica_Searchable::count
+ */
+ public function count($query = '')
+ {
+ return $this->getType()->count($query);
+ }
+
+ /**
+ * Returns the search index
+ *
+ * @return Elastica_Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Returns type object
+ *
+ * @return Elastica_Type Type object
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Converts given time to format: 1995-12-31T23:59:59Z
+ *
+ * This is the lucene date format
+ *
+ * @param int $date Date input (could be string etc.) -> must be supported by strtotime
+ * @return string Converted date string
+ */
+ public function convertDate($date)
+ {
+ return Elastica_Util::convertDate($date);
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Type/Mapping.php b/modules/thirdparty/elastica/lib/Elastica/Type/Mapping.php
new file mode 100644
index 0000000..19a5c8c
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Type/Mapping.php
@@ -0,0 +1,206 @@
+
+ * @link http://www.elasticsearch.org/guide/reference/mapping/
+ */
+class Elastica_Type_Mapping
+{
+ /**
+ * Mapping
+ *
+ * @var array Mapping
+ */
+ protected $_mapping = array();
+
+ /**
+ * Type
+ *
+ * @var Elastica_Type Type object
+ */
+ protected $_type = null;
+
+ /**
+ * Construct Mapping
+ *
+ * @param Elastica_Type $type OPTIONAL Type object
+ * @param array $properties OPTIONAL Properties
+ */
+ public function __construct(Elastica_Type $type = null, array $properties = array())
+ {
+ if ($type) {
+ $this->setType($type);
+ }
+
+ if (!empty($properties)) {
+ $this->setProperties($properties);
+ }
+ }
+
+ /**
+ * Sets the mapping type
+ * Enter description here ...
+ * @param Elastica_Type $type Type object
+ * @return Elastica_Type_Mapping Current object
+ */
+ public function setType(Elastica_Type $type)
+ {
+ $this->_type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Sets the mapping properites
+ *
+ * @param array $properties Prpoerties
+ * @return Elastica_Type_Mapping Mapping object
+ */
+ public function setProperties(array $properties)
+ {
+ return $this->setParam('properties', $properties);
+ }
+
+ /**
+ * Returns mapping type
+ *
+ * @return Elastica_Type Type
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Sets source values
+ *
+ * To disable source, argument is
+ * array('enabled' => false)
+ *
+ * @param array $source Source array
+ * @return Elastica_Type_Mapping Current object
+ * @link http://www.elasticsearch.org/guide/reference/mapping/source-field.html
+ */
+ public function setSource(array $source)
+ {
+ return $this->setParam('_source', $source);
+ }
+
+ /**
+ * Disables the source in the index
+ *
+ * Param can be set to true to enable again
+ *
+ * @param bool $enabled OPTIONAL (default = false)
+ * @return Elastica_Type_Mapping Current object
+ */
+ public function disableSource($enabled = false)
+ {
+ return $this->setSource(array('enabled' => $enabled));
+ }
+
+ /**
+ * Sets raw parameters
+ *
+ * Possible options:
+ * _uid
+ * _id
+ * _type
+ * _source
+ * _all
+ * _analyzer
+ * _boost
+ * _parent
+ * _routing
+ * _index
+ * _size
+ * properties
+ *
+ * @param string $key Key name
+ * @param mixed $value Key value
+ * @return Elastica_Type_Mapping Current object
+ */
+ public function setParam($key, $value)
+ {
+ $this->_mapping[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Set TTL
+ *
+ * @param array $params TTL Params (enabled, default, ...)
+ * @return Elastica_Type_Mapping
+ */
+ public function setTtl(array $params)
+ {
+ return $this->setParam('_ttl', $params);
+
+ }
+
+ /**
+ * Enables TTL for all documens in this type
+ *
+ * @param bool $enabled OPTIONAL (default = true)
+ * @return Elastica_Type_Mapping
+ */
+ public function enableTtl($enabled = true)
+ {
+ return $this->setTTL(array('enabled' => $enabled));
+ }
+
+ /**
+ * Converts the mapping to an array
+ *
+ * @return array Mapping as array
+ */
+ public function toArray()
+ {
+ $type = $this->getType();
+
+ if (empty($type)) {
+ throw new Elastica_Exception_Invalid('Type has to be set');
+ }
+
+ return array($type->getType() => $this->_mapping);
+ }
+
+ /**
+ * Submits the mapping and sends it to the server
+ *
+ * @return Elastica_Response Response object
+ */
+ public function send()
+ {
+ $path = '_mapping';
+
+ return $this->getType()->request($path, Elastica_Request::PUT, $this->toArray());
+ }
+
+ /**
+ * Creates a mapping object
+ *
+ * @param array|Elastica_Type_Mapping $mapping Mapping object or properties array
+ * @return Elastica_Type_Mapping Mapping object
+ * @throws Elastica_Exception_Invalid If invalid type
+ */
+ public static function create($mapping)
+ {
+ if (is_array($mapping)) {
+ $mappingObject = new Elastica_Type_Mapping();
+ $mappingObject->setProperties($mapping);
+ } else {
+ $mappingObject = $mapping;
+ }
+
+ if (!$mappingObject instanceof Elastica_Type_Mapping) {
+ throw new Elastica_Exception_Invalid('Invalid object type');
+ }
+
+ return $mappingObject;
+ }
+}
diff --git a/modules/thirdparty/elastica/lib/Elastica/Util.php b/modules/thirdparty/elastica/lib/Elastica/Util.php
new file mode 100644
index 0000000..acf8fc5
--- /dev/null
+++ b/modules/thirdparty/elastica/lib/Elastica/Util.php
@@ -0,0 +1,116 @@
+
+ * @author Thibault Duplessis
+ * @author Oleg Zinchenko
+ */
+class Elastica_Util
+{
+ /**
+ * Replace the following reserved words: AND OR NOT
+ * and
+ * escapes the following terms: + - && || ! ( ) { } [ ] ^ " ~ * ? : \
+ *
+ * @param string $term Query term to replare and escape
+ * @return string Replaced and escaped query term
+ * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boolean%20operators
+ * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Escaping%20Special%20Characters
+ */
+ public static function replaceBooleanWordsAndEscapeTerm($term)
+ {
+ $result = $term;
+ $result = self::replaceBooleanWords($result);
+ $result = self::escapeTerm($result);
+
+ return $result;
+ }
+
+ /**
+ * Escapes the following terms (because part of the query language)
+ * + - && || ! ( ) { } [ ] ^ " ~ * ? : \
+ *
+ * @param string $term Query term to escape
+ * @return string Escaped query term
+ * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Escaping%20Special%20Characters
+ */
+ public static function escapeTerm($term)
+ {
+ $result = $term;
+ // \ escaping has to be first, otherwise escaped later once again
+ $chars = array('\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':');
+
+ foreach ($chars as $char) {
+ $result = str_replace($char, '\\' . $char, $result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Replace the following reserved words (because part of the query language)
+ * AND OR NOT
+ *
+ * @param string $term Query term to replace
+ * @return string Replaced query term
+ * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boolean%20operators
+ */
+ public static function replaceBooleanWords($term)
+ {
+ $replacementMap = array('AND'=>'&&', 'OR'=>'||', 'NOT'=>'!');
+ $result = strtr($term, $replacementMap);
+
+ return $result;
+ }
+
+ /**
+ * Converts a snake_case string to CamelCase
+ *
+ * For example: hello_world to HelloWorld
+ *
+ * @param string $string snake_case string
+ * @return string CamelCase string
+ */
+ public static function toCamelCase($string)
+ {
+ return str_replace(" ", "", ucwords(str_replace("_", " ", $string)));
+ }
+
+ /**
+ * Converts a CamelCase string to snake_case
+ *
+ * For Example HelloWorld to hello_world
+ *
+ * @param string $string CamelCase String to Convert
+ * @return string SnakeCase string
+ */
+ public static function toSnakeCase($string)
+ {
+ $string = preg_replace('/([A-Z])/', '_$1', $string);
+
+ return strtolower(substr($string,1));
+ }
+
+ /**
+ * Converts given time to format: 1995-12-31T23:59:59Z
+ *
+ * This is the lucene date format
+ *
+ * @param int $date Date input (could be string etc.) -> must be supported by strtotime
+ * @return string Converted date string
+ */
+ public static function convertDate($date)
+ {
+ if (is_int($date)) {
+ $timestamp = $date;
+ } else {
+ $timestamp = strtotime($date);
+ }
+ $string = date('Y-m-d\TH:i:s\Z', $timestamp);
+
+ return $string;
+ }
+}
diff --git a/modules/thirdparty/elastica/phpdoc.dist.xml b/modules/thirdparty/elastica/phpdoc.dist.xml
new file mode 100644
index 0000000..73d161f
--- /dev/null
+++ b/modules/thirdparty/elastica/phpdoc.dist.xml
@@ -0,0 +1,13 @@
+
+
+ Elastica
+
+ ./build/api
+
+
+ ./build/api
+
+
+ ./lib
+
+
diff --git a/modules/thirdparty/elastica/test/benchmark/BulkMemoryUsageTest.php b/modules/thirdparty/elastica/test/benchmark/BulkMemoryUsageTest.php
new file mode 100644
index 0000000..d2f021a
--- /dev/null
+++ b/modules/thirdparty/elastica/test/benchmark/BulkMemoryUsageTest.php
@@ -0,0 +1,44 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $data = array(
+ 'text1' => 'Very long text for a string',
+ 'text2' => 'But this is not very long',
+ 'text3' => 'random or not random?',
+ );
+
+ $startMemory = memory_get_usage();
+
+ for ($n = 1; $n < 10; $n++) {
+ $docs = array();
+
+ for ($i = 1; $i <= 3000; $i++) {
+ $docs[] = new Elastica_Document(uniqid(), $data);
+ }
+
+ $type->addDocuments($docs);
+ $docs = array();
+ }
+
+ unset($docs);
+
+ $endMemory = memory_get_usage();
+
+ $this->assertLessThan(1.1, $endMemory/$startMemory);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/benchmark/ClientTest.php b/modules/thirdparty/elastica/test/benchmark/ClientTest.php
new file mode 100644
index 0000000..3221beb
--- /dev/null
+++ b/modules/thirdparty/elastica/test/benchmark/ClientTest.php
@@ -0,0 +1,29 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $start = microtime(true);
+
+ for ($i = 1; $i <= 10000; $i++) {
+ $doc = new Elastica_Document($i, array('test' => 1));
+ $type->addDocument($doc);
+ }
+
+ // Refresh index
+ $index->refresh();
+
+ $end = microtime(true);
+
+ //echo $end - $start;
+
+ }
+}
diff --git a/modules/thirdparty/elastica/test/bin/install_php_memcache.sh b/modules/thirdparty/elastica/test/bin/install_php_memcache.sh
new file mode 100755
index 0000000..da9288e
--- /dev/null
+++ b/modules/thirdparty/elastica/test/bin/install_php_memcache.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Build and install PHP Memcache extension
+wget http://pecl.php.net/get/memcache-2.2.6.tgz
+tar -xzf memcache-2.2.6.tgz
+sh -c "cd memcache-2.2.6 && phpize && ./configure --enable-memcache && make && sudo make install"
+echo "extension=memcache.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`
diff --git a/modules/thirdparty/elastica/test/bin/run_elasticsearch.sh b/modules/thirdparty/elastica/test/bin/run_elasticsearch.sh
new file mode 100755
index 0000000..0d25946
--- /dev/null
+++ b/modules/thirdparty/elastica/test/bin/run_elasticsearch.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+wget https://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.19.3.tar.gz
+tar -xzf elasticsearch-0.19.3.tar.gz
+sed 's/# index.number_of_shards: 1/index.number_of_shards: 2/' elasticsearch-0.19.3/config/elasticsearch.yml > elasticsearch-0.19.3/config/elasticsearch.yml
+sed 's/# index.number_of_replicas: 0/index.number_of_replicas: 0/' elasticsearch-0.19.3/config/elasticsearch.yml > elasticsearch-0.19.3/config/elasticsearch.yml
+sed 's/# discovery.zen.ping.multicast.enabled: false/discovery.zen.ping.multicast.enabled: false/' elasticsearch-0.19.3/config/elasticsearch.yml > elasticsearch-0.19.3/config/elasticsearch.yml
+elasticsearch-0.19.3/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/1.4.0
+
+export JAVA_OPTS="-server"
+elasticsearch-0.19.3/bin/elasticsearch &
+
+echo "Waiting until elasticsearch is ready on port 9200"
+while [[ -z `curl -s 'http://localhost:9200' ` ]]
+do
+ echo -n "."
+ sleep 2s
+done
+
+echo "elasticsearch is up"
diff --git a/modules/thirdparty/elastica/test/bootstrap.php b/modules/thirdparty/elastica/test/bootstrap.php
new file mode 100755
index 0000000..ea56496
--- /dev/null
+++ b/modules/thirdparty/elastica/test/bootstrap.php
@@ -0,0 +1,20 @@
+ $host, 'port' => $port));
+
+ $this->assertEquals($host, $client->getHost());
+ $this->assertEquals($port, $client->getPort());
+ }
+
+ public function testDefaults()
+ {
+ $client = new Elastica_Client();
+
+ $this->assertEquals(Elastica_Client::DEFAULT_HOST, 'localhost');
+ $this->assertEquals(Elastica_Client::DEFAULT_PORT, 9200);
+ $this->assertEquals(Elastica_Client::DEFAULT_TRANSPORT, 'Http');
+
+ $this->assertEquals(Elastica_Client::DEFAULT_HOST, $client->getHost());
+ $this->assertEquals(Elastica_Client::DEFAULT_PORT, $client->getPort());
+ $this->assertEquals(Elastica_Client::DEFAULT_TRANSPORT, $client->getTransport());
+ }
+
+ public function testServersArray()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $client = new Elastica_Client(array('servers' => array(array('host' => 'localhost', 'port' => 9200))));
+ $index = $client->getIndex('elastica_test1');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Elastica_Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Elastica_Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Elastica_Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ }
+
+ public function testTwoServersSame()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $client = new Elastica_Client(array('servers' => array(
+ array('host' => 'localhost', 'port' => 9200),
+ array('host' => 'localhost', 'port' => 9200),
+ )));
+ $index = $client->getIndex('elastica_test1');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Elastica_Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Elastica_Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Elastica_Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ }
+
+ public function testBulk()
+ {
+ $client = new Elastica_Client();
+
+ $params = array(
+ array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
+ array('user' => array('name' => 'hans')),
+ array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '2')),
+ array('user' => array('name' => 'peter')),
+ );
+
+ $client->bulk($params);
+ }
+
+ public function testOptimizeAll()
+ {
+ $client = new Elastica_Client();
+ $response = $client->optimizeAll();
+
+ $this->assertFalse($response->hasError());
+ }
+
+ public function testAddDocumentsEmpty()
+ {
+ $client = new Elastica_Client();
+ try {
+ $client->addDocuments(array());
+ $this->fail('Should throw exception');
+ } catch (Elastica_Exception_Invalid $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ /**
+ * Test deleteIds method using string parameters
+ *
+ * This test ensures that the deleteIds method of
+ * the Elastica_Client can properly accept and use
+ * an $index parameter and $type parameter that are
+ * strings
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ */
+ public function testDeleteIdsIdxStringTypeString()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex();
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Elastica_Document(null, $data);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $idxString = $index->getName();
+ $typeString = $type->getName();
+ $this->assertEquals(true, is_string($idxString));
+ $this->assertEquals(true, is_string($typeString));
+
+ // Using the existing $index and $type variables which
+ // are Elastica_Index and Elastica_Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+
+ /**
+ * Test deleteIds method using string parameter for $index
+ * and object parameter for $type
+ *
+ * This test ensures that the deleteIds method of
+ * the Elastica_Client can properly accept and use
+ * an $index parameter that is a string and a $type
+ * parameter that is of type Elastica_Type
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ */
+ public function testDeleteIdsIdxStringTypeObject()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex();
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Elastica_Document(null, $data);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $idxString = $index->getName();
+ $this->assertEquals(true, is_string($idxString));
+ $this->assertEquals(true, ($type instanceof Elastica_Type));
+
+ // Using the existing $index and $type variables which
+ // are Elastica_Index and Elastica_Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+
+ /**
+ * Test deleteIds method using object parameter for $index
+ * and string parameter for $type
+ *
+ * This test ensures that the deleteIds method of
+ * the Elastica_Client can properly accept and use
+ * an $index parameter that is of type Elasitca_Index
+ * and a $type parameter that is a string
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ */
+ public function testDeleteIdsIdxObjectTypeString()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex();
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Elastica_Document(null, $data);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $typeString = $type->getName();
+ $this->assertEquals(true, ($index instanceof Elastica_Index));
+ $this->assertEquals(true, is_string($typeString));
+
+ // Using the existing $index and $type variables which
+ // are Elastica_Index and Elastica_Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+
+ /**
+ * Test deleteIds method using object parameter for $index
+ * and object parameter for $type
+ *
+ * This test ensures that the deleteIds method of
+ * the Elastica_Client can properly accept and use
+ * an $index parameter that is an object and a $type
+ * parameter that is of type Elastica_Type
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ */
+ public function testDeleteIdsIdxObjectTypeObject()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex();
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Elastica_Document(null, $data);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $this->assertEquals(true, ($index instanceof Elastica_Index));
+ $this->assertEquals(true, ($type instanceof Elastica_Type));
+
+ // Using the existing $index and $type variables which
+ // are Elastica_Index and Elastica_Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Cluster/SettingsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Cluster/SettingsTest.php
new file mode 100644
index 0000000..96152c5
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Cluster/SettingsTest.php
@@ -0,0 +1,88 @@
+_createIndex();
+ $settings = new Elastica_Cluster_Settings($index->getClient());
+
+ $settings->setTransient('discovery.zen.minimum_master_nodes', 2);
+ $data = $settings->get();
+ $this->assertEquals(2, $data['transient']['discovery.zen.minimum_master_nodes']);
+
+ $settings->setTransient('discovery.zen.minimum_master_nodes', 1);
+ $data = $settings->get();
+ $this->assertEquals(1, $data['transient']['discovery.zen.minimum_master_nodes']);
+ }
+
+ public function testSetPersistent()
+ {
+ $index = $this->_createIndex();
+ $settings = new Elastica_Cluster_Settings($index->getClient());
+
+ $settings->setPersistent('discovery.zen.minimum_master_nodes', 2);
+ $data = $settings->get();
+ $this->assertEquals(2, $data['persistent']['discovery.zen.minimum_master_nodes']);
+
+ $settings->setPersistent('discovery.zen.minimum_master_nodes', 1);
+ $data = $settings->get();
+ $this->assertEquals(1, $data['persistent']['discovery.zen.minimum_master_nodes']);
+ }
+
+ public function testSetReadOnly()
+ {
+ // Create two indices to check that the complete cluster is read only
+ $index1 = $this->_createIndex('test1');
+ $index2 = $this->_createIndex('test2');
+
+ $settings = new Elastica_Cluster_Settings($index1->getClient());
+
+ $doc = new Elastica_Document(null, array('hello' => 'world'));
+
+ // Check that adding documents work
+ $index1->getType('test')->addDocument($doc);
+ $index2->getType('test')->addDocument($doc);
+
+ $response = $settings->setReadOnly(true);
+ $this->assertFalse($response->hasError());
+ $setting = $settings->getTransient('cluster.blocks.read_only');
+ $this->assertEquals('true', $setting);
+
+ // Make sure both index are read only
+ try {
+ $index1->getType('test')->addDocument($doc);
+ $this->fail('should throw read only exception');
+ } catch (Elastica_Exception_Response $e) {
+ $message = $e->getMessage();
+ $this->assertContains('ClusterBlockException', $message);
+ $this->assertContains('cluster read-only', $message);
+ }
+
+ try {
+ $index2->getType('test')->addDocument($doc);
+ $this->fail('should throw read only exception');
+ } catch (Elastica_Exception_Response $e) {
+ $message = $e->getMessage();
+ $this->assertContains('ClusterBlockException', $message);
+ $this->assertContains('cluster read-only', $message);
+ }
+
+ $response = $settings->setReadOnly(false);
+ $this->assertFalse($response->hasError());
+ $setting = $settings->getTransient('cluster.blocks.read_only');
+ $this->assertEquals('false', $setting);
+
+ // Check that adding documents works again
+ $index1->getType('test')->addDocument($doc);
+ $index2->getType('test')->addDocument($doc);
+
+ $index1->refresh();
+ $index2->refresh();
+
+ // 2 docs should be in each index
+ $this->assertEquals(2, $index1->count());
+ $this->assertEquals(2, $index2->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ClusterTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ClusterTest.php
new file mode 100644
index 0000000..304e6da
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/ClusterTest.php
@@ -0,0 +1,80 @@
+getNodeNames();
+
+ $this->assertInternalType('array', $names);
+ $this->assertGreaterThan(0, count($names));
+ }
+
+ public function testGetNodes()
+ {
+ $client = new Elastica_Client();
+ $cluster = $client->getCluster();
+
+ $nodes = $cluster->getNodes();
+
+ foreach ($nodes as $node) {
+ $this->assertInstanceOf('Elastica_Node', $node);
+ }
+
+ $this->assertGreaterThan(0, count($nodes));
+ }
+
+ public function testGetState()
+ {
+ $client = new Elastica_Client();
+ $cluster = $client->getCluster();
+ $state = $cluster->getState();
+ $this->assertInternalType('array', $state);
+ }
+
+ public function testShutdown()
+ {
+ $this->markTestSkipped('This test shuts down the cluster which means the following tests would not work');
+ $client = new Elastica_Client();
+ $cluster = $client->getCluster();
+
+ $cluster->shutdown('2s');
+
+ sleep(5);
+
+ try {
+ $client->getStatus();
+ $this->fail('Should throw exception because cluster is shut down');
+ } catch (Elastica_Exception_Client $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ public function testGetIndexNames()
+ {
+ $client = new Elastica_Client();
+ $cluster = $client->getCluster();
+
+ $indexName = 'elastica_test999';
+ $index = $this->_createIndex($indexName);
+ $index->delete();
+ $cluster->refresh();
+
+ // Checks that index does not exist
+ $indexNames = $cluster->getIndexNames();
+ $this->assertNotContains($index->getName(), $indexNames);
+
+ $index = $this->_createIndex($indexName);
+ $cluster->refresh();
+
+ // Now index should exist
+ $indexNames = $cluster->getIndexNames();
+ $this->assertContains($index->getname(), $indexNames);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/DocumentTest.php b/modules/thirdparty/elastica/test/lib/Elastica/DocumentTest.php
new file mode 100644
index 0000000..aa195ea
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/DocumentTest.php
@@ -0,0 +1,49 @@
+add('key', 'value');
+ $data = $doc->getData();
+ $this->assertArrayHasKey('key', $data);
+ $this->assertEquals('value', $data['key']);
+ $this->assertInstanceOf('Elastica_Document', $returnValue);
+ }
+
+ public function testAddFile()
+ {
+ $doc = new Elastica_Document();
+ $returnValue = $doc->addFile('key', '/dev/null');
+ $this->assertInstanceOf('Elastica_Document', $returnValue);
+ }
+
+ public function testAddGeoPoint()
+ {
+ $doc = new Elastica_Document();
+ $returnValue = $doc->addGeoPoint('point', 38.89859, -77.035971);
+ $this->assertInstanceOf('Elastica_Document', $returnValue);
+ }
+
+ public function testSetData()
+ {
+ $doc = new Elastica_Document();
+ $returnValue = $doc->setData(array('data'));
+ $this->assertInstanceOf('Elastica_Document', $returnValue);
+ }
+
+ public function testToArray()
+ {
+ $id = 17;
+ $data = array('hello' => 'world');
+ $type = 'testtype';
+ $index = 'textindex';
+
+ $doc = new Elastica_Document($id, $data, $type, $index);
+
+ $result = array('_index' => $index, '_type' => $type, '_id' => $id, '_source' => $data);
+ $this->assertEquals($result, $doc->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ExampleTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ExampleTest.php
new file mode 100755
index 0000000..fb4742a
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/ExampleTest.php
@@ -0,0 +1,39 @@
+getIndex('elastica_test');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Elastica_Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Elastica_Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Elastica_Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Exception/NotImplementedTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Exception/NotImplementedTest.php
new file mode 100644
index 0000000..a88236c
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Exception/NotImplementedTest.php
@@ -0,0 +1,20 @@
+assertInstanceOf('Elastica_Exception_NotImplemented', $exception);
+ $this->assertInstanceOf('Elastica_Exception_Abstract', $exception);
+ $this->assertInstanceOf('Exception', $exception);
+
+ $this->assertEquals($message, $exception->getMessage());
+ $this->assertEquals($code, $exception->getCode());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/DateHistogramTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/DateHistogramTest.php
new file mode 100644
index 0000000..9e2fa16
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/DateHistogramTest.php
@@ -0,0 +1,52 @@
+assertInstanceOf('Elastica_Facet_Histogram', $facet);
+ $this->assertInstanceOf('Elastica_Facet_Abstract', $facet);
+ unset($facet);
+ }
+
+ public function testTest()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $mapping = new Elastica_Type_Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no'),
+ 'dtmPosted' => array('type' => 'date', 'store' => 'no', 'format' => 'yyyy-MM-dd HH:mm:ss')
+ ));
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1, array('name' => 'nicolas ruflin', 'dtmPosted' => "2011-06-23 21:53:00"));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'raul martinez jr', 'dtmPosted' => "2011-06-23 09:53:00"));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'rachelle clemente', 'dtmPosted' => "2011-07-08 08:53:00"));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'elastica search', 'dtmPosted' => "2011-07-08 01:53:00"));
+ $type->addDocument($doc);
+
+ $facet = new Elastica_Facet_DateHistogram('dateHist1');
+ $facet->setInterval("day");
+ $facet->setField("dtmPosted");
+
+ $query = new Elastica_Query();
+ $query->addFacet($facet);
+ $query->setQuery(new Elastica_Query_MatchAll());
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(4, $response->getTotalHits());
+ $this->assertEquals(2, count($facets['dateHist1']['entries']));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/FilterTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/FilterTest.php
new file mode 100644
index 0000000..a163c05
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/FilterTest.php
@@ -0,0 +1,34 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $type->addDocument(new Elastica_Document(1, array('color' => 'red')));
+ $type->addDocument(new Elastica_Document(2, array('color' => 'green')));
+ $type->addDocument(new Elastica_Document(3, array('color' => 'blue')));
+
+ $index->refresh();
+
+ $filter = new Elastica_Filter_Term(array('color' => 'red'));
+
+ $facet = new Elastica_Facet_Filter('test');
+ $facet->setFilter($filter);
+
+ $query = new Elastica_Query();
+ $query->addFacet($facet);
+
+ $resultSet = $type->search($query);
+
+ $facets = $resultSet->getFacets();
+
+ $this->assertEquals(1, $facets['test']['count']);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/QueryTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/QueryTest.php
new file mode 100644
index 0000000..06b8610
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/QueryTest.php
@@ -0,0 +1,34 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $type->addDocument(new Elastica_Document(1, array('color' => 'red')));
+ $type->addDocument(new Elastica_Document(2, array('color' => 'green')));
+ $type->addDocument(new Elastica_Document(3, array('color' => 'blue')));
+
+ $index->refresh();
+
+ $termQuery = new Elastica_Query_Term(array('color' => 'red'));
+
+ $facet = new Elastica_Facet_Query('test');
+ $facet->setQuery($termQuery);
+
+ $query = new Elastica_Query();
+ $query->addFacet($facet);
+
+ $resultSet = $type->search($query);
+
+ $facets = $resultSet->getFacets();
+
+ $this->assertEquals(1, $facets['test']['count']);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/StatisticalTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/StatisticalTest.php
new file mode 100644
index 0000000..2679fd0
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/StatisticalTest.php
@@ -0,0 +1,73 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Elastica_Document(1, array('price' => 10));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('price' => 35));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('price' => 45));
+ $type->addDocument($doc);
+
+ $facet = new Elastica_Facet_Statistical('stats');
+ $facet->setField('price');
+
+ $query = new Elastica_Query();
+ $query->addFacet($facet);
+ $query->setQuery(new Elastica_Query_MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(55, $facets['stats']['total']);
+ $this->assertEquals(10, $facets['stats']['min']);
+ $this->assertEquals(45, $facets['stats']['max']);
+ }
+
+ public function testStatisticalWithSetFields()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Elastica_Document(1, array('price' => 10, 'price2' => 20));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('price' => 35, 'price2' => 70));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('price' => 45, 'price2' => 90));
+ $type->addDocument($doc);
+
+ $facet = new Elastica_Facet_Statistical('stats');
+ $facet->setFields(array('price','price2'));
+
+ $query = new Elastica_Query();
+ $query->addFacet($facet);
+ $query->setQuery(new Elastica_Query_MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(165, $facets['stats']['total']);
+ $this->assertEquals(10, $facets['stats']['min']);
+ $this->assertEquals(90, $facets['stats']['max']);
+ }
+
+ public function testStatisticalWithSetScript()
+ {
+ $this->markTestIncomplete('Test for setting the script value');
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsStatsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsStatsTest.php
new file mode 100644
index 0000000..ce7bd5e
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsStatsTest.php
@@ -0,0 +1,63 @@
+getIndex( 'test' );
+ $index->create( array( ), true );
+ $type = $index->getType( 'helloworld' );
+
+ $doc = new Elastica_Document( 1, array( 'name' => 'tom', 'paid' => 7 ) );
+ $type->addDocument( $doc );
+ $doc = new Elastica_Document( 2, array( 'name' => 'tom', 'paid' => 2 ) );
+ $type->addDocument( $doc );
+ $doc = new Elastica_Document( 3, array( 'name' => 'tom', 'paid' => 5 ) );
+ $type->addDocument( $doc );
+ $doc = new Elastica_Document( 4, array( 'name' => 'mike', 'paid' => 13 ) );
+ $type->addDocument( $doc );
+ $doc = new Elastica_Document( 5, array( 'name' => 'mike', 'paid' => 1 ) );
+ $type->addDocument( $doc );
+ $doc = new Elastica_Document( 6, array( 'name' => 'mike', 'paid' => 15 ) );
+ $type->addDocument( $doc );
+
+ $facet = new Elastica_Facet_TermsStats( 'test' );
+ $facet->setKeyField( 'name' );
+ $facet->setValueField( 'paid' );
+
+ $query = new Elastica_Query();
+ $query->addFacet( $facet );
+ $query->setQuery( new Elastica_Query_MatchAll() );
+
+ $index->refresh();
+
+ $response = $type->search( $query );
+ $facets = $response->getFacets();
+
+ $this->assertEquals( 2, count( $facets[ 'test' ][ 'terms' ] ) );
+ foreach ($facets[ 'test' ][ 'terms' ] as $facet) {
+ if ($facet[ 'term' ] === 'tom') {
+ $this->assertEquals( 14, $facet[ 'total' ] );
+ }
+ if ($facet[ 'term' ] === 'mike') {
+ $this->assertEquals( 29, $facet[ 'total' ] );
+ }
+ }
+ }
+
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsTest.php
new file mode 100644
index 0000000..2d820ee
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsTest.php
@@ -0,0 +1,35 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Elastica_Document(1, array('name' => 'nicolas ruflin'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'ruflin test'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'nicolas helloworld'));
+ $type->addDocument($doc);
+
+ $facet = new Elastica_Facet_Terms('test');
+ $facet->setField('name');
+
+ $query = new Elastica_Query();
+ $query->addFacet($facet);
+ $query->setQuery(new Elastica_Query_MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(3, count($facets['test']['terms']));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/Abstract/MultiTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/Abstract/MultiTest.php
new file mode 100644
index 0000000..f7b1604
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/Abstract/MultiTest.php
@@ -0,0 +1,96 @@
+getStub();
+
+ $this->assertEmpty($stub->getFilters());
+ }
+
+ public function testAddFilter()
+ {
+ $stub = $this->getStub();
+
+ $filter = new Elastica_Filter_MatchAll();
+ $stub->addFilter($filter);
+
+ $expected = array(
+ $filter->toArray()
+ );
+
+ $this->assertEquals($expected, $stub->getFilters());
+ }
+
+ public function testSetFilters()
+ {
+ $stub = $this->getStub();
+
+ $filter = new Elastica_Filter_MatchAll();
+ $stub->setFilters(array($filter));
+
+ $expected = array(
+ $filter->toArray()
+ );
+
+ $this->assertEquals($expected, $stub->getFilters());
+ }
+
+ public function testToArray()
+ {
+ $stub = $this->getStub();
+
+ $filter = new Elastica_Filter_MatchAll();
+ $stub->addFilter($filter);
+
+ $expected = array(
+ $stub->getBaseName() => array(
+ $filter->toArray()
+ )
+ );
+
+ $this->assertEquals($expected, $stub->toArray());
+ }
+
+ public function testToArrayWithParam()
+ {
+ $stub = $this->getStub();
+
+ $stub->setCached(true);
+
+ $filter = new Elastica_Filter_MatchAll();
+ $stub->addFilter($filter);
+
+ $expected = array(
+ $stub->getBaseName() => array(
+ '_cache' => true,
+ 'filters' => array(
+ $filter->toArray()
+ )
+ )
+ );
+
+ $this->assertEquals($expected, $stub->toArray());
+ }
+
+ private function getStub()
+ {
+ return $this->getMockForAbstractClass('Elastica_Filter_Abstract_MultiDebug');
+ }
+}
+
+abstract class Elastica_Filter_Abstract_MultiDebug extends Elastica_Filter_Abstract_Multi
+{
+ public function getFilters()
+ {
+ return $this->_filters;
+ }
+
+ public function getBaseName()
+ {
+ return parent::_getBaseName();
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/AbstractTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AbstractTest.php
new file mode 100644
index 0000000..b150b85
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AbstractTest.php
@@ -0,0 +1,67 @@
+getStub();
+
+ $stubFilter->setCached(true);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertTrue($arrayFilter['_cache']);
+
+ $stubFilter->setCached(false);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertFalse($arrayFilter['_cache']);
+ }
+
+ public function testSetCachedDefaultValue()
+ {
+ $stubFilter = $this->getStub();
+
+ $stubFilter->setCached();
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertTrue($arrayFilter['_cache']);
+ }
+
+ public function testSetCacheKey()
+ {
+ $stubFilter = $this->getStub();
+
+ $cacheKey = 'myCacheKey';
+
+ $stubFilter->setCacheKey($cacheKey);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertEquals($cacheKey, $arrayFilter['_cache_key']);
+ }
+
+ /**
+ * @expectedException Elastica_Exception_Invalid
+ */
+ public function testSetCacheKeyEmptyKey()
+ {
+ $stubFilter = $this->getStub();
+
+ $cacheKey = '';
+
+ $stubFilter->setCacheKey($cacheKey);
+ }
+
+ public function testSetName()
+ {
+ $stubFilter = $this->getStub();
+
+ $name = 'myFilter';
+
+ $stubFilter->setName($name);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertEquals($name, $arrayFilter['_name']);
+ }
+
+ private function getStub()
+ {
+ return $this->getMockForAbstractClass('Elastica_Filter_Abstract');
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/AndTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AndTest.php
new file mode 100644
index 0000000..6027743
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AndTest.php
@@ -0,0 +1,60 @@
+assertEquals(array('and' => array()), $and->toArray());
+
+ $idsFilter = new Elastica_Filter_Ids();
+ $idsFilter->setIds(12);
+
+ $and->addFilter($idsFilter);
+ $and->addFilter($idsFilter);
+
+ $expectedArray = array(
+ 'and' => array(
+ $idsFilter->toArray(),
+ $idsFilter->toArray()
+ )
+ );
+
+ $this->assertEquals($expectedArray, $and->toArray());
+ }
+
+ public function testSetCache()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $doc = new Elastica_Document(1, array('name' => 'hello world'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'nicolas ruflin'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'ruflin'));
+ $type->addDocument($doc);
+
+ $and = new Elastica_Filter_And();
+
+ $idsFilter1 = new Elastica_Filter_Ids();
+ $idsFilter1->setIds(1);
+
+ $idsFilter2 = new Elastica_Filter_Ids();
+ $idsFilter2->setIds(1);
+
+ $and->addFilter($idsFilter1);
+ $and->addFilter($idsFilter2);
+
+ $index->refresh();
+ $and->setCached(true);
+
+ $resultSet = $type->search($and);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/ExistsTests.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/ExistsTests.php
new file mode 100644
index 0000000..dc35b20
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/ExistsTests.php
@@ -0,0 +1,28 @@
+ array('field' => $field));
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ public function testSetField()
+ {
+ $field = 'test';
+ $filter = new Elastica_Filter_Exists($field);
+
+ $this->assertEquals($field, $filter->getParam('field'));
+
+ $newField = 'hello world';
+ $this->assertInstanceOf('Elastica_Filter_Exists', $filter->setField($newField));
+
+ $this->assertEquals($newField, $filter->getParam('field'));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoDistanceTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoDistanceTest.php
new file mode 100755
index 0000000..8af5a22
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoDistanceTest.php
@@ -0,0 +1,147 @@
+getIndex('test');
+ $index->create(array(), true);
+
+ $type = $index->getType('test');
+
+ // Set mapping
+ $type->setMapping(array('point' => array('type' => 'geo_point')));
+
+ // Add doc 1
+ $doc1 = new Elastica_Document(1,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc1->addGeoPoint('point', 17, 19);
+ $type->addDocument($doc1);
+
+ // Add doc 2
+ $doc2 = new Elastica_Document(2,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc2->addGeoPoint('point', 30, 40);
+ $type->addDocument($doc2);
+
+ $index->optimize();
+ $index->refresh();
+
+ // Only one point should be in radius
+ $query = new Elastica_Query();
+ $geoFilter = new Elastica_Filter_GeoDistance('point', array('lat' => 30, 'lon' => 40), '1km');
+
+ $query = new Elastica_Query(new Elastica_Query_MatchAll());
+ $query->setFilter($geoFilter);
+ $this->assertEquals(1, $type->search($query)->count());
+
+ // Both points should be inside
+ $query = new Elastica_Query();
+ $geoFilter = new Elastica_Filter_GeoDistance('point', array('lat' => 30, 'lon' => 40), '40000km');
+ $query = new Elastica_Query(new Elastica_Query_MatchAll());
+ $query->setFilter($geoFilter);
+ $index->refresh();
+
+ $this->assertEquals(2, $type->search($query)->count());
+ }
+
+ public function testConstructLatlon()
+ {
+ $key = 'location';
+ $location = array(
+ 'lat' => 48.86,
+ 'lon' => 2.35
+ );
+ $distance = '10km';
+
+ $filter = new Elastica_Filter_GeoDistance($key, $location, $distance);
+
+ $expected = array(
+ 'geo_distance' => array(
+ $key => $location,
+ 'distance' => $distance
+ )
+ );
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($expected, $data);
+ }
+
+ public function testConstructGeohash()
+ {
+ $key = 'location';
+ $location = 'u09tvqx';
+ $distance = '10km';
+
+ $filter = new Elastica_Filter_GeoDistance($key, $location, $distance);
+
+ $expected = array(
+ 'geo_distance' => array(
+ $key => $location,
+ 'distance' => $distance
+ )
+ );
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($expected, $data);
+ }
+
+ public function testConstructOldSignature()
+ {
+ $key = 'location';
+ $latitude = 48.86;
+ $longitude = 2.35;
+ $distance = '10km';
+
+ $filter = new Elastica_Filter_GeoDistance($key, $latitude, $longitude, $distance);
+
+ $expected = array(
+ 'geo_distance' => array(
+ $key => array(
+ 'lat' => $latitude,
+ 'lon' => $longitude
+ ),
+ 'distance' => $distance
+ )
+ );
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($expected, $data);
+ }
+
+ public function testSetDistanceType()
+ {
+ $filter = new Elastica_Filter_GeoDistance('location', array('lat' => 48.86, 'lon' => 2.35), '10km');
+ $distanceType = Elastica_Filter_GeoDistance::DISTANCE_TYPE_ARC;
+ $filter->setDistanceType($distanceType);
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($distanceType, $data['geo_distance']['distance_type']);
+ }
+
+ public function testSetOptimizeBbox()
+ {
+ $filter = new Elastica_Filter_GeoDistance('location', array('lat' => 48.86, 'lon' => 2.35), '10km');
+ $optimizeBbox = Elastica_Filter_GeoDistance::OPTIMIZE_BBOX_MEMORY;
+ $filter->setOptimizeBbox($optimizeBbox);
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($optimizeBbox, $data['geo_distance']['optimize_bbox']);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoPolygonTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoPolygonTest.php
new file mode 100755
index 0000000..de4babc
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoPolygonTest.php
@@ -0,0 +1,59 @@
+getIndex('test');
+ $index->create(array(), true);
+
+ $type = $index->getType('test');
+
+ // Set mapping
+ $type->setMapping(array('point' => array('type' => 'geo_point')));
+
+ // Add doc 1
+ $doc1 = new Elastica_Document(1,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc1->addGeoPoint('point', 17, 19);
+ $type->addDocument($doc1);
+
+ // Add doc 2
+ $doc2 = new Elastica_Document(2,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc2->addGeoPoint('point', 30, 40);
+ $type->addDocument($doc2);
+
+ $index->refresh();
+
+ // Only one point should be in polygon
+ $query = new Elastica_Query();
+ $points = array(array(16, 16), array(16, 20), array(20, 20), array(20, 16), array(16, 16));
+ $geoFilter = new Elastica_Filter_GeoPolygon('point', compact('points'));
+
+ $query = new Elastica_Query(new Elastica_Query_MatchAll());
+ $query->setFilter($geoFilter);
+ $this->assertEquals(1, $type->search($query)->count());
+
+ // Both points should be inside
+ $query = new Elastica_Query();
+ $points = array(array(16, 16), array(16, 40), array(40, 40), array(40, 16), array(16, 16));
+ $geoFilter = new Elastica_Filter_GeoPolygon('point', compact('points'));
+
+ $query = new Elastica_Query(new Elastica_Query_MatchAll());
+ $query->setFilter($geoFilter);
+
+ $this->assertEquals(2, $type->search($query)->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/IdsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/IdsTest.php
new file mode 100644
index 0000000..1777298
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/IdsTest.php
@@ -0,0 +1,185 @@
+getIndex('test');
+ $index->create(array(), true);
+
+ $type1 = $index->getType('helloworld1');
+ $type2 = $index->getType('helloworld2');
+
+ // Add documents to first type
+ for ($i = 1; $i < 100; $i++) {
+ $doc = new Elastica_Document($i, array('name' => 'ruflin'));
+ $type1->addDocument($doc);
+ }
+
+ // Add documents to second type
+ for ($i = 1; $i < 100; $i++) {
+ $doc = new Elastica_Document($i, array('name' => 'ruflin'));
+ $type2->addDocument($doc);
+ }
+
+ // This is a special id that will only be in the second type
+ $doc = new Elastica_Document('101', array('name' => 'ruflin'));
+ $type2->addDocument($doc);
+
+ $index->optimize();
+ $index->refresh();
+
+ $this->_type = $type1;
+ $this->_index = $index;
+ }
+
+ public function tearDown()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->delete();
+ }
+
+ public function testSetIdsSearchSingle()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds('1');
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetIdsSearchArray()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds(array(1, 7, 13));
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+ }
+
+ public function testAddIdsSearchSingle()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->addId('39');
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testAddIdsSearchSingleNotInType()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->addId('39');
+
+ // Add an ID that is not in the index
+ $filter->addId(104);
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testComboIdsSearchArray()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds(array(1, 7, 13));
+ $filter->addId('39');
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchSingle()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds('1');
+ $filter->setType('helloworld1');
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchArray()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds(array('1', '2'));
+ $filter->setType('helloworld1');
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchSingleDocInOtherType()
+ {
+ $filter = new Elastica_Filter_Ids();
+
+ // Doc 4 is in the second type...
+ $filter->setIds('101');
+ $filter->setType('helloworld1');
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_type->search($query);
+
+ // ...therefore 0 results should be returned
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchArrayDocInOtherType()
+ {
+ $filter = new Elastica_Filter_Ids();
+
+ // Doc 4 is in the second type...
+ $filter->setIds(array('1', '101'));
+ $filter->setType('helloworld1');
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_type->search($query);
+
+ // ...therefore only 1 result should be returned
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetTypeArraySearchArray()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds(array('1', '4'));
+ $filter->setType(array('helloworld1', 'helloworld2'));
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ public function testSetTypeArraySearchSingle()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds('4');
+ $filter->setType(array('helloworld1', 'helloworld2'));
+
+ $query = Elastica_Query::create($filter);
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/MatchAllTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/MatchAllTest.php
new file mode 100644
index 0000000..7cc5bce
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/MatchAllTest.php
@@ -0,0 +1,14 @@
+ new stdClass());
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/NestedTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NestedTest.php
new file mode 100644
index 0000000..01cf88b
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NestedTest.php
@@ -0,0 +1,114 @@
+getIndex('elastica_test_filter_nested');
+ $index->create(array(), true);
+ $type = $index->getType('user');
+ $mapping = new Elastica_Type_Mapping();
+ $mapping->setProperties(
+ array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ // default is store => no expected
+ 'lastname' => array('type' => 'string'),
+ 'hobbies' => array(
+ 'type' => 'nested',
+ 'include_in_parent' => true,
+ 'properties' => array('hobby' => array('type' => 'string'))
+ )
+ )
+ );
+ $type->setMapping($mapping);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Elastica_Document(1,
+ array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ruflin',
+ 'hobbies' => array(
+ array('hobby' => 'opensource')
+ )
+ )
+ );
+ $docs[] = new Elastica_Document(2,
+ array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ippolito',
+ 'hobbies' => array(
+ array('hobby' => 'opensource'),
+ array('hobby' => 'guitar'),
+ )
+ )
+ );
+ $response = $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+ }
+
+ public function tearDown()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('elastica_test_filter_nested');
+ $index->delete();
+ }
+
+ public function testToArray()
+ {
+ $f = new Elastica_Filter_Nested();
+ $this->assertEquals(array('nested' => array()), $f->toArray());
+ $q = new Elastica_Query_Terms();
+ $q->setTerms('hobby', array('guitar'));
+ $f->setPath('hobbies');
+ $f->setQuery($q);
+
+ $expectedArray = array(
+ 'nested' => array(
+ 'path' => 'hobbies',
+ 'query' => array('terms' => array(
+ 'hobby' => array('guitar')
+ ))
+ )
+ );
+
+ $this->assertEquals($expectedArray, $f->toArray());
+ }
+
+ public function testShouldReturnTheRightNumberOfResult()
+ {
+ $f = new Elastica_Filter_Nested();
+ $this->assertEquals(array('nested' => array()), $f->toArray());
+ $q = new Elastica_Query_Terms();
+ $q->setTerms('hobby', array('guitar'));
+ $f->setPath('hobbies');
+ $f->setQuery($q);
+
+ $c = new Elastica_Client();
+ $s = new Elastica_Search($c);
+ $i = $c->getIndex('elastica_test_filter_nested');
+ $s->addIndex($i);
+ $r = $s->search($f);
+
+ $this->assertEquals(1, $r->getTotalHits());
+
+ $f = new Elastica_Filter_Nested();
+ $this->assertEquals(array('nested' => array()), $f->toArray());
+ $q = new Elastica_Query_Terms();
+ $q->setTerms('hobby', array('opensource'));
+ $f->setPath('hobbies');
+ $f->setQuery($q);
+
+ $c = new Elastica_Client();
+ $s = new Elastica_Search($c);
+ $i = $c->getIndex('elastica_test_filter_nested');
+ $s->addIndex($i);
+ $r = $s->search($f);
+ $this->assertEquals(2, $r->getTotalHits());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/NotTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NotTest.php
new file mode 100644
index 0000000..63765f2
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NotTest.php
@@ -0,0 +1,21 @@
+setIds(12);
+ $filter = new Elastica_Filter_Not($idsFilter);
+
+ $expectedArray = array(
+ 'not' => array(
+ 'filter' => $idsFilter->toArray()
+ )
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/NumericRangeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NumericRangeTest.php
new file mode 100644
index 0000000..93961a1
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NumericRangeTest.php
@@ -0,0 +1,29 @@
+addField('fieldName', array('to' => 'value'));
+ $this->assertInstanceOf('Elastica_Filter_NumericRange', $returnValue);
+ }
+
+ public function testToArray()
+ {
+ $filter = new Elastica_Filter_NumericRange();
+
+ $fromTo = array('from' => 'ra', 'to' => 'ru');
+ $filter->addField('name', $fromTo);
+
+ $expectedArray = array(
+ 'numeric_range' => array(
+ 'name' => $fromTo
+ )
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/OrTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/OrTest.php
new file mode 100644
index 0000000..f6b687b
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/OrTest.php
@@ -0,0 +1,37 @@
+getMockForAbstractClass('Elastica_Filter_Abstract');
+ $orFilter = new Elastica_Filter_Or();
+ $returnValue = $orFilter->addFilter($filter);
+ $this->assertInstanceOf('Elastica_Filter_Or', $returnValue);
+ }
+
+ public function testToArray()
+ {
+ $orFilter = new Elastica_Filter_Or();
+
+ $filter1 = new Elastica_Filter_Ids();
+ $filter1->setIds('1');
+
+ $filter2 = new Elastica_Filter_Ids();
+ $filter2->setIds('2');
+
+ $orFilter->addFilter($filter1);
+ $orFilter->addFilter($filter2);
+
+ $expectedArray = array(
+ 'or' => array(
+ $filter1->toArray(),
+ $filter2->toArray()
+ )
+ );
+
+ $this->assertEquals($expectedArray, $orFilter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/PrefixTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/PrefixTest.php
new file mode 100644
index 0000000..cebc54c
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/PrefixTest.php
@@ -0,0 +1,144 @@
+ array(
+ $field => $prefix
+ )
+ );
+
+ $this->assertequals($expectedArray, $filter->toArray());
+ }
+
+ public function testDifferentPrefixes()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+
+ /*$indexParams = array(
+ 'analysis' => array(
+ 'analyzer' => array(
+ 'lw' => array(
+ 'type' => 'custom',
+ 'tokenizer' => 'keyword',
+ 'filter' => array('lowercase')
+ )
+ ),
+ )
+ );*/
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $mapping = new Elastica_Type_Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'index' => 'not_analyzed'),
+ )
+ );
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'New York'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'Baden Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(5, array('name' => 'New Orleans'));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $query = new Elastica_Filter_Prefix('name', 'Ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+
+ // Lower case should not return a result
+ $query = new Elastica_Filter_Prefix('name', 'ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+
+ $query = new Elastica_Filter_Prefix('name', 'Baden');
+ $resultSet = $index->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Elastica_Filter_Prefix('name', 'Baden B');
+ $resultSet = $index->search($query);
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Elastica_Filter_Prefix('name', 'Baden Bas');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ public function testDifferentPrefixesLowercase()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+
+ $indexParams = array(
+ 'analysis' => array(
+ 'analyzer' => array(
+ 'lw' => array(
+ 'type' => 'custom',
+ 'tokenizer' => 'keyword',
+ 'filter' => array('lowercase')
+ )
+ ),
+ )
+ );
+
+ $index->create($indexParams, true);
+ $type = $index->getType('test');
+
+ $mapping = new Elastica_Type_Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'lw'),
+ )
+ );
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'New York'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'Baden Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(5, array('name' => 'New Orleans'));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $query = new Elastica_Filter_Prefix('name', 'ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+
+ // Upper case should not return a result
+ $query = new Elastica_Filter_Prefix('name', 'Ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+
+ $query = new Elastica_Filter_Prefix('name', 'baden');
+ $resultSet = $index->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Elastica_Filter_Prefix('name', 'baden b');
+ $resultSet = $index->search($query);
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Elastica_Filter_Prefix('name', 'baden bas');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/QueryTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/QueryTest.php
new file mode 100644
index 0000000..a832ef9
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/QueryTest.php
@@ -0,0 +1,41 @@
+ array(
+ 'query_string' => array(
+ 'query' => 'foo bar',
+ )
+ )
+ );
+
+ $this->assertEquals($expected, $filter->toArray());
+ }
+
+ public function testExtended()
+ {
+ $query = new Elastica_Query_QueryString('foo bar');
+ $filter = new Elastica_Filter_Query($query);
+ $filter->setCached(true);
+
+ $expected = array(
+ 'fquery' => array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'foo bar',
+ ),
+ ),
+ '_cache' => true
+ )
+ );
+
+ $this->assertEquals($expected, $filter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/RangeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/RangeTest.php
new file mode 100644
index 0000000..ffc0e75
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/RangeTest.php
@@ -0,0 +1,29 @@
+addField('fieldName', array('to' => 'value'));
+ $this->assertInstanceOf('Elastica_Filter_Range', $returnValue);
+ }
+
+ public function testToArray()
+ {
+ $filter = new Elastica_Filter_Range();
+
+ $fromTo = array('from' => 'ra', 'to' => 'ru');
+ $filter->addField('name', $fromTo);
+
+ $expectedArray = array(
+ 'range' => array(
+ 'name' => $fromTo
+ )
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/TermTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TermTest.php
new file mode 100644
index 0000000..faf0ede
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TermTest.php
@@ -0,0 +1,20 @@
+setTerm($key, $value, $boost);
+
+ $data = $query->toArray();
+
+ $this->assertInternalType('array', $data['term']);
+ $this->assertEquals(array($key => $value), $data['term']);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/TypeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TypeTest.php
new file mode 100644
index 0000000..092d528
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TypeTest.php
@@ -0,0 +1,24 @@
+setType('type_name');
+ $this->assertInstanceOf('Elastica_Filter_Type', $returnValue);
+ }
+
+ public function testToArray()
+ {
+ $typeFilter = new Elastica_Filter_Type('type_name');
+
+ $expectedArray = array(
+ 'type' => array('value' => 'type_name')
+ );
+
+ $this->assertEquals($expectedArray, $typeFilter->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Index/SettingsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Index/SettingsTest.php
new file mode 100644
index 0000000..97fc904
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Index/SettingsTest.php
@@ -0,0 +1,239 @@
+getIndex($indexName);
+ $index->create(array(), true);
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertInternalType('array', $settings->get());
+ $this->assertNotNull($settings->get('number_of_replicas'));
+ $this->assertNotNull($settings->get('number_of_shards'));
+ $this->assertNull($settings->get('kjqwerjlqwer'));
+ }
+
+ public function testSetNumberOfReplicas()
+ {
+ $indexName = 'test';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $settings = $index->getSettings();
+
+ $settings->setNumberOfReplicas(2);
+ $index->refresh();
+ $this->assertEquals(2, $settings->get('number_of_replicas'));
+
+ $settings->setNumberOfReplicas(3);
+ $index->refresh();
+ $this->assertEquals(3, $settings->get('number_of_replicas'));
+ }
+
+ public function testSetRefreshInterval()
+ {
+ $indexName = 'test';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $settings = $index->getSettings();
+
+ $settings->setRefreshInterval('2s');
+ $index->refresh();
+ $this->assertEquals('2s', $settings->get('refresh_interval'));
+
+ $settings->setRefreshInterval('5s');
+ $index->refresh();
+ $this->assertEquals('5s', $settings->get('refresh_interval'));
+ }
+
+ public function testGetRefreshInterval()
+ {
+ $indexName = 'test';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $settings = $index->getSettings();
+
+ $this->assertEquals(Elastica_Index_Settings::DEFAULT_REFRESH_INTERVAL, $settings->getRefreshInterval());
+
+ $interval = '2s';
+ $settings->setRefreshInterval($interval);
+ $index->refresh();
+ $this->assertEquals($interval, $settings->getRefreshInterval());
+ $this->assertEquals($interval, $settings->get('refresh_interval'));
+ }
+
+ public function testSetMergePolicy()
+ {
+ $indexName = 'test';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $settings = $index->getSettings();
+
+ $settings->setMergePolicy('expunge_deletes_allowed', 15);
+ $this->assertEquals(15, $settings->getMergePolicy('expunge_deletes_allowed'));
+
+ $settings->setMergePolicy('expunge_deletes_allowed', 10);
+ $this->assertEquals(10, $settings->getMergePolicy('expunge_deletes_allowed'));
+ }
+
+ public function testSetMergeFactor()
+ {
+ $indexName = 'test';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $settings = $index->getSettings();
+
+ $response = $settings->setMergePolicy('merge_factor', 15);
+ $this->assertEquals(15, $settings->getMergePolicy('merge_factor'));
+ $this->assertInstanceOf('Elastica_Response', $response);
+ $data = $response->getData();
+ $this->assertTrue($data['ok']);
+
+ $settings->setMergePolicy('merge_factor', 10);
+ $this->assertEquals(10, $settings->getMergePolicy('merge_factor'));
+ }
+
+ public function testSetMergePolicyType()
+ {
+ $indexName = 'test';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $settings = $index->getSettings();
+
+ //$response = $settings->setMergePolicyType('LogByteSizeMergePolicyProvider');
+ $response = $settings->setMergePolicyType('log_byte_size');
+ $this->assertEquals('log_byte_size', $settings->getMergePolicyType());
+
+ $response = $settings->setMergePolicy('merge_factor', 15);
+ $this->assertEquals(15, $settings->getMergePolicy('merge_factor'));
+ $this->assertInstanceOf('Elastica_Response', $response);
+ $data = $response->getData();
+ $this->assertTrue($data['ok']);
+ }
+
+ public function testSetReadOnly()
+ {
+ $client = new Elastica_Client();
+ $index = new Elastica_Index($client, 'elastica_test');
+ $index->getSettings()->setReadOnly(false);
+
+ $index = $this->_createIndex();
+
+ // Add document to normal index
+ $doc = new Elastica_Document(null, array('hello' => 'world'));
+ $type = $index->getType('test');
+ $type->addDocument($doc);
+ $this->assertFalse((bool) $index->getSettings()->get('blocks.read_only'));
+
+ // Try to add doc to read only index
+ $index->getSettings()->setReadOnly(true);
+ $this->assertTrue((bool) $index->getSettings()->get('blocks.read_only'));
+
+ try {
+ $type->addDocument($doc);
+ $this->fail('Should throw exception because of read only');
+ } catch (Elastica_Exception_Response $e) {
+ $message = $e->getMessage();
+ $this->assertContains('ClusterBlockException', $message);
+ $this->assertContains('index read-only', $message);
+ }
+
+ // Remove read only, add document
+ $response = $index->getSettings()->setReadOnly(false);
+ $this->assertTrue($response->isOk());
+
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $this->assertEquals(2, $type->count());
+ }
+
+ public function testGetSetBlocksRead()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('elastica-test');
+ $index->create();
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertFalse($settings->getBlocksRead());
+
+ $settings->setBlocksRead(true);
+ $this->assertTrue($settings->getBlocksRead());
+
+ $settings->setBlocksRead(false);
+ $this->assertFalse($settings->getBlocksRead());
+
+ $settings->setBlocksRead();
+ $this->assertTrue($settings->getBlocksRead());
+
+ $index->delete();
+ }
+
+ public function testGetSetBlocksWrite()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('elastica-test');
+ $index->create();
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertFalse($settings->getBlocksWrite());
+
+ $settings->setBlocksWrite(true);
+ $this->assertTrue($settings->getBlocksWrite());
+
+ $settings->setBlocksWrite(false);
+ $this->assertFalse($settings->getBlocksWrite());
+
+ $settings->setBlocksWrite();
+ $this->assertTrue($settings->getBlocksWrite());
+
+ $index->delete();
+ }
+
+ public function testGetSetBlocksMetadata()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('elastica-test');
+ $index->create();
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertFalse($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata(true);
+ $this->assertTrue($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata(false);
+ $this->assertFalse($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata();
+ $this->assertTrue($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata(false); // Cannot delete index otherwise
+ $index->delete();
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Index/StatsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatsTest.php
new file mode 100644
index 0000000..a619ee8
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatsTest.php
@@ -0,0 +1,20 @@
+getIndex($indexName);
+ $index->create(array(), true);
+ $stats = $index->getStats();
+ $this->assertInstanceOf('Elastica_Index_Stats', $stats);
+
+ $this->assertTrue($stats->get('ok'));
+ $this->assertEquals(0, $stats->get('_all', 'indices', 'test', 'primaries', 'docs', 'count'));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Index/StatusTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatusTest.php
new file mode 100644
index 0000000..d2657ff
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatusTest.php
@@ -0,0 +1,62 @@
+getIndex($indexName);
+ $index->create(array(), true);
+
+ $status = new Elastica_Index_Status($index);
+
+ $aliases = $status->getAliases();
+
+ $this->assertTrue(empty($aliases));
+ $this->assertInternalType('array', $aliases);
+
+ $index->addAlias($aliasName);
+ $status->refresh();
+
+ $aliases = $status->getAliases();
+
+ $this->assertTrue(in_array($aliasName, $aliases));
+ }
+
+ public function testHasAlias()
+ {
+ $indexName = 'test';
+ $aliasName = 'test-alias';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $status = new Elastica_Index_Status($index);
+
+ $this->assertFalse($status->hasAlias($aliasName));
+
+ $index->addAlias($aliasName);
+ $status->refresh();
+
+ $this->assertTrue($status->hasAlias($aliasName));
+ }
+
+ public function testGetSettings()
+ {
+ $indexName = 'test';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $status = $index->getStatus();
+
+ $settings = $status->getSettings();
+ $this->assertInternalType('array', $settings);
+ $this->assertTrue(isset($settings['index.number_of_shards']));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/IndexTest.php b/modules/thirdparty/elastica/test/lib/Elastica/IndexTest.php
new file mode 100755
index 0000000..66decde
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/IndexTest.php
@@ -0,0 +1,497 @@
+_createIndex();
+ $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5')));
+
+ $type = $index->getType('test');
+
+ $mapping = array('id' => array('type' => 'integer', 'store' => 'yes'), 'email' => array('type' => 'string', 'store' => 'no'),
+ 'username' => array('type' => 'string', 'store' => 'no'), 'test' => array('type' => 'integer', 'store' => 'no'),);
+ $type->setMapping($mapping);
+
+ $type->addDocument($doc);
+ $index->optimize();
+
+ $storedMapping = $type->getMapping('test');
+
+ $this->assertEquals($storedMapping['test']['properties']['id']['type'], 'integer');
+ $this->assertEquals($storedMapping['test']['properties']['id']['store'], 'yes');
+ $this->assertEquals($storedMapping['test']['properties']['email']['type'], 'string');
+ $this->assertEquals($storedMapping['test']['properties']['username']['type'], 'string');
+ $this->assertEquals($storedMapping['test']['properties']['test']['type'], 'integer');
+
+ $result = $type->search('hanswurst');
+ }
+
+ public function testParent()
+ {
+ $index = $this->_createIndex();
+
+ $typeBlog = new Elastica_Type($index, 'blog');
+
+ $typeComment = new Elastica_Type($index, 'comment');
+
+ $mapping = new Elastica_Type_Mapping();
+ $mapping->setParam('_parent', array('type' => 'blog'));
+ $typeComment->setMapping($mapping);
+
+ $entry1 = new Elastica_Document(1);
+ $entry1->add('title', 'Hello world');
+ $typeBlog->addDocument($entry1);
+
+ $entry2 = new Elastica_Document(2);
+ $entry2->add('title', 'Foo bar');
+ $typeBlog->addDocument($entry2);
+
+ $entry3 = new Elastica_Document(3);
+ $entry3->add('title', 'Till dawn');
+ $typeBlog->addDocument($entry3);
+
+ $comment = new Elastica_Document(1);
+ $comment->add('author', 'Max');
+ $comment->setParent(2); // Entry Foo bar
+ $typeComment->addDocument($comment);
+
+ $index->optimize();
+
+ $query = new Elastica_Query_HasChild('Max', 'comment');
+ $resultSet = $typeBlog->search($query);
+ $this->assertEquals(1, $resultSet->count());
+ $this->assertEquals(array('title' => 'Foo bar'), $resultSet->current()->getData());
+ }
+
+ public function testAddPdfFile()
+ {
+ $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'no'), 'text' => array('type' => 'string', 'store' => 'no'),);
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),);
+
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'test');
+
+ $index->create($indexParams, true);
+ $type->setMapping($indexMapping);
+
+ $doc1 = new Elastica_Document(1);
+ $doc1->addFile('file', BASE_PATH . '/data/test.pdf');
+ $doc1->add('text', 'basel world');
+ $type->addDocument($doc1);
+
+ $doc2 = new Elastica_Document(2);
+ $doc2->add('text', 'running in basel');
+ $type->addDocument($doc2);
+
+ $index->optimize();
+
+ $resultSet = $type->search('xodoa');
+ $this->assertEquals(1, $resultSet->count());
+
+ $resultSet = $type->search('basel');
+ $this->assertEquals(2, $resultSet->count());
+
+ // Author is ruflin
+ $resultSet = $type->search('ruflin');
+ $this->assertEquals(1, $resultSet->count());
+
+ // String does not exist in file
+ $resultSet = $type->search('guschti');
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ public function testAddPdfFileContent()
+ {
+ $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'no'), 'text' => array('type' => 'string', 'store' => 'no'),);
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),);
+
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'test');
+
+ $index->create($indexParams, true);
+ $type->setMapping($indexMapping);
+
+ $doc1 = new Elastica_Document(1);
+ $doc1->addFileContent('file', file_get_contents(BASE_PATH . '/data/test.pdf'));
+ $doc1->add('text', 'basel world');
+ $type->addDocument($doc1);
+
+ $doc2 = new Elastica_Document(2);
+ $doc2->add('text', 'running in basel');
+ $type->addDocument($doc2);
+
+ $index->optimize();
+
+ $resultSet = $type->search('xodoa');
+ $this->assertEquals(1, $resultSet->count());
+
+ $resultSet = $type->search('basel');
+ $this->assertEquals(2, $resultSet->count());
+
+ // Author is ruflin
+ $resultSet = $type->search('ruflin');
+ $this->assertEquals(1, $resultSet->count());
+
+ // String does not exist in file
+ $resultSet = $type->search('guschti');
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ public function testAddWordxFile()
+ {
+ $indexMapping = array('file' => array('type' => 'attachment'), 'text' => array('type' => 'string', 'store' => 'no'),);
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),);
+
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'content');
+
+ $index->create($indexParams, true);
+ $type->setMapping($indexMapping);
+
+ $doc1 = new Elastica_Document(1);
+ $doc1->addFile('file', BASE_PATH . '/data/test.docx');
+ $doc1->add('text', 'basel world');
+ $type->addDocument($doc1);
+
+ $doc2 = new Elastica_Document(2);
+ $doc2->add('text', 'running in basel');
+ $type->addDocument($doc2);
+
+ $index->optimize();
+
+ $resultSet = $type->search('xodoa');
+ $this->assertEquals(1, $resultSet->count());
+
+ $resultSet = $type->search('basel');
+ $this->assertEquals(2, $resultSet->count());
+
+ $resultSet = $type->search('ruflin');
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ public function testExcludeFileSource()
+ {
+ $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'yes'), 'text' => array('type' => 'string', 'store' => 'yes'),
+ 'title' => array('type' => 'string', 'store' => 'yes'),);
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),);
+
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'content');
+
+ $mapping = Elastica_Type_Mapping::create($indexMapping);
+ $mapping->setSource(array('excludes' => array('file')));
+
+ $mapping->setType($type);
+
+ $index->create($indexParams, true);
+ $type->setMapping($mapping);
+
+ $docId = 1;
+ $text = 'Basel World';
+ $title = 'No Title';
+
+ $doc1 = new Elastica_Document($docId);
+ $doc1->addFile('file', BASE_PATH . '/data/test.docx');
+ $doc1->add('text', $text);
+ $doc1->add('title', $title);
+ $type->addDocument($doc1);
+
+ // Optimization necessary, as otherwise source still in realtime get
+ $index->optimize();
+
+ $data = $type->getDocument($docId)->getData();
+ $this->assertEquals($data['title'], $title);
+ $this->assertEquals($data['text'], $text);
+ $this->assertFalse(isset($data['file']));
+ }
+
+ public function testAddRemoveAlias()
+ {
+ $client = new Elastica_Client();
+
+ $indexName1 = 'test1';
+ $aliasName = 'test-alias';
+ $typeName = 'test';
+
+ $index = $client->getIndex($indexName1);
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'ruflin'));
+
+ $type = $index->getType($typeName);
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $resultSet = $type->search('ruflin');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $data = $index->addAlias($aliasName, true)->getData();
+ $this->assertTrue($data['ok']);
+
+ $index2 = $client->getIndex($aliasName);
+ $type2 = $index2->getType($typeName);
+
+ $resultSet2 = $type2->search('ruflin');
+ $this->assertEquals(1, $resultSet2->count());
+
+ $response = $index->removeAlias($aliasName)->getData();
+ $this->assertTrue($response['ok']);
+
+ try {
+ $client->getIndex($aliasName)->getType($typeName)->search('ruflin');
+ $this->fail('Should throw no index exception');
+ } catch (Elastica_Exception_Response $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ public function testDeleteIndexDeleteAlias()
+ {
+ $indexName = 'test';
+ $aliasName = 'test-aliase';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+
+ $index->create(array(), true);
+ $index->addAlias($aliasName);
+
+ $status = new Elastica_Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+ $this->assertTrue($status->aliasExists($aliasName));
+
+ // Deleting index should also remove alias
+ $index->delete();
+
+ $status->refresh();
+ $this->assertFalse($status->indexExists($indexName));
+ $this->assertFalse($status->aliasExists($aliasName));
+ }
+
+ public function testAddAliasTwoIndices()
+ {
+ $indexName1 = 'test1';
+ $indexName2 = 'test2';
+ $aliasName = 'test-alias';
+
+ $client = new Elastica_Client();
+ $index1 = $client->getIndex($indexName1);
+ $index2 = $client->getIndex($indexName2);
+
+ $index1->create(array(), true);
+ $index1->addAlias($aliasName);
+ $index2->create(array(), true);
+
+ $status = new Elastica_Status($client);
+ $this->assertTrue($status->indexExists($indexName1));
+ $this->assertTrue($status->indexExists($indexName2));
+ $this->assertTrue($status->aliasExists($aliasName));
+ $this->assertTrue($index1->getStatus()->hasAlias($aliasName));
+ $this->assertFalse($index2->getStatus()->hasAlias($aliasName));
+
+ $index2->addAlias($aliasName);
+ $this->assertTrue($index1->getStatus()->hasAlias($aliasName));
+ $this->assertTrue($index2->getStatus()->hasAlias($aliasName));
+ }
+
+ public function testReplaceAlias()
+ {
+ $indexName1 = 'test1';
+ $indexName2 = 'test2';
+ $aliasName = 'test-alias';
+
+ $client = new Elastica_Client();
+ $index1 = $client->getIndex($indexName1);
+ $index2 = $client->getIndex($indexName2);
+
+ $index1->create(array(), true);
+ $index1->addAlias($aliasName);
+ $index2->create(array(), true);
+
+ $status = new Elastica_Status($client);
+ $this->assertTrue($status->indexExists($indexName1));
+ $this->assertTrue($status->indexExists($indexName2));
+ $this->assertTrue($status->aliasExists($aliasName));
+ $this->assertTrue($index1->getStatus()->hasAlias($aliasName));
+ $this->assertFalse($index2->getStatus()->hasAlias($aliasName));
+
+ $index2->addAlias($aliasName, true);
+ $this->assertFalse($index1->getStatus()->hasAlias($aliasName));
+ $this->assertTrue($index2->getStatus()->hasAlias($aliasName));
+ }
+
+ public function testAddDocumentVersion()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = new Elastica_Type($index, 'test');
+
+ $doc1 = new Elastica_Document(1);
+ $doc1->add('title', 'Hello world');
+
+ $return = $type->addDocument($doc1);
+ $data = $return->getData();
+ $this->assertEquals(1, $data['_version']);
+
+ $return = $type->addDocument($doc1);
+ $data = $return->getData();
+ $this->assertEquals(2, $data['_version']);
+ }
+
+ public function testClearCache()
+ {
+ $client = new Elastica_Client();
+ $index1 = $client->getIndex('test1');
+
+ $response = $index1->clearCache();
+ $this->assertFalse($response->hasError());
+ }
+
+ public function testFlush()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test1');
+
+ $response = $index->flush();
+ $this->assertFalse($response->hasError());
+ }
+
+ public function testExists()
+ {
+ $index = $this->_createIndex();
+
+ $this->assertTrue($index->exists());
+
+ $index->delete();
+
+ $this->assertFalse($index->exists());
+ }
+
+ /**
+ * Test $index->delete() return value for unknown index
+ *
+ * Tests if deleting an index that does not exist in Elasticsearch,
+ * correctly returns a boolean true from the hasError() method of
+ * the Elastica_Response object
+ */
+ public function testDeleteMissingIndexHasError()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('index_does_not_exist');
+
+ try {
+ $index->delete();
+ $this->fail('This should never be reached. Deleting an unknown index will throw an exception');
+ } catch (Elastica_Exception_Response $error) {
+ $response = $error->getResponse();
+ $this->assertTrue($response->hasError());
+ }
+ }
+
+ /**
+ * Tests to see if the test type mapping exists when calling $index->getMapping()
+ */
+ public function testIndexGetMapping()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $mapping = array('id' => array('type' => 'integer', 'store' => 'yes'), 'email' => array('type' => 'string', 'store' => 'no'),
+ 'username' => array('type' => 'string', 'store' => 'no'), 'test' => array('type' => 'integer', 'store' => 'no'),);
+
+ $type->setMapping($mapping);
+ $indexMappings = $index->getMapping();
+
+ $this->assertEquals($indexMappings['elastica_test']['test']['properties']['id']['type'], 'integer');
+ $this->assertEquals($indexMappings['elastica_test']['test']['properties']['id']['store'], 'yes');
+ $this->assertEquals($indexMappings['elastica_test']['test']['properties']['email']['type'], 'string');
+ $this->assertEquals($indexMappings['elastica_test']['test']['properties']['username']['type'], 'string');
+ $this->assertEquals($indexMappings['elastica_test']['test']['properties']['test']['type'], 'integer');
+ }
+
+ /**
+ * Tests to see if the index is empty when there are no types set.
+ */
+ public function testEmptyIndexGetMapping()
+ {
+ $index = $this->_createIndex();
+ $indexMappings = $index->getMapping();
+
+ $this->assertTrue(empty($indexMappings['elastica_test']));
+ }
+
+ /**
+ * Test to see if search Default Limit works
+ */
+ public function testLimitDefaultIndex()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+
+ $docs[] = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ // default limit results (default limit is 10)
+ $resultSet = $index->search('farrelley');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $index->search('farrelley', 1);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testCreateArray()
+ {
+ $client = new Elastica_Client();
+ $indexName = 'test';
+ $aliasName = 'test-aliase';
+
+ //Testing recreate (backward compatibility)
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $status = new Elastica_Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+
+ //Testing create index with array options
+ $opts = array('recreate' => true, 'routing' => 'r1,r2');
+ $index->create(array(), $opts);
+ $status = new Elastica_Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+
+ //Testing invalid options
+ try {
+ $opts = array('recreate' => true, 'routing' => 'r1,r2', 'testing_invalid_option' => true);
+ $index->create(array(), $opts);
+ $status = new Elastica_Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+ $this->fail('Should throw Elastica_Exception_Invalid');
+ } catch (Exception $ex) {
+ $this->assertTrue($ex instanceof Elastica_Exception_Invalid);
+ }
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/LogTest.php b/modules/thirdparty/elastica/test/lib/Elastica/LogTest.php
new file mode 100644
index 0000000..c7ba7c0
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/LogTest.php
@@ -0,0 +1,64 @@
+ $logPath));
+ $this->assertEquals($logPath, $client->getConfig('log'));
+ }
+
+ public function testSetLogConfigEnable()
+ {
+ $client = new Elastica_Client(array('log' => true));
+ $this->assertTrue($client->getConfig('log'));
+ }
+
+ public function testEmptyLogConfig()
+ {
+ $client = new Elastica_Client();
+ $this->assertEmpty($client->getConfig('log'));
+ }
+
+ public function testDisabledLog()
+ {
+ $client = new Elastica_Client();
+ $log = new Elastica_Log($client);
+
+ $log->log('hello world');
+
+ $this->assertEmpty($log->getLastMessage());
+ }
+
+ public function testGetLastMessage()
+ {
+ $client = new Elastica_Client(array('log' => '/tmp/php.log'));
+ $log = new Elastica_Log($client);
+ $message = 'hello world';
+
+ $log->log($message);
+
+ $this->assertEquals($message, $log->getLastMessage());
+ }
+
+ public function testGetLastMessage2()
+ {
+ $client = new Elastica_Client(array('log' => true));
+ $log = new Elastica_Log($client);
+
+ // Set log path temp path as otherwise test fails with output
+ $errorLog = ini_get('error_log');
+ ini_set('error_log', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php.log');
+
+ $message = 'hello world';
+
+ $log->log($message);
+
+ ini_set('error_log', $errorLog);
+
+ $this->assertEquals($message, $log->getLastMessage());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Node/InfoTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Node/InfoTest.php
new file mode 100644
index 0000000..d087747
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Node/InfoTest.php
@@ -0,0 +1,25 @@
+getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Elastica_Node($name, $client);
+ $info = new Elastica_Node_Info($node);
+
+ $this->assertNull($info->get('os', 'mem', 'total'));
+
+ // Load os infos
+ $info = new Elastica_Node_Info($node, array('os'));
+
+ $this->assertInternalType('string', $info->get('os', 'mem', 'total'));
+ $this->assertInternalType('array', $info->get('os', 'mem'));
+ $this->assertNull($info->get('test', 'notest', 'notexist'));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/NodeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/NodeTest.php
new file mode 100644
index 0000000..a4e6ddb
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/NodeTest.php
@@ -0,0 +1,65 @@
+getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Elastica_Node($name, $client);
+ $this->assertInstanceOf('Elastica_Node', $node);
+ }
+
+ public function testGetInfo()
+ {
+ $client = new Elastica_Client();
+ $names = $client->getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Elastica_Node($name, $client);
+
+ $info = $node->getInfo();
+
+ $this->assertInstanceOf('Elastica_Node_Info', $info);
+ }
+
+ public function testGetStats()
+ {
+ $client = new Elastica_Client();
+ $names = $client->getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Elastica_Node($name, $client);
+
+ $stats = $node->getStats();
+
+ $this->assertInstanceOf('Elastica_Node_Stats', $stats);
+ }
+
+ public function testShutdown()
+ {
+ $client = new Elastica_Client();
+ $nodes = $client->getCluster()->getNodes();
+
+ $count = count($nodes);
+ if ($count < 2) {
+ $this->markTestSkipped('At least two nodes have to be running, because 1 node is shutdown');
+ }
+
+ // Stores node info for later
+ $info = $nodes[1]->getInfo();
+ $nodes[0]->shutdown('2s');
+
+ sleep(5);
+
+ $client = new Elastica_Client(array('host' => $info->getIp(), 'port' => $info->getPort()));
+ $names = $client->getCluster()->getNodeNames();
+
+ // One node less ...
+ $this->assertEquals($count - 1, count($names));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ParamTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ParamTest.php
new file mode 100644
index 0000000..01afbd9
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/ParamTest.php
@@ -0,0 +1,110 @@
+getMock('Elastica_Param', null, array(), $className);
+
+ $this->assertInstanceOf('Elastica_Param', $param);
+ $this->assertEquals(array('param_abstract' => array()), $param->toArray());
+ }
+
+ public function testToArrayEmpty()
+ {
+ $param = new Elastica_Param();
+ $this->assertInstanceOf('Elastica_Param', $param);
+ $this->assertEquals(array($this->_getFilterName($param) => array()), $param->toArray());
+ }
+
+ public function testSetParams()
+ {
+ $param = new Elastica_Param();
+ $params = array('hello' => 'word', 'nicolas' => 'ruflin');
+ $param->setParams($params);
+
+ $this->assertInstanceOf('Elastica_Param', $param);
+ $this->assertEquals(array($this->_getFilterName($param) => $params), $param->toArray());
+ }
+
+ public function testSetGetParam()
+ {
+ $param = new Elastica_Param();
+
+ $key = 'name';
+ $value = 'nicolas ruflin';
+
+ $params = array($key => $value);
+ $param->setParam($key, $value);
+
+ $this->assertEquals($params, $param->getParams());
+ $this->assertEquals($value, $param->getParam($key));
+ }
+
+ public function testAddParam()
+ {
+ $param = new Elastica_Param();
+
+ $key = 'name';
+ $value = 'nicolas ruflin';
+
+ $param->addParam($key, $value);
+
+ $this->assertEquals(array($key => array($value)), $param->getParams());
+ $this->assertEquals(array($value), $param->getParam($key));
+ }
+
+ public function testAddParam2()
+ {
+ $param = new Elastica_Param();
+
+ $key = 'name';
+ $value1 = 'nicolas';
+ $value2 = 'ruflin';
+
+ $param->addParam($key, $value1);
+ $param->addParam($key, $value2);
+
+ $this->assertEquals(array($key => array($value1, $value2)), $param->getParams());
+ $this->assertEquals(array($value1, $value2), $param->getParam($key));
+ }
+
+ public function testGetParamInvalid()
+ {
+ $param = new Elastica_Param();
+
+ try {
+ $param->getParam('notest');
+ $this->fail('Should throw exception');
+ } catch (Elastica_Exception_Invalid $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ public function testHasParam()
+ {
+ $param = new Elastica_Param();
+
+ $key = 'name';
+ $value = 'nicolas ruflin';
+
+ $this->assertFalse($param->hasParam($key));
+
+ $param->setParam($key, $value);
+ $this->assertTrue($param->hasParam($key));
+ }
+
+ protected function _getFilterName($filter)
+ {
+ // Picks the last part of the class name and makes it snake_case
+ $classNameParts = explode('_', get_class($filter));
+
+ return Elastica_Util::toSnakeCase(array_pop($classNameParts));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/PercolatorTest.php b/modules/thirdparty/elastica/test/lib/Elastica/PercolatorTest.php
new file mode 100644
index 0000000..2b3badb
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/PercolatorTest.php
@@ -0,0 +1,62 @@
+_createIndex($percolatorName);
+ $percolator = new Elastica_Percolator($index);
+
+ $query = new Elastica_Query_Term(array('field1' => 'value1'));
+ $response = $percolator->registerQuery($percolatorName, $query);
+
+ $data = $response->getData();
+
+ $expectedArray = array(
+ 'ok' => true,
+ '_type' => $index->getName(),
+ '_index' => '_percolator',
+ '_id' => $percolatorName,
+ '_version' => 1
+ );
+
+ $this->assertEquals($expectedArray, $data);
+ }
+
+ public function testMatchDoc()
+ {
+ $client = new Elastica_Client(array('persistent' => false));
+ $index = $client->getIndex('elastica_test');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $percolator = new Elastica_Percolator($index);
+
+ $percolatorName = 'percotest';
+
+ $query = new Elastica_Query_Term(array('name' => 'ruflin'));
+ $response = $percolator->registerQuery($percolatorName, $query);
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $doc1 = new Elastica_Document();
+ $doc1->add('name', 'ruflin');
+
+ $doc2 = new Elastica_Document();
+ $doc2->add('name', 'nicolas');
+
+ $index = new Elastica_Index($index->getClient(), '_percolator');
+ $index->refresh();
+
+ $matches1 = $percolator->matchDoc($doc1);
+
+ $this->assertTrue(in_array($percolatorName, $matches1));
+ $this->assertEquals(1, count($matches1));
+
+ $matches2 = $percolator->matchDoc($doc2);
+ $this->assertEmpty($matches2);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/ArrayTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/ArrayTest.php
new file mode 100644
index 0000000..595fae6
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/ArrayTest.php
@@ -0,0 +1,13 @@
+ array('world'), 'name' => 'ruflin');
+ $query = new Elastica_Query_Array($testQuery);
+
+ $this->assertEquals($testQuery, $query->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/BoolTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/BoolTest.php
new file mode 100755
index 0000000..ed2b1f0
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/BoolTest.php
@@ -0,0 +1,105 @@
+setIds(1);
+
+ $idsQuery2 = new Elastica_Query_Ids();
+ $idsQuery2->setIds(2);
+
+ $idsQuery3 = new Elastica_Query_Ids();
+ $idsQuery3->setIds(3);
+
+ $boost = 1.2;
+ $minMatch = 2;
+
+ $query->setBoost($boost);
+ $query->setMinimumNumberShouldMatch($minMatch);
+ $query->addMust($idsQuery1);
+ $query->addMustNot($idsQuery2);
+ $query->addShould($idsQuery3->toArray());
+
+ $expectedArray = array(
+ 'bool' => array(
+ 'must' => array($idsQuery1->toArray()),
+ 'should' => array($idsQuery3->toArray()),
+ 'minimum_number_should_match' => $minMatch,
+ 'must_not' => array($idsQuery2->toArray()),
+ 'boost' => $boost,
+ )
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * Test to resolve the following issue
+ *
+ * https://groups.google.com/forum/?fromgroups#!topic/elastica-php-client/zK_W_hClfvU
+ */
+ public function testToArrayStructure()
+ {
+ $boolQuery = new Elastica_Query_Bool();
+
+ $term1 = new Elastica_Query_Term();
+ $term1->setParam('interests', 84);
+
+ $term2 = new Elastica_Query_Term();
+ $term2->setParam('interests', 92);
+
+ $boolQuery->addShould($term1)->addShould($term2);
+
+ $jsonString = '{"bool":{"should":[{"term":{"interests":84}},{"term":{"interests":92}}]}}';
+ $this->assertEquals($jsonString, json_encode($boolQuery->toArray()));
+ }
+
+ public function testSearch()
+ {
+ $client = new Elastica_Client();
+ $index = new Elastica_Index($client, 'test');
+ $index->create(array(), true);
+
+ $type = new Elastica_Type($index, 'helloworld');
+
+ $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'hans@test.com', 'username' => 'hans', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('id' => 2, 'email' => 'emil@test.com', 'username' => 'emil', 'test' => array('1', '3', '6')));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('id' => 3, 'email' => 'ruth@test.com', 'username' => 'ruth', 'test' => array('2', '3', '7')));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $boolQuery = new Elastica_Query_Bool();
+ $termQuery1 = new Elastica_Query_Term(array('test' => '2'));
+ $boolQuery->addMust($termQuery1);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(2, $resultSet->count());
+
+ $termQuery2 = new Elastica_Query_Term(array('test' => '5'));
+ $boolQuery->addMust($termQuery2);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $termQuery3 = new Elastica_Query_Term(array('username' => 'hans'));
+ $boolQuery->addMust($termQuery3);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $termQuery4 = new Elastica_Query_Term(array('username' => 'emil'));
+ $boolQuery->addMust($termQuery4);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/BuilderTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/BuilderTest.php
new file mode 100644
index 0000000..a5eabe4
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/BuilderTest.php
@@ -0,0 +1,270 @@
+builder = new Elastica_Query_Builder();
+ }
+
+ public function tearDown()
+ {
+ $this->builder = null;
+ }
+
+ /**
+ * @covers Elastica_Query_Builder::factory
+ * @covers Elastica_Query_Builder::__construct
+ */
+ public function testFactory()
+ {
+ $this->assertInstanceOf(
+ 'Elastica_Query_Builder',
+ Elastica_Query_Builder::factory('some string')
+ );
+ }
+
+ public function getQueryData()
+ {
+ return array(
+ array('allowLeadingWildcard', false, '{"allow_leading_wildcard":"false"}'),
+ array('allowLeadingWildcard', true, '{"allow_leading_wildcard":"true"}'),
+ array('analyzeWildcard', false, '{"analyze_wildcard":"false"}'),
+ array('analyzeWildcard', true, '{"analyze_wildcard":"true"}'),
+ array('analyzer', 'someAnalyzer', '{"analyzer":"someAnalyzer"}'),
+ array('autoGeneratePhraseQueries', true, '{"auto_generate_phrase_queries":"true"}'),
+ array('autoGeneratePhraseQueries', false, '{"auto_generate_phrase_queries":"false"}'),
+ array('boost', 2, '{"boost":"2"}'),
+ array('boost', 4.2, '{"boost":"4.2"}'),
+ array('defaultField', 'fieldName', '{"default_field":"fieldName"}'),
+ array('defaultOperator', 'OR', '{"default_operator":"OR"}'),
+ array('defaultOperator', 'AND', '{"default_operator":"AND"}'),
+ array('enablePositionIncrements', true, '{"enable_position_increments":"true"}'),
+ array('enablePositionIncrements', false, '{"enable_position_increments":"false"}'),
+ array('explain', true, '{"explain":"true"}'),
+ array('explain', false, '{"explain":"false"}'),
+ array('from', 42, '{"from":"42"}'),
+ array('fuzzyMinSim', 4.2, '{"fuzzy_min_sim":"4.2"}'),
+ array('fuzzyPrefixLength', 2, '{"fuzzy_prefix_length":"2"}'),
+ array('gt', 10, '{"gt":"10"}'),
+ array('gte', 11, '{"gte":"11"}'),
+ array('lowercaseExpandedTerms', true, '{"lowercase_expanded_terms":"true"}'),
+ array('lt', 10, '{"lt":"10"}'),
+ array('lte', 11, '{"lte":"11"}'),
+ array('minimumNumberShouldMatch', 21, '{"minimum_number_should_match":"21"}'),
+ array('minimumShouldMatch', 21, '{"minimum_number_should_match":"21"}'),
+ array('phraseSlop', 6, '{"phrase_slop":"6"}'),
+ array('size', 7, '{"size":"7"}'),
+ array('tieBreakerMultiplier', 7, '{"tie_breaker_multiplier":"7"}'),
+ array('tieBreaker', 7, '{"tie_breaker_multiplier":"7"}'),
+ array('matchAll', 1.1, '{"match_all":{"boost":"1.1"}}'),
+ array('fields', array("age", "sex", "location"), '{"fields":["age","sex","location"]}'),
+ );
+ }
+
+ /**
+ * @dataProvider getQueryData
+ * @covers Elastica_Query_Builder::__toString
+ * @covers Elastica_Query_Builder::allowLeadingWildcard
+ * @covers Elastica_Query_Builder::analyzeWildcard
+ * @covers Elastica_Query_Builder::analyzer
+ * @covers Elastica_Query_Builder::autoGeneratePhraseQueries
+ * @covers Elastica_Query_Builder::boost
+ * @covers Elastica_Query_Builder::defaultField
+ * @covers Elastica_Query_Builder::defaultOperator
+ * @covers Elastica_Query_Builder::enablePositionIncrements
+ * @covers Elastica_Query_Builder::explain
+ * @covers Elastica_Query_Builder::from
+ * @covers Elastica_Query_Builder::fuzzyMinSim
+ * @covers Elastica_Query_Builder::fuzzyPrefixLength
+ * @covers Elastica_Query_Builder::gt
+ * @covers Elastica_Query_Builder::gte
+ * @covers Elastica_Query_Builder::lowercaseExpandedTerms
+ * @covers Elastica_Query_Builder::lt
+ * @covers Elastica_Query_Builder::lte
+ * @covers Elastica_Query_Builder::minimumNumberShouldMatch
+ * @covers Elastica_Query_Builder::minimumShouldMatch
+ * @covers Elastica_Query_Builder::phraseSlop
+ * @covers Elastica_Query_Builder::size
+ * @covers Elastica_Query_Builder::tieBreakerMultiplier
+ * @covers Elastica_Query_Builder::tieBreaker
+ * @covers Elastica_Query_Builder::matchAll
+ * @covers Elastica_Query_Builder::fields
+ */
+ public function testAllowLeadingWildcard($method, $argument, $result)
+ {
+ $this->assertSame($this->builder, $this->builder->$method($argument));
+ $this->assertSame($result, (string) $this->builder);
+ }
+
+ public function getQueryTypes()
+ {
+ return array(
+ array('bool', 'bool'),
+ array('constantScore', 'constant_score'),
+ array('disMax', 'dis_max'),
+ array('facets', 'facets'),
+ array('filter', 'filter'),
+ array('filteredQuery', 'filtered'),
+ array('must', 'must'),
+ array('mustNot', 'must_not'),
+ array('prefix', 'prefix'),
+ array('query', 'query'),
+ array('queryString', 'query_string'),
+ array('range', 'range'),
+ array('should', 'should'),
+ array('sort', 'sort'),
+ array('term', 'term'),
+ array('textPhrase', 'text_phrase'),
+ array('wildcard', 'wildcard'),
+ );
+ }
+
+ /**
+ * @dataProvider getQueryTypes
+ *
+ * @covers Elastica_Query_Builder::fieldClose
+ * @covers Elastica_Query_Builder::close
+ *
+ * @covers Elastica_Query_Builder::bool
+ * @covers Elastica_Query_Builder::boolClose
+ * @covers Elastica_Query_Builder::constantScore
+ * @covers Elastica_Query_Builder::constantScoreClose
+ * @covers Elastica_Query_Builder::disMax
+ * @covers Elastica_Query_Builder::disMaxClose
+ * @covers Elastica_Query_Builder::facets
+ * @covers Elastica_Query_Builder::facetsClose
+ * @covers Elastica_Query_Builder::filter
+ * @covers Elastica_Query_Builder::filterClose
+ * @covers Elastica_Query_Builder::filteredQuery
+ * @covers Elastica_Query_Builder::filteredQueryClose
+ * @covers Elastica_Query_Builder::must
+ * @covers Elastica_Query_Builder::mustClose
+ * @covers Elastica_Query_Builder::mustNot
+ * @covers Elastica_Query_Builder::mustNotClose
+ * @covers Elastica_Query_Builder::prefix
+ * @covers Elastica_Query_Builder::prefixClose
+ * @covers Elastica_Query_Builder::query
+ * @covers Elastica_Query_Builder::queryClose
+ * @covers Elastica_Query_Builder::queryString
+ * @covers Elastica_Query_Builder::queryStringClose
+ * @covers Elastica_Query_Builder::range
+ * @covers Elastica_Query_Builder::rangeClose
+ * @covers Elastica_Query_Builder::should
+ * @covers Elastica_Query_Builder::shouldClose
+ * @covers Elastica_Query_Builder::sort
+ * @covers Elastica_Query_Builder::sortClose
+ * @covers Elastica_Query_Builder::term
+ * @covers Elastica_Query_Builder::termClose
+ * @covers Elastica_Query_Builder::textPhrase
+ * @covers Elastica_Query_Builder::textPhraseClose
+ * @covers Elastica_Query_Builder::wildcard
+ * @covers Elastica_Query_Builder::wildcardClose
+ */
+ public function testQueryTypes($method, $queryType)
+ {
+ $this->assertSame($this->builder, $this->builder->$method()); // open
+ $this->assertSame($this->builder, $this->builder->{$method."Close"}()); // close
+ $this->assertSame('{"' . $queryType . '":{}}', (string) $this->builder);
+ }
+
+ /**
+ * @covers Elastica_Query_Builder::fieldOpen
+ * @covers Elastica_Query_Builder::fieldClose
+ * @covers Elastica_Query_Builder::open
+ * @covers Elastica_Query_Builder::close
+ */
+ public function testFieldOpenAndClose()
+ {
+ $this->assertSame($this->builder, $this->builder->fieldOpen('someField'));
+ $this->assertSame($this->builder, $this->builder->fieldClose());
+ $this->assertSame('{"someField":{}}', (string) $this->builder);
+ }
+
+ /**
+ * @covers Elastica_Query_Builder::sortField
+ */
+ public function testSortField()
+ {
+ $this->assertSame($this->builder, $this->builder->sortField('name', true));
+ $this->assertSame('{"sort":{"name":{"reverse":"true"}}}', (string) $this->builder);
+ }
+
+ /**
+ * @covers Elastica_Query_Builder::sortFields
+ */
+ public function testSortFields()
+ {
+ $this->assertSame($this->builder, $this->builder->sortFields(array('field1' => 'asc', 'field2' => 'desc', 'field3' => 'asc')));
+ $this->assertSame('{"sort":[{"field1":"asc"},{"field2":"desc"},{"field3":"asc"}]}', (string) $this->builder);
+ }
+
+ /**
+ * @covers Elastica_Query_Builder::queries
+ */
+ public function testQueries()
+ {
+ $queries = array();
+
+ $b1 = clone $this->builder;
+ $b2 = clone $this->builder;
+
+ $queries[] = $b1->term()->field('age', 34)->termClose();
+ $queries[] = $b2->term()->field('name', 'christer')->termClose();
+
+ $this->assertSame($this->builder, $this->builder->queries($queries));
+ $this->assertSame('{"queries":[{"term":{"age":"34"}},{"term":{"name":"christer"}}]}', (string) $this->builder);
+ }
+
+ public function getFieldData()
+ {
+ return array(
+ array('name', 'value', '{"name":"value"}'),
+ array('name', true, '{"name":"true"}'),
+ array('name', false, '{"name":"false"}'),
+ array('name', array(1, 2, 3), '{"name":["1","2","3"]}'),
+ array('name', array('foo', 'bar', 'baz'), '{"name":["foo","bar","baz"]}'),
+ );
+ }
+
+ /**
+ * @dataProvider getFieldData
+ * @covers Elastica_Query_Builder::field
+ */
+ public function testField($name, $value, $result)
+ {
+ $this->assertSame($this->builder, $this->builder->field($name, $value));
+ $this->assertSame($result, (string) $this->builder);
+ }
+
+ /**
+ * @expectedException Elastica_Exception_Invalid
+ * @covers Elastica_Query_Builder::toArray
+ */
+ public function testToArrayWithInvalidData()
+ {
+ $this->builder->open('foo');
+ $this->builder->toArray();
+ }
+
+ /**
+ * @covers Elastica_Query_Builder::toArray
+ */
+ public function testToArray()
+ {
+ $this->builder->query()->term()->field('category.id', array(1, 2, 3))->termClose()->queryClose();
+ $this->assertEquals(array(
+ 'query' => array(
+ 'term' => array(
+ 'category.id' => array(1, 2, 3)
+ )
+ )
+ ), $this->builder->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/ConstantScoreTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/ConstantScoreTest.php
new file mode 100644
index 0000000..88b0c01
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/ConstantScoreTest.php
@@ -0,0 +1,105 @@
+ array(
+ 'filter' => array(
+ 'term' => array(
+ 'foo',
+ 'bar',
+ ),
+ ),
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'and' => array(
+ array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'foo',
+ 'default_field' => 'something',
+ ),
+ ),
+ ),
+ array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'bar',
+ 'default_field' => 'something',
+ ),
+ ),
+ ),
+ ),
+ ),
+ '{"constant_score":{"filter":{"and":[{"query":{"query_string":{"query":"foo","default_field":"something"}}},{"query":{"query_string":{"query":"bar","default_field":"something"}}}]}}}',
+ ),
+ );
+ }
+ /**
+ * @dataProvider dataProviderSampleQueries
+ */
+ public function testSimple($filter, $expected)
+ {
+ $query = new Elastica_Query_ConstantScore();
+ $query->setFilter($filter);
+ if (is_string($expected)) {
+ $expected = json_decode($expected, true);
+ }
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ public function testToArray()
+ {
+ $query = new Elastica_Query_ConstantScore();
+
+ $boost = 1.2;
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds(array(1));
+
+ $query->setFilter($filter);
+ $query->setBoost($boost);
+
+ $expectedArray = array(
+ 'constant_score' => array(
+ 'filter' => $filter->toArray(),
+ 'boost' => $boost
+ )
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ public function testConstruct()
+ {
+ $filter = new Elastica_Filter_Ids();
+ $filter->setIds(array(1));
+
+ $query = new Elastica_Query_ConstantScore($filter);
+
+ $expectedArray = array(
+ 'constant_score' => array(
+ 'filter' => $filter->toArray(),
+ )
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+
+ }
+
+ public function testConstructEmpty()
+ {
+ $query = new Elastica_Query_ConstantScore();
+ $expectedArray = array('constant_score' => array());
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/CustomScoreTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/CustomScoreTest.php
new file mode 100644
index 0000000..0aa2030
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/CustomScoreTest.php
@@ -0,0 +1,19 @@
+setQuery($query);
+ $customscore_query->setScript("doc['hits'].value * (param1 + param2)");
+ $customscore_query->addParams(array('param1' => 1123, 'param2' => 2001));
+
+ $experted = '{"custom_score":{"query":{"match_all":{}},"script":"doc[\'hits\'].value * (param1 + param2)","params":{"param1":1123,"param2":2001}}}';
+
+ $this->assertEquals($experted, json_encode($customscore_query->toArray()));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FieldTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FieldTest.php
new file mode 100644
index 0000000..0945511
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FieldTest.php
@@ -0,0 +1,43 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'New York'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'Baden Baden'));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $type = 'text_phrase';
+ $field = 'name';
+
+ $query = new Elastica_Query_Field();
+ $query->setField('name');
+ $query->setQueryString('"Baden Baden"');
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testToArray()
+ {
+ $query = new Elastica_Query_Field('user', 'jack');
+ $expected = array('field' => array('user' => array('query' => 'jack')));
+
+ $this->assertSame($expected, $query->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FilteredTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FilteredTest.php
new file mode 100644
index 0000000..3061adb
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FilteredTest.php
@@ -0,0 +1,39 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('id' => 2, 'email' => 'test@test.com', 'username' => 'peter', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+
+ $queryString = new Elastica_Query_QueryString('test*');
+
+ $filter1 = new Elastica_Filter_Term();
+ $filter1->setTerm('username', 'peter');
+
+ $filter2 = new Elastica_Filter_Term();
+ $filter2->setTerm('username', 'qwerqwer');
+
+ $query1 = new Elastica_Query_Filtered($queryString, $filter1);
+ $query2 = new Elastica_Query_Filtered($queryString, $filter2);
+ $index->refresh();
+
+ $resultSet = $type->search($queryString);
+ $this->assertEquals(2, $resultSet->count());
+
+ $resultSet = $type->search($query1);
+ $this->assertEquals(1, $resultSet->count());
+
+ $resultSet = $type->search($query2);
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyLikeThisTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyLikeThisTest.php
new file mode 100644
index 0000000..41e981d
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyLikeThisTest.php
@@ -0,0 +1,97 @@
+create(array(), true);
+ $index->getSettings()->setNumberOfReplicas(0);
+ //$index->getSettings()->setNumberOfShards(1);
+
+ $type = new Elastica_Type($index, 'helloworldfuzzy');
+ $mapping = new Elastica_Type_Mapping($type , array(
+ 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ ));
+
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'This is a sample post. Hello World Fuzzy Like This!'));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $fltQuery = new Elastica_Query_FuzzyLikeThis();
+ $fltQuery->setLikeText("sample gmail");
+ $fltQuery->addFields(array("email","content"));
+ $fltQuery->setMinSimilarity(0.3);
+ $fltQuery->setMaxQueryTerms(3);
+ $resultSet = $type->search($fltQuery);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetPrefixLength()
+ {
+ $query = new Elastica_Query_FuzzyLikeThis();
+
+ $length = 3;
+ $query->setPrefixLength($length);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($length, $data['fuzzy_like_this']['prefix_length']);
+ }
+
+ public function testAddFields()
+ {
+ $query = new Elastica_Query_FuzzyLikeThis();
+
+ $fields = array('test1', 'test2');
+ $query->addFields($fields);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($fields, $data['fuzzy_like_this']['fields']);
+ }
+
+ public function testSetLikeText()
+ {
+ $query = new Elastica_Query_FuzzyLikeThis();
+
+ $text = ' hello world';
+ $query->setLikeText($text);
+
+ $data = $query->toArray();
+
+ $this->assertEquals(trim($text), $data['fuzzy_like_this']['like_text']);
+ }
+
+ public function testSetMinSimilarity()
+ {
+ $query = new Elastica_Query_FuzzyLikeThis();
+
+ $similarity = 2;
+ $query->setMinSimilarity($similarity);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($similarity, $data['fuzzy_like_this']['min_similarity']);
+ }
+
+ public function testSetBoost()
+ {
+ $query = new Elastica_Query_FuzzyLikeThis();
+
+ $boost = 2.2;
+ $query->setBoost($boost);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($boost, $data['fuzzy_like_this']['boost']);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyTest.php
new file mode 100644
index 0000000..8bba2cf
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyTest.php
@@ -0,0 +1,52 @@
+addField('user', array('value' => 'Nicolas', 'boost' => 1.0));
+
+ $expectedArray = array(
+ 'fuzzy' => array(
+ 'user' => array(
+ 'value' => 'Nicolas',
+ 'boost' => 1.0
+ )
+ )
+ );
+
+ $this->assertEquals($expectedArray, $fuzzy->toArray());
+ }
+
+ public function testQuery()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'New York'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'Baden Baden'));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $type = 'text_phrase';
+ $field = 'name';
+
+ $query = new Elastica_Query_Fuzzy();
+ $query->addField('name', array('value' => 'Baden'));
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/HasChildTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/HasChildTest.php
new file mode 100644
index 0000000..1e9cca5
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/HasChildTest.php
@@ -0,0 +1,25 @@
+setIds(12);
+
+ $type = 'test';
+
+ $query = new Elastica_Query_HasChild($ids, $type);
+ $query->setType($type);
+
+ $expectedArray = array(
+ 'has_child' => array(
+ 'type' => $type,
+ 'query' => $ids->toArray(),
+ )
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/HighlightTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/HighlightTest.php
new file mode 100644
index 0000000..a27043c
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/HighlightTest.php
@@ -0,0 +1,43 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $phrase = 'My name is ruflin';
+
+ $doc = new Elastica_Document(1, array('id' => 1, 'phrase' => $phrase, 'username' => 'hanswurst', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('id' => 2, 'phrase' => $phrase, 'username' => 'peter', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+
+ $queryString = new Elastica_Query_QueryString('rufl*');
+ $query = new Elastica_Query($queryString);
+ $query->setHighlight(array(
+ 'pre_tags' => array(''),
+ 'post_tags' => array(''),
+ 'fields' => array(
+ 'phrase' => array(
+ 'fragment_size' => 200,
+ 'number_of_fragments' => 1,
+ ),
+ ),
+ ));
+
+ $index->refresh();
+
+ $resultSet = $type->search($query);
+ foreach ($resultSet as $result) {
+ $highlight = $result->getHighlights();
+ $this->assertEquals(array('phrase' => array(0 => 'My name is ruflin')), $highlight);
+ }
+ $this->assertEquals(2, $resultSet->count());
+
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/IdsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/IdsTest.php
new file mode 100644
index 0000000..052c0e4
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/IdsTest.php
@@ -0,0 +1,160 @@
+getIndex('test');
+ $index->create(array(), true);
+
+ $type1 = $index->getType('helloworld1');
+ $type2 = $index->getType('helloworld2');
+
+ $doc = new Elastica_Document(1, array('name' => 'hello world'));
+ $type1->addDocument($doc);
+
+ $doc = new Elastica_Document(2, array('name' => 'nicolas ruflin'));
+ $type1->addDocument($doc);
+
+ $doc = new Elastica_Document(3, array('name' => 'ruflin'));
+ $type1->addDocument($doc);
+
+ $doc = new Elastica_Document(4, array('name' => 'hello world again'));
+ $type2->addDocument($doc);
+
+ $index->refresh();
+
+ $this->_type = $type1;
+ $this->_index = $index;
+ }
+
+ public function tearDown()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->delete();
+ }
+
+ public function testSetIdsSearchSingle()
+ {
+ $query = new Elastica_Query_Ids();
+ $query->setIds('1');
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetIdsSearchArray()
+ {
+ $query = new Elastica_Query_Ids();
+ $query->setIds(array('1', '2'));
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ public function testAddIdsSearchSingle()
+ {
+ $query = new Elastica_Query_Ids();
+ $query->addId('3');
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testComboIdsSearchArray()
+ {
+ $query = new Elastica_Query_Ids();
+
+ $query->setIds(array('1', '2'));
+ $query->addId('3');
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchSingle()
+ {
+ $query = new Elastica_Query_Ids();
+
+ $query->setIds('1');
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchArray()
+ {
+ $query = new Elastica_Query_Ids();
+
+ $query->setIds(array('1', '2'));
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchSingleDocInOtherType()
+ {
+ $query = new Elastica_Query_Ids();
+
+ // Doc 4 is in the second type...
+ $query->setIds('4');
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ // ...therefore 0 results should be returned
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ public function testSetTypeSingleSearchArrayDocInOtherType()
+ {
+ $query = new Elastica_Query_Ids();
+
+ // Doc 4 is in the second type...
+ $query->setIds(array('1', '4'));
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ // ...therefore only 1 result should be returned
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetTypeArraySearchArray()
+ {
+ $query = new Elastica_Query_Ids();
+
+ $query->setIds(array('1', '4'));
+ $query->setType(array('helloworld1', 'helloworld2'));
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ public function testSetTypeArraySearchSingle()
+ {
+ $query = new Elastica_Query_Ids();
+
+ $query->setIds('4');
+ $query->setType(array('helloworld1', 'helloworld2'));
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/MatchAllTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/MatchAllTest.php
new file mode 100644
index 0000000..e28be57
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/MatchAllTest.php
@@ -0,0 +1,14 @@
+ new stdClass());
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/MoreLikeThisTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/MoreLikeThisTest.php
new file mode 100644
index 0000000..2a92dd9
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/MoreLikeThisTest.php
@@ -0,0 +1,167 @@
+create(array(), true);
+ $index->getSettings()->setNumberOfReplicas(0);
+ //$index->getSettings()->setNumberOfShards(1);
+
+ $type = new Elastica_Type($index, 'helloworldmlt');
+ $mapping = new Elastica_Type_Mapping($type , array(
+ 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ ));
+
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'This is a sample post. Hello World Fuzzy Like This!'));
+ $type->addDocument($doc);
+
+ $doc = new Elastica_Document(1001, array('email' => 'nospam@gmail.com', 'content' => 'This is a fake nospam email address for gmail'));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $mltQuery = new Elastica_Query_MoreLikeThis();
+ $mltQuery->setLikeText('fake gmail sample');
+ $mltQuery->setFields(array('email','content'));
+ $mltQuery->setMaxQueryTerms(1);
+ $mltQuery->setMinDocFrequency(1);
+ $mltQuery->setMinTermFrequency(1);
+
+ $query = new Elastica_Query();
+ $query->setFields(array('email', 'content'));
+ $query->setQuery($mltQuery);
+
+ $resultSet = $type->search($query);
+ $resultSet->getResponse()->getData();
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ public function testSetFields()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $fields = array('firstname', 'lastname');
+ $query->setFields($fields);
+
+ $data = $query->toArray();
+ $this->assertEquals($fields, $data['more_like_this']['fields']);
+ }
+
+ public function testSetLikeText()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+ $query->setLikeText(' hello world');
+
+ $data = $query->toArray();
+ $this->assertEquals('hello world', $data['more_like_this']['like_text']);
+ }
+
+ public function testSetBoost()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $boost = 1.3;
+ $query->setBoost($boost);
+
+ $this->assertEquals($boost, $query->getParam('boost'));
+ }
+
+ public function testSetMaxQueryTerms()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $max = 3;
+ $query->setMaxQueryTerms($max);
+
+ $this->assertEquals($max, $query->getParam('max_query_terms'));
+ }
+
+ public function testSetPercentTermsToMatch()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $match = 0.8;
+ $query->setPercentTermsToMatch($match);
+
+ $this->assertEquals($match, $query->getParam('percent_terms_to_match'));
+ }
+
+ public function testSetMinDocFrequency()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $freq = 2;
+ $query->setMinDocFrequency($freq);
+
+ $this->assertEquals($freq, $query->getParam('min_doc_freq'));
+ }
+
+ public function testSetMaxDocFrequency()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $freq = 2;
+ $query->setMaxDocFrequency($freq);
+
+ $this->assertEquals($freq, $query->getParam('max_doc_freq'));
+ }
+
+ public function testSetMinWordLength()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $length = 4;
+ $query->setMinWordLength($length);
+
+ $this->assertEquals($length, $query->getParam('min_word_length'));
+ }
+
+ public function testSetMaxWordLength()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $length = 5;
+ $query->setMaxWordLength($length);
+
+ $this->assertEquals($length, $query->getParam('max_word_length'));
+ }
+
+ public function testSetBoostTerms()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $boost = false;
+ $query->setBoostTerms($boost);
+
+ $this->assertEquals($boost, $query->getParam('boost_terms'));
+ }
+
+ public function testSetAnalyzer()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $analyzer = 'UpperCase';
+ $query->setAnalyzer($analyzer);
+
+ $this->assertEquals($analyzer, $query->getParam('analyzer'));
+ }
+
+ public function testSetStopWords()
+ {
+ $query = new Elastica_Query_MoreLikeThis();
+
+ $stopWords = array('no', 'yes', 'test');
+ $query->setStopWords($stopWords);
+
+ $this->assertEquals($stopWords, $query->getParam('stop_words'));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/NestedTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/NestedTest.php
new file mode 100644
index 0000000..f7f43d5
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/NestedTest.php
@@ -0,0 +1,23 @@
+assertInstanceOf('Elastica_Query_Nested', $nested->setQuery($queryString));
+ $this->assertInstanceOf('Elastica_Query_Nested', $nested->setPath($path));
+ $expected = array(
+ 'nested' => array(
+ 'query' => $queryString->toArray(),
+ 'path' => $path,
+ )
+ );
+
+ $this->assertEquals($expected, $nested->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/QueryStringTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/QueryStringTest.php
new file mode 100755
index 0000000..e06029c
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/QueryStringTest.php
@@ -0,0 +1,100 @@
+ $str
+ );
+
+ $this->assertEquals(array('query_string' => $expected), $query->toArray());
+
+ $fields = array();
+ $max = rand() % 10 + 1;
+ for ($i = 0; $i < $max; $i++) {
+ $fields[] = md5(rand());
+ }
+
+ $query->setFields($fields);
+ $expected['fields'] = $fields;
+ $this->assertEquals(array('query_string' => $expected), $query->toArray());
+
+ foreach (array(false, true) as $val) {
+ $query->setUseDisMax($val);
+ $expected['use_dis_max'] = $val;
+
+ $this->assertEquals(array('query_string' => $expected), $query->toArray());
+ }
+ }
+
+ public function testSearch()
+ {
+ $client = new Elastica_Client();
+ $index = new Elastica_Index($client, 'test');
+ $index->create(array(), true);
+ $index->getSettings()->setNumberOfReplicas(0);
+ //$index->getSettings()->setNumberOfShards(1);
+
+ $type = new Elastica_Type($index, 'helloworld');
+
+ $doc = new Elastica_Document(1, array('email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $queryString = new Elastica_Query_QueryString('test*');
+ $resultSet = $type->search($queryString);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testSetDefaultOperator()
+ {
+ $operator = 'AND';
+ $query = new Elastica_Query_QueryString('test');
+ $query->setDefaultOperator($operator);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($data['query_string']['default_operator'], $operator);
+ }
+
+ public function testSetDefaultField()
+ {
+ $default = 'field1';
+ $query = new Elastica_Query_QueryString('test');
+ $query->setDefaultField($default);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($data['query_string']['default_field'], $default);
+ }
+
+ public function testSetRewrite()
+ {
+ $rewrite = 'scoring_boolean';
+ $query = new Elastica_Query_QueryString('test');
+ $query->setRewrite($rewrite);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($data['query_string']['rewrite'], $rewrite);
+ }
+
+ public function testSetQueryStringInvalid()
+ {
+ $query = new Elastica_Query_QueryString();
+ try {
+ $query->setQueryString(array());
+ $this->fail('should throw exception because no string');
+ } catch (Elastica_Exception_Invalid $e) {
+ $this->assertTrue(true);
+ }
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/RangeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/RangeTest.php
new file mode 100644
index 0000000..6771245
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/RangeTest.php
@@ -0,0 +1,21 @@
+ 20, 'to' => 40);
+ $range->addField('age', $field);
+
+ $expectedArray = array(
+ 'range' => array(
+ 'age' => $field,
+ )
+ );
+
+ $this->assertEquals($expectedArray, $range->toArray());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/TermTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermTest.php
new file mode 100644
index 0000000..a16a0f5
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermTest.php
@@ -0,0 +1,22 @@
+setTerm($key, $value, $boost);
+
+ $data = $query->toArray();
+
+ $this->assertInternalType('array', $data['term']);
+ $this->assertInternalType('array', $data['term'][$key]);
+ $this->assertEquals($data['term'][$key]['value'], $value);
+ $this->assertEquals($data['term'][$key]['boost'], $boost);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/TermsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermsTest.php
new file mode 100644
index 0000000..f9399d2
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermsTest.php
@@ -0,0 +1,60 @@
+getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Elastica_Document(1, array('name' => 'hello world'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'nicolas ruflin'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'ruflin'));
+ $type->addDocument($doc);
+
+ $query = new Elastica_Query_Terms();
+ $query->setTerms('name', array('nicolas', 'hello'));
+
+ $index->refresh();
+
+ $resultSet = $type->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+
+ $query->addTerm('ruflin');
+ $resultSet = $type->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+ }
+
+ public function testSetMinimum()
+ {
+ $key = 'name';
+ $terms = array('nicolas', 'ruflin');
+ $minimum = 2;
+
+ $query = new Elastica_Query_Terms($key, $terms);
+ $query->setMinimumMatch($minimum);
+
+ $data = $query->toArray();
+ $this->assertEquals($minimum, $data['terms']['minimum_match']);
+ }
+
+ public function testInvalidParams()
+ {
+ $query = new Elastica_Query_Terms();
+
+ try {
+ $query->toArray();
+ $this->fail('Should throw exception because no key');
+ } catch (Elastica_Exception_Invalid $e) {
+ $this->assertTrue(true);
+ }
+
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/TextTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/TextTest.php
new file mode 100644
index 0000000..b87e12c
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/TextTest.php
@@ -0,0 +1,64 @@
+setFieldQuery($field, $queryText);
+ $query->setFieldType($field, $type);
+ $query->setFieldParam($field, 'analyzer', $analyzer);
+ $query->setFieldMaxExpansions($field, $maxExpansions);
+
+ $expectedArray = array(
+ 'text' => array(
+ $field => array(
+ 'query' => $queryText,
+ 'type' => $type,
+ 'analyzer' => $analyzer,
+ 'max_expansions' => $maxExpansions,
+ )
+ )
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ public function testTextPhrase()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'New York'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'New Hampshire'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'Basel Land'));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $type = 'text_phrase';
+ $field = 'name';
+
+ $query = new Elastica_Query_Text();
+ $query->setFieldQuery($field, 'Basel New');
+ $query->setField('operator', 'OR');
+ $query->setFieldType($field, $type);
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/WildcardTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/WildcardTest.php
new file mode 100644
index 0000000..13ea562
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/WildcardTest.php
@@ -0,0 +1,95 @@
+assertEmpty($wildcard->getParams());
+ }
+
+ public function testToArray()
+ {
+ $key = 'name';
+ $value = 'Ru*lin';
+ $boost = 2.0;
+
+ $wildcard = new Elastica_Query_Wildcard($key, $value, $boost);
+
+ $expectedArray = array(
+ 'wildcard' => array(
+ $key => array(
+ 'value' => $value,
+ 'boost' => $boost
+ )
+ )
+ );
+
+ $this->assertEquals($expectedArray, $wildcard->toArray());
+ }
+
+ public function testSearchWithAnalyzer()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+
+ $indexParams = array(
+ 'analysis' => array(
+ 'analyzer' => array(
+ 'lw' => array(
+ 'type' => 'custom',
+ 'tokenizer' => 'keyword',
+ 'filter' => array('lowercase')
+ )
+ ),
+ )
+ );
+
+ $index->create($indexParams, true);
+ $type = $index->getType('test');
+
+ $mapping = new Elastica_Type_Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'lw'),
+ )
+ );
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'New York'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'Baden Baden'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(5, array('name' => 'New Orleans'));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $query = new Elastica_Query_Wildcard();
+ $query->setValue('name', 'ba*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+
+ $query = new Elastica_Query_Wildcard();
+ $query->setValue('name', 'baden*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Elastica_Query_Wildcard();
+ $query->setValue('name', 'baden b*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Elastica_Query_Wildcard();
+ $query->setValue('name', 'baden bas*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/QueryTest.php b/modules/thirdparty/elastica/test/lib/Elastica/QueryTest.php
new file mode 100644
index 0000000..f613a5a
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/QueryTest.php
@@ -0,0 +1,150 @@
+toArray();
+
+ $this->assertInternalType('array', $queryArray);
+
+ $this->assertEquals('2011-07-18 00:00:00', $queryArray['query']['filtered']['filter']['range']['due']['gte']);
+ }
+
+ public function testRawQuery()
+ {
+ $textQuery = new Elastica_Query_Text();
+ $textQuery->setField('title', 'test');
+
+ $query1 = Elastica_Query::create($textQuery);
+
+ $query2 = new Elastica_Query();
+ $query2->setRawQuery(array('query' => array('text' => array('title' => 'test'))));
+
+ $this->assertEquals($query1->toArray(), $query2->toArray());
+ }
+
+ public function testSetSort()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $doc = new Elastica_Document(1, array('name' => 'hello world'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('firstname' => 'guschti', 'lastname' => 'ruflin'));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('firstname' => 'nicolas', 'lastname' => 'ruflin'));
+ $type->addDocument($doc);
+
+ $queryTerm = new Elastica_Query_Term();
+ $queryTerm->setTerm('lastname', 'ruflin');
+
+ $index->refresh();
+
+ $query = Elastica_Query::create($queryTerm);
+
+ // ASC order
+ $query->setSort(array(array('firstname' => array('order' => 'asc'))));
+ $resultSet = $type->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $first = $resultSet->current()->getData();
+ $second = $resultSet->next()->getData();
+
+ $this->assertEquals('guschti', $first['firstname']);
+ $this->assertEquals('nicolas', $second['firstname']);
+
+ // DESC order
+ $query->setSort(array('firstname' => array('order' => 'desc')));
+ $resultSet = $type->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $first = $resultSet->current()->getData();
+ $second = $resultSet->next()->getData();
+
+ $this->assertEquals('nicolas', $first['firstname']);
+ $this->assertEquals('guschti', $second['firstname']);
+ }
+
+ public function testAddSort()
+ {
+ $query = new Elastica_Query();
+ $sortParam = array('firstname' => array('order' => 'asc'));
+ $query->addSort($sortParam);
+
+ $this->assertEquals($query->getParam('sort'), array($sortParam));
+ }
+
+ public function testSetRawQuery()
+ {
+ $query = new Elastica_Query();
+
+ $params = array('query' => 'test');
+ $query->setRawQuery($params);
+
+ $this->assertEquals($params, $query->toArray());
+ }
+
+ public function testSetFields()
+ {
+ $query = new Elastica_Query();
+
+ $params = array('query' => 'test');
+
+ $query->setFields(array('firstname', 'lastname'));
+
+ $data = $query->toArray();
+
+ $this->assertContains('firstname', $data['fields']);
+ $this->assertContains('lastname', $data['fields']);
+ $this->assertEquals(2, count($data['fields']));
+ }
+
+ public function testGetQuery()
+ {
+ $query = new Elastica_Query();
+
+ try {
+ $query->getQuery();
+ $this->fail('should throw exception because query does not exist');
+ } catch (Elastica_Exception_Invalid $e) {
+ $this->assertTrue(true);
+ }
+
+ $termQuery = new Elastica_Query_Term();
+ $termQuery->setTerm('text', 'value');
+ $query->setQuery($termQuery);
+
+ $this->assertEquals($termQuery->toArray(), $query->getQuery());
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ResponseTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ResponseTest.php
new file mode 100644
index 0000000..4e773b4
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/ResponseTest.php
@@ -0,0 +1,48 @@
+assertInstanceOf('Elastica_Facet_Histogram', $facet);
+ $this->assertInstanceOf('Elastica_Facet_Abstract', $facet);
+ unset($facet);
+ }
+
+ public function testResponse()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('helloworld');
+
+ $mapping = new Elastica_Type_Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no'),
+ 'dtmPosted' => array('type' => 'date', 'store' => 'no', 'format' => 'yyyy-MM-dd HH:mm:ss')
+ ));
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1, array('name' => 'nicolas ruflin', 'dtmPosted' => "2011-06-23 21:53:00"));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(2, array('name' => 'raul martinez jr', 'dtmPosted' => "2011-06-23 09:53:00"));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(3, array('name' => 'rachelle clemente', 'dtmPosted' => "2011-07-08 08:53:00"));
+ $type->addDocument($doc);
+ $doc = new Elastica_Document(4, array('name' => 'elastica search', 'dtmPosted' => "2011-07-08 01:53:00"));
+ $type->addDocument($doc);
+
+ $query = new Elastica_Query();
+ $query->setQuery(new Elastica_Query_MatchAll());
+ $index->refresh();
+
+ $resultSet = $type->search($query);
+
+ $engineTime = $resultSet->getResponse()->getEngineTime();
+ $shardsStats = $resultSet->getResponse()->getShardsStatistics();
+
+ $this->assertInternalType('int', $engineTime);
+ $this->assertTrue(is_array($shardsStats));
+ $this->assertArrayHasKey('total', $shardsStats);
+ $this->assertArrayHasKey('successful', $shardsStats);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ResultTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ResultTest.php
new file mode 100755
index 0000000..2cdfdcf
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/ResultTest.php
@@ -0,0 +1,97 @@
+_createIndex();
+ $type = $index->getType($typeName);
+
+ // Adds 1 document to the index
+ $docId = 3;
+ $doc1 = new Elastica_Document($docId, array('username' => 'hans'));
+ $type->addDocument($doc1);
+
+ // Refreshes index
+ $index->refresh();
+
+ $resultSet = $type->search('hans');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $result = $resultSet->current();
+
+ $this->assertInstanceOf('Elastica_Result', $result);
+ $this->assertEquals($index->getName(), $result->getIndex());
+ $this->assertEquals($typeName, $result->getType());
+ $this->assertEquals($docId, $result->getId());
+ $this->assertGreaterThan(0, $result->getScore());
+ $this->assertInternalType('array', $result->getData());
+ }
+
+ public function testGetIdNoSource()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $indexName = 'xodoa';
+ $typeName = 'user';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $type = $index->getType($typeName);
+
+ $mapping = new Elastica_Type_Mapping($type);
+ $mapping->disableSource();
+ $mapping->send();
+
+ // Adds 1 document to the index
+ $docId = 3;
+ $doc1 = new Elastica_Document($docId, array('username' => 'hans'));
+ $type->addDocument($doc1);
+
+ // Refreshes index
+ $index->refresh();
+
+ $resultSet = $type->search('hans');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $result = $resultSet->current();
+
+ $this->assertEquals(array(), $result->getSource());
+ $this->assertInstanceOf('Elastica_Result', $result);
+ $this->assertEquals($indexName, $result->getIndex());
+ $this->assertEquals($typeName, $result->getType());
+ $this->assertEquals($docId, $result->getId());
+ $this->assertGreaterThan(0, $result->getScore());
+ $this->assertInternalType('array', $result->getData());
+ }
+
+ public function testGetTotalTimeReturnsExpectedResults()
+ {
+ $typeName = 'user';
+ $index = $this->_createIndex();
+ $type = $index->getType($typeName);
+
+ // Adds 1 document to the index
+ $docId = 3;
+ $doc1 = new Elastica_Document($docId, array('username' => 'hans'));
+ $type->addDocument($doc1);
+
+ // Refreshes index
+ $index->refresh();
+
+ $resultSet = $type->search('hans');
+
+ $this->assertNotNull($resultSet->getTotalTime(), 'Get Total Time should never be a null value');
+ $this->assertEquals(
+ 'integer',
+ getType($resultSet->getTotalTime()),
+ 'Total Time should be an integer'
+ );
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ScriptFieldsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ScriptFieldsTest.php
new file mode 100644
index 0000000..f0ea5be
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/ScriptFieldsTest.php
@@ -0,0 +1,87 @@
+index = $this->_createIndex();
+ }
+
+ public function tearDown()
+ {
+ $this->index->delete();
+ }
+
+ public function testNewScriptFields()
+ {
+ $script = new Elastica_Script('1 + 2');
+
+ // addScript
+ $scriptFields = new Elastica_ScriptFields;
+ $scriptFields->addScript('test', $script);
+ $this->assertEquals($scriptFields->getParam('test'), $script->toArray());
+
+ // setScripts
+ $scriptFields = new Elastica_ScriptFields;
+ $scriptFields->setScripts(array(
+ 'test' => $script
+ ));
+ $this->assertEquals($scriptFields->getParam('test'), $script->toArray());
+
+ // Constructor
+ $scriptFields = new Elastica_ScriptFields(array(
+ 'test' => $script
+ ));
+ $this->assertEquals($scriptFields->getParam('test'), $script->toArray());
+ }
+
+ public function testSetScriptFields()
+ {
+ $query = new Elastica_Query;
+ $script = new Elastica_Script('1 + 2');
+
+ $scriptFields = new Elastica_ScriptFields(array(
+ 'test' => $script
+ ));
+ $query->setScriptFields($scriptFields);
+ $this->assertEquals($query->getParam('script_fields'), $scriptFields->toArray());
+
+ $query->setScriptFields(array(
+ 'test' => $script
+ ));
+ $this->assertEquals($query->getParam('script_fields'), $scriptFields->toArray());
+ }
+
+ public function testNameException()
+ {
+ $this->setExpectedException('Elastica_Exception_Invalid');
+
+ $script = new Elastica_Script('1 + 2');
+ $scriptFields = new Elastica_ScriptFields(array($script));
+ }
+
+ public function testQuery()
+ {
+ $type = $this->index->getType('test');
+
+ $doc = new Elastica_Document(1, array('firstname' => 'guschti', 'lastname' => 'ruflin'));
+ $type->addDocument($doc);
+ $this->index->refresh();
+
+ $query = new Elastica_Query();
+ $script = new Elastica_Script('1 + 2');
+ $scriptFields = new Elastica_ScriptFields(array(
+ 'test' => $script
+ ));
+ $query->setScriptFields($scriptFields);
+
+ $resultSet = $type->search($query);
+ $first = $resultSet->current()->getData();
+
+ // 1 + 2
+ $this->assertEquals(3, $first['test']);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/SearchTest.php b/modules/thirdparty/elastica/test/lib/Elastica/SearchTest.php
new file mode 100644
index 0000000..e44e19d
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/SearchTest.php
@@ -0,0 +1,287 @@
+assertInstanceOf('Elastica_Search', $search);
+ $this->assertSame($client, $search->getClient());
+ }
+
+ public function testAddIndex()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ $index1 = $this->_createIndex('test1');
+ $index2 = $this->_createIndex('test2');
+
+ $search->addIndex($index1);
+ $indices = $search->getIndices();
+
+ $this->assertEquals(1, count($indices));
+
+ $search->addIndex($index2);
+ $indices = $search->getIndices();
+
+ $this->assertEquals(2, count($indices));
+
+ $this->assertTrue(in_array($index1->getName(), $indices));
+ $this->assertTrue(in_array($index2->getName(), $indices));
+
+ // Add string
+ $search->addIndex('test3');
+ $indices = $search->getIndices();
+
+ $this->assertEquals(3, count($indices));
+ $this->assertTrue(in_array('test3', $indices));
+ }
+
+ public function testAddIndices()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ $indices = array();
+ $indices[] = $client->getIndex('elastica_test1');
+ $indices[] = $client->getIndex('elastica_test2');
+
+ $search->addIndices($indices);
+
+ $this->assertEquals(2, count($search->getIndices()));
+ }
+
+ public function testAddType()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ $index = $this->_createIndex();
+
+ $type1 = $index->getType('type1');
+ $type2 = $index->getType('type2');
+
+ $this->assertEquals(array(), $search->getTypes());
+
+ $search->addType($type1);
+ $types = $search->getTypes();
+
+ $this->assertEquals(1, count($types));
+
+ $search->addType($type2);
+ $types = $search->getTypes();
+
+ $this->assertEquals(2, count($types));
+
+ $this->assertTrue(in_array($type1->getName(), $types));
+ $this->assertTrue(in_array($type2->getName(), $types));
+
+ // Add string
+ $search->addType('test3');
+ $types = $search->getTypes();
+
+ $this->assertEquals(3, count($types));
+ $this->assertTrue(in_array('test3', $types));
+ }
+
+ public function testAddTypes()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ $index = $this->_createIndex();
+
+ $types = array();
+ $types[] = $index->getType('type1');
+ $types[] = $index->getType('type2');
+
+ $search->addTypes($types);
+
+ $this->assertEquals(2, count($search->getTypes()));
+ }
+
+ public function testAddTypeInvalid()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ try {
+ $search->addType(new stdClass());
+ $this->fail('Should throw invalid exception');
+ } catch (Elastica_Exception_Invalid $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ public function testAddIndexInvalid()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ try {
+ $search->addIndex(new stdClass());
+ $this->fail('Should throw invalid exception');
+ } catch (Elastica_Exception_Invalid $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ public function testGetPath()
+ {
+ $client = new Elastica_Client();
+ $search1 = new Elastica_Search($client);
+ $search2 = new Elastica_Search($client);
+
+ $index1 = $this->_createIndex('test1');
+ $index2 = $this->_createIndex('test2');
+
+ $type1 = $index1->getType('type1');
+ $type2 = $index1->getType('type2');
+
+ // No index
+ $this->assertEquals('_all/_search', $search1->getPath());
+
+ // Only index
+ $search1->addIndex($index1);
+ $this->assertEquals($index1->getName() . '/_search', $search1->getPath());
+
+ // MUltiple index, no types
+ $search1->addIndex($index2);
+ $this->assertEquals($index1->getName() . ',' . $index2->getName() . '/_search', $search1->getPath());
+
+ // Single type, no index
+ $search2->addType($type1);
+ $this->assertEquals('_all/' . $type1->getName() . '/_search', $search2->getPath());
+
+ // Multiple types
+ $search2->addType($type2);
+ $this->assertEquals('_all/' . $type1->getName() . ',' . $type2->getName() . '/_search', $search2->getPath());
+
+ // Combine index and types
+ $search2->addIndex($index1);
+ $this->assertEquals($index1->getName() . '/' . $type1->getName() . ',' . $type2->getName() . '/_search', $search2->getPath());
+ }
+
+ public function testSearchRequest()
+ {
+ $client = new Elastica_Client();
+ $search1 = new Elastica_Search($client);
+
+ $index1 = $this->_createIndex('test1');
+ $index2 = $this->_createIndex('test2');
+
+ $type1 = $index1->getType('hello1');
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+
+ $search1->addIndex($index1);
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+
+ $search1->addIndex($index2);
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+
+ $search1->addType($type1);
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+ }
+
+ /**
+ * Default Limit tests for Elastica_Search
+ */
+ public function testLimitDefaultSearch()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+ $docs[] = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $search->addIndex($index)->addType($type);
+
+ // default limit results (default limit is 10)
+ $resultSet = $search->search('farrelley');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $search->search('farrelley', 1);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testArrayConfigSearch()
+ {
+ $client = new Elastica_Client();
+ $search = new Elastica_Search($client);
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+ for ($i = 0; $i < 11; $i++) {
+ $docs[] = new Elastica_Document($i, array('id' => 1, 'email' => 'test@test.com', 'username' => 'test'));
+ }
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $search->addIndex($index)->addType($type);
+ //Backward compatibility, integer => limit
+ // default limit results (default limit is 10)
+ $resultSet = $search->search('test');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $search->search('test', 1);
+ $this->assertEquals(1, $resultSet->count());
+
+ //Array with limit
+ $resultSet = $search->search('test', array('limit' => 2));
+ $this->assertEquals(2, $resultSet->count());
+
+ //Array with routing
+ $resultSet = $search->search('test', array('routing' => 'r1,r2'));
+ $this->assertEquals(10, $resultSet->count());
+
+ //Array with limit and routing
+ $resultSet = $search->search('test', array('limit' => 5, 'routing' => 'r1,r2'));
+ $this->assertEquals(5, $resultSet->count());
+
+ //Search types
+ $resultSet = $search->search('test', array('limit' => 5, 'search_type' => 'count'));
+ $this->assertTrue(($resultSet->count() === 0) && $resultSet->getTotalHits() === 11);
+
+ //Invalid option
+ try {
+ $resultSet = $search->search('test', array('invalid_option' => 'invalid_option_value'));
+ $this->fail('Should throw Elastica_Exception_Invalid');
+ } catch (Exception $ex) {
+ $this->assertTrue($ex instanceof Elastica_Exception_Invalid);
+ }
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/StatusTest.php b/modules/thirdparty/elastica/test/lib/Elastica/StatusTest.php
new file mode 100644
index 0000000..57dff49
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/StatusTest.php
@@ -0,0 +1,103 @@
+_createIndex();
+ $status = new Elastica_Status($index->getClient());
+ $this->assertInstanceOf('Elastica_Response', $status->getResponse());
+ }
+
+ public function testGetIndexStatuses()
+ {
+ $index = $this->_createIndex();
+
+ $status = new Elastica_Status($index->getClient());
+ $statuses = $status->getIndexStatuses();
+
+ $this->assertInternalType('array', $statuses);
+
+ foreach ($statuses as $indexStatus) {
+ $this->assertInstanceOf('Elastica_Index_Status', $indexStatus);
+ }
+ }
+
+ public function testGetIndexNames()
+ {
+ $indexName = 'test';
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $index = $this->_createIndex();
+
+ $status = new Elastica_Status($index->getClient());
+ $names = $status->getIndexNames();
+
+ $this->assertInternalType('array', $names);
+ $this->assertTrue(in_array($index->getName(), $names));
+
+ foreach ($names as $name) {
+ $this->assertInternalType('string', $name);
+ }
+ }
+
+ public function testIndexExists()
+ {
+ $indexName = 'elastica_test';
+ $aliasName = 'elastica_test-alias';
+
+ $client = new Elastica_Client();
+ $index = $client->getIndex($indexName);
+
+ try {
+ // Make sure index is deleted first
+ $index->delete();
+ } catch (Elastica_Exception_Response $e) {
+ }
+
+ $status = new Elastica_Status($client);
+ $this->assertFalse($status->indexExists($indexName));
+ $index->create();
+
+ $status->refresh();
+ $this->assertTrue($status->indexExists($indexName));
+ }
+
+ public function testAliasExists()
+ {
+ $indexName = 'test';
+ $aliasName = 'elastica_test-alias';
+
+ $index1 = $this->_createIndex();
+
+ $status = new Elastica_Status($index1->getClient());
+
+ foreach ($status->getIndicesWithAlias($aliasName) as $tmpIndex) {
+ $tmpIndex->removeAlias($aliasName);
+ }
+
+ $this->assertFalse($status->aliasExists($aliasName));
+
+ $index1->addAlias($aliasName);
+ $status->refresh();
+ $this->assertTrue($status->aliasExists($aliasName));
+ }
+
+ public function testServerStatus()
+ {
+ $client = new Elastica_Client();
+ $status = $client->getStatus();
+ $serverStatus = $status->getServerStatus();
+
+ $this->assertTrue(!empty($serverStatus) );
+ $this->assertTrue('array' == gettype($serverStatus));
+ $this->assertArrayHasKey('ok', $serverStatus);
+ $this->assertTrue($serverStatus['ok']);
+ $this->assertArrayHasKey('version', $serverStatus);
+
+ $versionInfo = $serverStatus['version'];
+ $this->assertArrayHasKey('number', $versionInfo);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Test.php b/modules/thirdparty/elastica/test/lib/Elastica/Test.php
new file mode 100644
index 0000000..ee63d19
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Test.php
@@ -0,0 +1,23 @@
+_getClient();
+ $index = $client->getIndex('elastica_' . $name);
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ return $index;
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Transport/MemcacheTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Transport/MemcacheTest.php
new file mode 100644
index 0000000..c3f9a1c
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Transport/MemcacheTest.php
@@ -0,0 +1,56 @@
+markTestSkipped('pecl/memcache must be installed to run this test case');
+ }
+ }
+
+ public function testConstruct()
+ {
+ $host = 'localhost';
+ $port = 11211;
+ $client = new Elastica_Client(array('host' => $host, 'port' => $port, 'transport' => 'Memcache'));
+
+ $this->assertEquals($host, $client->getHost());
+ $this->assertEquals($port, $client->getPort());
+ }
+
+ public function testExample()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $host = 'localhost';
+ $port = 11211;
+ $client = new Elastica_Client(array('host' => $host, 'port' => $port, 'transport' => 'Memcache'));
+
+ $index = $client->getIndex('elastica_test1');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Elastica_Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Elastica_Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Elastica_Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+ $this->markTestSkipped('Memcache implementation is not finished yet');
+ $resultSet = $type->search('rolf');
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Type/MappingTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Type/MappingTest.php
new file mode 100644
index 0000000..ef55cc5
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/Type/MappingTest.php
@@ -0,0 +1,171 @@
+getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $mapping = new Elastica_Type_Mapping($type,
+ array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ // default is store => no expected
+ 'lastname' => array('type' => 'string'),
+ )
+ );
+ $mapping->disableSource();
+
+ $type->setMapping($mapping);
+
+ $firstname = 'Nicolas';
+ $doc = new Elastica_Document(1,
+ array(
+ 'firstname' => $firstname,
+ 'lastname' => 'Ruflin'
+ )
+ );
+
+ $type->addDocument($doc);
+
+ $index->refresh();
+ $queryString = new Elastica_Query_QueryString('ruflin');
+ $query = Elastica_Query::create($queryString);
+ $query->setFields(array('*'));
+
+ $resultSet = $type->search($query);
+ $result = $resultSet->current();
+ $fields = $result->getFields();
+
+ $this->assertEquals($firstname, $fields['firstname']);
+ $this->assertArrayNotHasKey('lastname', $fields);
+ $this->assertEquals(1, count($fields));
+
+ $index->flush();
+ $document = $type->getDocument(1);
+
+ $this->assertEmpty($document->getData());
+ }
+
+ public function testEnableTtl()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $mapping = new Elastica_Type_Mapping($type, array());
+
+ $mapping->enableTtl();
+
+ $data = $mapping->toArray();
+ $this->assertTrue($data[$type->getName()]['_ttl']['enabled']);
+ }
+
+ public function testNestedMapping()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $this->markTestIncomplete('nested mapping is not set right yet');
+ $mapping = new Elastica_Type_Mapping($type,
+ array(
+ 'test' => array(
+ 'type' => 'object', 'store' => 'yes', 'properties' => array(
+ 'user' => array(
+ 'properties' => array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ 'lastname' => array('type' => 'string', 'store' => 'yes'),
+ 'age' => array('type' => 'integer', 'store' => 'yes'),
+ )
+ ),
+ ),
+ ),
+ )
+ );
+
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1, array(
+ 'user' => array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ruflin',
+ 'age' => 9
+ ),
+ ));
+
+ //print_r($type->getMapping());
+ //exit();
+ $type->addDocument($doc);
+
+ $index->refresh();
+ $resultSet = $type->search('ruflin');
+ //print_r($resultSet);
+ }
+
+ public function testParentMapping()
+ {
+ $index = $this->_createIndex();
+ $parenttype = new Elastica_Type($index, 'parenttype');
+ $parentmapping = new Elastica_Type_Mapping($parenttype,
+ array(
+ 'name' => array('type' => 'string', 'store' => 'yes')
+ )
+ );
+
+ $parenttype->setMapping($parentmapping);
+
+ $childtype = new Elastica_Type($index, 'childtype');
+ $childmapping = new Elastica_Type_Mapping($childtype,
+ array(
+ 'name' => array('type' => 'string', 'store' => 'yes'),
+ )
+ );
+ $childmapping->setParam('_parent', array('type' => 'parenttype'));
+
+ $childtype->setMapping($childmapping);
+ }
+
+ public function testMappingExample()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('notes');
+
+ $mapping = new Elastica_Type_Mapping($type,
+ array(
+ 'note' => array(
+ 'store' => 'yes', 'properties' => array(
+ 'titulo' => array('type' => 'string', 'store' => 'no', 'include_in_all' => true, 'boost' => 1.0),
+ 'contenido' => array('type' => 'string', 'store' => 'no', 'include_in_all' => true, 'boost' => 1.0)
+ )
+ )
+ )
+ );
+
+ $type->setMapping($mapping);
+
+ $doc = new Elastica_Document(1, array(
+ 'note' => array(
+ array(
+ 'titulo' => 'nota1',
+ 'contenido' => 'contenido1'
+ ),
+ array(
+ 'titulo' => 'nota2',
+ 'contenido' => 'contenido2'
+ )
+ )
+ )
+ );
+
+ $type->addDocument($doc);
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/TypeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/TypeTest.php
new file mode 100755
index 0000000..54866a0
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/TypeTest.php
@@ -0,0 +1,301 @@
+_createIndex();
+
+ $type = new Elastica_Type($index, 'user');
+
+ // Adds 1 document to the index
+ $doc1 = new Elastica_Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Elastica_Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Elastica_Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ $this->assertEquals(1, $resultSet->count());
+
+ // Test if source is returned
+ $result = $resultSet->current();
+ $this->assertEquals(3, $result->getId());
+ $data = $result->getData();
+ $this->assertEquals('rolf', $data['username']);
+ }
+
+ public function testNoSource()
+ {
+ $index = $this->_createIndex();
+
+ $type = new Elastica_Type($index, 'user');
+ $mapping = new Elastica_Type_Mapping($type, array(
+ 'id' => array('type' => 'integer', 'store' => 'yes'),
+ 'username' => array('type' => 'string', 'store' => 'no'),
+ ));
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ // Adds 1 document to the index
+ $doc1 = new Elastica_Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Elastica_Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Elastica_Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // To update index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ // Tests if no source is in response except id
+ $result = $resultSet->current();
+ $this->assertEquals(3, $result->getId());
+ $this->assertEmpty($result->getData());
+ }
+
+ public function testDeleteDocument()
+ {
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'user');
+
+ // Adds hans, john and rolf to the index
+ $docs = array(
+ new Elastica_Document(1, array('username' => 'hans', 'test' => array('2', '3', '5'))),
+ new Elastica_Document(2, array('username' => 'john', 'test' => array('1', '3', '6'))),
+ new Elastica_Document(3, array('username' => 'rolf', 'test' => array('2', '3', '7'))),
+ );
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ // sanity check for rolf
+ $resultSet = $type->search('rolf');
+ $this->assertEquals(1, $resultSet->count());
+ $data = $resultSet->current()->getData();
+ $this->assertEquals('rolf', $data['username']);
+
+ // delete rolf
+ $type->deleteById(3);
+ $index->refresh();
+
+ // rolf should no longer be there
+ $resultSet = $type->search('rolf');
+ $this->assertEquals(0, $resultSet->count());
+
+ // it should not be possible to delete the entire type with this method
+ try {
+ $type->deleteById(' ');
+ } catch (Exception $e) {
+ /* ignore */
+ }
+
+ try {
+ $type->deleteById(null);
+ } catch (Exception $e) {
+ /* ignore */
+ }
+
+ try {
+ $type->deleteById(array());
+ } catch (Exception $e) {
+ /* ignore */
+ }
+
+ try {
+ $type->deleteById('*');
+ } catch (Exception $e) {
+ /* ignore */
+ }
+
+ try {
+ $type->deleteById('*:*');
+ } catch (Exception $e) {
+ /* ignore */
+ }
+
+ try {
+ $type->deleteById('!');
+ } catch (Exception $e) {
+ /* ignore */
+ }
+
+ $index->refresh();
+
+ // rolf should no longer be there
+ $resultSet = $type->search('john');
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ public function testGetDocumentNotExist()
+ {
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'test');
+ $type->addDocument(new Elastica_Document(1, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $type->getDocument(1);
+
+ try {
+ $type->getDocument(2);
+ $this->fail('Should throw exceptoin as doc does not exist');
+ } catch (Elastica_Exception_NotFound $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ public function testDeleteByQuery()
+ {
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'test');
+ $type->addDocument(new Elastica_Document(1, array('name' => 'ruflin nicolas')));
+ $type->addDocument(new Elastica_Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(1, $response->count());
+
+ // Delete first document
+ $response = $type->deleteByQuery('nicolas');
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ // Makes sure, document is deleted
+ $response = $index->search('ruflin*');
+ $this->assertEquals(1, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(0, $response->count());
+ }
+
+ /**
+ * Test to see if search Default Limit works
+ */
+ public function testLimitDefaultType()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+ $docs[] = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Elastica_Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ // default results (limit default is 10)
+ $resultSet = $type->search('farrelley');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $type->search('farrelley', 1);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * Test Delete of index type. After delete will check for type mapping.
+ */
+ public function testDeleteType()
+ {
+ $index = $this->_createIndex();
+ $type = new Elastica_Type($index, 'test');
+ $type->addDocument(new Elastica_Document(1, array('name' => 'ruflin nicolas')));
+ $type->addDocument(new Elastica_Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $type->delete();
+ try {
+ $type->getMapping();
+ } catch (Elastica_Exception_Response $expected) {
+ $this->assertEquals("TypeMissingException[[elastica_test] type[test] missing]", $expected->getMessage());
+
+ return;
+ }
+
+ $this->fail('Mapping for type[test] in [elastica_test] still exists');
+ }
+
+ public function testMoreLikeThisApi()
+ {
+ $client = new Elastica_Client(array('persistent' => false));
+ $index = $client->getIndex('elastica_test');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $type = new Elastica_Type($index, 'mlt_test');
+ $type->addDocument(new Elastica_Document(1, array('visible' => true, 'name' => 'bruce wayne batman')));
+ $type->addDocument(new Elastica_Document(2, array('visible' => true, 'name' => 'bruce wayne')));
+ $type->addDocument(new Elastica_Document(3, array('visible' => false, 'name' => 'bruce wayne')));
+ $type->addDocument(new Elastica_Document(4, array('visible' => true, 'name' => 'batman')));
+ $type->addDocument(new Elastica_Document(5, array('visible' => false, 'name' => 'batman')));
+ $type->addDocument(new Elastica_Document(6, array('visible' => true, 'name' => 'superman')));
+ $type->addDocument(new Elastica_Document(7, array('visible' => true, 'name' => 'spiderman')));
+
+ $index->refresh();
+
+ $document = $type->getDocument(1);
+
+ // Return all similar
+ $resultSet = $type->moreLikeThis($document, array('min_term_freq' => '1', 'min_doc_freq' => '1'));
+ $this->assertEquals(4, $resultSet->count());
+
+ // Return just the visible similar
+ $query = new Elastica_Query();
+ $filterTerm = new Elastica_Filter_Term();
+ $filterTerm->setTerm('visible', true);
+ $query->setFilter($filterTerm);
+
+ $resultSet = $type->moreLikeThis($document, array('min_term_freq' => '1', 'min_doc_freq' => '1'), $query);
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ public function testUpdateDocument()
+ {
+ $client = new Elastica_Client();
+ $index = $client->getIndex('elastica_test');
+ $type = $index->getType('update_type');
+ $id = 1;
+ $type->addDocument(new Elastica_Document($id, array('name' => 'bruce wayne batman')));
+ $newName = 'batman';
+ $update = new Elastica_Script("ctx._source.name = name", array('name' => $newName));
+ $type->updateDocument($id, $update, array('refresh' => true));
+ $updatedDoc = $type->getDocument($id)->getData();
+ $this->assertEquals($newName, $updatedDoc['name'], "Name was not updated");
+ }
+}
diff --git a/modules/thirdparty/elastica/test/lib/Elastica/UtilTest.php b/modules/thirdparty/elastica/test/lib/Elastica/UtilTest.php
new file mode 100644
index 0000000..a67a3ff
--- /dev/null
+++ b/modules/thirdparty/elastica/test/lib/Elastica/UtilTest.php
@@ -0,0 +1,51 @@
+assertEquals($escaped, Elastica_Util::escapeTerm($unescaped));
+ }
+
+ public function getEscapeTermPairs()
+ {
+ return array(
+ array('', ''),
+ array('pragmatic banana', 'pragmatic banana'),
+ array('oh yeah!', 'oh yeah\\!'),
+ // Seperate test below because phpunit seems to have some problems
+ //array('\\+-&&||!(){}[]^"~*?:', '\\\\\\+\\-\\&&\\||\\!\\(\\)\\{\\}\\[\\]\\^\\"\\~\\*\\?\\:'),
+ array('some signs, can stay.', 'some signs, can stay.')
+ );
+ }
+
+ public function testEscapeTermSpecialCharacters()
+ {
+ $before = '\\+-&&||!(){}[]^"~*?:';
+ $after = '\\\\\\+\\-\\&&\\||\\!\\(\\)\\{\\}\\[\\]\\^\\"\\~\\*\\?\\:';
+
+ $this->assertEquals(Elastica_Util::escapeTerm($before), $after);
+ }
+
+ public function testToCamelCase()
+ {
+ $string = 'hello_world';
+ $this->assertEquals('HelloWorld', Elastica_Util::toCamelCase($string));
+
+ $string = 'how_are_you_today';
+ $this->assertEquals('HowAreYouToday', Elastica_Util::toCamelCase($string));
+ }
+
+ public function testToSnakeCase()
+ {
+ $string = 'HelloWorld';
+ $this->assertEquals('hello_world', Elastica_Util::toSnakeCase($string));
+
+ $string = 'HowAreYouToday';
+ $this->assertEquals('how_are_you_today', Elastica_Util::toSnakeCase($string));
+ }
+}
diff --git a/modules/thirdparty/elastica/test/phpunit.xml.dist b/modules/thirdparty/elastica/test/phpunit.xml.dist
new file mode 100755
index 0000000..f80641f
--- /dev/null
+++ b/modules/thirdparty/elastica/test/phpunit.xml.dist
@@ -0,0 +1,33 @@
+
+
+
+
+ ./lib/Elastica/
+
+
+
+
+ ../lib/
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/ipnlistener/LICENSE b/modules/thirdparty/ipnlistener/LICENSE
new file mode 100755
index 0000000..bad71e3
--- /dev/null
+++ b/modules/thirdparty/ipnlistener/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2012, Micah Carrick
+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 Quixotix, LLC nor the names of its
+ 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 HOLDER 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/modules/thirdparty/ipnlistener/README.md b/modules/thirdparty/ipnlistener/README.md
new file mode 100755
index 0000000..a4afa9d
--- /dev/null
+++ b/modules/thirdparty/ipnlistener/README.md
@@ -0,0 +1,179 @@
+PHP-PayPal-IPN
+==============
+
+A PayPal Instant Payment Notification (IPN) class for PHP 5.
+
+Use the `IpnListener` class in your PHP IPN script to handle the encoding
+of POST data, post back to PayPal, and parsing of the response from PayPal.
+
+
+Features
+--------
+
+* Switch between live and sandbox by setting the `use_sandbox` property.
+* Supports both secure SSL and plain HTTP transactions by setting the `use_ssl`
+ property (SSL is recommended).
+* Supports both cURL and fsockopen network libraries by setting the `use_curl`
+ property (cURL is recommended).
+* Verifies an HTTP "200" response status code from the PayPal server.
+* Get detailed plain text reports of the entire IPN using the `getTextReport()`
+ method for use in emails and logs to administrators.
+* Throws various exceptions to differentiate between common errors in code or
+ server configuration versus invalid IPN responses.
+
+
+Getting Started
+---------------
+
+This code is intended for web developers. You should understand how the IPN
+process works conceptually and you should understand when and why you would be
+using IPN. Reading the [PayPal Instant Payment Notification Guide][1] is a good
+place to start.
+
+You should also have a [PayPal Sandbox Account][2] with a test buyer account and
+a test seller account. When logged into your sandbox account there is an IPN
+simulator under the 'Test Tools' menu which you can used to test your IPN
+listener.
+
+[1]: https://cms.paypal.com/cms_content/US/en_US/files/developer/IPNGuide.pdf
+[2]: https://developer.paypal.com
+
+Once you have your sandbox account setup, you simply create a PHP script that
+will be your IPN listener. In that script, use the `IpnListener()` class as shown
+below. For a more thoroughly documented example, take a look at the
+`example/ipn.php` script in the source code.
+
+ use_sandbox = true;
+
+ try {
+ $verified = $listener->processIpn();
+ } catch (Exception $e) {
+ // fatal error trying to process IPN.
+ exit(0);
+ }
+
+ if ($verified) {
+ // IPN response was "VERIFIED"
+ } else {
+ // IPN response was "INVALID"
+ }
+
+ ?>
+
+
+Documentation
+-------------
+
+Documentation has not been generated yet, but, there are phpDocumentor style
+docstrings (comments) throughout `ipnlistener.php` which explain the important
+public properties and methods.
+
+I have also written a more in-depth IPN tutorial on my blog: [PayPal IPN with PHP][3]
+
+[3]: http://www.micahcarrick.com/paypal-ipn-with-php.html
+
+
+Known Issues
+------------
+
+__Problem__
+
+The `processIpn()` method throws the following exception:
+
+ cURL error: [52] GnuTLS recv error (-9): A TLS packet with unexpected length was received.
+
+__Solution__
+
+When cURL is compiled with GnuTLS the call to PayPal will fail if the SSL version
+is not explicitly set as a cURL option. Set the `force_ssl_v3` property to force
+SSL 3:
+
+ $listener = new IpnListener();
+ $listener->force_ssl_v3 = true;
+
+_Note: force_ssl_v3 is now true by default_
+
+
+
+__Problem__
+
+ PHP Warning: curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION
+ cannot be activated when in safe_mode or an open_basedir is set in ...
+
+__Solution__
+
+If you need PHP safe mode, you can disable CURLOPT_FOLLOWLOCATION using the
+`follow_location` property.
+
+ $listener = new IpnListener();
+ $listener->follow_location = false;
+
+_Note: follow_location is now false enabled by default_
+
+
+Example Report
+--------------
+
+Here is an example of a report returned by the `getTextReport()` method. Create
+your own reports by extending the `IpnListener()` class or by accessing the data
+directly in your ipn script.
+
+ --------------------------------------------------------------------------------
+ [09/09/2011 8:35 AM] - https://www.sandbox.paypal.com/cgi-bin/webscr (curl)
+ --------------------------------------------------------------------------------
+ HTTP/1.1 200 OK
+ Date: Fri, 09 Sep 2011 13:35:39 GMT
+ Server: Apache
+ X-Frame-Options: SAMEORIGIN
+ Set-Cookie: c9MWDuvPtT9GIMyPc3jwol1VSlO=Ch-NORlHUjlmbEm__KG9LupR4mfMfQTkx1QQ6hHDyc0RImWr88NY_ILeICENiwtVX3iw4jEnT1-1gccYjQafWrQCkDmiykNT8TeDUg7R7L0D9bQm47PTG8MafmrpyrUAxQfst0%7c_jG1ZL6CffJgwrC-stQeqni04tKaYSIZqyqhFU7tKnV520wiYOw0hwk5Ehrh3hLDvBxkpm%7cYTFdl0w0YpEqxu0D1jDTVTlEGXlmLs4wob2Glu9htpZkFV9O2aCyfQ4CvA2kLJmlI6YiXm%7c1315575340; domain=.paypal.com; path=/; Secure; HttpOnly
+ Set-Cookie: cookie_check=yes; expires=Mon, 06-Sep-2021 13:35:40 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
+ Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly
+ Set-Cookie: navlns=0.0; expires=Thu, 04-Sep-2031 13:35:40 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
+ Set-Cookie: Apache=10.72.109.11.1315575339707456; path=/; expires=Sun, 01-Sep-41 13:35:39 GMT
+ X-Cnection: close
+ Transfer-Encoding: chunked
+ Content-Type: text/html; charset=UTF-8
+
+ VERIFIED
+ --------------------------------------------------------------------------------
+ test_ipn 1
+ payment_type instant
+ payment_date 06:34:51 Sep 09, 2011 PDT
+ payment_status Completed
+ address_status confirmed
+ payer_status verified
+ first_name John
+ last_name Smith
+ payer_email buyer@paypalsandbox.com
+ payer_id TESTBUYERID01
+ address_name John Smith
+ address_country United States
+ address_country_code US
+ address_zip 95131
+ address_state CA
+ address_city San Jose
+ address_street 123, any street
+ business seller@paypalsandbox.com
+ receiver_email seller@paypalsandbox.com
+ receiver_id TESTSELLERID1
+ residence_country US
+ item_name something
+ item_number AK-1234
+ quantity 1
+ shipping 3.04
+ tax 2.02
+ mc_currency USD
+ mc_fee 0.44
+ mc_gross 12.34
+ mc_gross_1 9.34
+ txn_type web_accept
+ txn_id 51991334
+ notify_version 2.1
+ custom xyz123
+ charset windows-1252
+ verify_sign Ah5rOpfPGo5g6FNg95DMPybP51J5AUEdXS1hqyRAP6WYYwaixKNDgQRR
diff --git a/modules/thirdparty/ipnlistener/cert/api_cert_chain.crt b/modules/thirdparty/ipnlistener/cert/api_cert_chain.crt
new file mode 100755
index 0000000..347f0eb
--- /dev/null
+++ b/modules/thirdparty/ipnlistener/cert/api_cert_chain.crt
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIIDgzCCAuygAwIBAgIQJUuKhThCzONY+MXdriJupDANBgkqhkiG9w0BAQUFADBf
+MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
+LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNOTcwNDE3MDAwMDAwWhcNMTExMDI0MjM1OTU5WjCBujEfMB0GA1UEChMWVmVy
+aVNpZ24gVHJ1c3QgTmV0d29yazEXMBUGA1UECxMOVmVyaVNpZ24sIEluYy4xMzAx
+BgNVBAsTKlZlcmlTaWduIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gQ2xhc3Mg
+MzFJMEcGA1UECxNAd3d3LnZlcmlzaWduLmNvbS9DUFMgSW5jb3JwLmJ5IFJlZi4g
+TElBQklMSVRZIExURC4oYyk5NyBWZXJpU2lnbjCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA2IKA6NYZAn0fhRg5JaJlK+G/1AXTvOY2O6rwTGxbtueqPHNFVbLx
+veqXQu2aNAoV1Klc9UAl3dkHwTKydWzEyruj/lYncUOqY/UwPpMo5frxCTvzt01O
+OfdcSVq4wR3Tsor+cDCVQsv+K1GLWjw6+SJPkLICp1OcTzTnqwSye28CAwEAAaOB
+4zCB4DAPBgNVHRMECDAGAQH/AgEAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw
+KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL0NQUzA0BgNV
+HSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIGCWCGSAGG+EIEAQYKYIZIAYb4RQEI
+ATALBgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgEGMDEGA1UdHwQqMCgwJqAk
+oCKGIGh0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4GBAAgB7ORolANC8XPxI6I63unx2sZUxCM+hurPajozq+qcBBQHNgYL+Yhv
+1RPuKSvD5HKNRO3RrCAJLeH24RkFOLA9D59/+J4C3IYChmFOJl9en5IeDCSk9dBw
+E88mw0M9SR2egi5SX7w+xmYpAY5Okiy8RnUDgqxz6dl+C2fvVFIa
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
diff --git a/modules/thirdparty/ipnlistener/example/ipn.php b/modules/thirdparty/ipnlistener/example/ipn.php
new file mode 100755
index 0000000..4e66cd6
--- /dev/null
+++ b/modules/thirdparty/ipnlistener/example/ipn.php
@@ -0,0 +1,111 @@
+use_sandbox = true;
+
+/*
+By default the IpnListener object is going going to post the data back to PayPal
+using cURL over a secure SSL connection. This is the recommended way to post
+the data back, however, some people may have connections problems using this
+method.
+
+To post over standard HTTP connection, use:
+$listener->use_ssl = false;
+
+To post using the fsockopen() function rather than cURL, use:
+$listener->use_curl = false;
+*/
+
+/*
+The processIpn() method will encode the POST variables sent by PayPal and then
+POST them back to the PayPal server. An exception will be thrown if there is
+a fatal error (cannot connect, your server is not configured properly, etc.).
+Use a try/catch block to catch these fatal errors and log to the ipn_errors.log
+file we setup at the top of this file.
+
+The processIpn() method will send the raw data on 'php://input' to PayPal. You
+can optionally pass the data to processIpn() yourself:
+$verified = $listener->processIpn($my_post_data);
+*/
+try {
+ $listener->requirePostMethod();
+ $verified = $listener->processIpn();
+} catch (Exception $e) {
+ error_log($e->getMessage());
+ exit(0);
+}
+
+
+/*
+The processIpn() method returned true if the IPN was "VERIFIED" and false if it
+was "INVALID".
+*/
+if ($verified) {
+ /*
+ Once you have a verified IPN you need to do a few more checks on the POST
+ fields--typically against data you stored in your database during when the
+ end user made a purchase (such as in the "success" page on a web payments
+ standard button). The fields PayPal recommends checking are:
+
+ 1. Check the $_POST['payment_status'] is "Completed"
+ 2. Check that $_POST['txn_id'] has not been previously processed
+ 3. Check that $_POST['receiver_email'] is your Primary PayPal email
+ 4. Check that $_POST['payment_amount'] and $_POST['payment_currency']
+ are correct
+
+ Since implementations on this varies, I will leave these checks out of this
+ example and just send an email using the getTextReport() method to get all
+ of the details about the IPN.
+ */
+ mail('YOUR EMAIL ADDRESS', 'Verified IPN', $listener->getTextReport());
+
+} else {
+ /*
+ An Invalid IPN *may* be caused by a fraudulent transaction attempt. It's
+ a good idea to have a developer or sys admin manually investigate any
+ invalid IPN.
+ */
+ mail('YOUR EMAIL ADDRESS', 'Invalid IPN', $listener->getTextReport());
+}
+
+?>
diff --git a/modules/thirdparty/ipnlistener/example/ipn_errors.log b/modules/thirdparty/ipnlistener/example/ipn_errors.log
new file mode 100755
index 0000000..e69de29
diff --git a/modules/thirdparty/ipnlistener/ipnlistener.php b/modules/thirdparty/ipnlistener/ipnlistener.php
new file mode 100755
index 0000000..bb8c93d
--- /dev/null
+++ b/modules/thirdparty/ipnlistener/ipnlistener.php
@@ -0,0 +1,312 @@
+use_ssl) {
+ $uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr';
+ $this->post_uri = $uri;
+ } else {
+ $uri = 'http://'.$this->getPaypalHost().'/cgi-bin/webscr';
+ $this->post_uri = $uri;
+ }
+
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+ curl_setopt($ch, CURLOPT_CAINFO,
+ dirname(__FILE__)."/cert/api_cert_chain.crt");
+ curl_setopt($ch, CURLOPT_URL, $uri);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location);
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HEADER, true);
+
+ if ($this->force_ssl_v3) {
+ curl_setopt($ch, CURLOPT_SSLVERSION, 3);
+ }
+
+ $this->response = curl_exec($ch);
+ $this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
+
+ if ($this->response === false || $this->response_status == '0') {
+ $errno = curl_errno($ch);
+ $errstr = curl_error($ch);
+ throw new Exception("cURL error: [$errno] $errstr");
+ }
+ }
+
+ /**
+ * Post Back Using fsockopen()
+ *
+ * Sends the post back to PayPal using the fsockopen() function. Called by
+ * the processIpn() method if the use_curl property is false. Throws an
+ * exception if the post fails. Populates the response, response_status,
+ * and post_uri properties on success.
+ *
+ * @param string The post data as a URL encoded string
+ */
+ protected function fsockPost($encoded_data) {
+
+ if ($this->use_ssl) {
+ $uri = 'ssl://'.$this->getPaypalHost();
+ $port = '443';
+ $this->post_uri = $uri.'/cgi-bin/webscr';
+ } else {
+ $uri = $this->getPaypalHost(); // no "http://" in call to fsockopen()
+ $port = '80';
+ $this->post_uri = 'http://'.$uri.'/cgi-bin/webscr';
+ }
+
+ $fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout);
+
+ if (!$fp) {
+ // fsockopen error
+ throw new Exception("fsockopen error: [$errno] $errstr");
+ }
+
+ $header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
+ $header .= "Host: ".$this->getPaypalHost()."\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: ".strlen($encoded_data)."\r\n";
+ $header .= "Connection: Close\r\n\r\n";
+
+ fputs($fp, $header.$encoded_data."\r\n\r\n");
+
+ while(!feof($fp)) {
+ if (empty($this->response)) {
+ // extract HTTP status from first line
+ $this->response .= $status = fgets($fp, 1024);
+ $this->response_status = trim(substr($status, 9, 4));
+ } else {
+ $this->response .= fgets($fp, 1024);
+ }
+ }
+
+ fclose($fp);
+ }
+
+ private function getPaypalHost() {
+ if ($this->use_sandbox) return self::SANDBOX_HOST;
+ else return self::PAYPAL_HOST;
+ }
+
+ /**
+ * Get POST URI
+ *
+ * Returns the URI that was used to send the post back to PayPal. This can
+ * be useful for troubleshooting connection problems. The default URI
+ * would be "ssl://www.sandbox.paypal.com:443/cgi-bin/webscr"
+ *
+ * @return string
+ */
+ public function getPostUri() {
+ return $this->post_uri;
+ }
+
+ /**
+ * Get Response
+ *
+ * Returns the entire response from PayPal as a string including all the
+ * HTTP headers.
+ *
+ * @return string
+ */
+ public function getResponse() {
+ return $this->response;
+ }
+
+ /**
+ * Get Response Status
+ *
+ * Returns the HTTP response status code from PayPal. This should be "200"
+ * if the post back was successful.
+ *
+ * @return string
+ */
+ public function getResponseStatus() {
+ return $this->response_status;
+ }
+
+ /**
+ * Get Text Report
+ *
+ * Returns a report of the IPN transaction in plain text format. This is
+ * useful in emails to order processors and system administrators. Override
+ * this method in your own class to customize the report.
+ *
+ * @return string
+ */
+ public function getTextReport() {
+
+ $r = '';
+
+ // date and POST url
+ for ($i=0; $i<80; $i++) { $r .= '-'; }
+ $r .= "\n[".date('m/d/Y g:i A').'] - '.$this->getPostUri();
+ if ($this->use_curl) $r .= " (curl)\n";
+ else $r .= " (fsockopen)\n";
+
+ // HTTP Response
+ for ($i=0; $i<80; $i++) { $r .= '-'; }
+ $r .= "\n{$this->getResponse()}\n";
+
+ // POST vars
+ for ($i=0; $i<80; $i++) { $r .= '-'; }
+ $r .= "\n";
+
+ foreach ($this->post_data as $key => $value) {
+ $r .= str_pad($key, 25)."$value\n";
+ }
+ $r .= "\n\n";
+
+ return $r;
+ }
+
+ /**
+ * Process IPN
+ *
+ * Handles the IPN post back to PayPal and parsing the response. Call this
+ * method from your IPN listener script. Returns true if the response came
+ * back as "VERIFIED", false if the response came back "INVALID", and
+ * throws an exception if there is an error.
+ *
+ * @param array
+ *
+ * @return boolean
+ */
+ public function processIpn($post_data=null) {
+
+ $encoded_data = 'cmd=_notify-validate';
+
+ if ($post_data === null) {
+ // use raw POST data
+ if (!empty($_POST)) {
+ $this->post_data = $_POST;
+ $encoded_data .= '&'.file_get_contents('php://input');
+ } else {
+ throw new Exception("No POST data found.");
+ }
+ } else {
+ // use provided data array
+ $this->post_data = $post_data;
+
+ foreach ($this->post_data as $key => $value) {
+ $encoded_data .= "&$key=".urlencode($value);
+ }
+ }
+
+ if ($this->use_curl) $this->curlPost($encoded_data);
+ else $this->fsockPost($encoded_data);
+
+ if (strpos($this->response_status, '200') === false) {
+ throw new Exception("Invalid response status: ".$this->response_status);
+ }
+
+ if (strpos($this->response, "VERIFIED") !== false) {
+ return true;
+ } elseif (strpos($this->response, "INVALID") !== false) {
+ return false;
+ } else {
+ throw new Exception("Unexpected response from PayPal.");
+ }
+ }
+
+ /**
+ * Require Post Method
+ *
+ * Throws an exception and sets a HTTP 405 response header if the request
+ * method was not POST.
+ */
+ public function requirePostMethod() {
+ // require POST requests
+ if ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') {
+ header('Allow: POST', true, 405);
+ throw new Exception("Invalid HTTP request method.");
+ }
+ }
+}
+
diff --git a/modules/thirdparty/jquery/barcode/jquery.barcode.min.js b/modules/thirdparty/jquery/barcode/jquery.barcode.min.js
new file mode 100644
index 0000000..55e37e3
--- /dev/null
+++ b/modules/thirdparty/jquery/barcode/jquery.barcode.min.js
@@ -0,0 +1,16 @@
+/*
+ * BarCode Coder Library (BCC Library)
+ * BCCL Version 2.0
+ *
+ * Porting : jQuery barcode plugin
+ * Version : 2.0.2
+ *
+ * Date : March 01, 2011
+ * Author : DEMONTE Jean-Baptiste
+ * HOUREZ Jonathan
+ *
+ * Web site: http://barcode-coder.com/
+ * dual licence : http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
+ * http://www.gnu.org/licenses/gpl.html
+ */
+(function(b){var a={settings:{barWidth:1,barHeight:50,moduleSize:5,showHRI:true,addQuietZone:true,marginHRI:5,bgColor:"#FFFFFF",color:"#000000",fontSize:10,output:"css",posX:0,posY:0},intval:function(d){var c=typeof(d);if(c=="string"){d=d.replace(/[^0-9-.]/g,"");d=parseInt(d*1,10);return isNaN(d)||!isFinite(d)?0:d}return c=="number"&&isFinite(d)?Math.floor(d):0},i25:{encoding:["NNWWN","WNNNW","NWNNW","WWNNN","NNWNW","WNWNN","NWWNN","NNNWW","WNNWN","NWNWN"],compute:function(g,j,f){if(!j){if(g.length%2!=0){g="0"+g}}else{if((f=="int25")&&(g.length%2==0)){g="0"+g}var h=true,c,e=0;for(var d=g.length-1;d>-1;d--){c=a.intval(g.charAt(d));if(isNaN(c)){return("")}e+=h?3*c:c;h=!h}g+=((10-e%10)%10).toString()}return(g)},getDigit:function(k,l,h){k=this.compute(k,l,h);if(k==""){return("")}result="";var f,d;if(h=="int25"){result+="1010";var g,e;for(f=0;f"9")){return("")}}h=this.compute(h,g);var j="101";if(g=="ean8"){for(var f=0;f<4;f++){j+=this.encoding[a.intval(h.charAt(f))][0]}j+="01010";for(var f=4;f<8;f++){j+=this.encoding[a.intval(h.charAt(f))][2]}}else{var e=this.first[a.intval(h.charAt(0))];for(var f=1;f<7;f++){j+=this.encoding[a.intval(h.charAt(f))][a.intval(e.charAt(f-1))]}j+="01010";for(var f=7;f<13;f++){j+=this.encoding[a.intval(h.charAt(f))][2]}}j+="101";return(j)},compute:function(f,e){var c=e=="ean13"?12:7;f=f.substring(0,c);var d=0,g=true;for(i=f.length-1;i>-1;i--){d+=(g?3:1)*a.intval(f.charAt(i));g=!g}return(f+((10-d%10)%10).toString())}},msi:{encoding:["100100100100","100100100110","100100110100","100100110110","100110100100","100110100110","100110110100","100110110110","110100100100","110100100110"],compute:function(c,d){if(typeof(d)=="object"){if(d.crc1=="mod10"){c=this.computeMod10(c)}else{if(d.crc1=="mod11"){c=this.computeMod11(c)}}if(d.crc2=="mod10"){c=this.computeMod10(c)}else{if(d.crc2=="mod11"){c=this.computeMod11(c)}}}else{if(typeof(d)=="boolean"){if(d){c=this.computeMod10(c)}}}return(c)},computeMod10:function(h){var d,g=h.length%2;var f=0,e=0;for(d=0;d=0;d--){e+=c*a.intval(f.charAt(d));c=c==7?2:c+1}return(f+((11-e%11)%11).toString())},getDigit:function(e,g){var d="0123456789";var c=0;var f="";e=this.compute(e,false);f="110";for(i=0;i=0;g--){p=p==10?1:p+1;j=j==10?1:j+1;l=q.indexOf(d.charAt(g));e+=p*l;m+=j*l}var n=e%11;m+=n;var f=m%11;o+=this.encoding[n]+h;if(d.length>=10){o+=this.encoding[f]+h}o+="1011001";return(o)}},code39:{encoding:["101001101101","110100101011","101100101011","110110010101","101001101011","110100110101","101100110101","101001011011","110100101101","101100101101","110101001011","101101001011","110110100101","101011001011","110101100101","101101100101","101010011011","110101001101","101101001101","101011001101","110101010011","101101010011","110110101001","101011010011","110101101001","101101101001","101010110011","110101011001","101101011001","101011011001","110010101011","100110101011","110011010101","100101101011","110010110101","100110110101","100101011011","110010101101","100110101101","100100100101","100100101001","100101001001","101001001001","100101101101"],getDigit:function(f){var e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*";var d,c,h="",g="0";if(f.indexOf("*")>=0){return("")}f=("*"+f+"*").toUpperCase();for(d=0;d0){h+=g}h+=this.encoding[c]}return(h)}},code93:{encoding:["100010100","101001000","101000100","101000010","100101000","100100100","100100010","101010000","100010010","100001010","110101000","110100100","110100010","110010100","110010010","110001010","101101000","101100100","101100010","100110100","100011010","101011000","101001100","101000110","100101100","100010110","110110100","110110010","110101100","110100110","110010110","110011010","101101100","101100110","100110110","100111010","100101110","111010100","111010010","111001010","101101110","101110110","110101110","100100110","111011010","111010110","100110010","101011110"],getDigit:function(d,h){var o="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%____*",l,m="";if(d.indexOf("*")>=0){return("")}d=d.toUpperCase();m+=this.encoding[47];for(i=0;i=0;i--){n=n==20?1:n+1;g=g==15?1:g+1;index=o.indexOf(d.charAt(i));e+=n*index;j+=g*index}var l=e%47;j+=l;var f=j%47;m+=this.encoding[l];m+=this.encoding[f]}m+=this.encoding[47];m+="1";return(m)}},code128:{encoding:["11011001100","11001101100","11001100110","10010011000","10010001100","10001001100","10011001000","10011000100","10001100100","11001001000","11001000100","11000100100","10110011100","10011011100","10011001110","10111001100","10011101100","10011100110","11001110010","11001011100","11001001110","11011100100","11001110100","11101101110","11101001100","11100101100","11100100110","11101100100","11100110100","11100110010","11011011000","11011000110","11000110110","10100011000","10001011000","10001000110","10110001000","10001101000","10001100010","11010001000","11000101000","11000100010","10110111000","10110001110","10001101110","10111011000","10111000110","10001110110","11101110110","11010001110","11000101110","11011101000","11011100010","11011101110","11101011000","11101000110","11100010110","11101101000","11101100010","11100011010","11101111010","11001000010","11110001010","10100110000","10100001100","10010110000","10010000110","10000101100","10000100110","10110010000","10110000100","10011010000","10011000010","10000110100","10000110010","11000010010","11001010000","11110111010","11000010100","10001111010","10100111100","10010111100","10010011110","10111100100","10011110100","10011110010","11110100100","11110010100","11110010010","11011011110","11011110110","11110110110","10101111000","10100011110","10001011110","10111101000","10111100010","11110101000","11110100010","10111011110","10111101110","11101011110","11110101110","11010000100","11010010000","11010011100","11000111010"],getDigit:function(d){var m=" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";var n="";var k=0;var e=0;var h=0;var g=0;var o=0;for(h=0;h1;var l="";for(h=0;h<3&&h="0"&&l<="9"}k=f?105:104;n=this.encoding[k];h=0;while(h="0")&&(d.charAt(h+g)<="9")){g++}f=(g>5)||((h+g-1==d.length)&&(g>3));if(f){n+=this.encoding[99];k+=++e*99}}else{if((h==d.length)||(d.charAt(h)<"0")||(d.charAt(h)>"9")||(d.charAt(h+1)<"0")||(d.charAt(h+1)>"9")){f=false;n+=this.encoding[100];k+=++e*100}}if(f){o=a.intval(d.charAt(h)+d.charAt(h+1));h+=2}else{o=m.indexOf(d.charAt(h));h+=1}n+=this.encoding[o];k+=++e*o}n+=this.encoding[k%103];n+=this.encoding[106];n+="11";return(n)}},codabar:{encoding:["101010011","101011001","101001011","110010101","101101001","110101001","100101011","100101101","100110101","110100101","101001101","101100101","1101011011","1101101011","1101101101","1011011011","1011001001","1010010011","1001001011","1010011001"],getDigit:function(f){var e="0123456789-$:/.+";var d,c,h="",g="0";h+=this.encoding[16]+g;for(d=0;d1558)&&!d){return -1}if((c<1||c>49)&&d){return -1}var e=0;if(d){e=24}while(this.dataCWCount[e]127){e[h]=235;g=g-127;h++}else{if((g>=48&&g<=57)&&(d+1=48&&f.charCodeAt(d+1)<=57)){g=((g-48)*10)+((f.charCodeAt(d+1))-48);g+=130;d++}else{g++}}e[h]=g;h++}return e},addPadCW:function(d,g,f){if(g>=f){return}d[g]=129;var e,c;for(c=g+1;c=0;d--){f[d]=this.champGaloisDoub(f[d],e);if(d>0){f[d]=this.champGaloisSum(f[d],f[d-1])}}}return f},addReedSolomonCW:function(c,g,l,m,h){var o=0;var n=c/h;var p=new Array();var f,e,d;for(d=0;d=0;e--){if(!o){p[e]=0}else{p[e]=this.champGaloisMult(o,g[e])}if(e>0){p[e]=this.champGaloisSum(p[e-1],p[e])}}}e=l+d;for(f=n-1;f>=0;f--){m[e]=p[f];e=e+h}}return m},getBits:function(d){var e=new Array();for(var c=0;c<8;c++){e[c]=d&(128>>c)?1:0}return e},next:function(h,k,d,j,g,c){var f=0;var l=4;var e=0;do{if((l==k)&&(e==0)){this.patternShapeSpecial1(g,c,j[f],k,d);f++}else{if((h<3)&&(l==k-2)&&(e==0)&&(d%4!=0)){this.patternShapeSpecial2(g,c,j[f],k,d);f++}else{if((l==k-2)&&(e==0)&&(d%8==4)){this.patternShapeSpecial3(g,c,j[f],k,d);f++}else{if((l==k+4)&&(e==2)&&(d%8==0)){this.patternShapeSpecial4(g,c,j[f],k,d);f++}}}}do{if((l=0)&&(c[l][e]!=1)){this.patternShapeStandard(g,c,j[f],l,e,k,d);f++}l-=2;e+=2}while((l>=0)&&(e=0)&&(e=0));l+=3;e+=1}while((l>8}return d},cRgb:function(e,d,c){return String.fromCharCode(c)+String.fromCharCode(d)+String.fromCharCode(e)},cHexColor:function(h){var d=parseInt("0x"+h.substr(1));var c=d&255;d=d>>8;var f=d&255;var e=d>>8;return(this.cRgb(e,f,c))}},hexToRGB:function(h){var d=parseInt("0x"+h.substr(1));var c=d&255;d=d>>8;var f=d&255;var e=d>>8;return({r:e,g:f,b:c})},isHexColor:function(d){var c=new RegExp("#[0-91-F]","gi");return d.match(c)},base64Encode:function(o){var c="",h,f,e,n,m,l,j;var d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var g=0;while(g>2;m=((h&3)<<4)|(f>>4);l=((f&15)<<2)|(e>>6);j=e&63;if(isNaN(f)){l=j=64}else{if(isNaN(e)){j=64}}c+=d.charAt(n)+d.charAt(m)+d.charAt(l)+d.charAt(j)}return c},bitStringTo2DArray:function(f){var e=[];e[0]=[];for(var c=0;c=0;h--){var l="";for(var j=0;j';var l='';var f,h;for(var k=0;k0){j+=(h=="0"?o:l).replace("&W",f*p)}}if(d.showHRI){j+='
+ AutoFill provides a number of customisable callback functions so you can tailor it's
+ actions to exactly what you need. This specific example shows fnCallback, which is fired when the mouse is released. Further documentation is below.
+
+
+
+
+ fnRead - Called when a cell is read for it's value. This allows you to override the default of reading the HTML value (or 'input' elements value if there is one present). For example reading the value from a select list.
+
+
Parameter 1: Node - TD element to be read from
+
Returns: String - read value
+
+
+
+ fnWrite - Called when a cell is to read to. This allows you to write in a specific format, or perhaps to an element within the cell.
+
+
Parameter 1: Node - TD element to be written to
+
Parameter 2: String - Value to write
+
Parameter 3: Boolean - Last cell to be written (useful for speeding up DataTables' fnUpdate)
+
Returns: void
+
+
+
+ fnStep - Called to calculate the new value to give to a cell
+
+
Parameter 1: Node - TD element to be written to
+
Parameter 2: String - Statement with a token to be replace with the calculated value
+
Parameter 3: Int - Step counter
+
Parameter 4: Boolean - increment (true), or decrement (false)
+
Parameter 5: String - Token to replace
+
Returns: String - string to write into the cell
+
+
+
+ fnCallback - Called when the AutoFill is complete, with information about the fill. This can be useful for updating a server database for example.
+
+
Parameter 1: Array - An array of objects with information about each cell that was written to. Object parameters are: "td", "newValue" and "oldValue".
$(document).ready( function () {
+ var oTable = $('#example').dataTable();
+ new AutoFill( oTable, {
+ "aoColumnDefs": [ {
+ "fnCallback": function ( ao ) {
+ var n = document.getElementById('output');
+ for ( var i=0, iLen=ao.length ; i<iLen ; i++ ) {
+ n.innerHTML += "Update: old value: {"+
+ ao[i].oldValue+"} - new value: {"+ao[i].newValue+"}<br>";
+ }
+ n.scrollTop = n.scrollHeight;
+ },
+ "aTargets": [ "_all" ]
+ } ]
+ } );
+} );
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/columns.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/columns.html
new file mode 100755
index 0000000..2d7ad1d
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/columns.html
@@ -0,0 +1,503 @@
+
+
+
+
+
+
+ AutoFill example
+
+
+
+
+
+
+
+
+
+ AutoFill example with column selection options
+
+
+
Preamble
+
+ Columns can be enabled (default) and disabled from providing the end user the AutoFill option
+ by using either aoColumns or aoColumnDefs and the bEnable option. These two arrays work in
+ exactly the same way has for DataTables.
+
+
+ This example shows how disabling columns counting from the right hand side of the table
+ can be achieved. In this case, the last three columns.
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/index.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/index.html
new file mode 100755
index 0000000..c9e9557
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/index.html
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+ AutoFill example
+
+
+
+
+
+
+
+
+
+ AutoFill example
+
+
+
Preamble
+
+ AutoFill gives an Excel like option to a DataTable to click and drag over multiple
+ cells, filling in information over the selected cells and incrementing numbers as needed.
+
+
Thanks to Phoniax AS for their sponsorship of this plug-in for DataTables.
$(document).ready( function () {
+ var oTable = $('#example').dataTable();
+ new AutoFill( oTable );
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/inputs.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/inputs.html
new file mode 100755
index 0000000..bdb9140
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/inputs.html
@@ -0,0 +1,519 @@
+
+
+
+
+
+
+ AutoFill example
+
+
+
+
+
+
+
+
+
+ AutoFill example with input elements
+
+
+
Preamble
+
+ AutoFill works with Input elements and Select elements, as well as plain HTML cells. This
+ example shows all inputs cells, combined with DataTables' DOM sorting plug-in. You can
+ even combine input and plain HTML cells if you wanted (useful from something like jEditable).
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/5a72546831.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/5a72546831.html
new file mode 100644
index 0000000..64d1cee
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/5a72546831.html
@@ -0,0 +1,77 @@
+
+
+
+
+ Namespace: Data cache for the position of the DataTables scrolling element (when scrolling
+ is enabled) - documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Namespace: Data cache for the position of the DataTables scrolling element (when scrolling
+ is enabled)
+
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/8ee4007a12.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/8ee4007a12.html
new file mode 100644
index 0000000..effbccd
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/8ee4007a12.html
@@ -0,0 +1,77 @@
+
+
+
+
+ Namespace: Data cache for information that we need for scrolling the screen when we near
+ the edges - documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Namespace: Data cache for information that we need for scrolling the screen when we near
+ the edges
AutoFill provides Excel like auto fill features for a DataTable
Constructor
+
+
+
Parameters:
+
+
+
+
+
+
Name
+
Type
+
Attributes
+
Default
+
Description
+
+
+
+
+
1
DataTables
object
settings object
2
Configuration
object
object for AutoFill
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/a69b02bcf2.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/a69b02bcf2.html
new file mode 100644
index 0000000..194635b
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/a69b02bcf2.html
@@ -0,0 +1,75 @@
+
+
+
+
+ Namespace: Common and useful DOM elements for the class instance - documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Namespace: Common and useful DOM elements for the class instance
AutoFill provides Excel like auto fill features for a DataTable
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/doc.css b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/doc.css
new file mode 100644
index 0000000..a239329
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/doc.css
@@ -0,0 +1,393 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.12.0
+*/
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}
+table{border-collapse:collapse;border-spacing:0;}
+fieldset,img{border:0;}
+address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
+ol,ul {list-style:none;}
+caption,th {text-align:left;}
+h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}
+q:before,q:after{content:'';}
+abbr,acronym {border:0;}
+
+
+html, body {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ font: 14px/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
+ color: #111;
+}
+
+div.fw_container {
+ width: 980px;
+ padding-top: 2em;
+ margin: 0 auto;
+}
+
+div.fw_header {
+ position: relative;
+}
+
+div.fw_content {
+ padding-top: 2em;
+}
+
+div.fw_footer {
+ padding-top: 4em;
+ font-size: 75%;
+ text-align: center;
+}
+
+
+
+
+.type-attr .type-signature {
+ background-color: #ccc;
+ color: white;
+ border-radius: 3px;
+ display: inline-block;
+ padding: 0 3px;
+ font-size: 0.9em;
+}
+
+.type-attr {
+ float: right;
+ color: #999;
+}
+
+.type-name {
+ font-weight: bold;
+}
+
+.type-sig {
+ color: #999;
+}
+
+.type-param {
+ color: #D32929;
+}
+
+.type-return {
+ color: #FF8080;
+}
+
+.type-brace {
+ color: #111;
+}
+
+.example-code {
+ margin-left: 30px;
+}
+.example-code td.code {
+ border-top: 1px solid #4E6CA3 !important;
+}
+
+.type-augmented {
+ position: absolute;
+ left: 8px;
+ top: 0;
+}
+
+dt, dd {
+ padding: 0.4em 10px;
+}
+
+dt {
+ padding-bottom: 0 !important;
+}
+
+dd {
+ position: relative;
+ padding-top: 0 !important;
+ padding-left: 3em;
+}
+
+dt.even, dd.even {
+ background-color: white;
+}
+
+dt.odd, dd.odd {
+ background-color: #F2F2F2;
+}
+
+div.doc_overview dd, div.doc_overview dt {
+ padding-left: 0 !important;
+}
+
+
+
+.right_border div {
+ width: 20px;
+ padding: 2px 0.5em 2px 1em;
+ text-align: right;
+}
+.right_border {
+ border-right: 3px solid #4E6CA3;
+}
+.bottom_border {
+ border-bottom: 1px solid #4E6CA3;
+}
+
+
+a {
+ text-decoration: none;
+ color: #4E6CA3;
+}
+
+a:hover {
+ text-decoration: underline;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+div.fw_content ul {
+ list-style-image: url('../images/arrow.png');
+ padding: 0 0 0 2em;
+}
+
+/*
+h2 {
+ font-size: 1.4em;
+ margin-top: 2em;
+ border-bottom: 3px solid #829ac6;
+ padding-left: 5px;
+}
+
+h3 {
+ font-size: 1.2em;
+ margin-top: 1em;
+ border-bottom: 1px solid #A4B5D5;
+ padding-left: 5px;
+}
+*/
+
+h1 {
+ font-size: 2em;
+}
+
+h2 {
+ font-size: 1.6em;
+ padding-top: 5px;
+}
+
+h2.ancestors {
+ font-size: 14px;
+ margin: 0;
+}
+
+h3 {
+ font-size: 1.3em;
+ padding-top: 5px;
+ margin-bottom: 5px;
+}
+
+h5 {
+ padding-top: 6px;
+ font-weight: bold;
+ font-size: 0.9em;
+ border-bottom: 1px solid #cad4e6;
+ margin-bottom: 1em;
+}
+
+div.doc_summary, div.doc_details {
+ margin-top: 2em;
+ clear: both;
+}
+
+div.doc_group {
+ margin-top: 1em;
+ border-top: 1px solid #A4B5D5;
+ border-left: 1px solid #A4B5D5;
+ padding-left: 10px;
+}
+
+div.extended {
+ margin-left: 30px;
+}
+
+table.params {
+ margin-left: 30px;
+ width: 97%;
+}
+
+table.params th,
+table.params td {
+ padding: 3px;
+}
+
+tr.odd {
+ background-color: white;
+}
+
+tr.even {
+ background-color: #F8F8F8;
+}
+
+th.name,
+td.name {
+ padding-left: 13px;
+}
+
+td.number {
+ background-color: white;
+ color: #5C5C5C;
+}
+
+dd.odd td.number {
+ background-color: #F2F2F2;
+}
+
+p {
+ margin: 1em 0;
+}
+
+p:first-child {
+ margin-top: 0;
+}
+
+p:last-child {
+ margin-bottom: 0;
+}
+
+p.returns {
+ margin-left: 5%;
+}
+
+div.page-info {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+
+
+.private {
+ display: none;
+}
+
+
+code {
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+ padding: 2px 4px !important;
+ white-space: pre;
+ font-size: 0.9em;
+
+ color: #D14;
+ background-color: #F7F7F9;
+
+ border: 1px solid #E1E1E8;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+pre {
+ background-color: #f8f8f8;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ padding: 6px 10px;
+}
+
+pre>code {
+ background-color: transparent;
+ border: none;
+ color: #111;
+}
+
+strong {
+ font-weight: bold;
+}
+
+em {
+ font-style: italic;
+}
+
+ol {
+ list-style-type: decimal;
+ list-style-position: outside;
+ padding-left: 30px;
+}
+
+
+
+div.fw_nav {
+ position: fixed;
+ top: 25px;
+ right: 30px;
+ width: 250px;
+ border: 1px solid #A4B5D5;
+ background-color: white;
+ padding: 10px;
+ z-index: 1001;
+ font-size: 12px;
+ overflow: hidden;
+}
+
+div.fw_nav h2 {
+ margin: -10px 0 10px -10px;
+ width: 250px;
+ padding: 5px 10px;
+ background-color: #A4B5D5;
+ font-size: 12px;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+div.fw_nav ul>li>div {
+ padding: 0 0 0 1em;
+}
+
+div.nav_blocker {
+ float: right;
+}
+
+div.fw_nav td {
+ color: #999;
+}
+
+div.fw_nav li {
+ margin-bottom: 5px;
+}
+
+div.fw_nav li>a {
+ font-weight: bold;
+}
+
+
+
+
+
+
+
+.css_clear {
+ clear: both;
+ height: 0;
+ line-height: 0;
+ visibility: hidden;
+}
+
+.css_right {
+ text-align: right;
+}
+
+.css_center {
+ text-align: center;
+}
+
+.css_spacing {
+ margin-top: 1.5em;
+}
+
+.css_small {
+ font-size: 75%;
+ line-height: 1.45em;
+}
+
+.css_vsmall {
+ font-size: 65%;
+ line-height: 1.45em;
+}
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shCore.css b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shCore.css
new file mode 100644
index 0000000..b0c4520
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shCore.css
@@ -0,0 +1,226 @@
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/SyntaxHighlighter
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
+ *
+ * @version
+ * 3.0.83 (July 02 2010)
+ *
+ * @copyright
+ * Copyright (C) 2004-2010 Alex Gorbatchev.
+ *
+ * @license
+ * Dual licensed under the MIT and GPL licenses.
+ */
+.syntaxhighlighter a,
+.syntaxhighlighter div,
+.syntaxhighlighter code,
+.syntaxhighlighter table,
+.syntaxhighlighter table td,
+.syntaxhighlighter table tr,
+.syntaxhighlighter table tbody,
+.syntaxhighlighter table thead,
+.syntaxhighlighter table caption,
+.syntaxhighlighter textarea {
+ -moz-border-radius: 0 0 0 0 !important;
+ -webkit-border-radius: 0 0 0 0 !important;
+ background: none !important;
+ border: 0 !important;
+ bottom: auto !important;
+ float: none !important;
+ height: auto !important;
+ left: auto !important;
+ line-height: 1.1em !important;
+ margin: 0 !important;
+ outline: 0 !important;
+ overflow: visible !important;
+ padding: 0 !important;
+ position: static !important;
+ right: auto !important;
+ text-align: left !important;
+ top: auto !important;
+ vertical-align: baseline !important;
+ width: auto !important;
+ box-sizing: content-box !important;
+ font-family: "Consolas","Monaco","Bitstream Vera Sans Mono","Courier New",Courier,monospace !important;
+ font-weight: normal !important;
+ font-style: normal !important;
+ font-size: 1em !important;
+ min-height: inherit !important;
+ min-height: auto !important;
+}
+
+.syntaxhighlighter {
+ width: 100% !important;
+ margin: 1em 0 1em 0 !important;
+ position: relative !important;
+ overflow: auto !important;
+ font-size: 1em !important;
+}
+.syntaxhighlighter.source {
+ overflow: hidden !important;
+}
+.syntaxhighlighter .bold {
+ font-weight: bold !important;
+}
+.syntaxhighlighter .italic {
+ font-style: italic !important;
+}
+.syntaxhighlighter .line {
+ white-space: pre !important;
+}
+.syntaxhighlighter table {
+ width: 100% !important;
+}
+.syntaxhighlighter table caption {
+ text-align: left !important;
+ padding: .5em 0 0.5em 1em !important;
+}
+.syntaxhighlighter table td.code {
+ width: 100% !important;
+}
+.syntaxhighlighter table td.code .container {
+ position: relative !important;
+}
+.syntaxhighlighter table td.code .container textarea {
+ box-sizing: border-box !important;
+ position: absolute !important;
+ left: 0 !important;
+ top: 0 !important;
+ width: 100% !important;
+ height: 100% !important;
+ border: none !important;
+ background: white !important;
+ padding-left: 1em !important;
+ overflow: hidden !important;
+ white-space: pre !important;
+}
+.syntaxhighlighter table td.gutter .line {
+ text-align: right !important;
+ padding: 2px 0.5em 2px 1em !important;
+}
+.syntaxhighlighter table td.code .line {
+ padding: 2px 1em !important;
+}
+.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
+ padding-left: 0em !important;
+}
+.syntaxhighlighter.show {
+ display: block !important;
+}
+.syntaxhighlighter.collapsed table {
+ display: none !important;
+}
+.syntaxhighlighter.collapsed .toolbar {
+ padding: 0.1em 0.8em 0em 0.8em !important;
+ font-size: 1em !important;
+ position: static !important;
+ width: auto !important;
+ height: auto !important;
+}
+.syntaxhighlighter.collapsed .toolbar span {
+ display: inline !important;
+ margin-right: 1em !important;
+}
+.syntaxhighlighter.collapsed .toolbar span a {
+ padding: 0 !important;
+ display: none !important;
+}
+.syntaxhighlighter.collapsed .toolbar span a.expandSource {
+ display: inline !important;
+}
+.syntaxhighlighter .toolbar {
+ position: absolute !important;
+ right: 1px !important;
+ top: 1px !important;
+ width: 11px !important;
+ height: 11px !important;
+ font-size: 10px !important;
+ z-index: 10 !important;
+}
+.syntaxhighlighter .toolbar span.title {
+ display: inline !important;
+}
+.syntaxhighlighter .toolbar a {
+ display: block !important;
+ text-align: center !important;
+ text-decoration: none !important;
+ padding-top: 1px !important;
+}
+.syntaxhighlighter .toolbar a.expandSource {
+ display: none !important;
+}
+.syntaxhighlighter.ie {
+ font-size: .9em !important;
+ padding: 1px 0 1px 0 !important;
+}
+.syntaxhighlighter.ie .toolbar {
+ line-height: 8px !important;
+}
+.syntaxhighlighter.ie .toolbar a {
+ padding-top: 0px !important;
+}
+.syntaxhighlighter.printing .line.alt1 .content,
+.syntaxhighlighter.printing .line.alt2 .content,
+.syntaxhighlighter.printing .line.highlighted .number,
+.syntaxhighlighter.printing .line.highlighted.alt1 .content,
+.syntaxhighlighter.printing .line.highlighted.alt2 .content {
+ background: none !important;
+}
+.syntaxhighlighter.printing .line .number {
+ color: #bbbbbb !important;
+}
+.syntaxhighlighter.printing .line .content {
+ color: black !important;
+}
+.syntaxhighlighter.printing .toolbar {
+ display: none !important;
+}
+.syntaxhighlighter.printing a {
+ text-decoration: none !important;
+}
+.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
+ color: black !important;
+}
+.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
+ color: #008200 !important;
+}
+.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
+ color: blue !important;
+}
+.syntaxhighlighter.printing .keyword {
+ color: #006699 !important;
+ font-weight: bold !important;
+}
+.syntaxhighlighter.printing .preprocessor {
+ color: gray !important;
+}
+.syntaxhighlighter.printing .variable {
+ color: #aa7700 !important;
+}
+.syntaxhighlighter.printing .value {
+ color: #009900 !important;
+}
+.syntaxhighlighter.printing .functions {
+ color: #ff1493 !important;
+}
+.syntaxhighlighter.printing .constants {
+ color: #0066cc !important;
+}
+.syntaxhighlighter.printing .script {
+ font-weight: bold !important;
+}
+.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
+ color: gray !important;
+}
+.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
+ color: #ff1493 !important;
+}
+.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
+ color: red !important;
+}
+.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
+ color: black !important;
+}
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shThemeDataTables.css b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shThemeDataTables.css
new file mode 100644
index 0000000..7e9790a
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shThemeDataTables.css
@@ -0,0 +1,128 @@
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/SyntaxHighlighter
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
+ *
+ * @version
+ * 3.0.83 (July 02 2010)
+ *
+ * @copyright
+ * Copyright (C) 2004-2010 Alex Gorbatchev.
+ *
+ * @license
+ * Dual licensed under the MIT and GPL licenses.
+ */
+.syntaxhighlighter {
+ background-color: white !important;
+ font-size: 14px !important;
+ overflow: visible !important;
+}
+.syntaxhighlighter .line.alt1 {
+ background-color: white !important;
+}
+.syntaxhighlighter .line.alt2 {
+ background-color: #F8F8F8 !important;
+}
+.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
+ background-color: #e0e0e0 !important;
+}
+.syntaxhighlighter .line.highlighted.number {
+ color: black !important;
+}
+.syntaxhighlighter table caption {
+ color: black !important;
+}
+.syntaxhighlighter .gutter {
+}
+.syntaxhighlighter .gutter div {
+ color: #5C5C5C !important;
+ width: 20px !important;
+}
+.syntaxhighlighter .gutter .line.alt1, .syntaxhighlighter .gutter .line.alt2 {
+ background-color: white !important;
+}
+.odd .syntaxhighlighter .gutter .line.alt1, .odd .syntaxhighlighter .gutter .line.alt2 {
+ background-color: #F2F2F2 !important;
+}
+.syntaxhighlighter .gutter .line {
+ border-right: 3px solid #4E6CA3 !important;
+}
+.syntaxhighlighter .gutter .line.highlighted {
+ background-color: #4E6CA3 !important;
+ color: white !important;
+}
+.syntaxhighlighter.printing .line .content {
+ border: none !important;
+}
+.syntaxhighlighter.collapsed {
+ overflow: visible !important;
+}
+.syntaxhighlighter.collapsed .toolbar {
+ color: blue !important;
+ background: white !important;
+ border: 1px solid #4E6CA3 !important;
+}
+.syntaxhighlighter.collapsed .toolbar a {
+ color: blue !important;
+}
+.syntaxhighlighter.collapsed .toolbar a:hover {
+ color: red !important;
+}
+.syntaxhighlighter .toolbar {
+ color: white !important;
+ background: #4E6CA3 !important;
+ border: none !important;
+}
+.syntaxhighlighter .toolbar a {
+ color: white !important;
+}
+.syntaxhighlighter .toolbar a:hover {
+ color: black !important;
+}
+.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
+ color: black !important;
+}
+.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
+ color: #008200 !important;
+}
+.syntaxhighlighter .string, .syntaxhighlighter .string a {
+ color: blue !important;
+}
+.syntaxhighlighter .keyword {
+ color: #006699 !important;
+}
+.syntaxhighlighter .preprocessor {
+ color: gray !important;
+}
+.syntaxhighlighter .variable {
+ color: #aa7700 !important;
+}
+.syntaxhighlighter .value {
+ color: #009900 !important;
+}
+.syntaxhighlighter .functions {
+ color: #ff1493 !important;
+}
+.syntaxhighlighter .constants {
+ color: #0066cc !important;
+}
+.syntaxhighlighter .script {
+ font-weight: bold !important;
+ color: #006699 !important;
+ background-color: none !important;
+}
+.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
+ color: gray !important;
+}
+.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
+ color: #ff1493 !important;
+}
+.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
+ color: red !important;
+}
+
+.syntaxhighlighter .keyword {
+ font-weight: bold !important;
+}
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.jpg b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.jpg
new file mode 100644
index 0000000..eba85ea
Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.jpg differ
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.png b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.png
new file mode 100644
index 0000000..08dbbb1
Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.png differ
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/extended.png b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/extended.png
new file mode 100644
index 0000000..5dd01bf
Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/extended.png differ
diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/js/doc.js b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/js/doc.js
new file mode 100644
index 0000000..932d7cf
--- /dev/null
+++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/js/doc.js
@@ -0,0 +1,121 @@
+
+(function() {
+
+var showingNav = true;
+
+$(document).ready( function () {
+ var jqNav = $('div.fw_nav');
+ jqNav.css('right', ($(window).width() - $('div.fw_container').width()) /2);
+
+ var n = $('div.nav_blocker')[0];
+ n.style.height = $(jqNav).outerHeight()+"px";
+ n.style.width = ($(jqNav).outerWidth()+20)+"px";
+
+ SyntaxHighlighter.highlight();
+
+ $('#private_toggle').click( function () {
+ if ( $('input[name=show_private]').val() == 0 ) {
+ $('input[name=show_private]').val( 1 );
+ $('#private_label').html('Showing');
+ $('.private').css('display', 'block');
+ } else {
+ $('input[name=show_private]').val( 0 );
+ $('#private_label').html('Hiding');
+ $('.private').css('display', 'none');
+ }
+ fnWriteCookie();
+ return false;
+ } );
+
+ $('#extended_toggle').click( function () {
+ if ( $('input[name=show_extended]').val() == 0 ) {
+ $('input[name=show_extended]').val( 1 );
+ $('#extended_label').html('Showing');
+ $('.augmented').css('display', 'block');
+ } else {
+ $('input[name=show_extended]').val( 0 );
+ $('#extended_label').html('Hiding');
+ $('.augmented').css('display', 'none');
+ }
+ fnWriteCookie();
+ return false;
+ } );
+
+ var savedHeight = $(jqNav).height();
+ $('div.fw_nav h2').click( function () {
+ if ( showingNav ) {
+ $('div.fw_nav').animate( {
+ "height": 10,
+ "opacity": 0.3
+ } );
+ showingNav = false;
+ } else {
+ $('div.fw_nav').animate( {
+ "height": savedHeight,
+ "opacity": 1
+ } );
+ showingNav = true;
+ }
+ fnWriteCookie();
+ } );
+
+ var cookie = fnReadCookie( 'SpryMedia_JSDoc' );
+ if ( cookie != null ) {
+ var a = cookie.split('-');
+ if ( a[0] == 1 ) {
+ $('#private_toggle').click();
+ }
+ if ( a[1] == 0 ) {
+ $('#extended_toggle').click();
+ }
+ if ( a[2] == 'false' ) {
+ $('div.fw_nav').css('height', 10).css('opacity', 0.3);
+ showingNav = false;
+ }
+ }
+} );
+
+
+function fnWriteCookie()
+{
+ var sVal =
+ $('input[name=show_private]').val()+'-'+
+ $('input[name=show_extended]').val()+'-'+
+ showingNav;
+
+ fnCreateCookie( 'SpryMedia_JSDoc', sVal );
+}
+
+
+function fnCreateCookie( sName, sValue )
+{
+ var iDays = 365;
+ var date = new Date();
+ date.setTime( date.getTime()+(iDays*24*60*60*1000) );
+ var sExpires = "; expires="+date.toGMTString();
+
+ document.cookie = sName+"="+sValue+sExpires+"; path=/";
+}
+
+
+function fnReadCookie( sName )
+{
+ var sNameEQ = sName + "=";
+ var sCookieContents = document.cookie.split(';');
+
+ for( var i=0 ; i)[^>]*$|#([\w\-]+)$)/,
+
+ // Check if a string has a non-whitespace character in it
+ rnotwhite = /\S/,
+
+ // Used for trimming whitespace
+ trimLeft = /^\s+/,
+ trimRight = /\s+$/,
+
+ // Check for digits
+ rdigit = /\d/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+ // Useragent RegExp
+ rwebkit = /(webkit)[ \/]([\w.]+)/,
+ ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+ rmsie = /(msie) ([\w.]+)/,
+ rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
+ // Keep a UserAgent string for use with jQuery.browser
+ userAgent = navigator.userAgent,
+
+ // For matching the engine and version of the browser
+ browserMatch,
+
+ // Has the ready events already been bound?
+ readyBound = false,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // Promise methods
+ promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
+
+ // The ready event handler
+ DOMContentLoaded,
+
+ // Save a reference to some core methods
+ toString = Object.prototype.toString,
+ hasOwn = Object.prototype.hasOwnProperty,
+ push = Array.prototype.push,
+ slice = Array.prototype.slice,
+ trim = String.prototype.trim,
+ indexOf = Array.prototype.indexOf,
+
+ // [[Class]] -> type pairs
+ class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem, ret, doc;
+
+ // Handle $(""), $(null), or $(undefined)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // The body element only exists once, optimize finding it
+ if ( selector === "body" && !context && document.body ) {
+ this.context = document;
+ this[0] = document.body;
+ this.selector = "body";
+ this.length = 1;
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ // Are we dealing with HTML string or an ID?
+ match = quickExpr.exec( selector );
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+ doc = (context ? context.ownerDocument || context : document);
+
+ // If a single string is passed in and it's a single tag
+ // just do a createElement and skip the rest
+ ret = rsingleTag.exec( selector );
+
+ if ( ret ) {
+ if ( jQuery.isPlainObject( context ) ) {
+ selector = [ document.createElement( ret[1] ) ];
+ jQuery.fn.attr.call( selector, context, true );
+
+ } else {
+ selector = [ doc.createElement( ret[1] ) ];
+ }
+
+ } else {
+ ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+ selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
+ }
+
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $("#id")
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return (context || rootjQuery).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if (selector.selector !== undefined) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The current version of jQuery being used
+ jquery: "1.5.1",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return slice.call( this, 0 );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems, name, selector ) {
+ // Build a new jQuery matched element set
+ var ret = this.constructor();
+
+ if ( jQuery.isArray( elems ) ) {
+ push.apply( ret, elems );
+
+ } else {
+ jQuery.merge( ret, elems );
+ }
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ ret.context = this.context;
+
+ if ( name === "find" ) {
+ ret.selector = this.selector + (this.selector ? " " : "") + selector;
+ } else if ( name ) {
+ ret.selector = this.selector + "." + name + "(" + selector + ")";
+ }
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Attach the listeners
+ jQuery.bindReady();
+
+ // Add the callback
+ readyList.done( fn );
+
+ return this;
+ },
+
+ eq: function( i ) {
+ return i === -1 ?
+ this.slice( i ) :
+ this.slice( i, +i + 1 );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ),
+ "slice", slice.call(arguments).join(",") );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ window.$ = _$;
+
+ if ( deep ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+ // A third-party is pushing the ready event forwards
+ if ( wait === true ) {
+ jQuery.readyWait--;
+ }
+
+ // Make sure that the DOM is not already loaded
+ if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger( "ready" ).unbind( "ready" );
+ }
+ }
+ },
+
+ bindReady: function() {
+ if ( readyBound ) {
+ return;
+ }
+
+ readyBound = true;
+
+ // Catch cases where $(document).ready() is called after the
+ // browser event has already occurred.
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Mozilla, Opera and webkit nightlies currently support this event
+ if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else if ( document.attachEvent ) {
+ // ensure firing before onload,
+ // maybe late but safe also for iframes
+ document.attachEvent("onreadystatechange", DOMContentLoaded);
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var toplevel = false;
+
+ try {
+ toplevel = window.frameElement == null;
+ } catch(e) {}
+
+ if ( document.documentElement.doScroll && toplevel ) {
+ doScrollCheck();
+ }
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ // A crude way of determining if an object is a window
+ isWindow: function( obj ) {
+ return obj && typeof obj === "object" && "setInterval" in obj;
+ },
+
+ isNaN: function( obj ) {
+ return obj == null || !rdigit.test( obj ) || isNaN( obj );
+ },
+
+ type: function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ toString.call(obj) ] || "object";
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw msg;
+ },
+
+ parseJSON: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test(data.replace(rvalidescape, "@")
+ .replace(rvalidtokens, "]")
+ .replace(rvalidbraces, "")) ) {
+
+ // Try to use the native JSON parser first
+ return window.JSON && window.JSON.parse ?
+ window.JSON.parse( data ) :
+ (new Function("return " + data))();
+
+ } else {
+ jQuery.error( "Invalid JSON: " + data );
+ }
+ },
+
+ // Cross-browser xml parsing
+ // (xml & tmp used internally)
+ parseXML: function( data , xml , tmp ) {
+
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+
+ tmp = xml.documentElement;
+
+ if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evalulates a script in a global context
+ globalEval: function( data ) {
+ if ( data && rnotwhite.test(data) ) {
+ // Inspired by code by Andrea Giammarchi
+ // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
+ var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement,
+ script = document.createElement( "script" );
+
+ if ( jQuery.support.scriptEval() ) {
+ script.appendChild( document.createTextNode( data ) );
+ } else {
+ script.text = data;
+ }
+
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709).
+ head.insertBefore( script, head.firstChild );
+ head.removeChild( script );
+ }
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ var name, i = 0,
+ length = object.length,
+ isObj = length === undefined || jQuery.isFunction(object);
+
+ if ( args ) {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.apply( object[ name ], args ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.apply( object[ i++ ], args ) === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( var value = object[0];
+ i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
+ }
+ }
+
+ return object;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: trim ?
+ function( text ) {
+ return text == null ?
+ "" :
+ trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( array, results ) {
+ var ret = results || [];
+
+ if ( array != null ) {
+ // The window, strings (and functions) also have 'length'
+ // The extra typeof function check is to prevent crashes
+ // in Safari 2 (See: #3039)
+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+ var type = jQuery.type(array);
+
+ if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
+ push.call( ret, array );
+ } else {
+ jQuery.merge( ret, array );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, array ) {
+ if ( array.indexOf ) {
+ return array.indexOf( elem );
+ }
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === elem ) {
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var i = first.length,
+ j = 0;
+
+ if ( typeof second.length === "number" ) {
+ for ( var l = second.length; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [], retVal;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var ret = [], value;
+
+ // Go through the array, translating each of the items to their
+ // new value (or values).
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Flatten any nested arrays
+ return ret.concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ proxy: function( fn, proxy, thisObject ) {
+ if ( arguments.length === 2 ) {
+ if ( typeof proxy === "string" ) {
+ thisObject = fn;
+ fn = thisObject[ proxy ];
+ proxy = undefined;
+
+ } else if ( proxy && !jQuery.isFunction( proxy ) ) {
+ thisObject = proxy;
+ proxy = undefined;
+ }
+ }
+
+ if ( !proxy && fn ) {
+ proxy = function() {
+ return fn.apply( thisObject || this, arguments );
+ };
+ }
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ if ( fn ) {
+ proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+ }
+
+ // So proxy can be declared as an argument
+ return proxy;
+ },
+
+ // Mutifunctional method to get and set values to a collection
+ // The value/s can be optionally by executed if its a function
+ access: function( elems, key, value, exec, fn, pass ) {
+ var length = elems.length;
+
+ // Setting many attributes
+ if ( typeof key === "object" ) {
+ for ( var k in key ) {
+ jQuery.access( elems, k, key[k], exec, fn, value );
+ }
+ return elems;
+ }
+
+ // Setting one attribute
+ if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = !pass && exec && jQuery.isFunction(value);
+
+ for ( var i = 0; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+
+ return elems;
+ }
+
+ // Getting an attribute
+ return length ? fn( elems[0], key ) : undefined;
+ },
+
+ now: function() {
+ return (new Date()).getTime();
+ },
+
+ // Create a simple deferred (one callbacks list)
+ _Deferred: function() {
+ var // callbacks list
+ callbacks = [],
+ // stored [ context , args ]
+ fired,
+ // to avoid firing when already doing so
+ firing,
+ // flag to know if the deferred has been cancelled
+ cancelled,
+ // the deferred itself
+ deferred = {
+
+ // done( f1, f2, ...)
+ done: function() {
+ if ( !cancelled ) {
+ var args = arguments,
+ i,
+ length,
+ elem,
+ type,
+ _fired;
+ if ( fired ) {
+ _fired = fired;
+ fired = 0;
+ }
+ for ( i = 0, length = args.length; i < length; i++ ) {
+ elem = args[ i ];
+ type = jQuery.type( elem );
+ if ( type === "array" ) {
+ deferred.done.apply( deferred, elem );
+ } else if ( type === "function" ) {
+ callbacks.push( elem );
+ }
+ }
+ if ( _fired ) {
+ deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
+ }
+ }
+ return this;
+ },
+
+ // resolve with given context and args
+ resolveWith: function( context, args ) {
+ if ( !cancelled && !fired && !firing ) {
+ firing = 1;
+ try {
+ while( callbacks[ 0 ] ) {
+ callbacks.shift().apply( context, args );
+ }
+ }
+ // We have to add a catch block for
+ // IE prior to 8 or else the finally
+ // block will never get executed
+ catch (e) {
+ throw e;
+ }
+ finally {
+ fired = [ context, args ];
+ firing = 0;
+ }
+ }
+ return this;
+ },
+
+ // resolve with this as context and given arguments
+ resolve: function() {
+ deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments );
+ return this;
+ },
+
+ // Has this deferred been resolved?
+ isResolved: function() {
+ return !!( firing || fired );
+ },
+
+ // Cancel
+ cancel: function() {
+ cancelled = 1;
+ callbacks = [];
+ return this;
+ }
+ };
+
+ return deferred;
+ },
+
+ // Full fledged deferred (two callbacks list)
+ Deferred: function( func ) {
+ var deferred = jQuery._Deferred(),
+ failDeferred = jQuery._Deferred(),
+ promise;
+ // Add errorDeferred methods, then and promise
+ jQuery.extend( deferred, {
+ then: function( doneCallbacks, failCallbacks ) {
+ deferred.done( doneCallbacks ).fail( failCallbacks );
+ return this;
+ },
+ fail: failDeferred.done,
+ rejectWith: failDeferred.resolveWith,
+ reject: failDeferred.resolve,
+ isRejected: failDeferred.isResolved,
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ if ( obj == null ) {
+ if ( promise ) {
+ return promise;
+ }
+ promise = obj = {};
+ }
+ var i = promiseMethods.length;
+ while( i-- ) {
+ obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
+ }
+ return obj;
+ }
+ } );
+ // Make sure only one callback list will be used
+ deferred.done( failDeferred.cancel ).fail( deferred.cancel );
+ // Unexpose cancel
+ delete deferred.cancel;
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( object ) {
+ var lastIndex = arguments.length,
+ deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ?
+ object :
+ jQuery.Deferred(),
+ promise = deferred.promise();
+
+ if ( lastIndex > 1 ) {
+ var array = slice.call( arguments, 0 ),
+ count = lastIndex,
+ iCallback = function( index ) {
+ return function( value ) {
+ array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value;
+ if ( !( --count ) ) {
+ deferred.resolveWith( promise, array );
+ }
+ };
+ };
+ while( ( lastIndex-- ) ) {
+ object = array[ lastIndex ];
+ if ( object && jQuery.isFunction( object.promise ) ) {
+ object.promise().then( iCallback(lastIndex), deferred.reject );
+ } else {
+ --count;
+ }
+ }
+ if ( !count ) {
+ deferred.resolveWith( promise, array );
+ }
+ } else if ( deferred !== object ) {
+ deferred.resolve( object );
+ }
+ return promise;
+ },
+
+ // Use of jQuery.browser is frowned upon.
+ // More details: http://docs.jquery.com/Utilities/jQuery.browser
+ uaMatch: function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = rwebkit.exec( ua ) ||
+ ropera.exec( ua ) ||
+ rmsie.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+ [];
+
+ return { browser: match[1] || "", version: match[2] || "0" };
+ },
+
+ sub: function() {
+ function jQuerySubclass( selector, context ) {
+ return new jQuerySubclass.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySubclass, this );
+ jQuerySubclass.superclass = this;
+ jQuerySubclass.fn = jQuerySubclass.prototype = this();
+ jQuerySubclass.fn.constructor = jQuerySubclass;
+ jQuerySubclass.subclass = this.subclass;
+ jQuerySubclass.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) {
+ context = jQuerySubclass(context);
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass );
+ };
+ jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;
+ var rootjQuerySubclass = jQuerySubclass(document);
+ return jQuerySubclass;
+ },
+
+ browser: {}
+});
+
+// Create readyList deferred
+readyList = jQuery._Deferred();
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+ jQuery.browser[ browserMatch.browser ] = true;
+ jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+ jQuery.browser.safari = true;
+}
+
+if ( indexOf ) {
+ jQuery.inArray = function( elem, array ) {
+ return indexOf.call( array, elem );
+ };
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+ trimLeft = /^[\s\xA0]+/;
+ trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+ DOMContentLoaded = function() {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ };
+
+} else if ( document.attachEvent ) {
+ DOMContentLoaded = function() {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( document.readyState === "complete" ) {
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ };
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+ if ( jQuery.isReady ) {
+ return;
+ }
+
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch(e) {
+ setTimeout( doScrollCheck, 1 );
+ return;
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+}
+
+// Expose jQuery to the global object
+return jQuery;
+
+})();
+
+
+(function() {
+
+ jQuery.support = {};
+
+ var div = document.createElement("div");
+
+ div.style.display = "none";
+ div.innerHTML = "
a";
+
+ var all = div.getElementsByTagName("*"),
+ a = div.getElementsByTagName("a")[0],
+ select = document.createElement("select"),
+ opt = select.appendChild( document.createElement("option") ),
+ input = div.getElementsByTagName("input")[0];
+
+ // Can't get basic test support
+ if ( !all || !all.length || !a ) {
+ return;
+ }
+
+ jQuery.support = {
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: div.firstChild.nodeType === 3,
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText insted)
+ style: /red/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: a.getAttribute("href") === "/a",
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.55$/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Make sure that if no value is specified for a checkbox
+ // that it defaults to "on".
+ // (WebKit defaults to "" instead)
+ checkOn: input.value === "on",
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Will be defined later
+ deleteExpando: true,
+ optDisabled: false,
+ checkClone: false,
+ noCloneEvent: true,
+ noCloneChecked: true,
+ boxModel: null,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableHiddenOffsets: true
+ };
+
+ input.checked = true;
+ jQuery.support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as diabled)
+ select.disabled = true;
+ jQuery.support.optDisabled = !opt.disabled;
+
+ var _scriptEval = null;
+ jQuery.support.scriptEval = function() {
+ if ( _scriptEval === null ) {
+ var root = document.documentElement,
+ script = document.createElement("script"),
+ id = "script" + jQuery.now();
+
+ try {
+ script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
+ } catch(e) {}
+
+ root.insertBefore( script, root.firstChild );
+
+ // Make sure that the execution of code works by injecting a script
+ // tag with appendChild/createTextNode
+ // (IE doesn't support this, fails, and uses .text instead)
+ if ( window[ id ] ) {
+ _scriptEval = true;
+ delete window[ id ];
+ } else {
+ _scriptEval = false;
+ }
+
+ root.removeChild( script );
+ // release memory in IE
+ root = script = id = null;
+ }
+
+ return _scriptEval;
+ };
+
+ // Test to see if it's possible to delete an expando from an element
+ // Fails in Internet Explorer
+ try {
+ delete div.test;
+
+ } catch(e) {
+ jQuery.support.deleteExpando = false;
+ }
+
+ if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+ div.attachEvent("onclick", function click() {
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ jQuery.support.noCloneEvent = false;
+ div.detachEvent("onclick", click);
+ });
+ div.cloneNode(true).fireEvent("onclick");
+ }
+
+ div = document.createElement("div");
+ div.innerHTML = "";
+
+ var fragment = document.createDocumentFragment();
+ fragment.appendChild( div.firstChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
+
+ // Figure out if the W3C box model works as expected
+ // document.body must exist before we can do this
+ jQuery(function() {
+ var div = document.createElement("div"),
+ body = document.getElementsByTagName("body")[0];
+
+ // Frameset documents with no body should not run this code
+ if ( !body ) {
+ return;
+ }
+
+ div.style.width = div.style.paddingLeft = "1px";
+ body.appendChild( div );
+ jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
+
+ if ( "zoom" in div.style ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2;
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "";
+ div.innerHTML = "";
+ jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2;
+ }
+
+ div.innerHTML = "
t
";
+ var tds = div.getElementsByTagName("td");
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0;
+
+ tds[0].style.display = "";
+ tds[1].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE < 8 fail this test)
+ jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;
+ div.innerHTML = "";
+
+ body.removeChild( div ).style.display = "none";
+ div = tds = null;
+ });
+
+ // Technique from Juriy Zaytsev
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
+ var eventSupported = function( eventName ) {
+ var el = document.createElement("div");
+ eventName = "on" + eventName;
+
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( !el.attachEvent ) {
+ return true;
+ }
+
+ var isSupported = (eventName in el);
+ if ( !isSupported ) {
+ el.setAttribute(eventName, "return;");
+ isSupported = typeof el[eventName] === "function";
+ }
+ el = null;
+
+ return isSupported;
+ };
+
+ jQuery.support.submitBubbles = eventSupported("submit");
+ jQuery.support.changeBubbles = eventSupported("change");
+
+ // release memory in IE
+ div = all = a = null;
+})();
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/;
+
+jQuery.extend({
+ cache: {},
+
+ // Please use with caution
+ uuid: 0,
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ jQuery.expando ] = id = ++jQuery.uuid;
+ } else {
+ id = jQuery.expando;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+ // metadata on plain JS objects when the object is serialized using
+ // JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
+ } else {
+ cache[ id ] = jQuery.extend(cache[ id ], name);
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // Internal jQuery data is stored in a separate object inside the object's data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data
+ if ( pvt ) {
+ if ( !thisCache[ internalKey ] ) {
+ thisCache[ internalKey ] = {};
+ }
+
+ thisCache = thisCache[ internalKey ];
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ name ] = data;
+ }
+
+ // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
+ // not attempt to inspect the internal events object using jQuery.data, as this
+ // internal data object is undocumented and subject to change.
+ if ( name === "events" && !thisCache[name] ) {
+ return thisCache[ internalKey ] && thisCache[ internalKey ].events;
+ }
+
+ return getByName ? thisCache[ name ] : thisCache;
+ },
+
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var internalKey = jQuery.expando, isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+
+ // See jQuery.data for more information
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+ var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
+
+ if ( thisCache ) {
+ delete thisCache[ name ];
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !isEmptyDataObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( pvt ) {
+ delete cache[ id ][ internalKey ];
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject(cache[ id ]) ) {
+ return;
+ }
+ }
+
+ var internalCache = cache[ id ][ internalKey ];
+
+ // Browsers that fail expando deletion also refuse to delete expandos on
+ // the window, but it will allow it on all other JS objects; other browsers
+ // don't care
+ if ( jQuery.support.deleteExpando || cache != window ) {
+ delete cache[ id ];
+ } else {
+ cache[ id ] = null;
+ }
+
+ // We destroyed the entire user cache at once because it's faster than
+ // iterating through each key, but we need to continue to persist internal
+ // data if it existed
+ if ( internalCache ) {
+ cache[ id ] = {};
+ // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+ // metadata on plain JS objects when the object is serialized using
+ // JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+
+ cache[ id ][ internalKey ] = internalCache;
+
+ // Otherwise, we need to eliminate the expando on the node to avoid
+ // false lookups in the cache for entries that no longer exist
+ } else if ( isNode ) {
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( jQuery.support.deleteExpando ) {
+ delete elem[ jQuery.expando ];
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ } else {
+ elem[ jQuery.expando ] = null;
+ }
+ }
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return jQuery.data( elem, name, data, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ if ( elem.nodeName ) {
+ var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ if ( match ) {
+ return !(match === true || elem.getAttribute("classid") !== match);
+ }
+ }
+
+ return true;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var data = null;
+
+ if ( typeof key === "undefined" ) {
+ if ( this.length ) {
+ data = jQuery.data( this[0] );
+
+ if ( this[0].nodeType === 1 ) {
+ var attr = this[0].attributes, name;
+ for ( var i = 0, l = attr.length; i < l; i++ ) {
+ name = attr[i].name;
+
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = name.substr( 5 );
+ dataAttr( this[0], name, data[ name ] );
+ }
+ }
+ }
+ }
+
+ return data;
+
+ } else if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ var parts = key.split(".");
+ parts[1] = parts[1] ? "." + parts[1] : "";
+
+ if ( value === undefined ) {
+ data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && this.length ) {
+ data = jQuery.data( this[0], key );
+ data = dataAttr( this[0], key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+
+ } else {
+ return this.each(function() {
+ var $this = jQuery( this ),
+ args = [ parts[0], value ];
+
+ $this.triggerHandler( "setData" + parts[1] + "!", args );
+ jQuery.data( this, key, value );
+ $this.triggerHandler( "changeData" + parts[1] + "!", args );
+ });
+ }
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ data = elem.getAttribute( "data-" + key );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ !jQuery.isNaN( data ) ? parseFloat( data ) :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
+// property to be considered empty objects; this property always exists in
+// order to make sure JSON.stringify does not expose internal metadata
+function isEmptyDataObject( obj ) {
+ for ( var name in obj ) {
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ if ( !elem ) {
+ return;
+ }
+
+ type = (type || "fx") + "queue";
+ var q = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( !data ) {
+ return q || [];
+ }
+
+ if ( !q || jQuery.isArray(data) ) {
+ q = jQuery._data( elem, type, jQuery.makeArray(data) );
+
+ } else {
+ q.push( data );
+ }
+
+ return q;
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ fn = queue.shift();
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ }
+
+ if ( fn ) {
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift("inprogress");
+ }
+
+ fn.call(elem, function() {
+ jQuery.dequeue(elem, type);
+ });
+ }
+
+ if ( !queue.length ) {
+ jQuery.removeData( elem, type + "queue", true );
+ }
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ }
+
+ if ( data === undefined ) {
+ return jQuery.queue( this[0], type );
+ }
+ return this.each(function( i ) {
+ var queue = jQuery.queue( this, type, data );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function() {
+ var elem = this;
+ setTimeout(function() {
+ jQuery.dequeue( elem, type );
+ }, time );
+ });
+ },
+
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ }
+});
+
+
+
+
+var rclass = /[\n\t\r]/g,
+ rspaces = /\s+/,
+ rreturn = /\r/g,
+ rspecialurl = /^(?:href|src|style)$/,
+ rtype = /^(?:button|input)$/i,
+ rfocusable = /^(?:button|input|object|select|textarea)$/i,
+ rclickable = /^a(?:rea)?$/i,
+ rradiocheck = /^(?:radio|checkbox)$/i;
+
+jQuery.props = {
+ "for": "htmlFor",
+ "class": "className",
+ readonly: "readOnly",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ tabindex: "tabIndex",
+ usemap: "useMap",
+ frameborder: "frameBorder"
+};
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, name, value, true, jQuery.attr );
+ },
+
+ removeAttr: function( name, fn ) {
+ return this.each(function(){
+ jQuery.attr( this, name, "" );
+ if ( this.nodeType === 1 ) {
+ this.removeAttribute( name );
+ }
+ });
+ },
+
+ addClass: function( value ) {
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ self.addClass( value.call(this, i, self.attr("class")) );
+ });
+ }
+
+ if ( value && typeof value === "string" ) {
+ var classNames = (value || "").split( rspaces );
+
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ var elem = this[i];
+
+ if ( elem.nodeType === 1 ) {
+ if ( !elem.className ) {
+ elem.className = value;
+
+ } else {
+ var className = " " + elem.className + " ",
+ setClass = elem.className;
+
+ for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+ if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
+ setClass += " " + classNames[c];
+ }
+ }
+ elem.className = jQuery.trim( setClass );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ self.removeClass( value.call(this, i, self.attr("class")) );
+ });
+ }
+
+ if ( (value && typeof value === "string") || value === undefined ) {
+ var classNames = (value || "").split( rspaces );
+
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ var elem = this[i];
+
+ if ( elem.nodeType === 1 && elem.className ) {
+ if ( value ) {
+ var className = (" " + elem.className + " ").replace(rclass, " ");
+ for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+ className = className.replace(" " + classNames[c] + " ", " ");
+ }
+ elem.className = jQuery.trim( className );
+
+ } else {
+ elem.className = "";
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.split( rspaces );
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space seperated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // toggle whole className
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ";
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ if ( !arguments.length ) {
+ var elem = this[0];
+
+ if ( elem ) {
+ if ( jQuery.nodeName( elem, "option" ) ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+
+ // We need to handle select boxes special
+ if ( jQuery.nodeName( elem, "select" ) ) {
+ var index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type === "select-one";
+
+ // Nothing was selected
+ if ( index < 0 ) {
+ return null;
+ }
+
+ // Loop through all the selected options
+ for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+ var option = options[ i ];
+
+ // Don't return options that are disabled or in a disabled optgroup
+ if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+ (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+ // Get the specific value for the option
+ value = jQuery(option).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+ if ( one && !values.length && options.length ) {
+ return jQuery( options[ index ] ).val();
+ }
+
+ return values;
+ }
+
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+
+ // Everything else, we just grab the value
+ return (elem.value || "").replace(rreturn, "");
+
+ }
+
+ return undefined;
+ }
+
+ var isFunction = jQuery.isFunction(value);
+
+ return this.each(function(i) {
+ var self = jQuery(this), val = value;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call(this, i, self.val());
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray(val) ) {
+ val = jQuery.map(val, function (value) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
+ this.checked = jQuery.inArray( self.val(), val ) >= 0;
+
+ } else if ( jQuery.nodeName( this, "select" ) ) {
+ var values = jQuery.makeArray(val);
+
+ jQuery( "option", this ).each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ this.selectedIndex = -1;
+ }
+
+ } else {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ attrFn: {
+ val: true,
+ css: true,
+ html: true,
+ text: true,
+ data: true,
+ width: true,
+ height: true,
+ offset: true
+ },
+
+ attr: function( elem, name, value, pass ) {
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) {
+ return undefined;
+ }
+
+ if ( pass && name in jQuery.attrFn ) {
+ return jQuery(elem)[name](value);
+ }
+
+ var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
+ // Whether we are setting (or getting)
+ set = value !== undefined;
+
+ // Try to normalize/fix the name
+ name = notxml && jQuery.props[ name ] || name;
+
+ // Only do all the following if this is a node (faster for style)
+ if ( elem.nodeType === 1 ) {
+ // These attributes require special treatment
+ var special = rspecialurl.test( name );
+
+ // Safari mis-reports the default selected property of an option
+ // Accessing the parent's selectedIndex property fixes it
+ if ( name === "selected" && !jQuery.support.optSelected ) {
+ var parent = elem.parentNode;
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ }
+
+ // If applicable, access the attribute via the DOM 0 way
+ // 'in' checks fail in Blackberry 4.7 #6931
+ if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) {
+ if ( set ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
+ jQuery.error( "type property can't be changed" );
+ }
+
+ if ( value === null ) {
+ if ( elem.nodeType === 1 ) {
+ elem.removeAttribute( name );
+ }
+
+ } else {
+ elem[ name ] = value;
+ }
+ }
+
+ // browsers index elements by id/name on forms, give priority to attributes.
+ if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
+ return elem.getAttributeNode( name ).nodeValue;
+ }
+
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ if ( name === "tabIndex" ) {
+ var attributeNode = elem.getAttributeNode( "tabIndex" );
+
+ return attributeNode && attributeNode.specified ?
+ attributeNode.value :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+
+ return elem[ name ];
+ }
+
+ if ( !jQuery.support.style && notxml && name === "style" ) {
+ if ( set ) {
+ elem.style.cssText = "" + value;
+ }
+
+ return elem.style.cssText;
+ }
+
+ if ( set ) {
+ // convert the value to a string (all browsers do this but IE) see #1070
+ elem.setAttribute( name, "" + value );
+ }
+
+ // Ensure that missing attributes return undefined
+ // Blackberry 4.7 returns "" from getAttribute #6938
+ if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) {
+ return undefined;
+ }
+
+ var attr = !jQuery.support.hrefNormalized && notxml && special ?
+ // Some attributes require a special call on IE
+ elem.getAttribute( name, 2 ) :
+ elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return attr === null ? undefined : attr;
+ }
+ // Handle everything which isn't a DOM element node
+ if ( set ) {
+ elem[ name ] = value;
+ }
+ return elem[ name ];
+ }
+});
+
+
+
+
+var rnamespaces = /\.(.*)$/,
+ rformElems = /^(?:textarea|input|select)$/i,
+ rperiod = /\./g,
+ rspace = / /g,
+ rescape = /[^\w\s.|`]/g,
+ fcleanup = function( nm ) {
+ return nm.replace(rescape, "\\$&");
+ };
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code originated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+ // Bind an event to an element
+ // Original by Dean Edwards
+ add: function( elem, types, handler, data ) {
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6)
+ // Minor release fix for bug #8018
+ try {
+ // For whatever reason, IE has trouble passing the window object
+ // around, causing it to be cloned in the process
+ if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
+ elem = window;
+ }
+ }
+ catch ( e ) {}
+
+ if ( handler === false ) {
+ handler = returnFalse;
+ } else if ( !handler ) {
+ // Fixes bug #7229. Fix recommended by jdalton
+ return;
+ }
+
+ var handleObjIn, handleObj;
+
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ }
+
+ // Make sure that the function being executed has a unique ID
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure
+ var elemData = jQuery._data( elem );
+
+ // If no elemData is found then we must be trying to bind to one of the
+ // banned noData elements
+ if ( !elemData ) {
+ return;
+ }
+
+ var events = elemData.events,
+ eventHandle = elemData.handle;
+
+ if ( !events ) {
+ elemData.events = events = {};
+ }
+
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function() {
+ // Handle the second event of a trigger and when
+ // an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
+ jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ }
+
+ // Add elem as a property of the handle function
+ // This is to prevent a memory leak with non-native events in IE.
+ eventHandle.elem = elem;
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ var type, i = 0, namespaces;
+
+ while ( (type = types[ i++ ]) ) {
+ handleObj = handleObjIn ?
+ jQuery.extend({}, handleObjIn) :
+ { handler: handler, data: data };
+
+ // Namespaced event handlers
+ if ( type.indexOf(".") > -1 ) {
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ handleObj.namespace = namespaces.slice(0).sort().join(".");
+
+ } else {
+ namespaces = [];
+ handleObj.namespace = "";
+ }
+
+ handleObj.type = type;
+ if ( !handleObj.guid ) {
+ handleObj.guid = handler.guid;
+ }
+
+ // Get the current list of functions bound to this event
+ var handlers = events[ type ],
+ special = jQuery.event.special[ type ] || {};
+
+ // Init the event handler queue
+ if ( !handlers ) {
+ handlers = events[ type ] = [];
+
+ // Check for a special event handler
+ // Only use addEventListener/attachEvent if the special
+ // events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add the function to the element's handler list
+ handlers.push( handleObj );
+
+ // Keep track of which events have been used, for global triggering
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, pos ) {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ if ( handler === false ) {
+ handler = returnFalse;
+ }
+
+ var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ events = elemData && elemData.events;
+
+ if ( !elemData || !events ) {
+ return;
+ }
+
+ // types is actually an event object here
+ if ( types && types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Unbind all events for the element
+ if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+ types = types || "";
+
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types );
+ }
+
+ return;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ while ( (type = types[ i++ ]) ) {
+ origType = type;
+ handleObj = null;
+ all = type.indexOf(".") < 0;
+ namespaces = [];
+
+ if ( !all ) {
+ // Namespaced event handlers
+ namespaces = type.split(".");
+ type = namespaces.shift();
+
+ namespace = new RegExp("(^|\\.)" +
+ jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ eventType = events[ type ];
+
+ if ( !eventType ) {
+ continue;
+ }
+
+ if ( !handler ) {
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ jQuery.event.remove( elem, origType, handleObj.handler, j );
+ eventType.splice( j--, 1 );
+ }
+ }
+
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+
+ for ( j = pos || 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( handler.guid === handleObj.guid ) {
+ // remove the given handler for the given type
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ if ( pos == null ) {
+ eventType.splice( j--, 1 );
+ }
+
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+
+ if ( pos != null ) {
+ break;
+ }
+ }
+ }
+
+ // remove generic event handler if no more handlers exist
+ if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ ret = null;
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ var handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ delete elemData.events;
+ delete elemData.handle;
+
+ if ( jQuery.isEmptyObject( elemData ) ) {
+ jQuery.removeData( elem, undefined, true );
+ }
+ }
+ },
+
+ // bubbling is internal
+ trigger: function( event, data, elem /*, bubbling */ ) {
+ // Event object or event type
+ var type = event.type || event,
+ bubbling = arguments[3];
+
+ if ( !bubbling ) {
+ event = typeof event === "object" ?
+ // jQuery.Event object
+ event[ jQuery.expando ] ? event :
+ // Object literal
+ jQuery.extend( jQuery.Event(type), event ) :
+ // Just the event type (string)
+ jQuery.Event(type);
+
+ if ( type.indexOf("!") >= 0 ) {
+ event.type = type = type.slice(0, -1);
+ event.exclusive = true;
+ }
+
+ // Handle a global trigger
+ if ( !elem ) {
+ // Don't bubble custom events when global (to avoid too much overhead)
+ event.stopPropagation();
+
+ // Only trigger if we've ever bound an event for it
+ if ( jQuery.event.global[ type ] ) {
+ // XXX This code smells terrible. event.js should not be directly
+ // inspecting the data cache
+ jQuery.each( jQuery.cache, function() {
+ // internalKey variable is just used to make it easier to find
+ // and potentially change this stuff later; currently it just
+ // points to jQuery.expando
+ var internalKey = jQuery.expando,
+ internalCache = this[ internalKey ];
+ if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
+ jQuery.event.trigger( event, data, internalCache.handle.elem );
+ }
+ });
+ }
+ }
+
+ // Handle triggering a single element
+
+ // don't do events on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return undefined;
+ }
+
+ // Clean up in case it is reused
+ event.result = undefined;
+ event.target = elem;
+
+ // Clone the incoming data, if any
+ data = jQuery.makeArray( data );
+ data.unshift( event );
+ }
+
+ event.currentTarget = elem;
+
+ // Trigger the event, it is assumed that "handle" is a function
+ var handle = jQuery._data( elem, "handle" );
+
+ if ( handle ) {
+ handle.apply( elem, data );
+ }
+
+ var parent = elem.parentNode || elem.ownerDocument;
+
+ // Trigger an inline bound script
+ try {
+ if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
+ if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
+ event.result = false;
+ event.preventDefault();
+ }
+ }
+
+ // prevent IE from throwing an error for some elements with some event types, see #3533
+ } catch (inlineError) {}
+
+ if ( !event.isPropagationStopped() && parent ) {
+ jQuery.event.trigger( event, data, parent, true );
+
+ } else if ( !event.isDefaultPrevented() ) {
+ var old,
+ target = event.target,
+ targetType = type.replace( rnamespaces, "" ),
+ isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
+ special = jQuery.event.special[ targetType ] || {};
+
+ if ( (!special._default || special._default.call( elem, event ) === false) &&
+ !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
+
+ try {
+ if ( target[ targetType ] ) {
+ // Make sure that we don't accidentally re-trigger the onFOO events
+ old = target[ "on" + targetType ];
+
+ if ( old ) {
+ target[ "on" + targetType ] = null;
+ }
+
+ jQuery.event.triggered = true;
+ target[ targetType ]();
+ }
+
+ // prevent IE from throwing an error for some elements with some event types, see #3533
+ } catch (triggerError) {}
+
+ if ( old ) {
+ target[ "on" + targetType ] = old;
+ }
+
+ jQuery.event.triggered = false;
+ }
+ }
+ },
+
+ handle: function( event ) {
+ var all, handlers, namespaces, namespace_re, events,
+ namespace_sort = [],
+ args = jQuery.makeArray( arguments );
+
+ event = args[0] = jQuery.event.fix( event || window.event );
+ event.currentTarget = this;
+
+ // Namespaced event handlers
+ all = event.type.indexOf(".") < 0 && !event.exclusive;
+
+ if ( !all ) {
+ namespaces = event.type.split(".");
+ event.type = namespaces.shift();
+ namespace_sort = namespaces.slice(0).sort();
+ namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ event.namespace = event.namespace || namespace_sort.join(".");
+
+ events = jQuery._data(this, "events");
+
+ handlers = (events || {})[ event.type ];
+
+ if ( events && handlers ) {
+ // Clone the handlers to prevent manipulation
+ handlers = handlers.slice(0);
+
+ for ( var j = 0, l = handlers.length; j < l; j++ ) {
+ var handleObj = handlers[ j ];
+
+ // Filter the functions by class
+ if ( all || namespace_re.test( handleObj.namespace ) ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handleObj.handler;
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ var ret = handleObj.handler.apply( this, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // store a copy of the original event object
+ // and "clone" to set read-only properties
+ var originalEvent = event;
+ event = jQuery.Event( originalEvent );
+
+ for ( var i = this.props.length, prop; i; ) {
+ prop = this.props[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary
+ if ( !event.target ) {
+ // Fixes #1925 where srcElement might not be defined either
+ event.target = event.srcElement || document;
+ }
+
+ // check if target is a textnode (safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement ) {
+ event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+ }
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var doc = document.documentElement,
+ body = document.body;
+
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
+ }
+
+ // Add which for key events
+ if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
+ event.which = event.charCode != null ? event.charCode : event.keyCode;
+ }
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey ) {
+ event.metaKey = event.ctrlKey;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button !== undefined ) {
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+ }
+
+ return event;
+ },
+
+ // Deprecated, use jQuery.guid instead
+ guid: 1E8,
+
+ // Deprecated, use jQuery.proxy instead
+ proxy: jQuery.proxy,
+
+ special: {
+ ready: {
+ // Make sure the ready event is setup
+ setup: jQuery.bindReady,
+ teardown: jQuery.noop
+ },
+
+ live: {
+ add: function( handleObj ) {
+ jQuery.event.add( this,
+ liveConvert( handleObj.origType, handleObj.selector ),
+ jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
+ },
+
+ remove: function( handleObj ) {
+ jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
+ }
+ },
+
+ beforeunload: {
+ setup: function( data, namespaces, eventHandle ) {
+ // We only want to do this special case on windows
+ if ( jQuery.isWindow( this ) ) {
+ this.onbeforeunload = eventHandle;
+ }
+ },
+
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
+ this.onbeforeunload = null;
+ }
+ }
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ if ( elem.detachEvent ) {
+ elem.detachEvent( "on" + type, handle );
+ }
+ };
+
+jQuery.Event = function( src ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !this.preventDefault ) {
+ return new jQuery.Event( src );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // timeStamp is buggy for some events on Firefox(#3843)
+ // So we won't rely on the native value
+ this.timeStamp = jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+ return false;
+}
+function returnTrue() {
+ return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // otherwise set the returnValue property of the original event to false (IE)
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function( event ) {
+ // Check if mouse(over|out) are still within the same parent element
+ var parent = event.relatedTarget;
+
+ // Firefox sometimes assigns relatedTarget a XUL element
+ // which we cannot access the parentNode property of
+ try {
+
+ // Chrome does something similar, the parentNode property
+ // can be accessed but is null.
+ if ( parent !== document && !parent.parentNode ) {
+ return;
+ }
+ // Traverse up the tree
+ while ( parent && parent !== this ) {
+ parent = parent.parentNode;
+ }
+
+ if ( parent !== this ) {
+ // set the correct event type
+ event.type = event.data;
+
+ // handle event if we actually just moused on to a non sub-element
+ jQuery.event.handle.apply( this, arguments );
+ }
+
+ // assuming we've left the element since we most likely mousedover a xul element
+ } catch(e) { }
+},
+
+// In case of event delegation, we only need to rename the event.type,
+// liveHandler will take care of the rest.
+delegate = function( event ) {
+ event.type = event.data;
+ jQuery.event.handle.apply( this, arguments );
+};
+
+// Create mouseenter and mouseleave events
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ setup: function( data ) {
+ jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
+ },
+ teardown: function( data ) {
+ jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+ }
+ };
+});
+
+// submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function( data, namespaces ) {
+ if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
+ jQuery.event.add(this, "click.specialSubmit", function( e ) {
+ var elem = e.target,
+ type = elem.type;
+
+ if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+ trigger( "submit", this, arguments );
+ }
+ });
+
+ jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
+ var elem = e.target,
+ type = elem.type;
+
+ if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+ trigger( "submit", this, arguments );
+ }
+ });
+
+ } else {
+ return false;
+ }
+ },
+
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialSubmit" );
+ }
+ };
+
+}
+
+// change delegation, happens here so we have bind.
+if ( !jQuery.support.changeBubbles ) {
+
+ var changeFilters,
+
+ getVal = function( elem ) {
+ var type = elem.type, val = elem.value;
+
+ if ( type === "radio" || type === "checkbox" ) {
+ val = elem.checked;
+
+ } else if ( type === "select-multiple" ) {
+ val = elem.selectedIndex > -1 ?
+ jQuery.map( elem.options, function( elem ) {
+ return elem.selected;
+ }).join("-") :
+ "";
+
+ } else if ( elem.nodeName.toLowerCase() === "select" ) {
+ val = elem.selectedIndex;
+ }
+
+ return val;
+ },
+
+ testChange = function testChange( e ) {
+ var elem = e.target, data, val;
+
+ if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
+ return;
+ }
+
+ data = jQuery._data( elem, "_change_data" );
+ val = getVal(elem);
+
+ // the current data will be also retrieved by beforeactivate
+ if ( e.type !== "focusout" || elem.type !== "radio" ) {
+ jQuery._data( elem, "_change_data", val );
+ }
+
+ if ( data === undefined || val === data ) {
+ return;
+ }
+
+ if ( data != null || val ) {
+ e.type = "change";
+ e.liveFired = undefined;
+ jQuery.event.trigger( e, arguments[1], elem );
+ }
+ };
+
+ jQuery.event.special.change = {
+ filters: {
+ focusout: testChange,
+
+ beforedeactivate: testChange,
+
+ click: function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
+ testChange.call( this, e );
+ }
+ },
+
+ // Change has to be called before submit
+ // Keydown will be called before keypress, which is used in submit-event delegation
+ keydown: function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
+ (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+ type === "select-multiple" ) {
+ testChange.call( this, e );
+ }
+ },
+
+ // Beforeactivate happens also before the previous element is blurred
+ // with this event you can't trigger a change event, but you can store
+ // information
+ beforeactivate: function( e ) {
+ var elem = e.target;
+ jQuery._data( elem, "_change_data", getVal(elem) );
+ }
+ },
+
+ setup: function( data, namespaces ) {
+ if ( this.type === "file" ) {
+ return false;
+ }
+
+ for ( var type in changeFilters ) {
+ jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
+ }
+
+ return rformElems.test( this.nodeName );
+ },
+
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialChange" );
+
+ return rformElems.test( this.nodeName );
+ }
+ };
+
+ changeFilters = jQuery.event.special.change.filters;
+
+ // Handle when the input is .focus()'d
+ changeFilters.focus = changeFilters.beforeactivate;
+}
+
+function trigger( type, elem, args ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ // Don't pass args or remember liveFired; they apply to the donor event.
+ var event = jQuery.extend( {}, args[ 0 ] );
+ event.type = type;
+ event.originalEvent = {};
+ event.liveFired = undefined;
+ jQuery.event.handle.call( elem, event );
+ if ( event.isDefaultPrevented() ) {
+ args[ 0 ].preventDefault();
+ }
+}
+
+// Create "bubbling" focus and blur events
+if ( document.addEventListener ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ this.addEventListener( orig, handler, true );
+ },
+ teardown: function() {
+ this.removeEventListener( orig, handler, true );
+ }
+ };
+
+ function handler( e ) {
+ e = jQuery.event.fix( e );
+ e.type = fix;
+ return jQuery.event.handle.call( this, e );
+ }
+ });
+}
+
+jQuery.each(["bind", "one"], function( i, name ) {
+ jQuery.fn[ name ] = function( type, data, fn ) {
+ // Handle object literals
+ if ( typeof type === "object" ) {
+ for ( var key in type ) {
+ this[ name ](key, data, type[key], fn);
+ }
+ return this;
+ }
+
+ if ( jQuery.isFunction( data ) || data === false ) {
+ fn = data;
+ data = undefined;
+ }
+
+ var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
+ jQuery( this ).unbind( event, handler );
+ return fn.apply( this, arguments );
+ }) : fn;
+
+ if ( type === "unload" && name !== "one" ) {
+ this.one( type, data, fn );
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.add( this[i], type, handler, data );
+ }
+ }
+
+ return this;
+ };
+});
+
+jQuery.fn.extend({
+ unbind: function( type, fn ) {
+ // Handle object literals
+ if ( typeof type === "object" && !type.preventDefault ) {
+ for ( var key in type ) {
+ this.unbind(key, type[key]);
+ }
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.remove( this[i], type, fn );
+ }
+ }
+
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.live( types, data, fn, selector );
+ },
+
+ undelegate: function( selector, types, fn ) {
+ if ( arguments.length === 0 ) {
+ return this.unbind( "live" );
+
+ } else {
+ return this.die( types, null, fn, selector );
+ }
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+
+ triggerHandler: function( type, data ) {
+ if ( this[0] ) {
+ var event = jQuery.Event( type );
+ event.preventDefault();
+ event.stopPropagation();
+ jQuery.event.trigger( event, data, this[0] );
+ return event.result;
+ }
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ i = 1;
+
+ // link all the functions, so any of them can unbind this click handler
+ while ( i < args.length ) {
+ jQuery.proxy( fn, args[ i++ ] );
+ }
+
+ return this.click( jQuery.proxy( fn, 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;
+ }));
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+});
+
+var liveMap = {
+ focus: "focusin",
+ blur: "focusout",
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+};
+
+jQuery.each(["live", "die"], function( i, name ) {
+ jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+ var type, i = 0, match, namespaces, preType,
+ selector = origSelector || this.selector,
+ context = origSelector ? this : jQuery( this.context );
+
+ if ( typeof types === "object" && !types.preventDefault ) {
+ for ( var key in types ) {
+ context[ name ]( key, data, types[key], selector );
+ }
+
+ return this;
+ }
+
+ if ( jQuery.isFunction( data ) ) {
+ fn = data;
+ data = undefined;
+ }
+
+ types = (types || "").split(" ");
+
+ while ( (type = types[ i++ ]) != null ) {
+ match = rnamespaces.exec( type );
+ namespaces = "";
+
+ if ( match ) {
+ namespaces = match[0];
+ type = type.replace( rnamespaces, "" );
+ }
+
+ if ( type === "hover" ) {
+ types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
+ continue;
+ }
+
+ preType = type;
+
+ if ( type === "focus" || type === "blur" ) {
+ types.push( liveMap[ type ] + namespaces );
+ type = type + namespaces;
+
+ } else {
+ type = (liveMap[ type ] || type) + namespaces;
+ }
+
+ if ( name === "live" ) {
+ // bind live handler
+ for ( var j = 0, l = context.length; j < l; j++ ) {
+ jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
+ { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
+ }
+
+ } else {
+ // unbind live handler
+ context.unbind( "live." + liveConvert( type, selector ), fn );
+ }
+ }
+
+ return this;
+ };
+});
+
+function liveHandler( event ) {
+ var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+ elems = [],
+ selectors = [],
+ events = jQuery._data( this, "events" );
+
+ // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
+ if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
+ return;
+ }
+
+ if ( event.namespace ) {
+ namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ event.liveFired = this;
+
+ var live = events.live.slice(0);
+
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
+ selectors.push( handleObj.selector );
+
+ } else {
+ live.splice( j--, 1 );
+ }
+ }
+
+ match = jQuery( event.target ).closest( selectors, event.currentTarget );
+
+ for ( i = 0, l = match.length; i < l; i++ ) {
+ close = match[i];
+
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
+ elem = close.elem;
+ related = null;
+
+ // Those two events require additional checking
+ if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+ event.type = handleObj.preType;
+ related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
+ }
+
+ if ( !related || related !== elem ) {
+ elems.push({ elem: elem, handleObj: handleObj, level: close.level });
+ }
+ }
+ }
+ }
+
+ for ( i = 0, l = elems.length; i < l; i++ ) {
+ match = elems[i];
+
+ if ( maxLevel && match.level > maxLevel ) {
+ break;
+ }
+
+ event.currentTarget = match.elem;
+ event.data = match.handleObj.data;
+ event.handleObj = match.handleObj;
+
+ ret = match.handleObj.origHandler.apply( match.elem, arguments );
+
+ if ( ret === false || event.isPropagationStopped() ) {
+ maxLevel = match.level;
+
+ if ( ret === false ) {
+ stop = false;
+ }
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
+ }
+ }
+
+ return stop;
+}
+
+function liveConvert( type, selector ) {
+ return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
+}
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.bind( name, data, fn ) :
+ this.trigger( name );
+ };
+
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
+ }
+});
+
+
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true,
+ rBackslash = /\\/g,
+ rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+// Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+ baseHasDuplicate = false;
+ return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+
+ var origContext = context;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var m, set, checkSet, extra, ret, cur, pop, i,
+ prune = true,
+ contextXML = Sizzle.isXML( context ),
+ parts = [],
+ soFar = selector;
+
+ // Reset the position of the chunker regexp (start from head)
+ do {
+ chunker.exec( "" );
+ m = chunker.exec( soFar );
+
+ if ( m ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+ } while ( m );
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context );
+
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] ) {
+ selector += parts.shift();
+ }
+
+ set = posProcess( selector, set );
+ }
+ }
+
+ } else {
+ // Take a shortcut and set the context if the root selector is an ID
+ // (but not if it'll be faster if the inner selector is an ID)
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+ ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set )[0] :
+ ret.set[0];
+ }
+
+ if ( context ) {
+ ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+ set = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set ) :
+ ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray( set );
+
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ cur = parts.pop();
+ pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ Sizzle.error( cur || selector );
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+
+ } else if ( context && context.nodeType === 1 ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+
+ } else {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[ i - 1 ] ) {
+ results.splice( i--, 1 );
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+ return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+ return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+ var set;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+ var match,
+ type = Expr.order[i];
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ var left = match[1];
+ match.splice( 1, 1 );
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace( rBackslash, "" );
+ set = Expr.find[ type ]( match, context, isXML );
+
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( "*" ) :
+ [];
+ }
+
+ return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+ var match, anyFound,
+ old = expr,
+ result = [],
+ curLoop = set,
+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+ while ( expr && set.length ) {
+ for ( var type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ var found, item,
+ filter = Expr.filter[ type ],
+ left = match[1];
+
+ anyFound = false;
+
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) === "\\" ) {
+ continue;
+ }
+
+ if ( curLoop === result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ var pass = not ^ !!found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+
+ } else {
+ curLoop[i] = false;
+ }
+
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Improper expression
+ if ( expr === old ) {
+ if ( anyFound == null ) {
+ Sizzle.error( expr );
+
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+ throw "Syntax error, unrecognized expression: " + msg;
+};
+
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+
+ match: {
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ },
+
+ leftMatch: {},
+
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+
+ attrHandle: {
+ href: function( elem ) {
+ return elem.getAttribute( "href" );
+ },
+ type: function( elem ) {
+ return elem.getAttribute( "type" );
+ }
+ },
+
+ relative: {
+ "+": function(checkSet, part){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !rNonWord.test( part ),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag ) {
+ part = part.toLowerCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+
+ ">": function( checkSet, part ) {
+ var elem,
+ isPartStr = typeof part === "string",
+ i = 0,
+ l = checkSet.length;
+
+ if ( isPartStr && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+ }
+ }
+
+ } else {
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+
+ "": function(checkSet, part, isXML){
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+ },
+
+ "~": function( checkSet, part, isXML ) {
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+ }
+ },
+
+ find: {
+ ID: function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ },
+
+ NAME: function( match, context ) {
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [],
+ results = context.getElementsByName( match[1] );
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+
+ TAG: function( match, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( match[1] );
+ }
+ }
+ },
+ preFilter: {
+ CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+ match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+ if ( !inplace ) {
+ result.push( elem );
+ }
+
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+
+ ID: function( match ) {
+ return match[1].replace( rBackslash, "" );
+ },
+
+ TAG: function( match, curLoop ) {
+ return match[1].replace( rBackslash, "" ).toLowerCase();
+ },
+
+ CHILD: function( match ) {
+ if ( match[1] === "nth" ) {
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ match[2] = match[2].replace(/^\+|\s*/g, '');
+
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+ else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = done++;
+
+ return match;
+ },
+
+ ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+ var name = match[1] = match[1].replace( rBackslash, "" );
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ // Handle if an un-quoted value was used
+ match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+
+ PSEUDO: function( match, curLoop, inplace, result, not ) {
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+
+ return false;
+ }
+
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+
+ POS: function( match ) {
+ match.unshift( true );
+
+ return match;
+ }
+ },
+
+ filters: {
+ enabled: function( elem ) {
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+
+ disabled: function( elem ) {
+ return elem.disabled === true;
+ },
+
+ checked: function( elem ) {
+ return elem.checked === true;
+ },
+
+ selected: function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ parent: function( elem ) {
+ return !!elem.firstChild;
+ },
+
+ empty: function( elem ) {
+ return !elem.firstChild;
+ },
+
+ has: function( elem, i, match ) {
+ return !!Sizzle( match[3], elem ).length;
+ },
+
+ header: function( elem ) {
+ return (/h\d/i).test( elem.nodeName );
+ },
+
+ text: function( elem ) {
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return "text" === elem.getAttribute( 'type' );
+ },
+ radio: function( elem ) {
+ return "radio" === elem.type;
+ },
+
+ checkbox: function( elem ) {
+ return "checkbox" === elem.type;
+ },
+
+ file: function( elem ) {
+ return "file" === elem.type;
+ },
+ password: function( elem ) {
+ return "password" === elem.type;
+ },
+
+ submit: function( elem ) {
+ return "submit" === elem.type;
+ },
+
+ image: function( elem ) {
+ return "image" === elem.type;
+ },
+
+ reset: function( elem ) {
+ return "reset" === elem.type;
+ },
+
+ button: function( elem ) {
+ return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
+ },
+
+ input: function( elem ) {
+ return (/input|select|textarea|button/i).test( elem.nodeName );
+ }
+ },
+ setFilters: {
+ first: function( elem, i ) {
+ return i === 0;
+ },
+
+ last: function( elem, i, match, array ) {
+ return i === array.length - 1;
+ },
+
+ even: function( elem, i ) {
+ return i % 2 === 0;
+ },
+
+ odd: function( elem, i ) {
+ return i % 2 === 1;
+ },
+
+ lt: function( elem, i, match ) {
+ return i < match[3] - 0;
+ },
+
+ gt: function( elem, i, match ) {
+ return i > match[3] - 0;
+ },
+
+ nth: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ },
+
+ eq: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ }
+ },
+ filter: {
+ PSEUDO: function( elem, match, i, array ) {
+ var name = match[1],
+ filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var j = 0, l = not.length; j < l; j++ ) {
+ if ( not[j] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ } else {
+ Sizzle.error( name );
+ }
+ },
+
+ CHILD: function( elem, match ) {
+ var type = match[1],
+ node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ case "nth":
+ var first = match[2],
+ last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ var doneName = match[0],
+ parent = elem.parentNode;
+
+ if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+ var count = 0;
+
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+
+ parent.sizcache = doneName;
+ }
+
+ var diff = elem.nodeIndex - last;
+
+ if ( first === 0 ) {
+ return diff === 0;
+
+ } else {
+ return ( diff % first === 0 && diff / first >= 0 );
+ }
+ }
+ },
+
+ ID: function( elem, match ) {
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+
+ TAG: function( elem, match ) {
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+ },
+
+ CLASS: function( elem, match ) {
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+
+ ATTR: function( elem, match ) {
+ var name = match[1],
+ result = Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value !== check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+
+ POS: function( elem, match, i, array ) {
+ var name = match[2],
+ filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS,
+ fescape = function(all, num){
+ return "\\" + (num - 0 + 1);
+ };
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+
+var makeArray = function( array, results ) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+ makeArray = function( array, results ) {
+ var i = 0,
+ ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+
+ } else {
+ for ( ; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ return a.compareDocumentPosition ? -1 : 1;
+ }
+
+ return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+ };
+
+} else {
+ sortOrder = function( a, b ) {
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+ siblingCheck = function( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+ };
+}
+
+// Utility function for retreiving the text value of an array of DOM nodes
+Sizzle.getText = function( elems ) {
+ var ret = "", elem;
+
+ for ( var i = 0; elems[i]; i++ ) {
+ elem = elems[i];
+
+ // Get the text from text nodes and CDATA nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+ ret += elem.nodeValue;
+
+ // Traverse everything else, except comment nodes
+ } else if ( elem.nodeType !== 8 ) {
+ ret += Sizzle.getText( elem.childNodes );
+ }
+ }
+
+ return ret;
+};
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("div"),
+ id = "script" + (new Date()).getTime(),
+ root = document.documentElement;
+
+ form.innerHTML = "";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( document.getElementById( id ) ) {
+ Expr.find.ID = function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+
+ return m ?
+ m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+ [m] :
+ undefined :
+ [];
+ }
+ };
+
+ Expr.filter.ID = function( elem, match ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+
+ // release memory in IE
+ root = form = null;
+})();
+
+(function(){
+ // Check to see if the browser returns only elements
+ // when doing getElementsByTagName("*")
+
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function( match, context ) {
+ var results = context.getElementsByTagName( match[1] );
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ // Check to see if an attribute returns normalized href attributes
+ div.innerHTML = "";
+
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+
+ Expr.attrHandle.href = function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ };
+ }
+
+ // release memory in IE
+ div = null;
+})();
+
+if ( document.querySelectorAll ) {
+ (function(){
+ var oldSizzle = Sizzle,
+ div = document.createElement("div"),
+ id = "__sizzle__";
+
+ div.innerHTML = "";
+
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode.
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function( query, context, extra, seed ) {
+ context = context || document;
+
+ // Only use querySelectorAll on non-XML documents
+ // (ID selectors don't work in non-HTML documents)
+ if ( !seed && !Sizzle.isXML(context) ) {
+ // See if we find a selector to speed up
+ var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+
+ if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+ // Speed-up: Sizzle("TAG")
+ if ( match[1] ) {
+ return makeArray( context.getElementsByTagName( query ), extra );
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+ return makeArray( context.getElementsByClassName( match[2] ), extra );
+ }
+ }
+
+ if ( context.nodeType === 9 ) {
+ // Speed-up: Sizzle("body")
+ // The body element only exists once, optimize finding it
+ if ( query === "body" && context.body ) {
+ return makeArray( [ context.body ], extra );
+
+ // Speed-up: Sizzle("#ID")
+ } else if ( match && match[3] ) {
+ var elem = context.getElementById( match[3] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id === match[3] ) {
+ return makeArray( [ elem ], extra );
+ }
+
+ } else {
+ return makeArray( [], extra );
+ }
+ }
+
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(qsaError) {}
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ var oldContext = context,
+ old = context.getAttribute( "id" ),
+ nid = old || id,
+ hasParent = context.parentNode,
+ relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+ if ( !old ) {
+ context.setAttribute( "id", nid );
+ } else {
+ nid = nid.replace( /'/g, "\\$&" );
+ }
+ if ( relativeHierarchySelector && hasParent ) {
+ context = context.parentNode;
+ }
+
+ try {
+ if ( !relativeHierarchySelector || hasParent ) {
+ return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+ }
+
+ } catch(pseudoError) {
+ } finally {
+ if ( !old ) {
+ oldContext.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ // release memory in IE
+ div = null;
+ })();
+}
+
+(function(){
+ var html = document.documentElement,
+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector,
+ pseudoWorks = false;
+
+ try {
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( document.documentElement, "[test!='']:sizzle" );
+
+ } catch( pseudoError ) {
+ pseudoWorks = true;
+ }
+
+ if ( matches ) {
+ Sizzle.matchesSelector = function( node, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+ if ( !Sizzle.isXML( node ) ) {
+ try {
+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+ return matches.call( node, expr );
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle(expr, null, null, [node]).length > 0;
+ };
+ }
+})();
+
+(function(){
+ var div = document.createElement("div");
+
+ div.innerHTML = "";
+
+ // Opera can't find a second classname (in 9.6)
+ // Also, make sure that getElementsByClassName actually exists
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+ return;
+ }
+
+ // Safari caches class attributes, doesn't catch changes (in 3.2)
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 ) {
+ return;
+ }
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function( match, context, isXML ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ // release memory in IE
+ div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName.toLowerCase() === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+if ( document.documentElement.contains ) {
+ Sizzle.contains = function( a, b ) {
+ return a !== b && (a.contains ? a.contains(b) : true);
+ };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+ Sizzle.contains = function( a, b ) {
+ return !!(a.compareDocumentPosition(b) & 16);
+ };
+
+} else {
+ Sizzle.contains = function() {
+ return false;
+ };
+}
+
+Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context ) {
+ var match,
+ tmpSet = [],
+ later = "",
+ root = context.nodeType ? [context] : context;
+
+ // Position selectors must be done after the filter
+ // And so must :not(positional) so we move all PSEUDOs to the end
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})();
+
+
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+ // Note: This RegExp should be improved, or likely pulled from Sizzle
+ rmultiselector = /,/,
+ isSimple = /^.[^:#\[\.,]*$/,
+ slice = Array.prototype.slice,
+ POS = jQuery.expr.match.POS,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var ret = this.pushStack( "", "find", selector ),
+ length = 0;
+
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ length = ret.length;
+ jQuery.find( selector, this[i], ret );
+
+ if ( i > 0 ) {
+ // Make sure that the results are unique
+ for ( var n = length; n < ret.length; n++ ) {
+ for ( var r = 0; r < length; r++ ) {
+ if ( ret[r] === ret[n] ) {
+ ret.splice(n--, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ has: function( target ) {
+ var targets = jQuery( target );
+ return this.filter(function() {
+ for ( var i = 0, l = targets.length; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false), "not", selector);
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true), "filter", selector );
+ },
+
+ is: function( selector ) {
+ return !!selector && jQuery.filter( selector, this ).length > 0;
+ },
+
+ closest: function( selectors, context ) {
+ var ret = [], i, l, cur = this[0];
+
+ if ( jQuery.isArray( selectors ) ) {
+ var match, selector,
+ matches = {},
+ level = 1;
+
+ if ( cur && selectors.length ) {
+ for ( i = 0, l = selectors.length; i < l; i++ ) {
+ selector = selectors[i];
+
+ if ( !matches[selector] ) {
+ matches[selector] = jQuery.expr.match.POS.test( selector ) ?
+ jQuery( selector, context || this.context ) :
+ selector;
+ }
+ }
+
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( selector in matches ) {
+ match = matches[selector];
+
+ if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
+ ret.push({ selector: selector, elem: cur, level: level });
+ }
+ }
+
+ cur = cur.parentNode;
+ level++;
+ }
+ }
+
+ return ret;
+ }
+
+ var pos = POS.test( selectors ) ?
+ jQuery( selectors, context || this.context ) : null;
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+
+ } else {
+ cur = cur.parentNode;
+ if ( !cur || !cur.ownerDocument || cur === context ) {
+ break;
+ }
+ }
+ }
+ }
+
+ ret = ret.length > 1 ? jQuery.unique(ret) : ret;
+
+ return this.pushStack( ret, "closest", selectors );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+ if ( !elem || typeof elem === "string" ) {
+ return jQuery.inArray( this[0],
+ // If it receives a string, the selector is used
+ // If it receives nothing, the siblings are used
+ elem ? jQuery( elem ) : this.parent().children() );
+ }
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+ all :
+ jQuery.unique( all ) );
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ }
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+ return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return jQuery.nth( elem, 2, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return jQuery.nth( elem, 2, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( elem.parentNode.firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.makeArray( elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until ),
+ // The variable 'args' was introduced in
+ // https://github.com/jquery/jquery/commit/52a0238
+ // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
+ // http://code.google.com/p/v8/issues/detail?id=1050
+ args = slice.call(arguments);
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+ if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret, name, args.join(",") );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function( cur, result, dir, elem ) {
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] ) {
+ if ( cur.nodeType === 1 && ++num === result ) {
+ break;
+ }
+ }
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return (elem === qualifier) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+ });
+}
+
+
+
+
+var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+ rtagName = /<([\w:]+)/,
+ rtbody = /", "" ],
+ legend: [ 1, "" ],
+ thead: [ 1, "
+ When dragging an AutoFill handle, the table (if DataTables scrolling is enabled) or the window will be automatically scrolled, as you approach the edge of the scrolling component. The example below shows the effect with DataTables scrolling (and also window if needed).
+