diff --git a/README.md b/README.md new file mode 100644 index 00000000..dbbe6321 --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +About this module : +=================== +This module provides an integration of ElasticSearch into Magento developed by the R&D to address a lot of shortcomings met with the native SolR integration shipped with Magento EE : + +* Fulltext search improvement (fuzzy text query, …) +* Rich autocomplete (products, categories, …) +* Highly tunable scoring features +* Relevancy using behavior of the customers (Not yet released OpenSource) +* Integration of all Smile experience about search solutions (e.g. : Virtual Categories, multiple select facetting, …) + +You can find more information in our slideshare slides : + +[![enter image description here](doc/assets/slideshare.png)](http://www.slideshare.net/SmileOpenSource/bargento-2014-searchandising1) + +Documentation : +=============== + +* [Installing the module](doc/install.md) +* [User documentation](doc/user-documentation.md) +* [Developper documentation](doc/developper-documentation.md) +* [Behavorial search documentation](doc/behavorial-search.md) (Not yet released OpenSource) +* [Indexing custom content](doc/indexing.md) + +FAQ +=== + +Why choosing ElaticSearch instead of extending the SolR implementation shipped with Magento EE ? +------------------------------------------------------------------------------------------------ +First, ElasticSearch contains a lot more features usefull we need to achieve some features of the project : + +* Query language is more complete and allow us toi build very complex use case models +* Rescoring used for behavorial content +* Ability to store many types of content into the same index (products, categories, ...) + +Into the future we plan to use even more features specific to ElasticSearch (percolation, aggregation), since they are very valuable into an eCommerce context. + +In the end ES has a lot of advantages over SolR : + +* A strong momentum with a community providing a lot of support and extensions to the core offer +* Supported by a commercial company +* Very well documented (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/) !!! +* Built for distributed environnement, making easier to scale it up for our biggest clients +* Built with replication features out of the box ensuring more security for the websites using the engine + + +Who is supporting the module ? What about upgrability ? +------------------------------------------------------- + +Smile is supporting the module and ensure it is compatible with new Magento versions. +The kind of feature we provide requires usually an external tool (FredHopper, ...) which requires a project by project upgrade which can take longer. + +Our main idea is to create a community of clients sharing investment and evolutions about searchandizing features. + + +What is the project roadmap ? +----------------------------- + +* More user behavior influence +* Promotional rules influence on the search engine, Search engine based distance to promotion. +* More website animation features to achieve a full searchandising suite ( +* Showcases based on widgets +* Banners selection +* Stamping based on rules (new product, special price, ...) +* Marketing facets +* Recommandations + + +What Magento version is supported ? +----------------------------------- + +The module has been successfully deployed and tested against the following Magento versions : +* Magento EE 1.13 +* Magento EE 1.14 +* Magento CE 1.8 +* Magento CE 1.9 + + +Can I install it on my existing project ? +----------------------------------------- + +If your project is using Magento EE >= 1.13 or Magento CE >= 1.8, the time you will need will depends only of the amount of custom developments you spent on SolR onto the project. The custom developments can be separated in two parts : + +* Custom development replaced by new features of Magento ElasticSearch module (multiple facets, virtual categories, ...). You should disable this features into your old project and adapt the new version to you specific needs +* Other features, you should be able to port with a very moderated effort (1 day / feature). + +If your project does not rely on SolR to achieve developments, the migration project should not be more than a few days project. + +For older version of Magento, an evaluation should be done for your specific project. + + +Bugs / RFC +---------- + +Don't hesitate to : + +* Submit a bug, RFC, idea of new feature +* Submit a merge request + + diff --git a/doc/assets/attribute-config.png b/doc/assets/attribute-config.png new file mode 100644 index 00000000..a460a33c Binary files /dev/null and b/doc/assets/attribute-config.png differ diff --git a/doc/assets/autocomplete.png b/doc/assets/autocomplete.png new file mode 100644 index 00000000..c71d2a2d Binary files /dev/null and b/doc/assets/autocomplete.png differ diff --git a/doc/assets/config-1.png b/doc/assets/config-1.png new file mode 100644 index 00000000..0770b753 Binary files /dev/null and b/doc/assets/config-1.png differ diff --git a/doc/assets/config-2.png b/doc/assets/config-2.png new file mode 100644 index 00000000..13f986c1 Binary files /dev/null and b/doc/assets/config-2.png differ diff --git a/doc/assets/config-3.png b/doc/assets/config-3.png new file mode 100644 index 00000000..9eea96e6 Binary files /dev/null and b/doc/assets/config-3.png differ diff --git a/doc/assets/config-tracker.png b/doc/assets/config-tracker.png new file mode 100644 index 00000000..d9390381 Binary files /dev/null and b/doc/assets/config-tracker.png differ diff --git a/doc/assets/constant-score-optimizer.png b/doc/assets/constant-score-optimizer.png new file mode 100644 index 00000000..c7ff729b Binary files /dev/null and b/doc/assets/constant-score-optimizer.png differ diff --git a/doc/assets/facets-1.png b/doc/assets/facets-1.png new file mode 100644 index 00000000..cb8ea451 Binary files /dev/null and b/doc/assets/facets-1.png differ diff --git a/doc/assets/facets-2.png b/doc/assets/facets-2.png new file mode 100644 index 00000000..18a36df8 Binary files /dev/null and b/doc/assets/facets-2.png differ diff --git a/doc/assets/optimizer-list.png b/doc/assets/optimizer-list.png new file mode 100644 index 00000000..f816269c Binary files /dev/null and b/doc/assets/optimizer-list.png differ diff --git a/doc/assets/popularity-optimizer.png b/doc/assets/popularity-optimizer.png new file mode 100644 index 00000000..c65fdc1b Binary files /dev/null and b/doc/assets/popularity-optimizer.png differ diff --git a/doc/assets/slideshare.png b/doc/assets/slideshare.png new file mode 100644 index 00000000..d1c9e9e0 Binary files /dev/null and b/doc/assets/slideshare.png differ diff --git a/doc/assets/virtual-categories.png b/doc/assets/virtual-categories.png new file mode 100644 index 00000000..481b7410 Binary files /dev/null and b/doc/assets/virtual-categories.png differ diff --git a/doc/behavorial-search.md b/doc/behavorial-search.md new file mode 100644 index 00000000..d7137411 --- /dev/null +++ b/doc/behavorial-search.md @@ -0,0 +1,242 @@ +Behavorial Search Features +========================== + +The module comes with mechanism which allows the engine to analyze behavior of the users of the website to modify search results scoring. + +This section explains how to configure this feature and extend the available models. + +Data collector +-------------- + +### Prepare ElasticSearch + +In order to make the feature working, you will need to install the ES tracking indexer shipped with the module (es/plugins/tracking-indexer/tracking-indexer-current.jar). + +The module is normally installed with ES if you have used the automated install script (see [Installing the module](install.md)). + +You can check the module is correctly installed by running the following command from the shell : + +```bash +/usr/share/elasticsearch/bin/plugin --list +``` + +If not installed, you can rerun the install script after you have check you have the last version of the module. +You can also run the following command to install the plugin from the source : + +```bash +/usr/share/elasticsearch/bin/plugin -i tracking-indexer -u file:///SOURCE_ROOT/es/tracking-indexer/tracking-indexer-current.jar +``` + +When installed the http://localhost:9200/tracker/hit URL of the search engine should respond with an empty PNG image and the search engine is ready to index events sent through this URL. + +> **Note :** +> When using SPBuilder, make sure the es directory of your project is part of your delivery package. It is not the case bu default, but you can add the path to the svn-components (More details at https://wiki.smile.fr/view/Dirtech/Projets/SpBuilderProperties) + +### Apache configuration + +You will need a new domain name to collect tracking. + +For a site named **www.mysite.com**, you can use a new domain called **t.mysite.com** or **hit.mysite.com** by example. + +This domain will be proxied to ES tracking plugin through an Apache vhost : + +``` conf + + + ServerName t.mysite.com + + ProxyPreserveHost On + + BalancerMember http://localhost:9200/tracker/hit + # Place all your ES nodes as balancer member + # If you have 2 nodes (es.node1.mywebsite.com and es.node2.mywebsite.com), + # you will have the following configuration : + # + # BalancerMember http://es.node1.mywebsite.com:9200/tracker/hit + # BalancerMember http://es.node1.mywebsite.com:9200/tracker/hit + + + RewriteEngine On + RewriteRule (.*) balancer://esnodes [P] + + ErrorLog /var/log/apache2/smile-tracker.log + CustomLog /var/log/apache2/smile-tracker.log combined + + +``` + +Before restarting apache, ensure the required Apache modules are correctly loaded : + +```bash +a2enmode proxy proxy_http proxy_balancer headers +``` + +> **Note :** +> * If using Varnish, you have to exclude the hit domain from the cache. +> * If using SSL on your website, you will need **to duplicate this configuration on the SSL port (443)** in order your website respond to https://t.mysite.com correctly. **You will need a valid certificate for this domain.** +> * Use the same domain name for SSL and non-SSL (a limitation into the tracking module does not allow different domain name). + + +### Smile Tracker + +The Smile_Tracker module is shipped with the ES install. This module is in charge of tagging pages of the website with small PNG image with relay information about customer navigation to the newly created Apache vhost. + +The only thing, you have to do is configuring the URL of your tracker. +This configuration can be found into **System > Configuration > Smile Searchandising Suite> Tagging** : + +![Tracking configuration](assets/config-tracker.png) + +|Param|Description| +|-----|-----------| +|Tracker Base Url|The URL of the Apache proxy.
Use an any png suffix (h.png, hit.png, ...).
Prefer URL relative protocol with // (http://www.paulirish.com/2010/the-protocol-relative-url/) especially if using a website with SSL.| +|Cookie params|Cookies can be adjusted to change the duration of the session or of the visitor identification. Their name can be changed (not recommended) to avoid collision with other cookies.| + + +Optimizer models +---------------- + +Once the data collect is installed, you can use the optimizer module. +The purpose of this module is to apply custom scoring models to search. + +You can access the optimizers though **Catalog > Search > Optimizers** and will found a list of all optimizers applied on the website : + +![Optimizer list](assets/optimizer-list.png) + +> **About applying optimizer on the categories list** +> +> There is a regression in ES (https://github.com/elasticsearch/elasticsearch/issues/6788), which preventing using the rescorer on categories. +> The bug will be fixed in a future release and updating ES will apply optimizer as a secondary sort on category product list (after the position of the product chosen by the admin). + +At this time two model of optimizer are available : + +* **Constant Score** +* **Popularity** + +### Constant Score Optimizers + +![Constant score optimizer](assets/constant-score-optimizer.png) + +> **Description :** This model apply a a boost defined in percent by the admin to a selection of products. + +### Popularity Optimizers + +![Popularity](assets/popularity-optimizer.png) + +> **Description :** This model give a boost to product according to their popularity. Value of the boost is computed using the params below + +|Param|Description| +|-----|-----------| +|Popularity type|The type of event that will be counted to determine popularity : number of sales or number of views| +|Scale function|The function that will be applied to the number of sales / views. Most of time, use logarithm (log10) is the best model and avoid product to be overrated| +|Scale factor|A multiplication factor applied to the count before applying the scale function.
Use low scale factor for views (0.1) and higher for sales (10)| +|Decrease duration (in days)|Every day, the count is decreased by a small amount. This param set the number of day before the count reaches 50% of it's value| + +**Exemples :** + +|scale function |scale factor|Count = 10|Count=100|Count = 1000| +|---------------|------------|----------|---------|------------| +|log | 1| 1| 2| 3| +|log | 10| 2| 3| 4| +|log | 0.1| 1| 1| 2| +|sqrt | 1| 3.1| 10| 31| +|sqrt | 10| 10| 31| 100| +|sqrt | 0.1| 1| 3.1| 10| +|linear | 1| 10| 100| 1000| +|linear | 10| 100| 1000| 10000| +|linear | 0.1| 1| 10| 100| + +### Custom Optimizer Development + +You can develop your own model in your module by implementing a class inherited **Smile_SearchOptimizer_Model_Optimizer_Abstract** and by appending it to the config : + +**Example :** + +The constant score implementation : + +``` php +class Smile_SearchOptimizer_Model_Optimizer_ConstantScore extends Smile_SearchOptimizer_Model_Optimizer_Abstract +{ + /** + * @var string + */ + protected $_name = 'Constant score'; + + /** + * Append model configuration to the form. + * + * @param Varien_Data_Form $form Form the config should be added to. + * @param Smile_SearchOptimizer_Model_Optimizer $optimizer Current optimizer. + * + * @return Smile_SearchOptimizer_Model_Optimizer_Abstract Self reference. + */ + public function prepareForm($form, $optimizer) + { + parent::prepareForm($form, $optimizer); + + $fieldset = $form->getElement('model_config_fieldset'); + + $fieldset->addField( + 'config_boost_value', + 'text', + array( + 'name' => 'config[boost_value]', + 'label' => Mage::helper('smile_searchoptimizer')->__('Boost value (%)'), + 'title' => Mage::helper('smile_searchoptimizer')->__('Boost value (%)'), + 'required' => true + ) + ); + } + + /** + * Apply the model to the query. + * + * @param Smile_SearchOptimizer_Model_Optimizer $optimizer Current optimizer. + * @param array $query Query to optimize. + * + * @return array The modified query. + */ + public function apply($optimizer, $query) + { + $boostFactor = 1 + ((float) $optimizer->getConfig('boost_value') / 100); + $rescoreQuery = array( + 'function_score' => array( + 'boost_factor' => $boostFactor, + 'boost_mode' => 'replace' + ) + ); + + $filterRuleSearchQuery = $optimizer->getFilterRuleSearchQuery(); + + if ($filterRuleSearchQuery !== false) { + $rescoreQuery['function_score']['filter'] = array( + 'query' => array('query_string' => array('query' => $filterRuleSearchQuery)) + ); + } else { + $rescoreQuery['function_score']['query'] = array('match_all' => array()); + } + + $query['body']['rescore'][] = array( + 'window_size' => 1000, + 'query' => array( + 'rescore_query' => $rescoreQuery, + 'score_mode' => 'multiply' + ) + ); + + return $query; + } +} +``` + +It's declaration into config.xml : + +``` xml + + + + + smile_searchoptimizer/optimizer_constantScore + + + + \ No newline at end of file diff --git a/doc/developper-documentation.md b/doc/developper-documentation.md new file mode 100644 index 00000000..3582d100 --- /dev/null +++ b/doc/developper-documentation.md @@ -0,0 +1,69 @@ +Developper documentation +======================== + +**First you should not modify any file shipped with the module (even templates or layout). It should be considered in the same way than Magento core. +You should use your own module / design / skin to extend the module to grant upgrabilty of the module. +Avoid to copy / paste layout files into you own design. Prefer create a new layout file and work into.** + +Indexing : +---------- + +The search engine can mix several types of document into the same index (product, categories, …). +Every document have a type associated with him. + +By default the index is named **magento-YYYY-MM-DD-HHmmss**. +The creation date is used for **YYYY-MM-DD-HHmmss** and the alias configured for the index is used as prefix. + +The process for a full reindex is : + +1. New index is created, +2. Data are pushed into +3. The alias is switched when indexing is finished +4. The old index is removed + +Layered categories : +-------------------- +All categories are anchor categories by default. +As a result only **catalog_category_layered** layout handle is used and the **catalog_category_default** one is useless. + + +Overriding facet templates : +---------------------------- + +By default all facets share the same template (**smile/elasticsearch/catalog/layer/filter.phtml**). It can be overridden using the same technique I used to override the price facet by using layout : + +```xml + + price + + +``` +Overriding autocomplete templates : +----------------------------------- + +Content and rendering of autocomplete can be managed with the **catalogsearch_ajax_suggest** handle of the layout (bellow the version shipped with the module) : + +```xml + + + + + + + + + + + + + + + + +``` \ No newline at end of file diff --git a/doc/indexing.md b/doc/indexing.md new file mode 100644 index 00000000..b303eabb --- /dev/null +++ b/doc/indexing.md @@ -0,0 +1,144 @@ +# Indexing external content example + + + +## Example of indexing content into Magento (ex CMS Page): + +### Event listening + +* smile_elasticsearch_index_create_before : Create the index mapping before it is published +* smile_elasticsearch_index_install_before : CMS page full reindex when reindexing the whole search engine +* cms_page_save_after : Index a single page + +``` xml + + + + + smile_elasticsearch/observer + addCmsPageMappingToIndex + + + + + + + smile_elasticsearch/observer + cmsPageFullReindex + + + + + + + my_module/observer + reindexCmsPage + + + + +``` + +### Observer.php + +The first method allows to publish the schema of your document type cms_page into ES : + +```php +public function addCmsPageMappingToIndex(Varien_Event_Observer $observer) +{ + $indexProperties = $observer->getIndexProperties(); + $indexPropertiesData = $indexProperties->getData(); + $properties = array(); + $categoryMapping = &$indexPropertiesData['body']['mappings']['cms_page']['properties']; + $helper = Mage::helper('smile_elasticsearch'); + + foreach (Mage::app()->getStores() as $store) { + $languageCode = $helper->getLanguageCodeByStore($store); + + // String / text fields : + foreach (array('title', 'content') as $field) { + $field = $field . '_' . $languageCode; + $properties[$field] = array( + 'type' => 'multi_field', + 'fields' => array( + $field => array( + 'type' => 'string', + 'boost' => $weight > 0 ? $weight : 1, + ), + 'untouched' => array( + 'type' => 'string', + 'index' => 'not_analyzed', + ), + ), + ); + } + + // Other field : + $properties['example_field'] = array( + 'type' => 'int|float|date' + ) + + } + + $indexPropertiesData['body']['mappings']['cms_page']['properties'] = $properties; + $indexProperties->setData($indexPropertiesData); + + return $this; +}) +``` + +The second method allows to index page from the CMS during full reindexing : + +```php +public function cmsPageFullReindex(Varien_Event_Observer $observer) +{ + + $engine = Mage::helper('catalogsearch')->getEngine(); + + if ($engine instanceof Smile_ElasticSearch_Model_Resource_Engine_ElasticSearch) { + + foreach (Mage::app()->getStores() as $store) { + $languageCode = $helper->getLanguageCodeByStore($store); + $data = array(); + + $pages = Mage::getResourceModel('cms/page_collection') + ->addStoreFilter($store); + + foreach ($pages as $page) { + $data[] = array( + 'title_' . $languageCode => $page->getTitle(), + 'description_' . $languageCode => $page->getDescription(), + // ... Other indexed fields + ); + } + + $engine->saveEntityIndexes($store->getId(), $data, 'cms_page'); + } + } + + return $this; + +} +``` + +The third part is in charge of reindexing a page when saving it : +```php +public function reindexCmsPage(Varien_Event_Observer $observer) +{ + $page = $observer->getDataObject(); + $data = array( + array( + 'title_' . $languageCode => $page->getTitle(), + 'description_' . $languageCode => $page->getDescription(), + // ... Other indexed fields + ) + ); + + $engine->saveEntityIndexes($store->getId(), $data, 'cms_page'); +} +``` + +You should be able to see indexed page at the URL : http://localhost:9200/magento/cms_page/_search + +## Querying custom content + diff --git a/doc/install.md b/doc/install.md new file mode 100644 index 00000000..52a99a7f --- /dev/null +++ b/doc/install.md @@ -0,0 +1,93 @@ +Install +======= + +:angry_face: **Whenever possible, you must install the module and all it's requirement during the technical kickoff of the project (at the same time you install Magento). Doing so, your developer will have no adaptation to handle ES specificity** + + +Installing ES +------------- + +The module comes with a script which can handle ElasticSearch 1.2 install for you. + +Install steps : + +* Install the module into Magento +* You can find the script into **scripts/install/install-es.sh** + +You need to choose a name for your cluster. You can use the name of your project as name for your cluster. + +Then you can run the installer : + +```bash +./install_es.sh cluster_name localhost:9200 +``` + +If you want to install ES on several nodes, you need to modify the setup command in the following way (fqdn = Full Qualified Domain Name, the address of the node) : +```bash +./install_es.sh cluster_name node1.fqdn:9200 node2.fqdn:9200 node3.fqdn:9200 +``` + +One the installer have finished, you should be able to access the engine at this address : http://localhost:9200/_plugin/head. + +:angry_face: **The command should be run on every nodes.** + +> **What is the installer doing ?** +> The installer proceed to ElasticSearch and all the required dependencies install from the ES official repositories. +> +> It also applies configuration specifics : +> * Unicast discorvery mode with list of nodes (usefull into firewalled environments) +> * Enable MVEL scripting (used by the module) +> * Set the logging to the correct level for production +> +> Additionally it does install the following plugins : +> * Head plugin : a lightweight admin plugin for ES +> * ICU plugin : a plugin which support internationalization enhancement for ES used by the Magento module + +The following port are used by default by ES and should be open : + +|Port|Description| +|-----|-----------| +|9200 |This port is used to communicate with ES through it's REST API.
It should be allowed to access this port from front and from other ES nodes| +|9200 |This port is used to between ES nodes. If you plan a multiple nodes install dont't forget to open this port for every other nodes.| + + +Installing the module +--------------------- + +The Magento module does not require a particular installation but deploying the code. + +**Warning :** The module disables SolR integration shipped with Magento EE. You will not be able to rely on it's feature. It is not a problem since ElasticSearch replicates them. + + +Module configuration +-------------------- + +To configure the module you will need to access the admin into **System > Configuration > Catalog > Catalog Search **. +You first need to make sure that the **Search Engine** param is set to **Smile Serchandizing Suite**. + +Then the following options are availables : + +![Technical configuration](assets/config-2.png) + +|Param|Description| +|------|----------| +|Enable Debug Mode|Display debug message on front office. Default = off| +|Servers|List of ElasticSearch nodes the plugin should try to connect. Default : localhost:9200| +|Timeout|Timeout to realize on operation. Should be raised only if indexing huge catalog (> 1 millions products )| +|Alias name|**This is the most important part of the configuration especially if you have several instance of Magento on the same ES server.
It is the name of the index that will be used by your Magento instance.**
If you have two instance of Magento name of the alias should be different (magento-dev and magento-staging by example).| +|Number of shards, Number of replicas|Sharding and replication management
. You can have more info about this at : http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html| + +Once everything is finished you can proceed to full reindex of your magento search engine. + +In Magento EE 1.14, the search engine reindexing is no more present into the admin and you have to proceed by the shell command : + +```bash +php shell/indexer.php reindexall +``` + + +> **Notes :** +> * A lot of the settings present here are environment related and should be included in your environment reconfiguration process. +> It has not yet been decided but it would be a good idea to move this settings to local.xml files just like the database or the cache. +> * You have to be sure your cron are correctly set up when using Magento EE 1.14 since it is the process in charge of reindexing data when index is invalidated and you have no access to reindexing from admin. +> * On Magento EE 1.13 a bug is present when adding / removing product from a category. It is not ES related. For more information : https://askbot.smile.fr/question/588/magento-1131-indexing-problem/ diff --git a/doc/user-documentation.md b/doc/user-documentation.md new file mode 100644 index 00000000..ef4b4704 --- /dev/null +++ b/doc/user-documentation.md @@ -0,0 +1,126 @@ +User documentation +================== + + +Global configuration +-------------------- + +The global configuration of the module can be found into the **Catalog Search** section of **System > Configuration > Catalog**. + +First, you have access to the global configuration of the search engine shared with all other engines (MySQL and SolR) : + +![Magento default configuration](assets/config-1.png) + + +Then you have access to the ES search engine parameters. +You can check here if the search engine is correctly set up (**Search Engine** param should be set to **Smile Serchandizing Suite**). +Other parameters should be changed only by developers and are documented into the [Installing the module](install.md). + +![Technical configuration](assets/config-2.png) + + +In the end, you have access to ElasticSearch specific configuration parameters : + +![Specific ES configuration](assets/config-3.png) + +|Param Name|Description| +-----------|------------ +|Facets Max Size|Maximum number of values to display into a facets
**Note :** *This param applies only on term facet and is not used for prices, rating and categories facets.*| +|Enable Search on Options Labels|By default Magento searches only on option ids for select attributes.
This setting allows to use their textual value into fulltext.
Since there is no uses case where the default behavior is expected this setting will be removed from a future version and it's value will be yes by default.| +|Enable ICU Folding Token Filter|ES plugin filter used to clean UTF-8 invalid characters. This feature comes at the expense of the performances and should be enabled only if your catalog contains bad UTF-8 characters.| +|Enable Fuzzy Search|Enable the approching search. Used to automatically fix user mistyping. This feature replaces the traditionnal "Did you mean" feature into the module| +|Fuzzy Prefix Length, Fuzzy Min Similarity, Fuzzy Prefix Length, Fuzzy Max Expansions|Fuzzy search fine tunning.
This parameters can be used to fix the fuzzy search behavior if it match too many or not enough products.
Full documentation for the params can be found into ElasticSearch official documentation : http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-flt-query.html| +|Fuzzy Query Boost|Relative weight of fuzzy search result.
Exact matches have a weight of 1.
The default value (0.3) will result approching result being 3 times less important than exact ones.| + + +> **What is fuzzy search ?** +> +> Approximate string matching (a.k.a. fuzzy search) is the technique of finding strings that match a pattern approximately (rather than exactly). The problem of approximate string matching is typically divided into two sub-problems: finding approximate substring matches inside a given string and finding dictionary strings that match the pattern approximately. +> +> Into our engine it is used to fix : + +> * User mystipings (ex: frankenshten instead of frankenstein) +> * Give reponse for other form of a same word (ex: playing instead of play) +> +> It avoid the usage of a "Did you mean" feature by fixing the user query and consequently avoid an user click to refine it's query. +> +> You can find a very complete documentation about possible implementation of fuzzy search into ES at this address : https://www.found.no/foundation/fuzzy-search/. +> +> The implementation is subject to change into the future. Currently we are using two queries (one for exact match and one for fuzzy) and we combine their scores. An alternative will be evaluated as described into #7. + + +Attributes configuration +------------------------ + +You can find all settings related to the configuration of an attribute into **Catalog > Attributes > Manage Attributes** + +This section is very similar to what Magento EE propose for the SolR implementation : + +![Attribute configuration](assets/attribute-config.png) + +The main settings related to the search engines are : + +|Param Name|Description| +-----------|------------ +|Use in Quick Search|Indicates if the attributes has a role in search relevancy computation.| +|Search weight|Weight of the attributes into search relevancy.
Typically we use higher score on product names than on it's description.| +|Use in advanced search|Advanced search is not implemented. This settings is useless.| +|Use in layer navigation|Should the attribute be used as a facet into categories navigation| +|Use in search result layer|Should the attribute be used as a facet into search result| + +**Notes :** +* This extension allows text attributes to be used as a facet (Magento only allows facets on select / multiselect attributes. Do this only on attributes that are imported from a clean source of data to avoid list which contains many times the same values with different typos (ex: "Robert De Niro" and "robert de Niro" will be two different facets). +* The attributes **Rating filter** is a vurtual attributes which allow to configure the rating facets and sort. You can change it's label per store view, show / hide the facet, manage the facet position or show / hide the sort order. + +Virtual categories +------------------ + +The module is shipped with interface allowing to configure Virtual Categories (sometimes called Smart Categories). The Virtual categories is a powerful mechanism allowing the admin to select product of a category by building a search engine query instead of picking the products one by one. + +**Examples of Virtual Categories :** + +* All blue products that are in stock into the category men +* All product of type "Blazer" +* All product having the containing the word "Kit" dans leur nom. + +To define a category as Virtual Category : + +* Go into the **Category tab** of your category : +* Set the category virtual using the "Enable virtual category" switcher +* The manual product picket is now hidden and you can define the rule to match your product instead +* Save the category and navigate into you category on the front to verify everything is working as expected. + +![Virtual categories](assets/virtual-categories.png) + + +> **About anchor categories** +> +> By default, Magento uses a categorie attribute call **Is Anchor** with is responsible of attributing all products of all children category to the parent category if the **Is Anchor**. This attribute is also responsible of triggering facet display / hide. +> +> The virtual categories hide this attribute into the admin and make the default value equals to **Yes** for the **Is Anchor** categories + + +Front Office +------------ + +### Facets + +The default module implementation make all facets being multi-select facets : + +![Multi-select facets](assets/facets-1.png) + +Some facets like the price or the ratings have default templates bundled with the module. Developers can define custom facet for every attributes (see [Developper documentation](developper-documentation.md) for more information). + +![Price facet](assets/facets-2.png) + +### Autocomplete + +The module comes with an autocomplete which allows by default to autocomplete : + +* Popular searches made by users of the website +* Products +* Categories + +Default template is very simple (only name) but can be overridden by developers to display additional attributes (eg. image) like described into [Developper documentation](developper-documentation.md) : + +![Price facet](assets/autocomplete.png) \ No newline at end of file diff --git a/modman b/modman new file mode 100644 index 00000000..68059d9e --- /dev/null +++ b/modman @@ -0,0 +1,13 @@ +src/app/code/community/Smile/* app/code/community/Smile/ +src/app/design/adminhtml/default/default/layout/smile/* app/design/adminhtml/default/default/layout/smile/ +src/app/design/adminhtml/default/default/template/smile/* app/design/adminhtml/default/default/template/smile/ +src/app/design/frontend/base/default/layout/smile/* app/design/frontend/base/default/layout/smile/ +src/app/design/frontend/base/default/template/smile/* app/design/frontend/base/default/template/smile/ +src/app/design/frontend/rwd/default/layout/smile/* app/design/frontend/rwd/default/layout/smile/ +src/app/design/frontend/rwd/default/template/smile/* app/design/frontend/rwd/default/template/smile/ +src/app/etc/modules/* app/etc/modules +src/app/locale/en_US/* app/locale/en_US/ +src/app/locale/fr_FR/* app/locale/fr_FR/ +src/js/smile/* js/smile/ +src/lib/* lib/ +src/skin/frontend/base/default/css/smile/* skin/frontend/base/default/css/smile/ \ No newline at end of file diff --git a/scripts/install/es-conf-templates/elasticsearch.yml b/scripts/install/es-conf-templates/elasticsearch.yml new file mode 100644 index 00000000..ba681ba4 --- /dev/null +++ b/scripts/install/es-conf-templates/elasticsearch.yml @@ -0,0 +1,379 @@ +##################### Elasticsearch Configuration Example ##################### + +# This file contains an overview of various configuration settings, +# targeted at operations staff. Application developers should +# consult the guide at . +# +# The installation procedure is covered at +# . +# +# Elasticsearch comes with reasonable defaults for most settings, +# so you can try it out without bothering with configuration. +# +# Most of the time, these defaults are just fine for running a production +# cluster. If you're fine-tuning your cluster, or wondering about the +# effect of certain configuration option, please _do ask_ on the +# mailing list or IRC channel [http://elasticsearch.org/community]. + +# Any element in the configuration can be replaced with environment variables +# by placing them in ${...} notation. For example: +# +# node.rack: ${RACK_ENV_VAR} + +# For information on supported formats and syntax for the config file, see +# + + +################################### Cluster ################################### + +# Cluster name identifies your cluster for auto-discovery. If you're running +# multiple clusters on the same network, make sure you're using unique names. +# +cluster.name: CLUSTER_NAME + + +#################################### Node ##################################### + +# Node names are generated dynamically on startup, so you're relieved +# from configuring them manually. You can tie this node to a specific name: +# +# node.name: "Franz Kafka" + +# Every node can be configured to allow or deny being eligible as the master, +# and to allow or deny to store the data. +# +# Allow this node to be eligible as a master node (enabled by default): +# +# node.master: true +# +# Allow this node to store data (enabled by default): +# +# node.data: true + +# You can exploit these settings to design advanced cluster topologies. +# +# 1. You want this node to never become a master node, only to hold data. +# This will be the "workhorse" of your cluster. +# +# node.master: false +# node.data: true +# +# 2. You want this node to only serve as a master: to not store any data and +# to have free resources. This will be the "coordinator" of your cluster. +# +# node.master: true +# node.data: false +# +# 3. You want this node to be neither master nor data node, but +# to act as a "search load balancer" (fetching data from nodes, +# aggregating results, etc.) +# +# node.master: false +# node.data: false + +# Use the Cluster Health API [http://localhost:9200/_cluster/health], the +# Node Info API [http://localhost:9200/_nodes] or GUI tools +# such as , +# , +# and +# to inspect the cluster state. + +# A node can have generic attributes associated with it, which can later be used +# for customized shard allocation filtering, or allocation awareness. An attribute +# is a simple key value pair, similar to node.key: value, here is an example: +# +# node.rack: rack314 + +# By default, multiple nodes are allowed to start from the same installation location +# to disable it, set the following: +# node.max_local_storage_nodes: 1 + + +#################################### Index #################################### + +# You can set a number of options (such as shard/replica options, mapping +# or analyzer definitions, translog settings, ...) for indices globally, +# in this file. +# +# Note, that it makes more sense to configure index settings specifically for +# a certain index, either when creating it or by using the index templates API. +# +# See and +# +# for more information. + +# Set the number of shards (splits) of an index (5 by default): +# +# index.number_of_shards: 5 + +# Set the number of replicas (additional copies) of an index (1 by default): +# +# index.number_of_replicas: 1 + +# Note, that for development on a local machine, with small indices, it usually +# makes sense to "disable" the distributed features: +# +# index.number_of_shards: 1 +# index.number_of_replicas: 0 + +# These settings directly affect the performance of index and search operations +# in your cluster. Assuming you have enough machines to hold shards and +# replicas, the rule of thumb is: +# +# 1. Having more *shards* enhances the _indexing_ performance and allows to +# _distribute_ a big index across machines. +# 2. Having more *replicas* enhances the _search_ performance and improves the +# cluster _availability_. +# +# The "number_of_shards" is a one-time setting for an index. +# +# The "number_of_replicas" can be increased or decreased anytime, +# by using the Index Update Settings API. +# +# Elasticsearch takes care about load balancing, relocating, gathering the +# results from nodes, etc. Experiment with different settings to fine-tune +# your setup. + +# Use the Index Status API () to inspect +# the index status. + + +#################################### Paths #################################### + +# Path to directory containing configuration (this file and logging.yml): +# +# path.conf: /path/to/conf + +# Path to directory where to store index data allocated for this node. +# +# path.data: /path/to/data +# +# Can optionally include more than one location, causing data to be striped across +# the locations (a la RAID 0) on a file level, favouring locations with most free +# space on creation. For example: +# +# path.data: /path/to/data1,/path/to/data2 + +# Path to temporary files: +# +# path.work: /path/to/work + +# Path to log files: +# +# path.logs: /path/to/logs + +# Path to where plugins are installed: +# +# path.plugins: /path/to/plugins + + +#################################### Plugin ################################### + +# If a plugin listed here is not installed for current node, the node will not start. +# +# plugin.mandatory: mapper-attachments,lang-groovy + + +################################### Memory #################################### + +# Elasticsearch performs poorly when JVM starts swapping: you should ensure that +# it _never_ swaps. +# +# Set this property to true to lock the memory: +# +# bootstrap.mlockall: true + +# Make sure that the ES_MIN_MEM and ES_MAX_MEM environment variables are set +# to the same value, and that the machine has enough memory to allocate +# for Elasticsearch, leaving enough memory for the operating system itself. +# +# You should also make sure that the Elasticsearch process is allowed to lock +# the memory, eg. by using `ulimit -l unlimited`. + + +############################## Network And HTTP ############################### + +# Elasticsearch, by default, binds itself to the 0.0.0.0 address, and listens +# on port [9200-9300] for HTTP traffic and on port [9300-9400] for node-to-node +# communication. (the range means that if the port is busy, it will automatically +# try the next port). + +# Set the bind address specifically (IPv4 or IPv6): +# +# network.bind_host: 192.168.0.1 + +# Set the address other nodes will use to communicate with this node. If not +# set, it is automatically derived. It must point to an actual IP address. +# +# network.publish_host: 192.168.0.1 + +# Set both 'bind_host' and 'publish_host': +# +# network.host: 192.168.0.1 + +# Set a custom port for the node to node communication (9300 by default): +# +# transport.tcp.port: 9300 + +# Enable compression for all communication between nodes (disabled by default): +# +# transport.tcp.compress: true + +# Set a custom port to listen for HTTP traffic: +# +# http.port: 9200 + +# Set a custom allowed content length: +# +# http.max_content_length: 100mb + +# Disable HTTP completely: +# +# http.enabled: false + + +################################### Gateway ################################### + +# The gateway allows for persisting the cluster state between full cluster +# restarts. Every change to the state (such as adding an index) will be stored +# in the gateway, and when the cluster starts up for the first time, +# it will read its state from the gateway. + +# There are several types of gateway implementations. For more information, see +# . + +# The default gateway type is the "local" gateway (recommended): +# +# gateway.type: local + +# Settings below control how and when to start the initial recovery process on +# a full cluster restart (to reuse as much local data as possible when using shared +# gateway). + +# Allow recovery process after N nodes in a cluster are up: +# +# gateway.recover_after_nodes: 1 + +# Set the timeout to initiate the recovery process, once the N nodes +# from previous setting are up (accepts time value): +# +# gateway.recover_after_time: 5m + +# Set how many nodes are expected in this cluster. Once these N nodes +# are up (and recover_after_nodes is met), begin recovery process immediately +# (without waiting for recover_after_time to expire): +# +# gateway.expected_nodes: 2 + + +############################# Recovery Throttling ############################# + +# These settings allow to control the process of shards allocation between +# nodes during initial recovery, replica allocation, rebalancing, +# or when adding and removing nodes. + +# Set the number of concurrent recoveries happening on a node: +# +# 1. During the initial recovery +# +# cluster.routing.allocation.node_initial_primaries_recoveries: 4 +# +# 2. During adding/removing nodes, rebalancing, etc +# +# cluster.routing.allocation.node_concurrent_recoveries: 2 + +# Set to throttle throughput when recovering (eg. 100mb, by default 20mb): +# +# indices.recovery.max_bytes_per_sec: 20mb + +# Set to limit the number of open concurrent streams when +# recovering a shard from a peer: +# +# indices.recovery.concurrent_streams: 5 + + +################################## Discovery ################################## + +# Discovery infrastructure ensures nodes can be found within a cluster +# and master node is elected. Multicast discovery is the default. + +# Set to ensure a node sees N other master eligible nodes to be considered +# operational within the cluster. Its recommended to set it to a higher value +# than 1 when running more than 2 nodes in the cluster. +# +# discovery.zen.minimum_master_nodes: 1 + +# Set the time to wait for ping responses from other nodes when discovering. +# Set this option to a higher value on a slow or congested network +# to minimize discovery failures: +# +# discovery.zen.ping.timeout: 3s + +# For more information, see +# + +# Unicast discovery allows to explicitly control which nodes will be used +# to discover the cluster. It can be used when multicast is not present, +# or to restrict the cluster communication-wise. +# +# 1. Disable multicast discovery (enabled by default): +# +discovery.zen.ping.multicast.enabled: false +# +# 2. Configure an initial list of master nodes in the cluster +# to perform discovery when new nodes (master or data) are started: +# +discovery.zen.ping.unicast.hosts: [HOSTS] + +# EC2 discovery allows to use AWS EC2 API in order to perform discovery. +# +# You have to install the cloud-aws plugin for enabling the EC2 discovery. +# +# For more information, see +# +# +# See +# for a step-by-step tutorial. + +# GCE discovery allows to use Google Compute Engine API in order to perform discovery. +# +# You have to install the cloud-gce plugin for enabling the GCE discovery. +# +# For more information, see . + +# Azure discovery allows to use Azure API in order to perform discovery. +# +# You have to install the cloud-azure plugin for enabling the Azure discovery. +# +# For more information, see . + +################################## Slow Log ################################## + +# Shard level query and fetch threshold logging. + +#index.search.slowlog.threshold.query.warn: 10s +#index.search.slowlog.threshold.query.info: 5s +#index.search.slowlog.threshold.query.debug: 2s +#index.search.slowlog.threshold.query.trace: 500ms + +#index.search.slowlog.threshold.fetch.warn: 1s +#index.search.slowlog.threshold.fetch.info: 800ms +#index.search.slowlog.threshold.fetch.debug: 500ms +#index.search.slowlog.threshold.fetch.trace: 200ms + +#index.indexing.slowlog.threshold.index.warn: 10s +#index.indexing.slowlog.threshold.index.info: 5s +#index.indexing.slowlog.threshold.index.debug: 2s +#index.indexing.slowlog.threshold.index.trace: 500ms + +################################## GC Logging ################################ + +#monitor.jvm.gc.young.warn: 1000ms +#monitor.jvm.gc.young.info: 700ms +#monitor.jvm.gc.young.debug: 400ms + +#monitor.jvm.gc.old.warn: 10s +#monitor.jvm.gc.old.info: 5s +#monitor.jvm.gc.old.debug: 2 + +script.disable_dynamic: false \ No newline at end of file diff --git a/scripts/install/es-conf-templates/logging.yml b/scripts/install/es-conf-templates/logging.yml new file mode 100644 index 00000000..6a7bc96f --- /dev/null +++ b/scripts/install/es-conf-templates/logging.yml @@ -0,0 +1,56 @@ +# you can override this using by setting a system property, for example -Des.logger.level=DEBUG +es.logger.level: WARN +rootLogger: ${es.logger.level}, console, file +logger: + # log action execution errors for easier debugging + action: DEBUG + # reduce the logging for aws, too much is logged under the default INFO + com.amazonaws: WARN + + # gateway + #gateway: DEBUG + #index.gateway: DEBUG + + # peer shard recovery + #indices.recovery: DEBUG + + # discovery + #discovery: TRACE + + index.search.slowlog: TRACE, index_search_slow_log_file + index.indexing.slowlog: TRACE, index_indexing_slow_log_file + +additivity: + index.search.slowlog: false + index.indexing.slowlog: false + +appender: + console: + type: console + layout: + type: consolePattern + conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n" + + file: + type: dailyRollingFile + file: ${path.logs}/${cluster.name}.log + datePattern: "'.'yyyy-MM-dd" + layout: + type: pattern + conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n" + + index_search_slow_log_file: + type: dailyRollingFile + file: ${path.logs}/${cluster.name}_index_search_slowlog.log + datePattern: "'.'yyyy-MM-dd" + layout: + type: pattern + conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n" + + index_indexing_slow_log_file: + type: dailyRollingFile + file: ${path.logs}/${cluster.name}_index_indexing_slowlog.log + datePattern: "'.'yyyy-MM-dd" + layout: + type: pattern + conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n" \ No newline at end of file diff --git a/scripts/install/install-es.sh b/scripts/install/install-es.sh new file mode 100755 index 00000000..6d6372a8 --- /dev/null +++ b/scripts/install/install-es.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +# ElasticSearch server install +# @author Aurelien FOUCRET +# + +# Configuration stuffs +ES_VERSION=1.2 +ES_PLUGIN_CMD=/usr/share/elasticsearch/bin/plugin +ES_LOCAL_PLUGIN_DIR=`dirname $0`/../../es/plugins + +if [ "$#" -lt 2 ]; then + echo "Usage : ./install-es.sh cluster_name server1:port ..." + exit 1 +fi +CLUSTER_NAME=$1 +HOSTS=`printf -- "\"%s\", " ${@:2} | rev | cut -c3- | rev` + +# Installing Java and ES from the packages +wget -O - http://packages.elasticsearch.org/GPG-KEY-elasticsearch | apt-key add - +echo "deb http://packages.elasticsearch.org/elasticsearch/$ES_VERSION/debian stable main" > /etc/apt/sources.list.d/elaticsearch.list +apt-get update +apt-get install elasticsearch openjdk-7-jdk + +# Deploy configuration +sed -e "s/CLUSTER_NAME/\"$CLUSTER_NAME\"/;s/HOSTS/$HOSTS/;" es-conf-templates/elasticsearch.yml > /etc/elasticsearch/elasticsearch.yml +cp -rfv es-conf-templates/logging.yml /etc/elasticsearch/ + +# Start ES and ensure it starts with the system +service elasticsearch restart +update-rc.d elasticsearch defaults + +# Installing plugins required by Magento modules +$ES_PLUGIN_CMD -r mobz/elasticsearch-head +$ES_PLUGIN_CMD -install mobz/elasticsearch-head +$ES_PLUGIN_CMD -r elasticsearch/elasticsearch-analysis-icu +$ES_PLUGIN_CMD -install elasticsearch/elasticsearch-analysis-icu/2.2.0 diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Abstract.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Abstract.php new file mode 100644 index 00000000..0375ed23 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Abstract.php @@ -0,0 +1,30 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_Filter_Abstract extends Mage_Catalog_Block_Layer_Filter_Abstract +{ + /** + * Return the filter request var (used to build URL) + * + * @return string + */ + public function getRequestVar() + { + return $this->_filter->getRequestVar(); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Attribute.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Attribute.php new file mode 100644 index 00000000..9f13bcae --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Attribute.php @@ -0,0 +1,58 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_Filter_Attribute extends Smile_ElasticSearch_Block_Catalog_Layer_Filter_Abstract +{ + /** + * Defines specific filter model name. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute + */ + public function __construct() + { + parent::__construct(); + $this->_filterModelName = 'smile_elasticsearch/catalog_layer_filter_attribute'; + $this->setIsMultipleSelect(true); + $this->setTemplate('smile/elasticsearch/catalog/layer/filter.phtml'); + } + + /** + * Prepares filter model. + * + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Attribute + */ + protected function _prepareFilter() + { + $this->_filter->setAttributeModel($this->getAttributeModel()); + $this->_filter->setIsMultipleSelect(true); + return $this; + } + + /** + * Adds facet condition to filter. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute::addFacetCondition() + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Attribute + */ + public function addFacetCondition() + { + $this->_filter->addFacetCondition(); + + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Boolean.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Boolean.php new file mode 100644 index 00000000..a5551a60 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Boolean.php @@ -0,0 +1,31 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_Filter_Boolean extends Smile_ElasticSearch_Block_Catalog_Layer_Filter_Attribute +{ + /** + * Defines specific filter model name. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Boolean + */ + public function __construct() + { + parent::__construct(); + $this->_filterModelName = 'smile_elasticsearch/catalog_layer_filter_boolean'; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Category.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Category.php new file mode 100644 index 00000000..d849c078 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Category.php @@ -0,0 +1,67 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_Filter_Category extends Smile_ElasticSearch_Block_Catalog_Layer_Filter_Abstract +{ + /** + * Defines specific filter model name. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Category + */ + public function __construct() + { + parent::__construct(); + $this->_filterModelName = 'smile_elasticsearch/catalog_layer_filter_category'; + } + + /** + * Init filter model object + * + * @return Mage_Catalog_Block_Layer_Filter_Abstract + */ + protected function _initFilter() + { + if (!$this->_filterModelName) { + Mage::throwException(Mage::helper('catalog')->__('Filter model name must be declared.')); + } + $this->_filter = Mage::getModel($this->_filterModelName) + ->setLayer($this->getLayer()); + + if ($this->getUseUrlRewrites()) { + $this->_filter->setUseUrlRewrites(true); + } + + $this->_prepareFilter(); + + $this->_filter->apply($this->getRequest(), $this); + return $this; + } + + /** + * Adds facet condition to filter. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Category::addFacetCondition() + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Attribute + */ + public function addFacetCondition() + { + $this->_filter->addFacetCondition(); + + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Decimal.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Decimal.php new file mode 100644 index 00000000..364e7b17 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Decimal.php @@ -0,0 +1,56 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_Filter_Decimal extends Smile_ElasticSearch_Block_Catalog_Layer_Filter_Abstract +{ + /** + * Defines specific filter model name. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal + */ + public function __construct() + { + parent::__construct(); + $this->_filterModelName = 'smile_elasticsearch/catalog_layer_filter_decimal'; + } + + /** + * Prepares filter model. + * + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Decimal + */ + protected function _prepareFilter() + { + $this->_filter->setAttributeModel($this->getAttributeModel()); + + return $this; + } + + /** + * Adds facet condition to filter. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal::addFacetCondition() + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Decimal + */ + public function addFacetCondition() + { + $this->_filter->addFacetCondition(); + + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Price.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Price.php new file mode 100644 index 00000000..3c8f96ae --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Price.php @@ -0,0 +1,152 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_Filter_Price extends Smile_ElasticSearch_Block_Catalog_Layer_Filter_Abstract +{ + /** + * Defines specific filter model name. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Price + */ + public function __construct() + { + parent::__construct(); + $this->_filterModelName = 'smile_elasticsearch/catalog_layer_filter_price'; + } + + /** + * Prepares filter model. + * + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Price + */ + protected function _prepareFilter() + { + $this->_filter->setAttributeModel($this->getAttributeModel()); + + return $this; + } + + /** + * Adds facet condition to filter. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Price::addFacetCondition() + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Price + */ + public function addFacetCondition() + { + $this->_filter->addFacetCondition(); + return $this; + } + + /** + * Return the lowest price avaiblable for filtering. + * + * @param bool $rounding Enable rounding feature according price range + * + * @return int + */ + public function getMinPriceInt($rounding = false) + { + $minPrice = $this->_filter->getMinPriceInt(); + if ($rounding === true) { + $range = $this->getPriceRange(); + $minPrice = max(0, floor($minPrice / $range) * $range); + } + return $minPrice; + } + + /** + * Return the highest price avaiblable for filtering. + * + * @param bool $rounding Enable rounding feature according price range + * + * @return int + */ + public function getMaxPriceInt($rounding = false) + { + $maxPrice = $this->_filter->getMaxPriceInt(); + if ($rounding === true) { + $range = $this->getPriceRange(); + $maxPrice = ceil($maxPrice / $range) * $range; + } + return $maxPrice; + } + + /** + * Return the size of the filtering interval + * + * @return int + */ + public function getPriceRange() + { + return $this->_filter->getPriceRange(); + } + + /** + * JS template of the get var filter + * + * @return string + */ + public function getFilterJsTemplate() + { + $requestVar = $this->getRequestVar(); + return "$requestVar=#{min}-#{max}"; + } + + /** + * Return the currently selected interval. + * + * @return array + */ + public function getInterval() + { + $interval = $this->_filter->getInterval(); + if (is_null($interval)) { + $interval = array($this->getMinPriceInt(true), $this->getMaxPriceInt(true)); + } + return $interval; + } + + /** + * Return the price format used by JS to display prices. + * + * @return array + */ + public function getJsPriceFormat() + { + return Mage::helper('core/data')->jsonEncode(Mage::app()->getLocale()->getJsPriceFormat()); + } + + /** + * Array of the interval containing products (used to build sliders) + * + * @return array + */ + public function getAllowedIntervals() + { + $minPriceInt = $this->getMinPriceInt(true); + $maxPriceInt = $this->getMaxPriceInt(true); + $allowedIntervals = array(); + + foreach ($this->getItems() as $currentItem) { + $allowedIntervals[] = array('value' => $currentItem->getValue(), 'count' => $currentItem->getCount()); + } + + return $allowedIntervals; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Rating.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Rating.php new file mode 100644 index 00000000..9961b613 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/Filter/Rating.php @@ -0,0 +1,58 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_Filter_Rating extends Smile_ElasticSearch_Block_Catalog_Layer_Filter_Abstract +{ + /** + * Defines specific filter model name. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Rating + */ + public function __construct() + { + parent::__construct(); + $this->_filterModelName = 'smile_elasticsearch/catalog_layer_filter_rating'; + } + + /** + * Prepares filter model. + * + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Price + */ + protected function _prepareFilter() + { + $this->_filter->setAttributeModel($this->getAttributeModel()); + + return $this; + } + + /** + * Adds facet condition to filter. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Price::addFacetCondition() + * @return Smile_ElasticSearch_Block_Catalog_Layer_Filter_Price + */ + public function addFacetCondition() + { + if (!$this->getRequest()->getParam('rating')) { + $this->_filter->addFacetCondition(); + } + + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/View.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/View.php new file mode 100644 index 00000000..d4ad89dc --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalog/Layer/View.php @@ -0,0 +1,200 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalog_Layer_View extends Mage_Catalog_Block_Layer_View +{ + + /** + * Templates of the filters. + * If no template found using the default one (catalog/layer/filter.phtml) + * + * See the smile/elaticssearch.xml layout file for a complete example + * + * @var array + */ + protected $_filterTemplates = array(); + + /** + * Boolean block name. + * + * @var string + */ + protected $_booleanFilterBlockName; + + /** + * Rating block name. + * + * @var string + */ + protected $_ratingFilterBlockName; + + /** + * Modifies default block names to specific ones if engine is active. + * + * @return void + */ + protected function _initBlocks() + { + parent::_initBlocks(); + + if (Mage::helper('smile_elasticsearch')->isActiveEngine()) { + $this->_categoryBlockName = 'smile_elasticsearch/catalog_layer_filter_category'; + $this->_attributeFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_attribute'; + $this->_priceFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_price'; + $this->_ratingFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_rating'; + $this->_decimalFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_decimal'; + $this->_booleanFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_boolean'; + } + } + + /** + * Prepares layout if engine is active. + * Difference between parent method is addFacetCondition() call on each created block. + * + * @return Smile_ElasticSearch_Block_Catalog_Layer_View + */ + protected function _prepareLayout() + { + /** @var $helper Smile_ElasticSearch_Helper_Data */ + $helper = Mage::helper('smile_elasticsearch'); + if (!$helper->isActiveEngine()) { + parent::_prepareLayout(); + } else { + $stateBlock = $this->getLayout()->createBlock($this->_stateBlockName) + ->setLayer($this->getLayer()); + + $categoryBlock = $this->getLayout()->createBlock($this->_categoryBlockName) + ->setUseUrlRewrites(true) + ->setLayer($this->getLayer()) + ->init(); + + $this->setChild('layer_state', $stateBlock); + $this->setChild('category_filter', $categoryBlock->addFacetCondition()); + + $filterableAttributes = $this->_getFilterableAttributes(); + + $filters = array(); + foreach ($filterableAttributes as $attribute) { + + if ($attribute->getAttributeCode() == 'price') { + $filterBlockName = $this->_priceFilterBlockName; + } elseif ($attribute->getAttributeCode() == 'rating_filter') { + $filterBlockName = $this->_ratingFilterBlockName; + } elseif ($attribute->getBackendType() == 'decimal') { + $filterBlockName = $this->_decimalFilterBlockName; + } elseif ($attribute->getSourceModel() == 'eav/entity_attribute_source_boolean') { + $filterBlockName = $this->_booleanFilterBlockName; + } else { + $filterBlockName = $this->_attributeFilterBlockName; + } + + $filters[$attribute->getAttributeCode() . '_filter'] = $this->getLayout()->createBlock($filterBlockName) + ->setLayer($this->getLayer()) + ->setAttributeModel($attribute) + ->init(); + } + //die; + foreach ($filters as $filterName => $block) { + $this->setChild($filterName, $block->addFacetCondition()); + } + + $this->getLayer()->apply(); + } + + return $this; + } + + /** + * Returns current catalog layer. + * + * @return Smile_ElasticSearch_Model_Catalog_Layer|Mage_Catalog_Model_Layer + */ + public function getLayer() + { + /** @var $helper Smile_ElasticSearch_Helper_Data */ + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isActiveEngine()) { + return Mage::getSingleton('smile_elasticsearch/catalog_layer'); + } + + return parent::getLayer(); + } + + /** + * Check availability display layer options + * + * @return bool + */ + public function canShowOptions() + { + + foreach ($this->getFilters() as $filter) { + if ($filter->getItemsCount() > 1) { + return true; + } + } + + return false; + } + + /** + * Indicates if the block should be shown or not. + * Append forced category loading to make the system more resistant to layout changes + * + * @return bool + */ + public function canShowBlock() + { + if (!$this->getLayer()->getProductCollection()->isLoaded()) { + $this->getLayer()->getProductCollection()->getSize(); + } + return parent::canShowBlock(); + } + + /** + * Assign a custom template for a given filter + * + * @param string $filterName Name of the filter + * @param string $template Template + * + * @return Smile_ElasticSearch_Model_Catalog_Layer Self reference + */ + public function addFilterTemplate($filterName, $template) + { + $this->_filterTemplates[$filterName] = $template; + return $this; + } + + /** + * Custom template handling for children blocks (filters) before to display theme + * + * @return Smile_ElasticSearch_Model_Catalog_Layer Self reference + */ + protected function _beforeToHtml() + { + if (Mage::helper('smile_elasticsearch')->isActiveEngine()) { + foreach ($this->_filterTemplates as $filterName => $template) { + $block = $this->getChild($filterName . '_filter'); + if ($block) { + $block->setTemplate($template); + } + } + } + return parent::_beforeToHtml(); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Category.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Category.php new file mode 100644 index 00000000..9530f663 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Category.php @@ -0,0 +1,60 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalogsearch_Autocomplete_Suggest_Category extends Mage_Core_Block_Template +{ + /** + * Check if the block is active or not. Block is disabled if : + * - ES is not the selected engine into Magento + * + * @return bool + */ + public function isActive() + { + return Mage::helper('smile_elasticsearch')->isActiveEngine(); + } + + /** + * Return the list of all suggested products + * + * @return Mage_Catalog_Model_Resource_Category_Collection + */ + public function getCategoryCollection() + { + $collection = Mage::getResourceModel('smile_elasticsearch/catalog_category_suggest_collection') + ->setEngine(Mage::helper('catalogsearch')->getEngine()) + ->setStoreId(Mage::app()->getStore()->getId()) + ->setPageSize(10) + ->addAttributeToSelect('name') + ->setOrder('level', Varien_Data_Collection::SORT_ORDER_ASC) + ->addSuggestFilter($this->_getQuery()) + ->addUrlRewriteToResult(); + + return $collection; + } + + /** + * Return the string query we want to retrive suggests for + * + * @return string + */ + protected function _getQuery() + { + return Mage::app()->getRequest()->getParam('q', false); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Product.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Product.php new file mode 100644 index 00000000..b3dbe638 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Product.php @@ -0,0 +1,69 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalogsearch_Autocomplete_Suggest_Product extends Mage_Core_Block_Template +{ + const AUTOCOMPLETE_ATTRIBUTES_XPATH = 'global/smile_elasticsearch/autocomplete/product/attributes'; + + /** + * Check if the block is active or not. Block is disabled if : + * - ES is not the selected engine into Magento + * + * @todo : Implements a configuration per type of suggester + * + * @return bool + */ + public function isActive() + { + return Mage::helper('smile_elasticsearch')->isActiveEngine(); + } + + /** + * Return the list of all suggested products + * + * @return Mage_Catalog_Model_Resource_Product_Collection + */ + public function getProductCollection() + { + $attributes = array_keys(Mage::getConfig()->getNode(self::AUTOCOMPLETE_ATTRIBUTES_XPATH)->asArray()); + + $collection = Mage::getResourceModel('smile_elasticsearch/catalog_product_suggest_collection') + ->setEngine(Mage::helper('catalogsearch')->getEngine()) + ->setStoreId(Mage::app()->getStore()->getId()) + ->setPageSize(10) + ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes()) + ->addAttributeToSelect($attributes) + ->addSuggestFilter($this->_getQuery()) + ->addMinimalPrice() + ->addFinalPrice() + ->addTaxPercents() + ->addUrlRewrite(); + + return $collection; + } + + /** + * Return the string query we want to retrive suggests for + * + * @return string + */ + protected function _getQuery() + { + return Mage::app()->getRequest()->getParam('q', false); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Terms.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Terms.php new file mode 100644 index 00000000..014f32b4 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Autocomplete/Suggest/Terms.php @@ -0,0 +1,56 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalogsearch_Autocomplete_Suggest_Terms extends Mage_Core_Block_Template +{ + /** + * @var null|array + */ + protected $_suggestData = null; + + /** + * Retrive the list of terms that would be suggested to the user + * + * @return array + */ + public function getSuggestData() + { + if (!$this->_suggestData) { + $collection = $this->helper('catalogsearch')->getSuggestCollection(); + $collection->setPageSize(10); + $query = $this->helper('catalogsearch')->getQueryText(); + $counter = 0; + $data = array(); + foreach ($collection as $item) { + $_data = array( + 'title' => $item->getQueryText(), + 'row_class' => (++$counter)%2?'odd':'even', + 'num_of_results' => $item->getNumResults() + ); + + if ($item->getQueryText() == $query) { + array_unshift($data, $_data); + } else { + $data[] = $_data; + } + } + $this->_suggestData = $data; + } + return $this->_suggestData; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Layer.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Layer.php new file mode 100644 index 00000000..536c99ae --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Layer.php @@ -0,0 +1,197 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalogsearch_Layer extends Mage_CatalogSearch_Block_Layer +{ + /** + * Templates of the filters. + * If no template found using the default one (catalog/layer/filter.phtml) + * + * See the smile/elaticssearch.xml layout file for a complete example + * + * @var array + */ + protected $_filterTemplates = array(); + + /** + * Boolean block name. + * + * @var string + */ + protected $_booleanFilterBlockName; + + /** + * Rating block name. + * + * @var string + */ + protected $_ratingFilterBlockName; + + /** + * Modifies default block names to specific ones if engine is active. + * + * @return void + */ + protected function _initBlocks() + { + parent::_initBlocks(); + + if (Mage::helper('smile_elasticsearch')->isActiveEngine()) { + $this->_categoryBlockName = 'smile_elasticsearch/catalog_layer_filter_category'; + $this->_attributeFilterBlockName = 'smile_elasticsearch/catalogsearch_layer_filter_attribute'; + $this->_ratingFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_rating'; + $this->_priceFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_price'; + $this->_decimalFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_decimal'; + $this->_booleanFilterBlockName = 'smile_elasticsearch/catalog_layer_filter_boolean'; + } + } + + /** + * Prepares layout if engine is active. + * Difference between parent method is addFacetCondition() call on each created block. + * + * @return Smile_ElasticSearch_Block_Catalogsearch_Layer + */ + protected function _prepareLayout() + { + /** @var $helper Smile_ElasticSearch_Helper_Data */ + $helper = Mage::helper('smile_elasticsearch'); + if (!$helper->isActiveEngine()) { + parent::_prepareLayout(); + } else { + $stateBlock = $this->getLayout()->createBlock($this->_stateBlockName) + ->setLayer($this->getLayer()); + + $categoryBlock = $this->getLayout()->createBlock($this->_categoryBlockName) + ->setLayer($this->getLayer()) + ->init(); + + $this->setChild('layer_state', $stateBlock); + $this->setChild('category_filter', $categoryBlock->addFacetCondition()); + + $filterableAttributes = $this->_getFilterableAttributes(); + $filters = array(); + foreach ($filterableAttributes as $attribute) { + if ($attribute->getAttributeCode() == 'price') { + $filterBlockName = $this->_priceFilterBlockName; + } elseif ($attribute->getAttributeCode() == 'rating_filter') { + $filterBlockName = $this->_ratingFilterBlockName; + } elseif ($attribute->getSourceModel() == 'eav/entity_attribute_source_boolean') { + $filterBlockName = $this->_booleanFilterBlockName; + } elseif ($attribute->getBackendType() == 'decimal') { + $filterBlockName = $this->_decimalFilterBlockName; + } else { + $filterBlockName = $this->_attributeFilterBlockName; + } + + $filters[$attribute->getAttributeCode() . '_filter'] = $this->getLayout()->createBlock($filterBlockName) + ->setLayer($this->getLayer()) + ->setAttributeModel($attribute) + ->init(); + } + + foreach ($filters as $filterName => $block) { + $this->setChild($filterName, $block->addFacetCondition()); + } + + $this->getLayer()->apply(); + } + + return $this; + } + + /** + * Check availability display layer options + * + * @return bool + */ + public function canShowOptions() + { + foreach ($this->getFilters() as $filter) { + if ($filter->getItemsCount()) { + return true; + } + } + + return false; + } + + /** + * Indicates if the block should be shown or not. + * Append forced category loading to make the system more resistant to layout changes + * + * @return bool + */ + public function canShowBlock() + { + if (!$this->getLayer()->getProductCollection()->isLoaded()) { + $this->getLayer()->getProductCollection()->getSize(); + } + + return ($this->canShowOptions() || count($this->getLayer()->getState()->getFilters())); + } + + /** + * Returns current catalog layer. + * + * @return Smile_ElasticSearch_Model_Catalogsearch_Layer|Mage_Catalog_Model_Layer + */ + public function getLayer() + { + /** @var $helper Smile_ElasticSearch_Helper_Data */ + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isActiveEngine()) { + return Mage::getSingleton('smile_elasticsearch/catalogsearch_layer'); + } + + return parent::getLayer(); + } + + /** + * Assign a custom template for a given filter + * + * @param string $filterName Name of the filter + * @param string $template Template + * + * @return Smile_ElasticSearch_Model_Catalog_Layer Self reference + */ + public function addFilterTemplate($filterName, $template) + { + $this->_filterTemplates[$filterName] = $template; + return $this; + } + + /** + * Custom template handling for children blocks (filters) before to display theme + * + * @return Smile_ElasticSearch_Model_Catalog_Layer Self reference + */ + protected function _beforeToHtml() + { + if (Mage::helper('smile_elasticsearch')->isActiveEngine()) { + foreach ($this->_filterTemplates as $filterName => $template) { + $block = $this->getChild($filterName . '_filter'); + if ($block) { + $block->setTemplate($template); + } + } + } + + return parent::_beforeToHtml(); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Layer/Filter/Attribute.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Layer/Filter/Attribute.php new file mode 100644 index 00000000..2042da1d --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Layer/Filter/Attribute.php @@ -0,0 +1,58 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalogsearch_Layer_Filter_Attribute extends Mage_Catalog_Block_Layer_Filter_Abstract +{ + /** + * Defines specific filter model name. + * + * @see Smile_ElasticSearch_Model_Catalogsearch_Layer_Filter_Attribute + */ + public function __construct() + { + parent::__construct(); + $this->_filterModelName = 'smile_elasticsearch/catalogsearch_layer_filter_attribute'; + $this->setIsMultipleSelect(true); + $this->setTemplate('smile/elasticsearch/catalog/layer/filter.phtml'); + } + + /** + * Prepares filter model. + * + * @return Smile_ElasticSearch_Block_Catalogsearch_Layer_Filter_Attribute + */ + protected function _prepareFilter() + { + $this->_filter->setAttributeModel($this->getAttributeModel()); + $this->_filter->setIsMultipleSelect(true); + return $this; + } + + /** + * Adds facet condition to filter. + * + * @see Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute::addFacetCondition() + * @return Smile_ElasticSearch_Block_Catalogsearch_Layer_Filter_Attribute + */ + public function addFacetCondition() + { + $this->_filter->addFacetCondition(); + + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Result.php b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Result.php new file mode 100644 index 00000000..7cc76e3c --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Block/Catalogsearch/Result.php @@ -0,0 +1,41 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Block_Catalogsearch_Result extends Mage_CatalogSearch_Block_Result +{ + /** + * Retrieve search result count + * + * @return string + */ + public function getResultCount() + { + if (!$this->getData('result_count')) { + $productCollection = $this->_getProductCollection(); + $size = $productCollection->getSize(); + if (Mage::helper('smile_elasticsearch')->isActiveEngine() && $productCollection->isSpellchecked()) { + $this->_getQuery()->setNumResults(0); + } else { + $this->_getQuery()->setNumResults($size); + } + + $this->setResultCount($size); + } + return $this->getData('result_count'); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Helper/Data.php b/src/app/code/community/Smile/ElasticSearch/Helper/Data.php new file mode 100644 index 00000000..d57b27d5 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Helper/Data.php @@ -0,0 +1,367 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Helper_Data extends Mage_Core_Helper_Abstract +{ + /** + * Allowed languages. + * Example: array('en_US' => 'en', 'fr_FR' => 'fr') + * + * @var array + */ + protected $_languageCodes = array(); + + /** + * Text field types. + * + * @var array + */ + protected $_textFieldTypes = array( + 'text', + 'varchar', + ); + + /** + * Returns cache lifetime in seconds. + * + * @return int + */ + public function getCacheLifetime() + { + return Mage::getStoreConfig('core/cache/lifetime'); + } + + /** + * Returns search engine config data. + * + * @param string $prefix Configuration prefix to be loaded + * @param mixed $store Store we want the configuration for + * + * @return array + */ + public function getEngineConfigData($prefix = '', $store = null) + { + $config = Mage::getStoreConfig('catalog/search', $store); + $data = array(); + if ($prefix) { + foreach ($config as $key => $value) { + $matches = array(); + if (preg_match("#^{$prefix}(.*)#", $key, $matches)) { + $data[$matches[1]] = $value; + } + } + } else { + $data = $config; + } + + return $data; + } + + /** + * Returns EAV config singleton. + * + * @return Mage_Eav_Model_Config + */ + public function getEavConfig() + { + return Mage::getSingleton('eav/config'); + } + + /** + * Returns language code of specified locale code. + * + * @param string $localeCode Locale we want the ES language code + * + * @return bool + */ + public function getLanguageCodeByLocaleCode($localeCode) + { + $localeCode = (string) $localeCode; + if (!$localeCode) { + return false; + } + + if (!isset($this->_languageCodes[$localeCode])) { + $languages = $this->getSupportedLanguages(); + $this->_languageCodes[$localeCode] = false; + foreach ($languages as $code => $locales) { + if (is_array($locales)) { + if (in_array($localeCode, $locales)) { + $this->_languageCodes[$localeCode] = $code; + } + } elseif ($localeCode == $locales) { + $this->_languageCodes[$localeCode] = $code; + } + } + } + + return $this->_languageCodes[$localeCode]; + } + + /** + * Returns store language code. + * + * @param mixed $store The store we want the language code for + * + * @return bool + */ + public function getLanguageCodeByStore($store = null) + { + return $this->getLanguageCodeByLocaleCode($this->getLocaleCode($store)); + } + + /** + * Returns store locale code. + * + * @param null $store The store we want the locale code for + * + * @return string + */ + public function getLocaleCode($store = null) + { + return Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $store); + } + + /** + * Get suggest field name for a store + * + * @param string|int|Mage_Core_Model_Store $store The store (current store is used if null) + * + * @return string + */ + public function getSuggestFieldName($store = null) + { + $languageCode = $this->getLanguageCodeByStore($store); + return $this->getSuggestFieldNameByLanguageCode($languageCode); + } + + /** + * Get suggest field name for a locale + * + * @param string $localeCode The locale code (current store locale is used if null) + * + * @return string + */ + public function getSuggestFieldNameByLocaleCode($localeCode = null) + { + $languageCode = $this->getLanguageCodeByLocaleCode($localeCode); + return $this->getSuggestFieldNameByLanguageCode($languageCode); + + } + + /** + * Get suggest field name for a language code + * + * @param string $languageCode The language code + * + * @return string + */ + public function getSuggestFieldNameByLanguageCode($languageCode = null) + { + $languageCode = $languageCode !== null ? $languageCode : $this->getLanguageCodeByStore(); + $languageSuffix = $languageCode ? '_' . $languageCode : ''; + return 'suggest' . $languageSuffix; + } + + /** + * Returns search config data field value. + * + * @param string $field Name of the fied (ie: elasticsearch_servers) + * @param mixed $store Store we want the config for + * + * @return mixed + */ + public function getSearchConfigData($field, $store = null) + { + $path = 'catalog/search/' . $field; + + return Mage::getStoreConfig($path, $store); + } + + + /** + * Defines supported languages for snowball filter. + * + * @return array + */ + public function getSupportedLanguages() + { + $default = array( + /** + * SnowBall filter based + */ + // Danish + 'da' => 'da_DK', + // Dutch + 'nl' => 'nl_NL', + // English + 'en' => array('en_AU', 'en_CA', 'en_NZ', 'en_GB', 'en_US'), + // Finnish + 'fi' => 'fi_FI', + // French + 'fr' => array('fr_CA', 'fr_FR'), + // German + 'de' => array('de_DE','de_DE','de_AT'), + // Hungarian + 'hu' => 'hu_HU', + // Italian + 'it' => array('it_IT','it_CH'), + // Norwegian + 'nb' => array('nb_NO', 'nn_NO'), + // Portuguese + 'pt' => array('pt_BR', 'pt_PT'), + // Romanian + 'ro' => 'ro_RO', + // Russian + 'ru' => 'ru_RU', + // Spanish + 'es' => array('es_AR', 'es_CL', 'es_CO', 'es_CR', 'es_ES', 'es_MX', 'es_PA', 'es_PE', 'es_VE'), + // Swedish + 'sv' => 'sv_SE', + // Turkish + 'tr' => 'tr_TR', + + /** + * Lucene class based + */ + // Czech + 'cs' => 'cs_CZ', + // Greek + 'el' => 'el_GR', + // Thai + 'th' => 'th_TH', + // Chinese + 'zh' => array('zh_CN', 'zh_HK', 'zh_TW'), + // Japanese + 'ja' => 'ja_JP', + // Korean + 'ko' => 'ko_KR' + ); + + return $default; + } + + /** + * Checks if configured engine is active. + * + * @return bool + */ + public function isActiveEngine() + { + $engine = $this->getSearchConfigData('engine'); + if ($engine && Mage::getConfig()->getResourceModelClassName($engine)) { + $model = Mage::getResourceSingleton($engine); + return $model + && $model instanceof Smile_ElasticSearch_Model_Resource_Engine_ElasticSearch + && $model->test(); + } + + return false; + } + + /** + * Checks if specified attribute is indexable by search engine. + * + * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute Attribute to be tested + * + * @return bool + */ + public function isAttributeIndexable($attribute) + { + if ($attribute->getBackendType() == 'varchar' && !$attribute->getBackendModel()) { + return true; + } + + if ($attribute->getBackendType() == 'int' + && $attribute->getSourceModel() != 'eav/entity_attribute_source_boolean' + && ($attribute->getIsSearchable() || $attribute->getIsFilterable() || $attribute->getIsFilterableInSearch()) + ) { + return true; + } + + if ($attribute->getIsSearchable() || $attribute->getIsFilterable() || $attribute->getIsFilterableInSearch()) { + return true; + } + + return false; + } + + /** + * Checks if specified attribute is using options. + * + * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute Attribute to be tested + * + * @return bool + */ + public function isAttributeUsingOptions($attribute) + { + $model = Mage::getModel($attribute->getSourceModel()); + + return $attribute->usesSource() && + $attribute->getBackendType() == 'int' && + $model instanceof Mage_Eav_Model_Entity_Attribute_Source_Table; + } + + /** + * Checks if debug mode is enabled. + * + * @return bool + */ + public function isDebugEnabled() + { + $config = $this->getEngineConfigData(); + + return array_key_exists('enable_debug_mode', $config) && $config['enable_debug_mode']; + } + + /** + * Method that can be overriden for customing product data indexation. + * + * @param array $index Data to be indexed + * @param string $separator Separator used into the index + * + * @return array + */ + public function prepareIndexData($index, $separator = null) + { + return $index; + } + + /** + * Forces error display. + * + * @param string $error Error to be displayed + * + * @return void + */ + public function showError($error) + { + echo Mage::app()->getLayout()->createBlock('core/messages') + ->addError($error)->getGroupedHtml(); + } + + /** + * Indicates if the current Magento instance is a Enterprise one. + * + * @return bool + */ + public function isEnterpriseSupportEnabled() + { + return Mage::helper('core')->isModuleEnabled('Enterprise_CatalogSearch'); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Helper/Elasticsearch.php b/src/app/code/community/Smile/ElasticSearch/Helper/Elasticsearch.php new file mode 100644 index 00000000..c10179b3 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Helper/Elasticsearch.php @@ -0,0 +1,51 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Helper_Elasticsearch extends Smile_ElasticSearch_Helper_Data +{ + /** + * Returns Elasticsearch engine config data. + * + * @param string $prefix Configuration prefix to be loaded (not used but present for compatibility) + * @param mixed $store Store we want the configuration for + * + * @return array + */ + public function getEngineConfigData($prefix = '', $store = null) + { + $config = parent::getEngineConfigData('elasticsearch_', $store); + $servers = array(); + foreach (explode(',', $config['servers']) as $server) { + $servers[] = $server; + } + $config['hosts'] = $servers; + + return $config; + } + + /** + * Should Elasticsearch also search on options? + * + * @return bool + */ + public function shouldSearchOnOptions() + { + return Mage::getStoreConfigFlag('catalog/search/elasticsearch_enable_options_search'); + } + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Adminhtml/System/Config/Backend/Engine.php b/src/app/code/community/Smile/ElasticSearch/Model/Adminhtml/System/Config/Backend/Engine.php new file mode 100644 index 00000000..d0e986b9 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Adminhtml/System/Config/Backend/Engine.php @@ -0,0 +1,36 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Adminhtml_System_Config_Backend_Engine extends Mage_Core_Model_Config_Data +{ + /** + * Requires catalog category products and catalog search reindexation. + * + * @return Smile_ElasticSearch_Model_Adminhtml_System_Config_Backend_Engine + */ + protected function _afterSave() + { + $indexer = Mage::getSingleton('index/indexer'); + $indexer->getProcessByCode('catalogsearch_fulltext') + ->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX); + $indexer->getProcessByCode('catalog_category_product') + ->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX); + + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Adminhtml/System/Config/Source/Engine.php b/src/app/code/community/Smile/ElasticSearch/Model/Adminhtml/System/Config/Source/Engine.php new file mode 100644 index 00000000..ff5e0e22 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Adminhtml/System/Config/Source/Engine.php @@ -0,0 +1,43 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Adminhtml_System_Config_Source_Engine +{ + /** + * Return liste of search engines for config. + * + * @return array + */ + public function toOptionArray() + { + $engines = array( + 'catalogsearch/fulltext_engine' => Mage::helper('adminhtml')->__('MySQL'), + 'smile_elasticsearch/engine_elasticsearch' => Mage::helper('smile_elasticsearch')->__('Smile Searchandising Suite'), + ); + + $options = array(); + foreach ($engines as $k => $v) { + $options[] = array( + 'value' => $k, + 'label' => $v + ); + } + + return $options; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer.php new file mode 100644 index 00000000..e029cae7 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer.php @@ -0,0 +1,71 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer extends Mage_Catalog_Model_Layer +{ + /** + * Returns product collection for current category. + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function getProductCollection() + { + /** @var $category Mage_Catalog_Model_Category */ + $category = $this->getCurrentCategory(); + /** @var $collection Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection */ + if (isset($this->_productCollections[$category->getId()])) { + $collection = $this->_productCollections[$category->getId()]; + } else { + $collection = Mage::helper('catalogsearch') + ->getEngine() + ->getResultCollection() + ->setStoreId($category->getStoreId()); + + $this->prepareProductCollection($collection); + $this->_productCollections[$category->getId()] = $collection; + } + + return $collection; + } + + /** + * Initialize product collection + * + * @param Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection $collection Product collection. + * + * @return Mage_Catalog_Model_Layer + */ + public function prepareProductCollection($collection) + { + $query = $collection->getSearchEngineQuery(); + + $allowedVisibilities = Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds(); + $query->addFilter('terms', array('visibility' => $allowedVisibilities)); + + $allowedStatuses = Mage::getSingleton('catalog/product_status')->getVisibleStatusIds(); + $query->addFilter('terms', array('status' => $allowedStatuses)); + + if (Mage::helper('cataloginventory')->isShowOutOfStock() == false) { + $query->addFilter('terms', array('in_stock' => 1)); + } + + $query->setQueryType('category_products_layer'); + + return parent::prepareProductCollection($collection); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Attribute.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Attribute.php new file mode 100644 index 00000000..07f44dde --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Attribute.php @@ -0,0 +1,271 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Model_Layer_Filter_Attribute +{ + /** + * @var array() + */ + protected $_appliedItems = array(); + + /** + * @var array() + */ + protected $_rawFilter = array(); + + /** + * Adds facet condition to product collection. + * + * @see Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection::addFacetCondition() + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute + */ + public function addFacetCondition() + { + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $options = array('field' => $this->_getFilterField()); + $query->addFacet($this->_getFilterField(), 'terms', $options); + + return $this; + } + + /** + * Retrieves request parameter and applies it to product collection. + * + * @param Zend_Controller_Request_Abstract $request Request containing filter var and value + * @param Mage_Core_Block_Abstract $filterBlock Layer block representing the filter + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute + */ + public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) + { + $filter = $request->getParam($this->_requestVar); + + if ($filter === null) { + return $this; + } + if (!is_array($filter)) { + $filter = array($filter); + } + + $filterText = array(); + + foreach ($filter as $currentFilter) { + $text = $this->_getOptionText($currentFilter); + if ($this->_isValidFilter($currentFilter) && strlen($text)) { + $filterText[] = $text; + $this->_rawFilter[] = $currentFilter; + $this->_appliedItems[$currentFilter] = $text; + } + } + + if (!empty($this->_rawFilter)) { + $this->applyFilterToCollection($filter); + $this->getLayer()->getState()->addFilter($this->_createItem(implode(' , ', $filterText), $filter)); + } + + return $this; + } + + /** + * Applies filter to product collection. + * + * @param mixed $value Value of the filter + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute + */ + public function applyFilterToCollection($value) + { + if (!is_array($value)) { + $value = array($value); + } + + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $query->addFilter('terms', array($this->_getFilterField() => $value), $this->_getFilterField()); + + return $this; + } + + /** + * Returns facets data of current attribute. + * + * @return array + */ + protected function _getFacets() + { + /** @var $productCollection Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection */ + $productCollection = $this->getLayer()->getProductCollection(); + $fieldName = $this->_getFilterField(); + $facets = $productCollection->getFacetedData($fieldName); + return $facets; + } + + /** + * Returns attribute field name. + * + * @return string + */ + protected function _getFilterField() + { + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = $this->getAttributeModel(); + $currentIndex = Mage::helper('catalogsearch')->getEngine()->getCurrentIndex(); + $mapping = $currentIndex->getMapping('product'); + $store = Mage::app()->getStore(); + $languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + $fieldName = $mapping->getFieldName($attribute->getAttributeCode(), $languageCode, 'filter'); + return $fieldName; + } + + /** + * Retrieves current items data. + * + * @return array + */ + protected function _getItemsData() + { + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = $this->getAttributeModel(); + $this->_requestVar = $attribute->getAttributeCode(); + + $layer = $this->getLayer(); + $key = $layer->getStateKey() . '_' . $this->_requestVar; + $data = $layer->getAggregator()->getCacheData($key); + + if ($data === null) { + $facets = $this->_getFacets(); + $data = array(); + if (array_sum($facets) > 0) { + if ($attribute->getFrontendInput() != 'text') { + $options = $attribute->getFrontend()->getSelectOptions(); + } else { + $options = array(); + foreach ($facets as $label => $count) { + $options[] = array( + 'label' => $label, + 'value' => $label, + 'count' => $count, + ); + } + } + foreach ($options as $option) { + if (is_array($option['value']) || !Mage::helper('core/string')->strlen($option['value'])) { + continue; + } + $count = 0; + $label = $option['label']; + if (isset($facets[$option['value']])) { + $count = (int) $facets[$option['value']]; + } + if (!$count && $this->_getIsFilterableAttribute($attribute) == self::OPTIONS_ONLY_WITH_RESULTS) { + continue; + } + + $data[$option['value']] = array( + 'label' => $label, + 'value' => $option['value'], + 'count' => (int) $count, + ); + } + + foreach ($this->_appliedItems as $value => $label) { + if (!isset($data[$value])) { + $data[] = array('label' => $label, 'value' => $value, 'count' => 0); + } + } + + $data = array_values($data); + } + + $tags = array( + Mage_Eav_Model_Entity_Attribute::CACHE_TAG . ':' . $attribute->getId() + ); + + $tags = $layer->getStateTags($tags); + $layer->getAggregator()->saveCacheData($data, $key, $tags); + } + + return $data; + } + + /** + * Returns option label if attribute uses options. + * + * @param int $optionId Option Id we want the label for + * + * @return bool|int|string + */ + protected function _getOptionText($optionId) + { + if ($this->getAttributeModel()->getFrontendInput() == 'text') { + return $optionId; // not an option id + } + + return parent::_getOptionText($optionId); + } + + /** + * Checks if given filter is valid before being applied to product collection. + * + * @param string $filter Validate a Filter to be validated + * + * @return bool + */ + protected function _isValidFilter($filter) + { + return !empty($filter); + } + + /** + * Create filter item object + * + * @param string $label Label of the filter value + * @param mixed $value Value of the filter + * @param int $count Number of result (default is 0) + * + * @return Mage_Catalog_Model_Layer_Filter_Item + */ + protected function _createItem($label, $value, $count=0) + { + $isSelected = false; + + if ($this->getIsMultipleSelect() && $value) { + if (in_array($value, $this->_rawFilter)) { + $isSelected = true; + } + + $values = $this->_rawFilter; + + if (($key = array_search($value, $values)) !== false) { + unset($values[$key]); + $value = array_values($values); + } else { + if (!is_array($value)) { + $value = array($value); + } + $value = array_merge($values, $value); + } + } + + $item = parent::_createItem($label, $value, $count); + $item->setSelected($isSelected); + + + return $item; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Boolean.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Boolean.php new file mode 100644 index 00000000..523648bd --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Boolean.php @@ -0,0 +1,52 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer_Filter_Boolean extends Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute +{ + /** + * Returns facets data of current attribute. + * + * @return array + */ + protected function _getFacets() + { + $facets = parent::_getFacets(); + $result = array(); + foreach ($facets as $value => $count) { + $key = 0; // false by default + if ($value === 'true' || $value === 'T' || $value === '1' || $value === 1 || $value === true) { + $key = 1; + } + $result[$key] = $count; + } + + return $result; + } + + /** + * Checks if given filter is valid before being applied to product collection. + * + * @param string $filter Filter to be validated + * + * @return bool + */ + protected function _isValidFilter($filter) + { + return $filter === '0' || $filter === '1' || false === $filter || true === $filter; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Category.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Category.php new file mode 100644 index 00000000..8839ac74 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Category.php @@ -0,0 +1,238 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer_Filter_Category extends Mage_Catalog_Model_Layer_Filter_Category +{ + /** + * Adds category filter to product collection. + * + * @param Mage_Catalog_Model_Category $category Category to filter + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Category + */ + public function addCategoryFilter($category) + { + $this->setCategory($category); + + + Mage::dispatchEvent('category_filter_add_filter_to_collection_before', array('filter' => $this, 'category' => $category)); + + if (!$this->getProductCollectionFilterSet()) { + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $categoryId = $category->getId(); + $qs = "(categories:{$categoryId} OR show_in_categories:{$categoryId})"; + $query->addFilter('query', array('query_string' => $qs)); + } + + return $this; + } + + /** + * Adds facet condition to product collection. + * + * @see Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection::addFacetCondition() + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Category + */ + public function addFacetCondition() + { + $category = $this->getCategory(); + + Mage::dispatchEvent('category_filter_add_facet_to_collection_before', array('filter' => $this, 'category' => $category)); + + if (!$this->getProductCollectionFacetSet()) { + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $options = array('script_field' => 'doc.categories.values + doc.show_in_categories.values'); + $query->addFacet('categories', 'terms', $options); + } + + return $this; + } + + /** + * Retrieves request parameter and applies it to product collection. + * + * @param Zend_Controller_Request_Abstract $request Request containing filter var and value + * @param Mage_Core_Block_Abstract $filterBlock Layer block representing the filter + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Category + */ + public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) + { + $minLevel = Mage::getStoreConfig('catalog/search/elasticsearch_min_category_filter_level'); + + if (!$this->getUseUrlRewrites()) { + $minLevel = 2; + } + + $filter = (int) $request->getParam($this->getRequestVar()); + if ($filter) { + $this->_categoryId = $filter; + } + + /** @var $category Mage_Catalog_Model_Category */ + $category = $this->getCategory(); + if (!Mage::registry('current_category_filter')) { + Mage::register('current_category_filter', $category); + } + + if (!$filter && $this->getCategory()) { + if ($this->getCategory()->getLevel() >= $minLevel) { + $filter = $this->getCategory()->getId(); + } else if ($this->getCategory()) { + $this->addCategoryFilter($category); + } + } + + if ($filter) { + $this->addCategoryFilter($category); + } + + $this->_appliedCategory = Mage::getModel('catalog/category') + ->setStoreId(Mage::app()->getStore()->getId()) + ->load($filter); + + if ($this->_isValidCategory($this->_appliedCategory)) { + $this->getLayer()->getState()->addFilter( + $this->_createItem($this->_appliedCategory->getName(), $this->_appliedCategory->getId()) + ); + } + + return $this; + } + + /** + * Retrieves current items data. + * + * @return array + */ + protected function _getItemsData() + { + $layer = $this->getLayer(); + $key = $layer->getStateKey().'_SUBCATEGORIES'; + $data = $layer->getCacheData($key); + + if ($data === null) { + $categories = $this->getCategory()->getChildrenCategories(); + + /** @var $productCollection Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection */ + $productCollection = $layer->getProductCollection(); + $facets = $productCollection->getFacetedData('categories'); + + $data = array(); + foreach ($categories as $category) { + /** @var $category Mage_Catalog_Model_Category */ + $categoryId = $category->getId(); + if (isset($facets[$categoryId])) { + $category->setProductCount($facets[$categoryId]); + } else { + $category->setProductCount(0); + } + if ($category->getIsActive() && $category->getProductCount()) { + $data[$categoryId] = array( + 'label' => Mage::helper('core')->escapeHtml($category->getName()), + 'value' => $categoryId, + 'count' => $category->getProductCount(), + ); + } + } + + if ($this->getUseUrlRewrites()) { + $data = $this->_appendUrlRewritesToData($data); + } + + $data = array_values($data); + + $tags = $layer->getStateTags(); + $layer->getAggregator()->saveCacheData($data, $key, $tags); + } + + return $data; + } + + + /** + * Create filter item object + * + * @param string $label Label of the filter value + * @param mixed $value Value of the filter + * @param int $count Number of result (default is 0) + * @param string $url URL of the category + * + * @return Mage_Catalog_Model_Layer_Filter_Item + */ + protected function _createItem($label, $value, $count=0, $url = null) + { + $item = parent::_createItem($label, $value, $count); + + if ($this->getUseUrlRewrites()) { + $item = Mage::getModel('smile_elasticsearch/catalog_layer_filter_item_category') + ->setFilter($this) + ->setLabel($label) + ->setValue($value) + ->setCount($count) + ->setCategoryUrl($url); + } + + return $item; + } + + /** + * Append categories URL rewrites to facet items. + * + * @param array $data Facet items data + * + * @return array + */ + protected function _appendUrlRewritesToData($data) + { + + $categoryIds = array_keys($data); + $categories = Mage::getResourceModel('catalog/category_collection') + ->setStoreId(Mage::app()->getStore()->getId()) + ->addIdFilter($categoryIds) + ->addUrlRewriteToResult(); + + foreach ($categories as $currentCategory) { + $data[$currentCategory->getId()]['category_url'] = $currentCategory->getUrl(); + } + + return $data; + } + + /** + * Initialize filter items + * + * @return Mage_Catalog_Model_Layer_Filter_Abstract + */ + protected function _initItems() + { + $data = $this->_getItemsData(); + $items=array(); + foreach ($data as $itemData) { + $items[] = $this->_createItem( + $itemData['label'], + $itemData['value'], + $itemData['count'], + isset($itemData['category_url']) ? $itemData['category_url'] : null + ); + } + $this->_items = $items; + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Decimal.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Decimal.php new file mode 100644 index 00000000..d8c05bff --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Decimal.php @@ -0,0 +1,197 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal extends Mage_Catalog_Model_Layer_Filter_Decimal +{ + const CACHE_TAG = 'MAXVALUE'; + + /** + * Adds facet condition to product collection. + * + * @see Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection::addFacetCondition() + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal + */ + public function addFacetCondition() + { + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $options = array('interval' => 1, 'field' => $this->_getFilterField()); + $query->addFacet($this->_getFilterField(), 'histogram', $options); + + return $this; + } + + /** + * Retrieves request parameter and applies it to product collection. + * + * @param Zend_Controller_Request_Abstract $request Request containing filter var and value + * @param Mage_Core_Block_Abstract $filterBlock Layer block representing the filter + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal + */ + public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) + { + $filter = $request->getParam($this->getRequestVar()); + if (!$filter) { + return $this; + } + + $filter = explode(',', $filter); + if (count($filter) != 2) { + return $this; + } + + list($index, $range) = $filter; + + if ((int) $index && (int) $range) { + $this->setRange((int) $range); + + $this->applyFilterToCollection($this, $range, $index); + $this->getLayer()->getState()->addFilter( + $this->_createItem($this->_renderItemLabel($range, $index), $filter) + ); + + $this->_items = array(); + } + + return $this; + } + + /** + * Apply decimal filter range to product collection. + * + * @param Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal $filter Filter to be applied + * @param int $range Size of the range to be applied + * @param int $index Offset position + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal + */ + public function applyFilterToCollection($filter, $range, $index) + { + $value = array( + $this->_getFilterField() => array( + 'from' => ($range * ($index - 1)), + 'to' => $range * $index, + ) + ); + $filter->getLayer()->getProductCollection()->addFqFilter($value); + + return $this; + } + + /** + * Return the max value of the attribute + * + * @see Mage_Catalog_Model_Layer_Filter_Decimal::getMaxValue() + * + * @return float + */ + public function getMaxValue() + { + $searchParams = $this->getLayer()->getProductCollection()->getExtendedSearchParams(); + $uniquePart = strtoupper(md5(serialize($searchParams))); + $cacheKey = 'MAXVALUE_' . $this->getLayer()->getStateKey() . '_' . $uniquePart; + + $cachedData = Mage::app()->loadCache($cacheKey); + if (!$cachedData) { + $stats = $this->getLayer()->getProductCollection()->getStats($this->_getFilterField()); + + $max = $stats[$this->_getFilterField()]['max']; + if (!is_numeric($max)) { + $max = parent::getMaxValue(); + } + + $cachedData = (float) $max; + $tags = $this->getLayer()->getStateTags(); + $tags[] = self::CACHE_TAG; + Mage::app()->saveCache($cachedData, $cacheKey, $tags); + } + + return $cachedData; + } + + /** + * Returns decimal field name. + * + * @return string + */ + protected function _getFilterField() + { + $fieldName = Mage::helper('smile_elasticsearch')->getAttributeFieldName($this->getAttributeModel()); + + return $fieldName; + } + + /** + * Retrieves current items data. + * + * @return array + */ + protected function _getItemsData() + { + $range = $this->getRange(); + $fieldName = $this->_getFilterField(); + $facets = $this->getLayer()->getProductCollection()->getFacetedData($fieldName); + + $data = array(); + if (!empty($facets)) { + foreach ($facets as $key => $count) { + if ($count > 0) { + preg_match('/TO ([\d\.]+)\]$/', $key, $rangeKey); + $rangeKey = round($rangeKey[1] / $range); + $data[] = array( + 'label' => $this->_renderItemLabel($range, $rangeKey), + 'value' => $rangeKey . ',' . $range, + 'count' => $count, + ); + } + } + } + + return $data; + } + + /** + * Renders decimal ranges. + * + * @param int $range Range size + * @param float $value Current value + * + * @return string + */ + protected function _renderItemLabel($range, $value) + { + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = $this->getAttributeModel(); + + if ($attribute->getFrontendInput() == 'price') { + return parent::_renderItemLabel($range, $value); + } + + $from = ($value - 1) * $range; + $to = $value * $range; + + if ($from != $to) { + $to -= 0.01; + } + + $to = Zend_Locale_Format::toFloat($to, array('locale' => Mage::helper('smile_elasticsearch')->getLocaleCode())); + + return Mage::helper('catalog')->__('%s - %s', $from, $to); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Item/Category.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Item/Category.php new file mode 100644 index 00000000..d0fbbad6 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Item/Category.php @@ -0,0 +1,86 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer_Filter_Item_Category extends Mage_Catalog_Model_Layer_Filter_Item +{ + /** + * Allow to keep some filter active when changing category + * + * @param string $url URL of the category + * + * @return string + */ + protected function _addCurrentParameters($url) + { + $queryParams = Mage::app()->getRequest()->getParams(); + $paramsReset = array(Mage::getBlockSingleton('page/html_pager')->getPageVarName() => null, 'id' => null); + $queryPart = http_build_query(array_merge($queryParams, $paramsReset)); + if ($queryPart) { + $url .= strpos($url, '?') === false ? '?' . $queryPart : '&' . $queryPart; + } + return $url; + } + + /** + * Get filter item url + * + * @return string + */ + public function getUrl() + { + $categoryUrl = $this->getCategoryUrl(); + if (!$categoryUrl) { + $categoryUrl = Mage::getModel('catalog/category')->load($this->getValue())->getUrl(); + } + return $this->_addCurrentParameters($categoryUrl); + } + + /** + * Get url for remove item from filter + * + * @return string + */ + public function getRemoveUrl() + { + $parentCategory = Mage::getModel('catalog/category')->load($this->getValue()) + ->getParentCategory(); + + return $this->_addCurrentParameters($parentCategory->getUrl()); + } + + /** + * Get url for "clear" link + * + * @return false|string + */ + public function getClearLinkUrl() + { + $clearLinkText = $this->getFilter()->getClearLinkText(); + if (!$clearLinkText) { + return false; + } + + $urlParams = array( + '_current' => true, + '_use_rewrite' => true, + '_query' => array($this->getFilter()->getRequestVar() => null), + '_escape' => true, + ); + return Mage::getUrl('*/*/*', $urlParams); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Price.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Price.php new file mode 100644 index 00000000..37c676b6 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Price.php @@ -0,0 +1,226 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer_Filter_Price extends Mage_Catalog_Model_Layer_Filter_Price +{ + const CACHE_TAG = 'MAXPRICE'; + + protected $_stats = null; + + /** + * Adds facet condition to product collection. + * + * @see Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection::addFacetCondition() + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Decimal + */ + public function addFacetCondition() + { + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $options = array('interval' => 1, 'field' => $this->_getFilterField()); + $query->addFacet($this->_getFilterField(), 'histogram', $options); + + return $this; + } + + /** + * Returns cache tag. + * + * @return string + */ + public function getCacheTag() + { + return self::CACHE_TAG; + } + + + /** + * Return stats (min, max, avg, ...) for the field + * + * @return array + */ + protected function _getFieldStats() + { + + if (is_null($this->_stats)) { + $facets = $this->getLayer()->getProductCollection()->getFacetedData($this->_getFilterField()); + $this->_stats['min'] = key($facets); + $this->_stats['max'] = key(array_reverse($facets, true)); + } + + return $this->_stats; + } + + /** + * Get price range for building filter steps + * + * @return int + */ + public function getPriceRange() + { + $range = $this->getData('price_range'); + if (!$range) { + $currentCategory = Mage::registry('current_category_filter'); + if ($currentCategory) { + $range = $currentCategory->getFilterPriceRange(); + } else { + $range = $this->getLayer()->getCurrentCategory()->getFilterPriceRange(); + } + + $maxPrice = $this->getMaxPriceInt(); + $minPrice = $this->getMinPriceInt(); + if (!$range) { + $calculation = Mage::app()->getStore()->getConfig(self::XML_PATH_RANGE_CALCULATION); + if ($calculation == self::RANGE_CALCULATION_AUTO) { + $range = pow(10, (strlen(floor($maxPrice - $minPrice)) - 1)); + } else { + $range = (float)Mage::app()->getStore()->getConfig(self::XML_PATH_RANGE_STEP); + } + } + + $this->setData('price_range', $range); + } + return $range; + } + + /** + * Retrieves max price for ranges definition. + * + * @return float + */ + public function getMaxPriceInt() + { + $stats = $this->_getFieldStats(); + $max = $stats['max']; + if (!is_numeric($max)) { + $max = parent::getMaxPriceInt(); + } + return $max; + } + + /** + * Retrieves max price for ranges definition. + * + * @return float + */ + public function getMinPriceInt() + { + $stats = $this->_getFieldStats(); + $min = $stats['min']; + if (!is_numeric($min)) { + $min = 0; + } + return $min; + } + + /** + * Apply price range filter to product collection. + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Price + */ + protected function _applyPriceRange() + { + $interval = $this->getInterval(); + + if (!$interval) { + return $this; + } + + list($from, $to) = $interval; + if ($from === '' && $to === '') { + return $this; + } + + $field = $this->_getFilterField(); + $limits = array(); + if (!empty($from)) { + $limits['gte'] = $from; + } + if (!empty($to)) { + $limits['lte'] = $to; + } + + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $query->addFilter('range', array($this->_getFilterField() => $limits), $this->_getFilterField()); + + return $this; + } + + /** + * Returns price field according to current customer group and website. + * + * @return string + */ + protected function _getFilterField() + { + $websiteId = Mage::app()->getStore()->getWebsiteId(); + $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId(); + $priceField = 'price_' . $customerGroupId . '_' . $websiteId; + + return $priceField; + } + + /** + * Retrieves current items data. + * + * @return array + */ + protected function _getItemsData() + { + if (Mage::app()->getStore()->getConfig(self::XML_PATH_RANGE_CALCULATION) == self::RANGE_CALCULATION_IMPROVED) { + return $this->_getCalculatedItemsData(); + } + + $data = array(); + + $facets = $this->getLayer()->getProductCollection()->getFacetedData($this->_getFilterField()); + + if (!empty($facets) && count($facets) > 1) { + foreach ($facets as $key => $count) { + $data[] = array( + 'label' => $key, + 'value' => $key, + 'count' => $count + ); + } + } + + return $data; + } + + /** + * Prepare text of range label + * + * @param float|string $fromPrice Interval min. + * @param float|string $toPrice Interval max. + * + * @return string + */ + protected function _renderRangeLabel($fromPrice, $toPrice) + { + $store = Mage::app()->getStore(); + $formattedFromPrice = $store->formatPrice($fromPrice); + if ($toPrice === '') { + return Mage::helper('catalog')->__('%s and above', $formattedFromPrice); + } elseif ($fromPrice == $toPrice && Mage::app()->getStore()->getConfig(self::XML_PATH_ONE_PRICE_INTERVAL)) { + return $formattedFromPrice; + } else { + return Mage::helper('catalog')->__('%s - %s', $formattedFromPrice, $store->formatPrice($toPrice)); + } + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Rating.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Rating.php new file mode 100644 index 00000000..a9f11a60 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalog/Layer/Filter/Rating.php @@ -0,0 +1,132 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalog_Layer_Filter_Rating extends Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute +{ + /** + * @var int + */ + const RATING_AGG_INTERVAL = 20; + + /** + * Adds facet condition to product collection. + * + * @see Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection::addFacetCondition() + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute + */ + public function addFacetCondition() + { + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $options = array('interval' => self::RATING_AGG_INTERVAL, 'field' => $this->_getFilterField()); + $query->addFacet($this->_getFilterField(), 'histogram', $options); + + return $this; + } + + /** + * Retrieves current items data. + * + * @return array + */ + protected function _getItemsData() + { + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = $this->getAttributeModel(); + $this->_requestVar = $attribute->getAttributeCode(); + + $layer = $this->getLayer(); + $key = $layer->getStateKey() . '_' . $this->_requestVar; + $data = $layer->getAggregator()->getCacheData($key); + + if ($data === null) { + + $data = array(); + $facets = array_reverse($this->_getFacets(), true); + $sumCount = 0; + + $maxValue = current(array_keys($facets)); + + while (($maxValue = $maxValue - self::RATING_AGG_INTERVAL) && $maxValue >0) { + if (!isset($facets[$maxValue])) { + $facets[$maxValue] = 0; + } + } + + foreach ($facets as $key => $count) { + $sumCount += $count ; + $data[] = array( + 'label' => $key, + 'value' => $key, + 'count' => (int) $sumCount, + ); + } + + $tags = array( + Mage_Eav_Model_Entity_Attribute::CACHE_TAG . ':' . $attribute->getId() + ); + + $tags = $layer->getStateTags($tags); + $layer->getAggregator()->saveCacheData($data, $key, $tags); + } + + return $data; + } + + + /** + * Retrieves request parameter and applies it to product collection. + * + * @param Zend_Controller_Request_Abstract $request Request containing filter var and value + * @param Mage_Core_Block_Abstract $filterBlock Layer block representing the filter + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute + */ + public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) + { + $filter = $request->getParam($this->_requestVar); + if (is_array($filter) || null === $filter) { + return $this; + } + + $text = Mage::helper('smile_elasticsearch')->__('%d / 5 and more', $filter / self::RATING_AGG_INTERVAL); + if ($this->_isValidFilter($filter) && strlen($text)) { + $this->applyFilterToCollection((int) $filter); + $this->getLayer()->getState()->addFilter($this->_createItem($text, $filter)); + } + + return $this; + } + + /** + * Applies filter to product collection. + * + * @param mixed $value Value of the filter + * + * @return Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute + */ + public function applyFilterToCollection($value) + { + $limits = array('gte' => $value); + $query = $this->getLayer()->getProductCollection()->getSearchEngineQuery(); + $query->addFilter('range', array($this->_getFilterField() => $limits), $this->_getFilterField()); + + return $this; + } + +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalogsearch/Layer.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalogsearch/Layer.php new file mode 100644 index 00000000..828b553e --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalogsearch/Layer.php @@ -0,0 +1,70 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalogsearch_Layer extends Mage_CatalogSearch_Model_Layer +{ + /** + * Returns product collection for current category. + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function getProductCollection() + { + $category = $this->getCurrentCategory(); + if (isset($this->_productCollections[$category->getId()])) { + $collection = $this->_productCollections[$category->getId()]; + } else { + /** @var $collection Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection */ + $collection = Mage::helper('catalogsearch') + ->getEngine() + ->getResultCollection() + ->setStoreId($category->getStoreId()); + + $this->prepareProductCollection($collection); + $this->_productCollections[$category->getId()] = $collection; + } + + return $collection; + } + + /** + * Initialize product collection + * + * @param Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection $collection Product collection. + * + * @return Mage_Catalog_Model_Layer + */ + public function prepareProductCollection($collection) + { + $query = $collection->getSearchEngineQuery(); + + $allowedVisibilities = Mage::getSingleton('catalog/product_visibility')->getVisibleInSearchIds(); + $query->addFilter('terms', array('visibility' => $allowedVisibilities)); + + $allowedStatuses = Mage::getSingleton('catalog/product_status')->getVisibleStatusIds(); + $query->addFilter('terms', array('status' => $allowedStatuses)); + + if (Mage::helper('cataloginventory')->isShowOutOfStock() == false) { + $query->addFilter('terms', array('in_stock' => 1)); + } + + $query->setQueryType('product_search_layer'); + + return parent::prepareProductCollection($collection); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Catalogsearch/Layer/Filter/Attribute.php b/src/app/code/community/Smile/ElasticSearch/Model/Catalogsearch/Layer/Filter/Attribute.php new file mode 100644 index 00000000..334ba6f7 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Catalogsearch/Layer/Filter/Attribute.php @@ -0,0 +1,32 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Catalogsearch_Layer_Filter_Attribute extends Smile_ElasticSearch_Model_Catalog_Layer_Filter_Attribute +{ + /** + * Indicate if attribute is filterable in search. + * + * @param Mage_Catalog_Model_Entity_Attribute $attribute Attribute to be tested + * + * @return bool + */ + protected function _getIsFilterableAttribute($attribute) + { + return $attribute->getIsFilterableInSearch(); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh.php b/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh.php new file mode 100644 index 00000000..f3702155 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh.php @@ -0,0 +1,52 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Index_Action_Fulltext_Refresh + extends Enterprise_CatalogSearch_Model_Index_Action_Fulltext_Refresh +{ + /** + * Run full reindex only when needed + * + * @return Enterprise_CatalogSearch_Model_Index_Action_Fulltext_Refresh + * + * @throws Enterprise_Index_Model_Action_Exception + */ + public function execute() + { + if (Mage::helper('smile_elasticsearch')->isActiveEngine() == false) { + parent::execute(); + } else { + $this->_getLastVersionId(); + $this->_metadata->setInProgressStatus()->save(); + + $engine = Mage::helper('catalogsearch')->getEngine(); + $index = $engine->getCurrentIndex(); + + $index->prepareNewIndex(); + foreach ($index->getAllMappings() as $mapping) { + $mapping->rebuildIndex(); + } + $index->installNewIndex(); + + $this->_updateMetadata(); + $this->_app->dispatchEvent('after_reindex_process_catalogsearch_index', array()); + } + + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh/Changelog.php b/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh/Changelog.php new file mode 100644 index 00000000..368d23a6 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh/Changelog.php @@ -0,0 +1,69 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Index_Action_Fulltext_Refresh_Changelog + extends Enterprise_CatalogSearch_Model_Index_Action_Fulltext_Refresh_Changelog +{ + + /** + * Refresh rows by ids from changelog + * + * + * @return Enterprise_CatalogSearch_Model_Index_Action_Fulltext_Refresh_Changelog + * + * @throws Enterprise_Index_Model_Action_Exception + */ + public function execute() + { + if (!$this->_metadata->isValid()) { + throw new Enterprise_Index_Model_Action_Exception("Can't perform operation, incomplete metadata!"); + } + + if (Mage::helper('smile_elasticsearch')->isActiveEngine() == false) { + parent::execute(); + } else { + + try { + if (!empty($this->_changedIds)) { + $engine = Mage::helper('catalogsearch')->getEngine(); + $this->_metadata->setInProgressStatus()->save(); + // Index basic products + $this->_setProductIdsFromValue(); + $productIds = $this->_productIds; + $this->_setProductIdsFromParents(); + $productIds = array_merge($productIds, $this->_productIds); + + $engine->cleanIndex(null, $productIds); + $engine->getCurrentIndex() + ->getMapping('product') + ->rebuildIndex(null, $productIds); + + // Clear search results + $this->_resetSearchResults(); + $this->_updateMetadata(); + } + } catch (Exception $e) { + $this->_metadata->setInvalidStatus()->save(); + throw new Enterprise_Index_Model_Action_Exception($e->getMessage(), $e->getCode()); + } + } + + return $this; + } + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh/Row.php b/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh/Row.php new file mode 100644 index 00000000..7dc245cf --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Index/Action/Fulltext/Refresh/Row.php @@ -0,0 +1,53 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Index_Action_Fulltext_Refresh_Row + extends Enterprise_CatalogSearch_Model_Index_Action_Fulltext_Refresh_Row +{ + + /** + * Refresh rows by ids from changelog + * + * Reindex modified produts rows + * + * @return Enterprise_CatalogSearch_Model_Index_Action_Fulltext_Refresh_Changelog + * + * @throws Enterprise_Index_Model_Action_Exception + */ + public function execute() + { + if (Mage::helper('smile_elasticsearch')->isActiveEngine() == false) { + parent::execute(); + } else { + $engine = Mage::helper('catalogsearch')->getEngine(); + + $this->_setProductIdsFromValue(); + $productIds = $this->_productIds; + $this->_setProductIdsFromParents(); + $productIds = array_merge($productIds, $this->_productIds); + + $engine->cleanIndex(null,$productIds); + $engine->getCurrentIndex() + ->getMapping('product') + ->rebuildIndex(null, $productIds); + } + + return $this; + } + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Indexer/Fulltext.php b/src/app/code/community/Smile/ElasticSearch/Model/Indexer/Fulltext.php new file mode 100644 index 00000000..917312c3 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Indexer/Fulltext.php @@ -0,0 +1,199 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Indexer_Fulltext extends Mage_CatalogSearch_Model_Indexer_Fulltext +{ + /** + * (Dummy) Register indexer event + * + * @param Mage_Index_Model_Event $event + * + * @return Mage_CatalogSearch_Model_Indexer_Fulltext + */ + public function register(Mage_Index_Model_Event $event) + { + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isEnterpriseSupportEnabled() == true) { + return $this; + } + return parent::register($event); + } + + /** + * (Dummy) Process event + * + * @param Mage_Index_Model_Event $event + * + * @return Mage_Index_Model_Indexer_Abstract + */ + public function processEvent(Mage_Index_Model_Event $event) + { + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isEnterpriseSupportEnabled() == true) { + return $this; + } + return parent::processEvent($event); + } + + /** + * (Dummy) Check if event can be matched by process + * + * @param Mage_Index_Model_Event $event + * + * @return bool + */ + public function matchEvent(Mage_Index_Model_Event $event) + { + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isEnterpriseSupportEnabled() == true) { + return false; + } + return parent::matchEvent($event); + } + + + /** + * Process event + * + * @param Mage_Index_Model_Event $event Event to be indexed. + * + * @return void + */ + protected function _processEvent(Mage_Index_Model_Event $event) + { + $data = $event->getNewData(); + + if (!empty($data['catalogsearch_fulltext_reindex_all'])) { + $this->reindexAll(); + } else if (!empty($data['catalogsearch_delete_product_id'])) { + $productId = $data['catalogsearch_delete_product_id']; + + if (!$this->_isProductComposite($productId)) { + $parentIds = $this->_getResource()->getRelationsByChild($productId); + if (!empty($parentIds)) { + $this->_getMapping('product')->rebuildIndex(null, $parentIds); + } + } + + $this->_getIndexer() + ->cleanIndex(null, $productId) + ->resetSearchResults(); + + } else if (!empty($data['catalogsearch_update_product_id'])) { + $productId = $data['catalogsearch_update_product_id']; + $productIds = array($productId); + + if (!$this->_isProductComposite($productId)) { + $parentIds = $this->_getResource()->getRelationsByChild($productId); + if (!empty($parentIds)) { + $productIds = array_merge($productIds, $parentIds); + } + } + $this->_getIndexer()->cleanIndex(null, $productIds); + $this->_getMapping('product')->rebuildIndex(null, $productIds); + + $this->_getIndexer()->resetSearchResults(); + + } else if (!empty($data['catalogsearch_product_ids'])) { + // mass action + $productIds = $data['catalogsearch_product_ids']; + $parentIds = $this->_getResource()->getRelationsByChild($productIds); + if (!empty($parentIds)) { + $productIds = array_merge($productIds, $parentIds); + } + + if (!empty($data['catalogsearch_website_ids'])) { + $websiteIds = $data['catalogsearch_website_ids']; + $actionType = $data['catalogsearch_action_type']; + + foreach ($websiteIds as $websiteId) { + foreach (Mage::app()->getWebsite($websiteId)->getStoreIds() as $storeId) { + if ($actionType == 'remove') { + $this->_getIndexer() + ->cleanIndex($storeId, $productIds) + ->resetSearchResults(); + } else if ($actionType == 'add') { + $this->_getMapping('product')->rebuildIndex($storeId, $productIds); + $this->_getIndexer()->resetSearchResults(); + } + } + } + } + if (isset($data['catalogsearch_status'])) { + $status = $data['catalogsearch_status']; + if ($status == Mage_Catalog_Model_Product_Status::STATUS_ENABLED) { + $this->_getIndexer() + ->rebuildIndex(null, $productIds) + ->resetSearchResults(); + } else { + $this->_getIndexer()->cleanIndex(null, $productIds); + $this->_getMapping('product')->resetSearchResults(); + } + } + if (isset($data['catalogsearch_force_reindex'])) { + $this->_getIndexer()->cleanIndex(null, $productIds); + $this->_getMapping('product')->rebuildIndex(null, $productIds); + $this->_getIndexer()->resetSearchResults(); + } + } else if (isset($data['catalogsearch_category_update_product_ids'])) { + $productIds = $data['catalogsearch_category_update_product_ids']; + $categoryIds = $data['catalogsearch_category_update_category_ids']; + $this->_getMapping('category')->rebuildIndex(null, $categoryIds); + } + } + + /** + * Return a mapping used to index entities. + * + * @param string $type Retrieve mapping for a type (product, category, ...). + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract + */ + protected function _getMapping($type) + { + $index = $this->getCurrentIndex(); + return $index->getMapping($type); + } + + /** + * Return the current index where to put new documents. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Index + */ + public function getCurrentIndex() + { + $engine = Mage::helper('catalogsearch')->getEngine(); + return $engine->getCurrentIndex(); + } + + /** + * Rebuild all index data + * + * @return void + */ + public function reindexAll() + { + $index = $this->getCurrentIndex(); + + $index->prepareNewIndex(); + foreach ($index->getAllMappings() as $mapping) { + $mapping->rebuildIndex(); + } + $index->installNewIndex(); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Observer.php b/src/app/code/community/Smile/ElasticSearch/Model/Observer.php new file mode 100644 index 00000000..65ba9309 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Observer.php @@ -0,0 +1,221 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Observer +{ + /** + * Adds search weight parameter in attribute form. + * + * @param Varien_Event_Observer $observer Event data + * + * @return Smile_ElasticSearch_Model_Observer Self Reference + */ + public function eavAttributeEditFormInit(Varien_Event_Observer $observer) + { + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = $observer->getEvent()->getAttribute(); + $form = $observer->getEvent()->getForm(); + $fieldset = $form->getElement('front_fieldset'); + + $fieldset->addField( + 'search_weight', + 'select', array( + 'name' => 'search_weight', + 'label' => Mage::helper('smile_elasticsearch')->__('Search Weight'), + 'values' => array( + 1 => 1, + 2 => 2, + 3 => 3, + 4 => 4, + 5 => 5 + ), + ), + 'is_searchable' + ); + + if ($attribute->getAttributeCode() == 'name') { + $form->getElement('is_searchable')->setDisabled(1); + } + + return $this; + } + + /** + * Requires catalog search indexation. + * + * @param Varien_Event_Observer $observer Event data + * + * @return Smile_ElasticSearch_Model_Observer Self Reference + */ + public function requireCatalogsearchReindex(Varien_Event_Observer $observer) + { + if (Mage::helper('smile_elasticsearch')->isActiveEngine()) { + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = $observer->getEvent()->getAttribute(); + if ($attribute->getData('search_weight') != $attribute->getOrigData('search_weight')) { + Mage::getSingleton('index/indexer')->getProcessByCode('catalogsearch_fulltext') + ->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX); + } + } + + return $this; + } + + /** + * Reset search engine if it is enabled for catalog navigation + * + * @param Varien_Event_Observer $observer Event data + * + * @return Smile_ElasticSearch_Model_Observer Self Reference + */ + public function resetCurrentCatalogLayer(Varien_Event_Observer $observer) + { + if (Mage::helper('smile_elasticsearch')->isActiveEngine()) { + Mage::register('current_layer', Mage::getSingleton('smile_elasticsearch/catalog_layer')); + } + + return $this; + } + + /** + * Reset search engine if it is enabled for search navigation + * + * @param Varien_Event_Observer $observer Event data + * + * @return Smile_ElasticSearch_Model_Observer Self Reference + */ + public function resetCurrentSearchLayer(Varien_Event_Observer $observer) + { + if (Mage::helper('smile_elasticsearch')->isActiveEngine()) { + Mage::register('current_layer', Mage::getSingleton('smile_elasticsearch/catalogsearch_layer')); + } + + return $this; + } + + /** + * Retrieve Fulltext Search instance + * + * @return Mage_CatalogSearch_Model_Fulltext + */ + protected function _getIndexer() + { + return Mage::getSingleton('catalogsearch/fulltext'); + } + + /** + * Fix category product indexing when product list changes for a category + * + * @param Varien_Event_Observer $observer Event data + * + * @return Smile_ElasticSearch_Model_Observer + */ + public function reindexCategoryAfterSave(Varien_Event_Observer $observer) + { + $helper = Mage::helper('smile_elasticsearch'); + $category = $observer->getEvent()->getCategory(); + if ($helper->isEnterpriseSupportEnabled() == false) { + $productIds = $category->getProductCollection()->getAllIds(); + $this->_getIndexer()->resetSearchResults(); + $currentIndex = Mage::helper('catalogsearch')->getEngine()->getCurrentIndex(); + $currentIndex->getMapping('product')->rebuildIndex(null, $productIds); + } else { + $category = $observer->getEvent()->getCategory(); + $productIds = $category->getAffectedProductIds(); + if (empty($productIds)) { + return $this; + } + $client = Mage::getModel('enterprise_mview/client'); + $client->init('catalogsearch_fulltext'); + + $client->execute('enterprise_catalogsearch/index_action_fulltext_refresh_row', array( + 'value' => $productIds, + )); + } + + if ($helper->isActiveEngine()) { + $engine = Mage::helper('catalogsearch')->getEngine(); + $index = $engine->getCurrentIndex(); + $mapping = $index->getMapping('category'); + $engine->cleanIndex(null, $category->getId(), 'category'); + $mapping->rebuildIndex(null, $category->getId()); + } + + return $this; + } + + /** + * Remove category from index after delete + * + * @param Varien_Event_Observer $observer Event data + * + * @return Smile_ElasticSearch_Model_Observer + */ + public function cleanCategoryAfterDelete(Varien_Event_Observer $observer) + { + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isActiveEngine()) { + $category = $observer->getEvent()->getCategory(); + $engine = Mage::helper('catalogsearch')->getEngine(); + $engine->cleanIndex(null, $category->getId(), 'category'); + } + } + + /** + * Reindex categories when row category indexer need it + * + * @param Varien_Event_Observer $observer Event data + * + * @return Smile_ElasticSearch_Model_Observer + */ + public function reindexProductOnPartialCategoryReindex(Varien_Event_Observer $observer) + { + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isActiveEngine()) { + $productIds = $category = $observer->getEvent()->getProductIds(); + if (empty($productIds)) { + return $this; + } + $client = Mage::getModel('enterprise_mview/client'); + $client->init('catalogsearch_fulltext'); + + $client->execute('enterprise_catalogsearch/index_action_fulltext_refresh_row', array( + 'value' => $productIds, + )); + } + } + + /** + * Process shell reindex catalog full text refresh event + * + * @param Varien_Event_Observer $observer Event to observe. + * + * @return Smile_CatalogSearch_Model_Observer + */ + public function processShellFulltextReindexEvent(Varien_Event_Observer $observer) + { + $helper = Mage::helper('smile_elasticsearch'); + if ($helper->isEnterpriseSupportEnabled() == true && $helper->isActiveEngine() == false) { + $client = $this->_factory->getModel('enterprise_mview/client', array(array('factory' => $this->_factory))); + $client->init('catalogsearch_fulltext'); + $client->execute('enterprise_catalogsearch/index_action_fulltext_refresh'); + } + return $this; + } +} + diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Advanced.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Advanced.php new file mode 100644 index 00000000..9af5d4b5 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Advanced.php @@ -0,0 +1,22 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Advanced extends Mage_CatalogSearch_Model_Resource_Advanced +{ + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Category/Suggest/Collection.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Category/Suggest/Collection.php new file mode 100644 index 00000000..2215c089 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Category/Suggest/Collection.php @@ -0,0 +1,147 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Catalog_Category_Suggest_Collection + extends Mage_Catalog_Model_Resource_Category_Collection +{ + /** + * $_suggestQuery + */ + protected $_suggestQuery = null; + + /** + * $_suggestionsIds + */ + protected $_suggestionsIds = null; + + /** + * $_suggestionsOutput + */ + protected $_suggestionsOutput = array(); + + /** + * $_engine + */ + protected $_engine; + + /** + * $_isSuggestionFilterSet + */ + protected $_isSuggestionFilterSet = false; + + /** + * Register suggest input text. + * + * @param string $query The text input + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Suggest_Collection + */ + public function addSuggestFilter($query) + { + $this->_suggestQuery = $query; + return $this; + } + + /** + * Defines current search engine. + * + * @param Smile_ElasticSearch_Model_Resource_Engine_ElasticSearch $engine Search engine to be set + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function setEngine(Smile_ElasticSearch_Model_Resource_Engine_ElasticSearch $engine) + { + $this->_engine = $engine; + + return $this; + } + + /** + * Get size of the csuggest collection + * + * @return int Size of the collection + */ + public function getSize() + { + if ($this->_isSuggestionFilterSet === false) { + $this->addIdFilter($this->getSuggestionIds()); + $this->_isSuggestionFilterSet = true; + } + return parent::getSize(); + } + + /** + * Apply filters before load + * + * @return Mage_Catalog_Model_Resource_Product_Collection Self reference + */ + protected function _beforeLoad() + { + if ($this->_isSuggestionFilterSet === false) { + $this->addIdFilter($this->getSuggestionIds()); + $this->_isSuggestionFilterSet = true; + } + return parent::_beforeLoad(); + } + + /** + * Return ids of the suggested product + * + * @return array Ids of the selected products + */ + public function getSuggestionIds() + { + if (is_null($this->_suggestionsIds) && !is_null($this->_suggestQuery)) { + $context = array('type' => 'category', 'store_id' => $this->getStoreId(), 'visibility' => null, 'status' => 1); + $suggestions = $this->_engine->suggest($this->_suggestQuery, $context); + $idsFilter = array(); + foreach ($suggestions as $suggestion) { + if (isset($suggestion['payload']) && isset($suggestion['payload']['entity_id'])) { + $categoryId = $suggestion['payload']['entity_id']; + $idsFilter[] = $categoryId; + $this->_suggestionsOutput[$categoryId] = $suggestion['text']; + } + } + + if (empty($idsFilter)) { + $idsFilter = array(0); + } + + $this->_suggestionsIds = $idsFilter; + } + + return $this->_suggestionsIds; + } + + /** + * Load suggestion text into items + * + * @return Mage_Catalog_Model_Resource_Product_Collection Self reference + */ + protected function _afterLoad() + { + parent::_afterLoad(); + + foreach ($this->_items as $item) { + + $item->setOutputText($this->_suggestionsOutput[$item->getId()]); + } + + return $this; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Product/Collection.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Product/Collection.php new file mode 100644 index 00000000..fc313b9c --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Product/Collection.php @@ -0,0 +1,231 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection extends Mage_Catalog_Model_Resource_Product_Collection +{ + /** + * @var Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch Search engine. + */ + protected $_engine; + + + protected $_searchEngineQuery = null; + + /** + * @var array Faceted data. + */ + protected $_facetedData = array(); + + + /** + * @var array Search entity ids. + */ + protected $_searchedEntityIds = array(); + + /** + * @var array Sort by definition. + */ + protected $_sortBy = array(); + + + /** + * Add some fields to filter. + * + * @param array $fields Field to be filtered and filter values + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function addFieldsToFilter($fields) + { + return $this; + } + + /** + * Stores query text filter. + * + * @param string $query Fulltext search query to be applied + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function addSearchFilter($query) + { + $this->getSearchEngineQuery()->setFulltextQuery($query); + return $this; + } + + + /** + * Returns faceted data. + * + * @param string $field Facet to be retrieved + * + * @return array + */ + public function getFacetedData($field) + { + if (array_key_exists($field, $this->_facetedData)) { + return $this->_facetedData[$field]; + } + + return array(); + } + + /** + * Returns collection size. + * + * @return int + */ + public function getSize() + { + if (is_null($this->_totalRecords)) { + $this->_beforeLoad(); + } + + return $this->_totalRecords; + } + + /** + * Defines current search engine. + * + * @param Smile_ElasticSearch_Model_Resource_Engine_ElasticSearch $engine Search engine to be set + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function setEngine(Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch $engine) + { + $this->_engine = $engine; + + return $this; + } + + /** + * Stores sort order. + * + * @param string $attribute Attribute name to sort by + * @param string $dir Sort direction + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function setOrder($attribute, $dir = self::SORT_ORDER_DESC) + { + $this->_sortBy[] = array($attribute => $dir); + + return $this; + } + + /** + * Reorder collection according to current sort order. + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + protected function _afterLoad() + { + parent::_afterLoad(); + if (!empty($this->_searchedEntityIds)) { + $sortedItems = array(); + foreach ($this->_searchedEntityIds as $id) { + if (isset($this->_items[$id])) { + $sortedItems[$id] = $this->_items[$id]; + } + } + $this->_items = &$sortedItems; + } + + return $this; + } + + /** + * Handles collection filtering by ids retrieves from search engine. + * Will also stores faceted data and total records. + * + * @return Mage_Catalog_Model_Resource_Product_Collection + */ + protected function _beforeLoad() + { + $this->_prepareQuery(); + + $ids = array(); + $result = $this->getSearchEngineQuery()->search(); + + $ids = isset($result['ids']) ? $result['ids'] : array(); + $this->_facetedData = isset($result['faceted_data']) ? $result['faceted_data'] : array(); + $this->_totalRecords = isset($result['total_count']) ? $result['total_count'] : null; + $this->_isSpellChecked = isset($result['is_spellchecked']) ? $result['is_spellchecked'] : false; + + if (empty($ids)) { + $ids = array(0); // Fix for no result + } + + $this->addIdFilter($ids); + $this->_searchedEntityIds = $ids; + $this->_pageSize = false; + + return parent::_beforeLoad(); + } + + /** + * Retrieves parameters. + * + * @return array + */ + protected function _prepareQuery() + { + $query = $this->getSearchEngineQuery(); + + if (!empty($this->_sortBy)) { + $query->addSortOrder($this->_sortBy); + } + + if ($this->_pageSize !== false && $this->_curPage !== false) { + $query->setPageParams($this->_curPage, $this->_pageSize); + } + + if ($this->getStoreId()) { + $query->addFilter('terms', array('store_id' => $this->getStoreId())); + } + } + + /** + * Get the ES query model associated with the product collection. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function getSearchEngineQuery() + { + if ($this->_searchEngineQuery === null) { + $this->_searchEngineQuery = $this->_engine->createQuery('product'); + + if ($this->getStoreId()) { + $store = Mage::app()->getStore(); + $this->_searchEngineQuery->setLanguageCode(Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store)); + } + } + + return $this->_searchEngineQuery; + } + + /** + * Indicates if spellchecker the collection has exact matches or not. + * + * @return boolean + */ + public function isSpellchecked() + { + return false; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Product/Suggest/Collection.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Product/Suggest/Collection.php new file mode 100644 index 00000000..2242e938 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Catalog/Product/Suggest/Collection.php @@ -0,0 +1,117 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Catalog_Product_Suggest_Collection + extends Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection +{ + /** + * @var null|string + */ + protected $_suggestQuery = null; + + /** + * @var null|array + */ + protected $_suggestionsIds = null; + + /** + * @var bool + */ + protected $_isSuggestionFilterSet = false; + + /** + * Register suggest input text. + * + * @param string $query The text input + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Suggest_Collection + */ + public function addSuggestFilter($query) + { + $this->_suggestQuery = $query; + return $this; + } + + /** + * Apply filters before load + * + * @return Mage_Catalog_Model_Resource_Product_Collection Self reference + */ + protected function _beforeLoad() + { + if ($this->_isSuggestionFilterSet === false) { + $query = $this->getSearchEngineQuery(); + $query->addFilter('terms', array('id' => $this->getSuggestionIds())); + $this->_isSuggestionFilterSet = true; + } + return parent::_beforeLoad(); + } + + /** + * Get size of the csuggest collection + * + * @return int Size of the collection + */ + public function getSize() + { + if ($this->_isSuggestionFilterSet === false) { + $query = $this->getSearchEngineQuery(); + $query->addFilter('terms', array('id' => $this->getSuggestionIds())); + $this->_isSuggestionFilterSet = true; + } + return parent::getSize(); + } + + /** + * Return ids of the suggested product + * + * @return array Ids of the selected products + */ + public function getSuggestionIds() + { + $allowedVisibilities = Mage::getSingleton('catalog/product_visibility')->getVisibleInSiteIds(); + $allowedStatuses = Mage::getSingleton('catalog/product_status')->getVisibleStatusIds(); + + if (is_null($this->_suggestionsIds) && !is_null($this->_suggestQuery)) { + + $context = array( + 'type' => 'product', + 'store_id' => $this->getStoreId(), + 'visibility' => $allowedVisibilities, + 'status' => $allowedStatuses + ); + + $suggestions = $this->_engine->suggest($this->_suggestQuery, $context); + $idsFilter = array(); + + foreach ($suggestions as $suggestion) { + if (isset($suggestion['payload']) && isset($suggestion['payload']['entity_id'])) { + $idsFilter[] = $suggestion['payload']['entity_id']; + } + } + + if (empty($idsFilter)) { + $idsFilter = array(0); + } + + $this->_suggestionsIds = $idsFilter; + } + + return $this->_suggestionsIds; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch.php new file mode 100644 index 00000000..c9a4bc24 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch.php @@ -0,0 +1,477 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + +// Include the Elasticsearch required libraries used by the adapter +require_once 'vendor/autoload.php'; + +/** + * Elastic search engine. + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + * + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch +{ + + const CACHE_INDEX_PROPERTIES_ID = 'elasticsearch_index_properties'; + + const UNIQUE_KEY = 'unique'; + + /** + * + * @var array List of default query parameters. + */ + protected $_defaultQueryParams = array( + 'offset' => 0, + 'limit' => 100, + 'sort_by' => array( + array( + 'relevance' => 'desc' + ) + ), + 'store_id' => null, + 'locale_code' => null, + 'fields' => array(), + 'params' => array(), + 'ignore_handler' => false, + 'filters' => array() + ); + + /** + * + * @var bool Stores search engine availibility + */ + protected $_test = null; + + /** + * + * @var array List of used fields. + */ + protected $_usedFields = array( + self::UNIQUE_KEY, + 'id', + 'sku', + 'price', + 'store_id', + 'categories', + 'show_in_categories', + 'visibility', + 'in_stock', + 'score' + ); + + /** + * + * @var Varien_Object + */ + protected $_config; + + /** + * + * @var Elasticsearch\Client + */ + protected $_client = null; + + /** + * + * @var Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Index + */ + protected $_currentIndex = null; + + /** + * + * @var string + */ + protected $_currentIndexName = null; + + /** + * @var array() + */ + protected $_dateFormats = array(); + + /** + * Initializes search engine config and index name. + * + * @param array|bool $params Client init params. + */ + public function __construct($params = false) + { + $config = $this->_getHelper()->getEngineConfigData(); + + $this->_config = new Varien_Object($config); + + $this->_client = new \Elasticsearch\Client(array('hosts' => $config['hosts'], 'logging' => false)); + // parent::__construct($config); + if (! isset($config['alias'])) { + Mage::throwException('Alias must be defined for search engine client.'); + } + + $this->_currentIndex = Mage::getResourceModel('smile_elasticsearch/engine_elasticsearch_index'); + $this->_currentIndex->setAdapter($this)->setCurrentName($config['alias']); + } + + /** + * Get the ElasticSearch client instance + * + * @return \Elasticsearch\Client + */ + public function getClient() + { + return $this->_client; + } + + /** + * Return the current index instance + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Index + */ + public function getCurrentIndex() + { + return $this->_currentIndex; + } + + /** + * Cleans caches. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch + */ + public function cleanCache() + { + Mage::app()->removeCache(self::CACHE_INDEX_PROPERTIES_ID); + + return $this; + } + + /** + * Cleans index. + * + * @param int $storeId Store ind to be cleaned + * @param int $id Document id to be cleaned + * @param string $type Document type to be cleaned + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch + */ + public function cleanIndex($storeId = null, $id = null, $type = 'product') + { + if (is_null($id)) { + return $this; + } else if (!is_array($id)) { + $id = array($id); + } + + if (is_null($storeId)) { + $storeId = array_keys(Mage::app()->getStores()); + } else if (!is_array($storeId)) { + $storeId = array($storeId); + } + + $bulk = array('body' => array()); + + foreach ($id as $currentId) { + foreach ($storeId as $currentStoreId) { + $bulk['body'][] = array( + 'delete' => array( + '_index' => $this->getCurrentIndex()->getCurrentName(), + '_type' => $type, + '_id' => $currentId . '|' .$currentStoreId + ) + ); + } + } + + if (!empty($bulk['body'])) { + $this->getClient()->bulk($bulk); + } + + return $this; + } + + /** + * Saves products data in index. + * + * @param int $storeId Store id + * @param array $indexes Documents data + * @param string $type Documents type + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch + */ + public function saveEntityIndexes($storeId, $indexes, $type = 'product') + { + $docs = $this->_prepareDocs($indexes, $type); + $this->getCurrentIndex()->addDocuments($docs); + + return $this; + } + + /** + * Checks Elasticsearch availability. + * + * @return bool + */ + public function test() + { + if (null !== $this->_test) { + return $this->_test; + } + + try { + $this->_test = $this->getStatus(); + } catch (Exception $e) { + Mage::logException($e); + $this->_test = false; + } + + if ($this->_test === false && $this->_getHelper()->isDebugEnabled()) { + $this->_getHelper()->showError('Elasticsearch engine is not available'); + } + + return $this->_test; + } + + /** + * Run autocomplete for products on the search engigne + * + * @param string $text Text to be autocompleted + * @param array $context Context of the autocomplete (store_id, visibility, ...) + * + * @return array + */ + public function suggest($text, $context) + { + $suggestFieldName = $this->_getHelper()->getSuggestFieldName(); + $params = array( + 'index' => $this->_currentIndex->getCurrentName() + ); + + $params['body']['suggestions'] = array( + 'text' => $text, + 'completion' => array( + 'size' => 20, + 'field' => $suggestFieldName, + 'fuzzy' => array( + 'fuzziness' => 0.7, + 'unicode_aware' => true + ), + 'context' => $context + ), + ); + + $response = $this->_client->suggest($params); + + $data = array(); + + if (!isset($response['error']) && isset($response['suggestions'])) { + $suggestions = current($response['suggestions']); + foreach ($suggestions['options'] as $suggestion) { + $data[] = $suggestion; + } + } + + return $data; + } + + /** + * Adds advanced index fields to index data. + * + * @param array $index Product data + * @param int $storeId Store id + * @param array $productIds Product ids + * + * @return array + */ + public function addAdvancedIndex($index, $storeId, $productIds = null) + { + return Mage::getResourceSingleton('smile_elasticsearch/engine_index')->addAdvancedIndex($index, $storeId, $productIds); + } + + /** + * Returns advanced search results. + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function getAdvancedResultCollection() + { + return $this->getResultCollection(); + } + + /** + * Checks if advanced index is allowed for current search engine. + * + * @return bool + */ + public function allowAdvancedIndex() + { + return true; + } + + /** + * Return a new query instance + * + * @param string $type Type of document for the query + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function createQuery($type) + { + $query = Mage::getResourceModel('smile_elasticsearch/engine_elasticsearch_query') + ->setAdapter($this) + ->setType($type); + + return $query; + } + + /** + * Returns resource name. + * + * @return string + */ + public function getResourceName() + { + return 'smile_elasticsearch/advanced'; + } + + /** + * Returns catalog product collection with current search engine set. + * + * @return Smile_ElasticSearch_Model_Resource_Catalog_Product_Collection + */ + public function getResultCollection() + { + return Mage::getResourceModel('smile_elasticsearch/catalog_product_collection')->setEngine($this); + } + + /** + * Checks if layered navigation is available for current search engine. + * + * @return bool + */ + public function isLayeredNavigationAllowed() + { + return true; + } + + /** + * Prepares index data. + * Should be overriden in child classes if needed. + * + * @param array $index Indexed data + * @param string $separator Field separator into the index + * + * @return array + */ + public function prepareEntityIndex($index, $separator = null) + { + return $this->_getHelper()->prepareIndexData($index, $separator); + } + + /** + * Transforms specified date to basic YYYY-MM-dd format. + * + * @param int $storeId Current store id + * @param string $date Date to be transformed + * + * @return null string + */ + protected function _getDate($storeId, $date = null) + { + if (! isset($this->_dateFormats[$storeId])) { + $timezone = Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_TIMEZONE, $storeId); + $locale = Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $storeId); + $locale = new Zend_Locale($locale); + + $dateObj = new Zend_Date(null, null, $locale); + $dateObj->setTimezone($timezone); + $this->_dateFormats[$storeId] = array( + $dateObj, + $locale->getTranslation(null, 'date', $locale) + ); + } + + if (is_empty_date($date)) { + return null; + } + + list ($dateObj, $localeDateFormat) = $this->_dateFormats[$storeId]; + $dateObj->setDate($date, $localeDateFormat); + + return $dateObj->toString('YYYY-MM-dd'); + } + + /** + * Perpare document to be indexed + * + * @param array $docsData Source document data to be indexed + * @param string $type Document type + * + * @return array + */ + protected function _prepareDocs($docsData, $type) + { + if (! is_array($docsData) || empty($docsData)) { + return array(); + } + + $docs = array(); + + foreach ($docsData as $entityId => $index) { + $index[self::UNIQUE_KEY] = $entityId . '|' . $index['store_id']; + $index['id'] = $entityId; + $docs[] = $this->getCurrentIndex()->createDocument($index[self::UNIQUE_KEY], $index, $type); + } + + return $docs; + } + + + /** + * Indicates if connection to the search engine is up or not + * + * @return bool + */ + public function getStatus() + { + return $this->_client->ping(); + } + + /** + * Read configuration from key + * + * @param string $key Name of the config param to retrieve + * + * @return mixed + */ + public function getConfig($key) + { + return $this->_config->getData($key); + } + + /** + * Returns search helper. + * + * @return Smile_ElasticSearch_Helper_Elasticsearch + */ + protected function _getHelper() + { + return Mage::helper('smile_elasticsearch/elasticsearch'); + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Abstract.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Abstract.php new file mode 100644 index 00000000..6a4e9ec8 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Abstract.php @@ -0,0 +1,82 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Abstract +{ + /** + * @var Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch + */ + protected $_adapter; + + + /** + * Returns search helper. + * + * @return Smile_ElasticSearch_Helper_Elasticsearch + */ + protected function _getHelper() + { + return Mage::helper('smile_elasticsearch/elasticsearch'); + } + + /** + * Set the adapter. + * + * @param Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch $adapter Adapter. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Abstract + */ + public function setAdapter($adapter) + { + $this->_adapter = $adapter; + return $this; + } + + /** + * Get the adapter. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Set the client. + * + * @return \Elasticsearch\Client + */ + public function getClient() + { + return $this->getAdapter()->getClient(); + } + + /** + * Return engine config param. + * + * @param string $key Config path. + * + * @return mixed + */ + public function getConfig($key) + { + return $this->getAdapter()->getConfig($key); + } + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Index.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Index.php new file mode 100644 index 00000000..6e9c4338 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Index.php @@ -0,0 +1,486 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Index + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Abstract +{ + /** + * @var int + */ + const COPY_DATA_BULK_SIZE = 1000; + + const MAPPING_CONF_ROOT_NODE = 'global/smile_elasticsearch/mapping'; + + /** + * @var string + */ + protected $_name; + + protected $_mappings = array(); + + /** + * @var boolean + */ + protected $_indexNeedInstall = false; + + /** + * @var string + */ + protected $_dateFormat = 'date'; + + /** + * @var array Stop languages for token filter. + * @link http://www.elasticsearch.org/guide/reference/index-modules/analysis/stop-tokenfilter.html + */ + protected $_stopLanguages = array( + 'arabic', 'armenian', 'basque', 'brazilian', 'bulgarian', 'catalan', 'czech', + 'danish', 'dutch', 'english', 'finnish', 'french', 'galician', 'german', 'greek', + 'hindi', 'hungarian', 'indonesian', 'italian', 'norwegian', 'persian', 'portuguese', + 'romanian', 'russian', 'spanish', 'swedish', 'turkish', + ); + + /** + * @var array Snowball languages. + * @link http://www.elasticsearch.org/guide/reference/index-modules/analysis/snowball-tokenfilter.html + */ + protected $_snowballLanguages = array( + 'Armenian', 'Basque', 'Catalan', 'Danish', 'Dutch', 'English', 'Finnish', 'French', + 'German', 'Hungarian', 'Italian', 'Kp', 'Lovins', 'Norwegian', 'Porter', 'Portuguese', + 'Romanian', 'Russian', 'Spanish', 'Swedish', 'Turkish', + ); + + /** + * Init mappings while the index is init + */ + public function __construct() + { + $mappingConfig = Mage::getConfig()->getNode(self::MAPPING_CONF_ROOT_NODE)->asArray(); + foreach ($mappingConfig as $type => $config) { + $this->_mappings[$type] = Mage::getResourceSingleton($config['model']); + $this->_mappings[$type]->setType($type); + } + } + + /** + * Set current index name. + * + * @param string $indexName Name of the index. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Index + */ + public function setCurrentName($indexName) + { + $this->_currentIndexName = $indexName; + return $this; + } + + /** + * Get name of the current index. + * + * @return string + */ + public function getCurrentName() + { + return $this->_currentIndexName; + } + + + /** + * Refreshes index + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Index Self reference + */ + public function refresh() + { + $indices = $this->getClient()->indices(); + $params = array('index' => $this->getCurrentName()); + if ($indices->exists($params)) { + $indices->refresh($params); + } + return $this; + } + + + /** + * Return index settings. + * + * @return array + */ + protected function _getSettings() + { + $indexSettings = array(); + $indexSettings['number_of_replicas'] = (int) $this->getConfig('number_of_replicas'); + $indexSettings['analysis']['analyzer'] = array( + 'whitespace' => array( + 'tokenizer' => 'standard', + 'filter' => array('lowercase'), + 'char_filter' => array('html_strip'), + ), + 'edge_ngram_front' => array( + 'tokenizer' => 'standard', + 'filter' => array('length', 'edge_ngram_front', 'lowercase'), + 'char_filter' => array('html_strip'), + ), + 'edge_ngram_back' => array( + 'tokenizer' => 'standard', + 'filter' => array('length', 'edge_ngram_back', 'lowercase'), + 'char_filter' => array('html_strip'), + ), + 'shingle' => array( + 'tokenizer' => 'standard', + 'filter' => array('shingle', 'length', 'lowercase'), + 'char_filter' => array('html_strip'), + ), + 'shingle_strip_ws' => array( + 'tokenizer' => 'standard', + 'filter' => array('shingle', 'strip_whitespaces', 'length', 'lowercase'), + 'char_filter' => array('html_strip'), + ), + 'shingle_strip_apos_and_ws' => array( + 'tokenizer' => 'standard', + 'filter' => array('shingle', 'strip_apostrophes', 'strip_whitespaces', 'length', 'lowercase'), + 'char_filter' => array('html_strip'), + ), + 'sortable' => array( + 'tokenizer' => 'keyword', + 'filter' => array('lowercase'), + 'char_filter' => array('html_strip') + ), + ); + $indexSettings['analysis']['filter'] = array( + 'shingle' => array( + 'type' => 'shingle', + 'min_shingle_size' => 2, + 'max_shingle_size' => 20, + 'output_unigrams' => true, + ), + 'strip_whitespaces' => array( + 'type' => 'pattern_replace', + 'pattern' => '\s', + 'replacement' => '', + ), + 'strip_apostrophes' => array( + 'type' => 'pattern_replace', + 'pattern' => "'", + 'replacement' => '', + ), + 'edge_ngram_front' => array( + 'type' => 'edgeNGram', + 'min_gram' => 5, + 'max_gram' => 50, + 'side' => 'front', + ), + 'edge_ngram_back' => array( + 'type' => 'edgeNGram', + 'min_gram' => 3, + 'max_gram' => 10, + 'side' => 'back', + ), + 'length' => array( + 'type' => 'length', + 'min' => 2, + ), + ); + /** @var $helper Smile_ElasticSearch_Helper_Data */ + $helper = $this->_getHelper(); + foreach (Mage::app()->getStores() as $store) { + /** @var $store Mage_Core_Model_Store */ + $languageCode = $helper->getLanguageCodeByStore($store); + $lang = Zend_Locale_Data::getContent('en_GB', 'language', $helper->getLanguageCodeByStore($store)); + if (!in_array($lang, $this->_snowballLanguages)) { + continue; // language not present by default in elasticsearch + } + $indexSettings['analysis']['analyzer']['analyzer_' . $languageCode] = array( + 'type' => 'custom', + 'tokenizer' => 'standard', + 'filter' => array('length', 'lowercase', 'snowball_' . $languageCode), + 'char_filter' => array('html_strip') + ); + $indexSettings['analysis']['filter']['snowball_' . $languageCode] = array( + 'type' => 'snowball', + 'language' => $lang, + ); + } + + if ($this->isIcuFoldingEnabled()) { + foreach ($indexSettings['analysis']['analyzer'] as &$analyzer) { + array_unshift($analyzer['filter'], 'icu_folding'); + } + unset($analyzer); + } + + return $indexSettings; + } + + /** + * Return a mapping used to index entities. + * + * @param string $type Retrieve mapping for a type (product, category, ...). + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract + */ + public function getMapping($type) + { + return $this->_mappings[$type]; + } + + /** + * Return all available mappings. + * + * @return array + */ + public function getAllMappings() + { + return $this->_mappings; + } + + /** + * Creates or updates Elasticsearch index. + * + * @link http://www.elasticsearch.org/guide/reference/mapping/core-types.html + * @link http://www.elasticsearch.org/guide/reference/mapping/multi-field-type.html + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Adapter + * + * @throws Exception + */ + protected function _prepareIndex() + { + try { + $indexSettings = $this->_getSettings(); + $indices = $this->getClient()->indices(); + $params = array('index' => $this->getCurrentName()); + + if ($indices->exists($params)) { + + $indices->close($params); + + $settingsParams = $params; + $settingsParams['body']['settings'] = $this->_getSettings(); + $indices->putSettings($settingsParams); + + $mapping = $params; + foreach ($this->_mappings as $type => $mappingModel) { + $mapping['body']['mappings'][$type] = $mappingModel->getMappingProperties(false); + } + + $indices->putMapping($mapping); + + $indices->open(); + } else { + $params['body']['settings'] = $this->_getSettings(); + $params['body']['settings']['number_of_shards'] = (int) $this->getConfig('number_of_shards'); + foreach ($this->_mappings as $type => $mappingModel) { + $mappingModel->setType($type); + $params['body']['mappings'][$type] = $mappingModel->getMappingProperties(false); + } + $properties = new Varien_Object($params); + Mage::dispatchEvent('smile_elasticsearch_index_create_before', array('index_properties' => $properties )); + $indices->create($properties->getData()); + } + } catch (Exception $e) { + Mage::logException($e); + Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); + throw $e; + } + + return $this; + } + + + /** + * Checks if ICU folding is enabled. + * + * @link http://www.elasticsearch.org/guide/reference/index-modules/analysis/icu-plugin.html + * @return bool + */ + public function isIcuFoldingEnabled() + { + return (bool) $this->getConfig('enable_icu_folding'); + } + + /** + * Checks if attribute is indexable. + * + * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute Attribute + * + * @return bool + */ + protected function _isAttributeIndexable($attribute) + { + return $this->_getHelper()->isAttributeIndexable($attribute); + } + + /** + * Prepare a new index for full reindex + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Adapter Self Reference + */ + public function prepareNewIndex() + { + // Current date use to compute the index name + $currentDate = new Zend_Date(); + + // Default pattern if nothing set into the config + $pattern = '{{YYYYMMdd}}-{{HHmmss}}'; + + // Try to get the pattern from config + $config = $this->_getHelper()->getEngineConfigData(); + if (isset($config['indices_pattern'])) { + $pattern = $config['indices_pattern']; + } + + // Parse pattern to extract datetime tokens + $matches = array(); + preg_match_all('/{{([\w]*)}}/', $pattern, $matches); + + foreach (array_combine($matches[0], $matches[1]) as $k => $v) { + // Replace tokens (UTC date used) + $pattern = str_replace($k, $currentDate->toString($v), $pattern); + } + + $indexName = $config['alias'] . '-' . $pattern; + + // Set the new index name + $this->setCurrentName($indexName); + + // Indicates an old index exits + $this->_indexNeedInstall = true; + $this->_prepareIndex(); + + return $this; + } + + /** + * Install the new index after full reindex + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Adapter + */ + public function installNewIndex() + { + if ($this->_indexNeedInstall) { + + Mage::dispatchEvent('smile_elasticsearch_index_install_before', array('index_name' => $this->getCurrentName())); + + $indices = $this->getClient()->indices(); + $alias = $this->getConfig('alias'); + $indices->putAlias(array('index' => $this->getCurrentName(), 'name' => $alias)); + $allIndices = $indices->getMapping(array('index'=> $alias)); + foreach (array_keys($allIndices) as $index) { + if ($index != $this->getCurrentName()) { + $indices->delete(array('index' => $index)); + } + } + } + } + + /** + * Create document to index. + * + * @param string $id Document Id + * @param array $data Data indexed + * @param string $type Document type + * + * @return string Json representation of the bulk document + */ + public function createDocument($id, array $data = array(), $type = 'product') + { + $headerData = array( + '_index' => $this->getCurrentName(), + '_type' => $type, + '_id' => $id + ); + + if (isset($data['_parent'])) { + $headerData['_parent'] = $data['_parent']; + } + + $headerRow = json_encode(array('index' => $headerData)); + $dataRow = json_encode($data); + + $result = array($headerRow, $dataRow); + return implode("\n", $result); + } + + /** + * Bulk document insert + * + * @param array $docs Document prepared with createDoc methods + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Adapter Self reference + * + * @throws Exception + */ + public function addDocuments(array $docs) + { + try { + if (!empty($docs)) { + $docs[] = ''; + $bulkParams = array('body' => implode("\n", $docs)); + $ret = $this->getClient()->bulk($bulkParams); + } + } catch (Exception $e) { + throw($e); + } + + $this->refresh(); + + return $this; + } + + /** + * Copy all data of a type from an index to the current one + * + * @param string $index Source Index for the copy. + * @param string $type Type of documents to be copied. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Adapter Self reference + */ + public function copyDataFromIndex($index, $type) + { + if ($this->getClient()->indices()->exists(array('index' => $index))) { + $scrollQuery = array( + 'index' => $index, + 'type' => $type, + 'size' => self::COPY_DATA_BULK_SIZE, + 'scroll' => '5m', + 'search_type' => 'scan' + ); + + $scroll = $this->getClient()->search($scrollQuery); + $indexDocumentCount = 0; + + if ($scroll['_scroll_id'] && $scroll['hits']['total'] > 0) { + $scroller = array('scroll' => '5m', 'scroll_id' => $scroll['_scroll_id']); + while ($indexDocumentCount <= $scroll['hits']['total']) { + $docs = array(); + $data = $this->getClient()->scroll($scroller); + + foreach ($data['hits']['hits'] as $item) { + $docs[] = $this->createDocument($item['_id'], $item['_source'], 'stats'); + } + + $this->addDocuments($docs); + $indexDocumentCount = $indexDocumentCount + self::COPY_DATA_BULK_SIZE; + } + } + } + + return $this; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Abstract.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Abstract.php new file mode 100644 index 00000000..91a5d7ef --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Abstract.php @@ -0,0 +1,118 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +abstract class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract +{ + /** + * Field type constant + * + * @var string + */ + const FIELD_TYPE_SEARCH = 'search'; + const FIELD_TYPE_FILTER = 'filter'; + const FIELD_TYPE_SORT = 'sort'; + + /** + * @var string + */ + protected $_type; + + /** + * @var array + */ + protected $_searchFields = null; + + /** + * Set index type for the current mapping. + * + * @param string $type The new type. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract + */ + public function setType($type) + { + $this->_type = $type; + return $this; + } + + /** + * Return a list of all searchable field for the current type (by locale code). + * + * @param string $localeCode Locale code. + * + * @return array. + */ + abstract public function getSearchFields($localeCode); + + /** + * Return the ES field name + * + * @param string $field Magento field. + * @param string $localeCode Locale code we want the field for. + * @param string $type How the field will be used : search, facet, sort + * + * @return string + */ + public function getFieldName($field, $localeCode, $type = self::FIELD_TYPE_SEARCH) + { + $mapping = $this->getMappingProperties(); + + if (in_array($type, array(self::FIELD_TYPE_SEARCH, self::FIELD_TYPE_SORT)) && + isset($mapping['properties']['options_' . $field . '_' . $localeCode]) + ) { + $field = 'options_' . $field . '_' . $localeCode; + } else { + if (isset($mapping['properties'][$field . '_' . $localeCode])) { + $field = $field . '_' . $localeCode; + } + if (isset($mapping['properties'][$field]['type'])) { + + if (!in_array($mapping['properties'][$field]['type'], array('string', 'multi_field')) && + $type == self::FIELD_TYPE_SEARCH + ) { + $field = false; + } + + if ($field && $mapping['properties'][$field]['type'] == 'multi_field') { + $field .= $type == self::FIELD_TYPE_FILTER ? '.untouched' : ($type == self::FIELD_TYPE_SORT ? '.sortable' : ''); + } + } + } + + return $field; + } + + /** + * Get mapping properties as stored into the index + * + * @param string $useCache Indicates if the cache should be used or if the mapping should be rebuilt. + * + * @return array + */ + abstract public function getMappingProperties($useCache = true); + + /** + * Rebuild the index (full or diff). + * + * @param int|null $storeId Store id the index should be rebuilt for. If null, all store id will be rebuilt. + * @param array|null $ids Ids the index should be rebuilt for. If null, processing a fulll reindex + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract + */ + abstract public function rebuildIndex($storeId = null, $ids = null); +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Catalog/Eav/Abstract.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Catalog/Eav/Abstract.php new file mode 100644 index 00000000..33a9cb97 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Catalog/Eav/Abstract.php @@ -0,0 +1,704 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +abstract class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Catalog_Eav_Abstract + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract +{ + /** + * @var Mage_Eav_Model_Resource_Attribute_Collection + */ + protected $_attributeCollectionModel; + + /** + * @var array + */ + protected $_mapping = null; + + /** + * @var array + */ + protected $_authorizedBackendModels = array(); + + /** + * @var array + */ + protected $_suggestInputAttributes = array('name'); + + /** + * @var array + */ + protected $_suggestPayloadAttributes = array('entity_id'); + + /** + * Get mapping properties as stored into the index + * + * @param string $useCache Indicates if the cache should be used or if the mapping should be rebuilt. + * + * @return array + */ + public function getMappingProperties($useCache = true) + { + $cacheKey = 'SEARCH_ENGINE_MAPPING_' . $this->_type; + + if ($this->_mapping == null && $useCache) { + $mapping = Mage::app()->loadCache($cacheKey); + if ($mapping) { + $this->_mapping = unserialize($mapping); + } + } + + if ($this->_mapping === null) { + + $this->_mapping = array('properties' => array()); + + $entityType = Mage::getModel('eav/entity_type')->loadByCode($this->_entityType); + + $attributes = Mage::getResourceModel($this->_attributeCollectionModel) + ->setEntityTypeFilter($entityType->getEntityTypeId()); + + foreach ($attributes as $attribute) { + $this->_mapping['properties'] = array_merge($this->_mapping['properties'], $this->_getAttributeMapping($attribute)); + } + + $this->_mapping['properties']['unique'] = array('type' => 'string'); + $this->_mapping['properties']['id'] = array('type' => 'long'); + $this->_mapping['properties']['store_id'] = array('type' => 'integer'); + + foreach (Mage::app()->getStores() as $store) { + $languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + $this->_mapping['properties'][Mage::helper('smile_elasticsearch')->getSuggestFieldName($store)] = array( + 'type' => 'completion', + 'payloads' => true, + 'index_analyzer' => 'analyzer_' . $languageCode, + 'search_analyzer' => 'analyzer_' . $languageCode, + 'preserve_separators' => false, + 'preserve_position_increments' => false, + 'context' => array( + 'store_id' => array('type' => 'category', 'default' => '0'), + 'type' => array('type' => 'category', 'default' => $this->_type), + 'visibility' => array('type' => 'category', 'default' => 1), + 'status' => array('type' => 'category', 'default' => 1) + ) + ); + } + + $mapping = serialize($this->_mapping); + + Mage::app()->saveCache( + $mapping, + $cacheKey, + array('CONFIG', 'EAV_ATTRIBUTE'), + Mage::helper('smile_elasticsearch')->getCacheLifetime() + ); + } + + return $this->_mapping; + } + + /** + * Return mapping for an attribute. + * + * @param Mage_Eav_Model_Attribute $attribute Attribute we want the mapping for. + * + * @return array + */ + protected function _getAttributeMapping($attribute) + { + $mapping = array(); + + if ($this->_canIndexAttribute($attribute)) { + $attributeCode = $attribute->getAttributeCode(); + $type = $this->_getAttributeType($attribute); + + if ($type === 'string' && !$attribute->getBackendModel() && $attribute->getFrontendInput() != 'media_image') { + foreach (Mage::app()->getStores() as $store) { + $languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + $fieldName = $attributeCode . '_' . $languageCode; + $mapping[$fieldName] = array('type' => $type, 'analyzer' => 'analyzer_' . $languageCode); + + if ($attribute->getBackendType() == 'varchar') { + $mapping[$fieldName] = array('type' => 'multi_field', 'fields' => array($fieldName => $mapping[$fieldName])); + $mapping[$fieldName]['fields']['sortable'] = array('type' => $type, 'analyzer' => 'sortable'); + $mapping[$fieldName]['fields']['untouched'] = array('type' => $type, 'index' => 'not_analyzed'); + } + } + } else if ($type === 'date') { + $mapping[$attributeCode] = array( + 'type' => $type, + 'format' => implode('||', array(Varien_Date::DATETIME_INTERNAL_FORMAT, Varien_Date::DATE_INTERNAL_FORMAT)) + ); + } else { + $mapping[$attributeCode] = array('type' => $type); + } + + if ($attribute->usesSource()) { + foreach (Mage::app()->getStores() as $store) { + $languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + $fieldName = $attributeCode . '_' . $languageCode; + $mapping['options_' . $attributeCode . '_' . $languageCode] = array( + 'type' => 'string', + 'analyzer' => 'analyzer_' . $languageCode + ); + } + } + } + + return $mapping; + } + + /** + * Returns attribute type for indexation. + * + * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute Attribute + * + * @return string + */ + protected function _getAttributeType($attribute) + { + $type = 'string'; + if ($attribute->getBackendType() == 'int' || $attribute->getFrontendClass() == 'validate-digits') { + $type = 'integer'; + } elseif ($attribute->getBackendType() == 'decimal') { + $type = 'double'; + } elseif ($attribute->getSourceModel() == 'eav/entity_attribute_source_boolean') { + $type = 'boolean'; + } elseif ($attribute->getBackendType() == 'datetime') { + $type = 'date'; + } elseif ($attribute->usesSource() && $attribute->getSourceModel() === null) { + $type = 'integer'; + } else if ($attribute->usesSource()) { + $type = 'string'; + } + + return $type; + } + + /** + * Indicates if an attribute can be indexed or not. + * + * @param Mage_Eav_Model_Attribute $attribute Attribute + * + * @return boolean + */ + protected function _canIndexAttribute($attribute) + { + $canIndex = true; + + if ($attribute->getBackendModel() && !in_array($attribute->getBackendModel(), $this->_authorizedBackendModels)) { + $canIndex = false; + } + + return $canIndex; + } + + + /** + * Rebuild the index (full or diff). + * + * @param int|null $storeId Store id the index should be rebuilt for. If null, all store id will be rebuilt. + * @param array|null $ids Ids the index should be rebuilt for. If null, processing a fulll reindex + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract + */ + public function rebuildIndex($storeId = null, $ids = null) + { + if (is_null($storeId)) { + $storeIds = array_keys(Mage::app()->getStores()); + foreach ($storeIds as $storeId) { + $this->_rebuildStoreIndex($storeId, $ids); + } + } else { + $this->_rebuildStoreIndex($storeId, $ids); + } + + return $this; + } + + /** + * Returns the main entity table. + * + * @param string $modelEntity Entity name + * + * @return string + */ + public function getTable($modelEntity) + { + return Mage::getSingleton('core/resource')->getTableName($modelEntity); + } + + /** + * Return DB connection. + * + * @return Varien_Db_Adapter_Interface + */ + public function getConnection() + { + return Mage::getSingleton('core/resource')->getConnection('write');; + } + + /** + * Rebuild the index (full or diff). + * + * @param int $storeId Store id the index should be rebuilt for. + * @param array|null $entityIds Ids the index should be rebuilt for. If null, processing a fulll reindex + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract + */ + protected function _rebuildStoreIndex($storeId, $entityIds = null) + { + $store = Mage::app()->getStore($storeId); + $websiteId = $store->getWebsiteId(); + + $languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + + $dynamicFields = array(); + $attributesById = $this->_getAttributesById(); + + foreach ($attributesById as $attribute) { + if ($this->_canIndexAttribute($attribute) && $attribute->getBackendType() != 'static') { + $dynamicFields[$attribute->getBackendTable()][] = $attribute->getAttributeId(); + } + } + + $websiteId = Mage::app()->getStore($storeId)->getWebsite()->getId(); + $lastObjectId = 0; + + while (true) { + + $entities = $this->_getSearchableEntities($storeId, $entityIds, $lastObjectId); + + if (!$entities) { + break; + } + + $ids = array(); + + foreach ($entities as $entityData) { + $lastObjectId = $entityData['entity_id']; + $ids[] = $entityData['entity_id']; + } + + $entityRelations = $this->_getChildrenIds($ids, $websiteId); + foreach ($entityRelations as $childrenIds) { + $ids = array_merge($ids, $childrenIds); + } + + $entityIndexes = array(); + $entityAttributes = $this->_getAttributes($storeId, $ids, $dynamicFields); + + foreach ($entities as $entityData) { + + if (!isset($entityAttributes[$entityData['entity_id']])) { + continue; + } + + $entityAttr = array(); + + foreach ($entityAttributes[$entityData['entity_id']] as $attributeId => $value) { + $attribute = $attributesById[$attributeId]; + $entityAttr = array_merge( + $entityAttr, + $this->_getAttributeIndexValues($attribute, $value, $storeId, $languageCode) + ); + + } + + $entityAttr = array_merge($entityData, $entityAttr); + $entityAttr['store_id'] = $storeId; + $entityIndexes[$entityData['entity_id']] = $entityAttr; + } + + $entityIndexes = $this->_addChildrenData($entityIndexes, $entityAttributes, $entityRelations, $storeId, $languageCode); + $entityIndexes = $this->_addSuggestField($entityIndexes, $storeId, $languageCode); + + $this->_saveIndexes($storeId, $entityIndexes); + } + + return $this; + } + + /** + * Return the indexed attribute value. + * + * @param Mage_Eav_Model_Attribute $attribute Attribute we want the value for. + * @param mixed $value Raw value + * @param int $storeId Store id + * @param string $languageCode Locale code + * + * @return mixed. + */ + protected function _getAttributeIndexValues($attribute, $value, $storeId, $languageCode) + { + $attrs = array(); + + if ($value && $attribute) { + $field = $this->_getAttributeFieldName($attribute, $languageCode); + if ($field) { + $storedValue = $this->_getAttributeValue($attribute, $value, $storeId); + + if ($storedValue != null && $storedValue != false && $storedValue != '0000-00-00 00:00:00') { + $attrs[$field] = $storedValue; + } + + if ($attribute->usesSource() && $attribute->getSourceModel()) { + $field = 'options_' . $attribute->getAttributeCode() . '_' . $languageCode; + $value = $this->_getOptionsText($attribute, $value, $storeId); + if ($value) { + $attrs[$field] = $value; + } + } + } + } + + return $attrs; + } + + /** + * Load all entity attributes by ids. + * + * @return array. + */ + protected function _getAttributesById() + { + $entityType = Mage::getModel('eav/entity_type')->loadByCode($this->_entityType); + $attributes = Mage::getResourceModel($this->_attributeCollectionModel) + ->setEntityTypeFilter($entityType->getEntityTypeId()); + + $attributesById = array(); + + foreach ($attributes as $attribute) { + if ($this->_canIndexAttribute($attribute) && $attribute->getBackendType() != 'static') { + $attributesById[$attribute->getAttributeId()] = $attribute; + } + } + + return $attributesById; + } + + /** + * Append children attributes to parents doc. + * + * @param array $entityIndexes Final index results + * @param array $entityAttributes Attributes values by entity id + * @param array $entityRelations Array of the entities relations + * @param int $storeId Store id + * @param string $languageCode Locale + * + * @return array + */ + protected function _addChildrenData($entityIndexes, $entityAttributes, $entityRelations, $storeId, $languageCode) + { + + $attributesById = $this->_getAttributesById(); + + foreach ($entityRelations as $parentId => $childrenIds) { + + $values = $entityIndexes[$parentId]; + + foreach ($childrenIds as $childrenId) { + if (isset($entityAttributes[$childrenId])) { + foreach ($entityAttributes[$childrenId] as $attributeId => $value) { + if (isset($attributesById[$attributeId]) && + in_array($attributesById[$attributeId]->getFrontendInput(), array('select', 'multiselect')) + ) { + $attribute = $attributesById[$attributeId]; + $childrenValues = $this->_getAttributeIndexValues($attribute, $value, $storeId, $languageCode); + foreach ($childrenValues as $field => $fieldValue) { + $parentValue = array(); + + if (!is_array($fieldValue)) { + $fieldValue = array($fieldValue); + } + + if (isset($values[$field])) { + $parentValue = is_array($values[$field]) ? $values[$field] : array($values[$field]); + } + $values[$field] = array_unique(array_merge($parentValue, $fieldValue)); + } + } + } + } + } + + $entityIndexes[$parentId] = $values; + } + + return $entityIndexes; + } + + /** + * Retrieve entities children ids + * + * @param array $entityIds Parent entities ids. + * @param int $websiteId Current website ids + * + * @return array + */ + protected function _getChildrenIds($entityIds, $websiteId) + { + return array(); + } + + /** + * Save docs to the index + * + * @param int $storeId Store id + * @param array $entityIndexes Doc values. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Catalog_Eav_Abstract + */ + protected function _saveIndexes($storeId, $entityIndexes) + { + Mage::helper('catalogsearch')->getEngine()->saveEntityIndexes($storeId, $entityIndexes, $this->_type); + return $this; + } + + /** + * Retrieve values for attributes. + * + * @param int $storeId Store id. + * @param array $entityIds Entities ids. + * @param array $attributeTypes Attributes to be indexed. + * + * @return array + */ + protected function _getAttributes($storeId, array $entityIds, array $attributeTypes) + { + $result = array(); + $selects = array(); + $websiteId = Mage::app()->getStore($storeId)->getWebsiteId(); + $adapter = $this->getConnection(); + $ifStoreValue = $adapter->getCheckSql('t_store.value_id > 0', 't_store.value', 't_default.value'); + + foreach ($attributeTypes as $tableName => $attributeIds) { + if ($attributeIds) { + $select = $adapter->select() + ->from(array('t_default' => $tableName), array('entity_id', 'attribute_id')) + ->joinLeft( + array('t_store' => $tableName), + $adapter->quoteInto( + 't_default.entity_id=t_store.entity_id' . + ' AND t_default.attribute_id=t_store.attribute_id' . + ' AND t_store.store_id=?', + $storeId + ), + array('value' => new Zend_Db_Expr('COALESCE(t_store.value, t_default.value)')) + ) + ->where('t_default.store_id=?', 0) + ->where('t_default.attribute_id IN (?)', $attributeIds) + ->where('t_default.entity_id IN (?)', $entityIds); + + /** + * Add additional external limitation + */ + $eventName = sprintf('prepare_catalog_%s_index_select', $this->_type); + Mage::dispatchEvent( + $eventName, + array( + 'select' => $select, + 'entity_field' => new Zend_Db_Expr('t_default.entity_id'), + 'website_field' => $websiteId, + 'store_field' => new Zend_Db_Expr('t_store.store_id') + ) + ); + + $selects[] = $select; + } + } + + if ($selects) { + $select = $adapter->select()->union($selects, Zend_Db_Select::SQL_UNION_ALL); + $query = $adapter->query($select); + while ($row = $query->fetch()) { + $result[$row['entity_id']][$row['attribute_id']] = $row['value']; + } + } + + return $result; + } + + /** + * Return the indexed attribute value. + * + * @param Mage_Eav_Model_Attribute $attribute Attribute we want the value for. + * @param mixed $value Raw value + * @param int $storeId Store id + * + * @return mixed. + */ + protected function _getAttributeValue($attribute, $value, $storeId) + { + if ($attribute->usesSource()) { + $inputType = $attribute->getFrontend()->getInputType(); + if ($inputType == 'multiselect') { + $value = explode(',', $value); + } + } else { + $inputType = $attribute->getFrontend()->getInputType(); + if ($inputType == 'price') { + $value = Mage::app()->getStore($storeId)->roundPrice($value); + } + } + + if (is_string($value)) { + $value = preg_replace("#\s+#siu", ' ', trim(strip_tags($value))); + } + + return $value; + } + + /** + * Retrieve the field name for an attributes. + * + * @param Mage_Eav_Model_Attribute $attribute Attribute we want the value for. + * @param string $languageCode Language code + * + * @return string + */ + protected function _getAttributeFieldName($attribute, $languageCode) + { + + $mapping = $this->getMappingProperties()['properties']; + $fieldName = $attribute->getAttributeCode(); + + if (!isset($mapping[$fieldName])) { + $fieldName = $fieldName . '_' . $languageCode; + } + + if (!isset($mapping[$fieldName])) { + $fieldName = false; + } + + return $fieldName; + } + + /** + * Append suggest data to the index + * + * @param array $entityIndexes Index data + * @param int $storeId Store id + * @param string $languageCode Language code + * + * @return array + */ + protected function _addSuggestField($entityIndexes, $storeId, $languageCode) + { + $store = Mage::app()->getStore($storeId); + $languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + $fieldName = Mage::helper('smile_elasticsearch')->getSuggestFieldName($store); + $inputFields = array(); + foreach ($this->_suggestInputAttributes as $attribute) { + $field = $this->getFieldName($attribute, $languageCode); + $inputFields[] = $field; + } + + $payloadFields = array(); + foreach ($this->_suggestPayloadAttributes as $attribute) { + $field = $this->getFieldName($attribute, $languageCode, 'filter'); + $payloadFields[] = $field; + } + + foreach ($entityIndexes as $entityId => $index) { + $suggest = array('input' => '', 'payload' => array()); + + foreach ($inputFields as $field) { + if (isset($index[$field])) { + + if (!isset($suggest['output'])) { + $suggest['output'] = is_array($index[$field]) ? current($index[$field]) : $index[$field]; + } + + if (is_array($index[$field])) { + $index[$field] = implode(' ', $index[$field]); + } + $suggest['input'] = implode(' ', array($suggest['input'], $index[$field])); + } + } + + foreach ($payloadFields as $field) { + if (isset($index[$field])) { + if (!isset($suggest['payload'][$field])) { + $suggest['payload'][$field] = $index[$field]; + } else { + if (!is_array($index[$field])) { + $index[$field] = array($index[$field]); + } + if (!is_array($suggest['payload'][$field])) { + $suggest['payload'][$field] = array($suggest['payload'][$field]); + } + $suggest['payload'][$field] = array_merge($suggest['payload'][$field], $index[$field]); + } + } + } + + $suggest['context']['store_id'] = $storeId; + $inputs = explode(' ', $suggest['input']); + $suggest['input'] = array_merge(array($suggest['input']), $inputs); + $suggest['input'] = array_values(array_filter($suggest['input'])); + + $suggest = $this->_appendCustomSuggestData($index, $suggest); + + $entityIndexes[$index['entity_id']][$fieldName] = $suggest; + } + + return $entityIndexes; + } + + /** + * Append custom data for an entity + * + * @param array $entityData Data for current entity + * @param array $suggestData Suggest data for the entity + * + * @return array + */ + protected function _appendCustomSuggestData($entityData, $suggestData) + { + return $suggestData; + } + + /** + * Return the text value for an atribute using source model. + * + * @param Mage_Eav_Model_Attribute $attribute Attribute we want the value for. + * @param mixed $value Raw value + * @param int $storeId Store id + * + * @return mixed. + */ + protected function _getOptionsText($attribute, $value, $storeId) + { + $attribute->setStoreId($storeId); + if ($attribute->getSource()) { + $value = $attribute->getSource()->getIndexOptionText($value); + } + return $value; + } + + /** + * Retrive a bucket of indexable entities. + * + * @param int $storeId Store id + * @param string|null $ids Ids filter + * @param int $lastId First id + * @param int $limit Size of the bucket + * + * @return array + */ + abstract protected function _getSearchableEntities($storeId, $ids = null, $lastId = 0, $limit = 100); +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Category.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Category.php new file mode 100644 index 00000000..5ba2c36c --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Category.php @@ -0,0 +1,96 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Category + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Catalog_Eav_Abstract +{ + /** + * @var string + */ + protected $_attributeCollectionModel = 'catalog/category_attribute_collection'; + + /** + * @var string + */ + protected $_entityType = 'catalog_category'; + + /** + * Return a list of all searchable field for the current type (by locale code). + * + * @param string $localeCode Locale code + * + * @return array. + */ + public function getSearchFields($localeCode) + { + return array('name', $localeCode); + } + + /** + * Get mapping properties as stored into the index + * + * @param string $useCache Indicates if the cache should be used or if the mapping should be rebuilt. + * + * @return array + */ + public function getMappingProperties($useCache = true) + { + parent::getMappingProperties(true); + $this->_mapping['properties']['path'] = array('type' => 'string'); + return $this->_mapping; + } + + /** + * Retrive a bucket of indexable entities. + * + * @param int $storeId Store id + * @param string|null $ids Ids filter + * @param int $lastId First id + * @param int $limit Size of the bucket + * + * @return array + */ + protected function _getSearchableEntities($storeId, $ids = null, $lastId = 0, $limit = 100) + { + $rootCategoryId = Mage::app()->getStore($storeId)->getRootCategoryId(); + $rootCategory = Mage::getModel('catalog/category')->load($rootCategoryId); + $rootPath = $rootCategory->getPath(); + + $adapter = $this->getConnection(); + + $select = $adapter + ->select() + ->useStraightJoin(true) + ->from( + array('e' => $this->getTable('catalog/category')) + ); + + if (!is_null($ids)) { + $select->where('e.entity_id IN(?)', $ids); + } + + $select->where('e.entity_id>?', $lastId) + ->where('path like ?', $rootPath . '/%') + ->limit($limit) + ->order('e.entity_id'); + + $result = $adapter->fetchAll($select); + + return $result; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Product.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Product.php new file mode 100644 index 00000000..56d618fb --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Mapping/Product.php @@ -0,0 +1,261 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Product + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Catalog_Eav_Abstract +{ + + /** + * @var string + */ + protected $_attributeCollectionModel = 'catalog/product_attribute_collection'; + + /** + * @var array + */ + protected $_authorizedBackendModels = array( + 'catalog/product_attribute_backend_sku', + 'eav/entity_attribute_backend_array', + 'catalog/product_attribute_backend_price', + 'eav/entity_attribute_backend_time_created', + 'eav/entity_attribute_backend_time_updated', + 'catalog/product_attribute_backend_startdate', + 'catalog/product_attribute_backend_startdate_specialprice', + 'eav/entity_attribute_backend_datetime', + 'catalog/product_status', + 'catalog/visibility' + ); + + /** + * @var string + */ + protected $_entityType = 'catalog_product'; + + /** + * @var array + */ + protected $_suggestInputAttributes = array('name', 'category_name'); + + /** + * Get mapping properties as stored into the index + * + * @param string $useCache Indicates if the cache should be used or if the mapping should be rebuilt. + * + * @return array + */ + public function getMappingProperties($useCache = true) + { + if ($this->_mapping === null) { + parent::getMappingProperties(true); + $this->_mapping['properties']['categories'] = array('type' => 'long'); + $this->_mapping['properties']['in_stock'] = array('type' => 'integer'); + $this->_mapping['properties']['category_name'] = array('type' => 'string'); + + // Append dynamic mapping for product category position field + $fieldTemplate = array('match' => 'position_category_*', 'mapping' => array('type' => 'integer')); + $this->_mapping['dynamic_templates'][] = array('category_position' => $fieldTemplate); + } + + return $this->_mapping; + } + + /** + * Append custom data for an entity + * + * @param array $entityData Data for current entity + * @param array $suggestData Suggest data for the entity + * + * @return array + */ + protected function _appendCustomSuggestData($entityData, $suggestData) + { + $suggestData['context']['visibility'] = $entityData['visibility']; + return $suggestData; + } + + /** + * Retrive a bucket of indexable entities. + * + * @param int $storeId Store id + * @param string|null $ids Ids filter + * @param int $lastId First id + * @param int $limit Size of the bucket + * + * @return array + */ + protected function _getSearchableEntities($storeId, $ids = null, $lastId = 0, $limit = 100) + { + $websiteId = Mage::app()->getStore($storeId)->getWebsiteId(); + $adapter = $this->getConnection(); + + $select = $adapter->select() + ->useStraightJoin(true) + ->from( + array('e' => $this->getTable('catalog/product')) + ) + ->join( + array('website' => $this->getTable('catalog/product_website')), + $adapter->quoteInto( + 'website.product_id=e.entity_id AND website.website_id=?', + $websiteId + ), + array() + ) + ->joinLeft( + array('stock_status' => $this->getTable('cataloginventory/stock_status')), + $adapter->quoteInto( + 'stock_status.product_id=e.entity_id AND stock_status.website_id=?', + $websiteId + ), + array('in_stock' => new Zend_Db_Expr("COALESCE(stock_status.stock_status, 0)")) + ); + + if (!is_null($ids)) { + $select->where('e.entity_id IN(?)', $ids); + } + + $select->where('e.entity_id>?', $lastId) + ->limit($limit) + ->order('e.entity_id'); + + /** + * Add additional external limitation + */ + $eventName = sprintf('prepare_catalog_%s_index_select', $this->_type); + Mage::dispatchEvent( + $eventName, + array( + 'select' => $select, + 'entity_field' => new Zend_Db_Expr('e.entity_id'), + 'website_field' => new Zend_Db_Expr('website.website_id'), + 'store_field' => $storeId + ) + ); + + $result = $adapter->fetchAll($select); + + return $result; + } + + /** + * Save docs to the index + * + * @param int $storeId Store id + * @param array $entityIndexes Doc values. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Catalog_Eav_Abstract + */ + protected function _saveIndexes($storeId, $entityIndexes) + { + $index = Mage::getResourceSingleton('smile_elasticsearch/engine_index'); + $entityIndexes = $index->addAdvancedIndex($entityIndexes, $storeId); + return parent::_saveIndexes($storeId, $entityIndexes); + } + + /** + * Return a list of all searchable field for the current type (by locale code). + * + * @param string $localeCode Locale code + * + * @return array. + */ + public function getSearchFields($localeCode) + { + if ($this->_searchFields == null) { + + $mapping = $this->getMappingProperties(); + $this->_searchFields = array(); + + $entityType = Mage::getModel('eav/entity_type')->loadByCode($this->_entityType); + + $attributes = Mage::getResourceModel($this->_attributeCollectionModel) + ->setEntityTypeFilter($entityType->getEntityTypeId()); + + foreach ($attributes as $attribute) { + if ($attribute->getIsSearchable()) { + $field = $this->getFieldName($attribute->getAttributeCode(), $localeCode); + if ($field !== false) { + if ($attribute->getSearchWeight()) { + $field .= '^' . $attribute->getSearchWeight(); + } + $this->_searchFields[] = $field; + } + } + } + + $this->_searchFields[] = 'category_name'; + } + + return $this->_searchFields; + } + + /** + * Retrieve entities children ids (simple products for configurable, grouped and bundles). + * + * @param array $entityIds Parent entities ids. + * @param int $websiteId Current website ids + * + * @return array + */ + protected function _getChildrenIds($entityIds, $websiteId) + { + $children = array(); + $productTypes = array_keys(Mage::getModel('catalog/product_type')->getOptionArray()); + foreach ($productTypes as $productType) { + + $productEmulator = new Varien_Object(); + $productEmulator->setIdFieldName('entity_id'); + $productEmulator->setTypeId($productType); + $typeInstance = Mage::getSingleton('catalog/product_type')->factory($productEmulator); + $relation = $typeInstance->isComposite() ? $typeInstance->getRelationInfo() : false; + + if ($relation && $relation->getTable() && $relation->getParentFieldName() && $relation->getChildFieldName()) { + + $select = $this->getConnection() + ->select() + ->from( + array('main' => $this->getTable($relation->getTable())), + array($relation->getParentFieldName(), $relation->getChildFieldName()) + ) + ->where("main.{$relation->getParentFieldName()} in (?)", $entityIds); + + if (!is_null($relation->getWhere())) { + $select->where($relation->getWhere()); + } + + Mage::dispatchEvent( + 'prepare_product_children_id_list_select', + array('select' => $select, 'entity_field' => 'main.product_id', 'website_field' => $websiteId) + ); + + $data = $this->getConnection()->fetchAll($select); + + foreach ($data as $link) { + $parentId = $link[$relation->getParentFieldName()]; + $childId = $link[$relation->getChildFieldName()]; + if (!isset($children[$parentId])) { + $children[$parentId] = array(); + } + $children[$parentId][] = $childId; + } + } + } + + return $children; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query.php new file mode 100644 index 00000000..41467c0b --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query.php @@ -0,0 +1,625 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Abstract +{ + const DEFAULT_ROWS_LIMIT = 10000; + + /** + * @var string + */ + protected $_queryType = 'default'; + + + /** + * @var string + */ + protected $_type; + + /** + * @var array + */ + protected $_filters = array(); + + /** + * @var array + */ + protected $_facets = array(); + + /** + * @var array + */ + protected $_page = array('from' => 0, 'size' => self::DEFAULT_ROWS_LIMIT); + + /** + * @var string + */ + protected $_fulltextQuery = ''; + + /** + * @var array + */ + protected $_sort = array(); + + /** + * @var string + */ + protected $_languageCode; + + /** + * @var array + */ + protected $_facetModelNames = array( + 'terms' => 'smile_elasticsearch/engine_elasticsearch_query_facet_terms', + 'histogram' => 'smile_elasticsearch/engine_elasticsearch_query_facet_histogram', + 'queryGroup' => 'smile_elasticsearch/engine_elasticsearch_query_facet_queryGroup', + ); + + /** + * @var array + */ + protected $_filterModelNames = array( + 'terms' => 'smile_elasticsearch/engine_elasticsearch_query_filter_terms', + 'range' => 'smile_elasticsearch/engine_elasticsearch_query_filter_range', + 'query' => 'smile_elasticsearch/engine_elasticsearch_query_filter_queryString' + ); + + /** + * Set types of documents matched by the query. + * + * @param string $type Type of documents + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function setType($type) + { + $this->_type = $type; + return $this; + } + + /** + * Return the current query language code. + * + * @return string + */ + public function getLanguageCode() + { + if ($this->_languageCode == null) { + $currentStore = Mage::app()->getStore(); + $this->_languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + } + return $this->_languageCode; + } + + /** + * Set the query language code. + * + * @param string $languageCode Language code + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function setLanguageCode($languageCode) + { + $this->_languageCode = $languageCode; + return $this; + } + + /** + * Allow to give the query a type. + * Can be used by observers to know if they should be applied to the query or not. + * + * Default query type is equal to default. + * Layer views change query type to "product_search_layer" and "category_products_layer" + * + * @param string $type Type of the query. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function setQueryType($type) + { + $this->_queryType = $type; + return $this; + } + + /** + * Return the query type. + * + * @return string + */ + public function getQueryType() + { + return $this->_queryType; + } + + /** + * Get types of documents matched by the query. + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Run the query against ElasticSearch. + * + * @return array + */ + public function search() + { + $result = array(); + + Varien_Profiler::start('ES:ASSEMBLE:QUERY'); + $query = $this->_assembleQuery(); + Varien_Profiler::stop('ES:ASSEMBLE:QUERY'); + + $eventData = new Varien_Object(array('query' => $query, 'query_type' => $this->getQueryType())); + Varien_Profiler::start('ES:ASSEMBLE:QUERY:OBSERVERS'); + Mage::dispatchEvent('smile_elasticsearch_query_assembled', array('query_data' => $eventData)); + Varien_Profiler::stop('ES:ASSEMBLE:QUERY:OBSERVERS'); + $query = $eventData->getQuery(); + + Varien_Profiler::start('ES:EXECUTE:QUERY'); + $response = $this->getClient()->search($query); + Varien_Profiler::stop('ES:EXECUTE:QUERY'); + + if (!isset($data['error'])) { + $result = array( + 'total_count' => $response['hits']['total'], + 'faceted_data' => array(), + 'docs' => array(), + 'ids' => array() + ); + + foreach ($response['hits']['hits'] as $doc) { + $result['docs'][] = $doc['fields']; + $result['ids'][] = (int) current($doc['fields']['entity_id']); + } + + if (isset($response['facets'])) { + foreach ($this->_facets as $facetName => $facetModel) { + if ($facetModel->isGroup()) { + $result['faceted_data'][$facetName] = $facetModel->getItems($response['facets']); + } else if (isset($response['facets'][$facetName])) { + $result['faceted_data'][$facetName] = $facetModel->getItems($response['facets'][$facetName]); + } + } + } + } + + return $result; + } + + /** + * Set the fulltext query part of the query. + * + * @param string $query The fulltext query + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function setFulltextQuery($query) + { + $this->_fulltextQuery = $query; + return $this; + } + + /** + * Append a sort order. + * + * @param array $sortOrder Sort order definition + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function addSortOrder($sortOrder) + { + if (array(is_array($sortOrder)) && is_array(current($sortOrder))) { + foreach ($sortOrder as $currentSortOrder) { + $this->addSortOrder($currentSortOrder); + } + } else if (is_array($sortOrder)) { + $this->_sort[] = $sortOrder; + } + return $this; + } + + /** + * Escapes specified value. + * + * @param string $value Value to be escaped + * + * @return mixed + * + * @link http://lucene.apache.org/core/3_6_0/queryparsersyntax.html + */ + protected function _escape($value) + { + $result = $value; + // \ escaping has to be first, otherwise escaped later once again + $chars = array('\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '/'); + + foreach ($chars as $char) { + $result = str_replace($char, '\\' . $char, $result); + } + + return $result; + } + + /** + * Escapes specified phrase. + * + * @param string $value Value to be escaped + * + * @return string + */ + protected function _escapePhrase($value) + { + $pattern = '/("|\\\)/'; + $replace = '\\\$1'; + + return preg_replace($pattern, $replace, $value); + } + + /** + * Phrases specified value. + * + * @param string $value Value to be escaped + * + * @return string + */ + protected function _phrase($value) + { + return '"' . $this->_escapePhrase($value) . '"'; + } + + /** + * Prepares filter query text. + * + * @param string $text Fulltext query + * + * @return mixed|string + */ + public function prepareFilterQueryText($text) + { + $words = explode(' ', $text); + if (count($words) > 1) { + $text = $this->_escapePhrase($text); + } else { + $text = $this->_escape($text); + } + + return $text; + } + + /** + * Set pagination. + * + * @param int $currentPage Current page navigated. + * @param int $pageSize Size of a single page. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function setPageParams($currentPage = 0, $pageSize = self::DEFAULT_ROWS_LIMIT) + { + $page = ($currentPage > 0) ? (int) $currentPage : 1; + $rowCount = ($pageSize > 0) ? (int) $pageSize : 1; + $this->_page['from'] = $rowCount * ($page - 1); + $this->_page['size'] = $pageSize; + + return $this; + } + + /** + * Transform the query into an ES syntax compliant array. + * + * @return array + */ + protected function _assembleQuery() + { + $query = array('index' => $this->getAdapter()->getCurrentIndex()->getCurrentName(), 'type' => $this->getType()); + $query['body']['query']['filtered']['query']['bool']['must'][] = $this->_prepareFulltextCondition(); + + foreach ($this->_facets as $facetName => $facet) { + + $facets = $facet->getFacetQuery(); + + if (!$facet->isGroup()) { + $facets = array($facetName => $facets); + } + + foreach ($facets as $realFacetName => $facet) { + foreach ($this->_filters as $filterFacetName => $filters) { + $rawFilter = array(); + + foreach ($filters as $filter) { + $rawFilter[] = $filter->getFilterQuery(); + } + + if ($filterFacetName != $facetName && $filterFacetName != '_none_') { + $mustConditions = $rawFilter; + if (isset($facet['facet_filter']['bool']['must'])) { + $mustConditions = array_merge($facet['facet_filter']['bool']['must'], $rawFilter); + } + $facet['facet_filter']['bool']['must'] = $mustConditions; + } + } + $query['body']['facets'][$realFacetName] = $facet; + } + } + + foreach ($this->_filters as $facetName => $filters) { + $rawFilter = array(); + foreach ($filters as $filter) { + $rawFilter[] = $filter->getFilterQuery(); + } + if ($facetName == '_none_') { + if (!isset($query['body']['query']['filtered']['filter']['bool']['must'])) { + $query['body']['query']['filtered']['filter']['bool']['must'] = array(); + $query['body']['query']['filtered']['filter']['bool']['_cache'] = true; + } + $mustConditions = array_merge($query['body']['query']['filtered']['filter']['bool']['must'], $rawFilter); + $query['body']['query']['filtered']['filter']['bool']['must'] = $mustConditions; + } else { + if (!isset($query['body']['filter']['bool']['must'])) { + $query['body']['filter']['bool']['must'] = array(); + } + $query['body']['filter']['bool']['must'] = array_merge($query['body']['filter']['bool']['must'], $rawFilter); + } + } + // Patch : score not computed when using another sort order than score + // as primary sort order + $query['body']['fields'] = array('entity_id'); + $query['body']['track_scores'] = true; + $query['body']['sort'] = $this->_prepareSortCondition(); + $query['body'] = array_merge($query['body'], $this->_page); + + return $query; + } + + /** + * Build the sort part of the query. + * + * @return array + */ + protected function _prepareSortCondition() + { + $result = array(); + $hasRelevance = false; + + foreach ($this->_sort as $sort) { + $_sort = each($sort); + $sortField = $_sort['key']; + $sortType = $_sort['value']; + if ($sortField == 'relevance') { + $sortField = '_score'; + // Score has to be reversed + $hasRelevance = true; + } elseif ($sortField == 'position') { + $category = Mage::registry('current_category'); + if ($category) { + $sortField = 'position_category_' . Mage::registry('current_category')->getId(); + } else { + $sortField = '_score'; + $sortType = $sortType == 'asc' ? 'desc' : 'asc'; + } + } elseif ($sortField == 'price') { + $websiteId = Mage::app()->getStore()->getWebsiteId(); + $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId(); + $sortField = 'price_'. $customerGroupId .'_'. $websiteId; + } else { + $sortField = $this->getMapping()->getFieldName($sortField, $this->getLanguageCode(), 'sort'); + } + + $result[] = array( + $sortField => array('order' => trim(strtolower($sortType)), 'missing' => '_last', 'ignore_unmapped' => true) + ); + } + + if (!$hasRelevance) { + // Append relevance has last field if not yet present + // Allow rescoring methods to be applied + $result[] = array('_score' => 'desc'); + } + + return $result; + } + + /** + * Encode a text to be used into a query. + * + * @param string $text Text to be encoded + * + * @return string + */ + protected function _prepareQueryText($text) + { + $words = explode(' ', $text); + if (count($words) > 1) { + foreach ($words as $key => &$val) { + if (!empty($val)) { + $val = $this->_escape($val); + } else { + unset($words[$key]); + } + } + $text = '(' . implode(' ', $words) . ')'; + } else { + $text = $this->_escape($text); + } + + return $text; + } + + /** + * Build the fulltext query condition for the query. + * + * @return array + */ + protected function _prepareFulltextCondition() + { + $query = array('match_all' => array()); + + if ($this->_fulltextQuery) { + $query = array('dis_max' => array('queries' => array())); + $searchFields = $this->getSearchFields(); + $query['dis_max'] = array('tie_breaker' => 0); + $query['dis_max']['queries'][] = array( + 'multi_match' => array( + 'query' => $this->prepareFilterQueryText($this->_fulltextQuery), + 'fields' => $searchFields, + 'type' => 'cross_fields', + "tie_breaker" => 0.1, + 'minimum_should_match' => '2<100% 100<50%' + ) + ); + + if ((bool) $this->getConfig('enable_fuzzy_query')) { + $query['dis_max']['queries'][] = array( + 'multi_match' => array( + 'query' => $this->prepareFilterQueryText($this->_fulltextQuery), + 'fields' => $searchFields, + 'type' => 'best_fields', + 'tie_breaker' => 0.9, + 'fuzziness' => min(0.99, max(0, (float) $this->getConfig('fuzzy_min_similarity'))), + 'boost' => 0.1, //(float) $this->getConfig('fuzzy_query_boost'), + 'minimum_should_match' => '2<100% 100<50%' + ) + ); + /*$fuzzyQuery = array( + 'fields' => $this->getSearchFields(), + 'like_text' => $this->_fulltextQuery, + 'min_similarity' => min(0.99, max(0, (float) $this->getConfig('fuzzy_min_similarity'))), + 'prefix_length' => (int) $this->getConfig('fuzzy_prefix_length'), + 'max_query_terms' => (int) $this->getConfig('fuzzy_max_query_terms'), + 'boost' => (float) $this->getConfig('fuzzy_query_boost'), + 'ignore_tf' => true + );*/ + //$query['dis_max']['queries'][] = array('fuzzy_like_this' => $fuzzyQuery); + } + } + + return $query; + } + + /** + * Retrive mapping for the current query type. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Abstract + */ + public function getMapping() + { + return $this->getAdapter()->getCurrentIndex()->getMapping($this->_type); + } + + /** + * Retrieves searchable fields according to text query. + * + * @return array + */ + public function getSearchFields() + { + return $this->getMapping()->getSearchFields($this->getLanguageCode()); + } + + /** + * Add a filter to the query. + * + * @param string $modelName Name of the model to be used to create the filter. + * @param array $options Options to be passed to the filter constructor. + * @param string $facetName Associate the filter to a facet. The filter will not be applied to the facet. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function addFilter($modelName, $options = array(), $facetName = '_none_') + { + $modelName = $this->_getFilterModelName($modelName); + + if (!isset($this->_filters)) { + $this->_filters[$facetName] = array(); + } + + $filter = Mage::getResourceModel($modelName, $options); + if ($filter) { + $filter->setQuery($this); + $this->_filters[$facetName][] = $filter; + } + + return $this; + } + + /** + * Add a facet to the query. + * + * @param string $name Name of the facet. + * @param string $modelName Name of the model to be used to create the facet. + * @param array $options Options to be passed to the facet constructor. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function addFacet($name, $modelName, $options = array()) + { + $modelName = $this->_getFacetModelName($modelName); + + $facet = Mage::getResourceModel($modelName, $options); + + if ($facet) { + $facet->setQuery($this); + $this->_facets[$name] = $facet; + } + + return $this; + } + + /** + * Try to convert the model name from short name (eg."terms") + * to the model name (eg. "smile_elasticsearch/engine_elasticsearch_query_facet_terms"). + * + * If no match is found, return the model name unchanged. + * + * @param string $modelName Shortname to be converted. + * + * @return string + */ + protected function _getFacetModelName($modelName) + { + if (isset($this->_facetModelNames[$modelName])) { + $modelName = $this->_facetModelNames[$modelName]; + } + return $modelName; + } + + /** + * Try to convert the model name from short name (eg."terms") + * to the model name (eg. "smile_elasticsearch/engine_elasticsearch_query_filter_terms"). + * + * If no match is found, return the model name unchanged. + * + * @param string $modelName Shortname to be converted. + * + * @return string + */ + protected function _getFilterModelName($modelName) + { + if (isset($this->_filterModelNames[$modelName])) { + $modelName = $this->_filterModelNames[$modelName]; + } + return $modelName; + } + +} diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Abstract.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Abstract.php new file mode 100644 index 00000000..7455e9af --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Abstract.php @@ -0,0 +1,81 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +abstract class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Abstract +{ + /** + * @var array + */ + protected $_options = array(); + + /** + * @var Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + protected $_query = null; + + /** + * Init the facet with it's options + * + * @param array $options Facet options. + */ + public function __construct($options = null) + { + if (!is_null($options)) { + $this->_options = array_merge($this->_options, $options); + } + } + + /** + * Associate a query to the facet. + * + * @param Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query $query Query the facet belong to. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Abstract + */ + public function setQuery($query) + { + $this->_query = $query; + return $this; + } + + /** + * Set the facet as group of facet + * + * @return bool + */ + public function isGroup() + { + return false; + } + + /** + * Transform the facet into an ES syntax compliant array. + * + * @return array + */ + abstract public function getFacetQuery(); + + /** + * Parse the response to extract facet items. + * + * @param array $response Query response data. + * + * @return array + */ + abstract public function getItems($response); +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Histogram.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Histogram.php new file mode 100644 index 00000000..9ddab1a8 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Histogram.php @@ -0,0 +1,57 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Histogram + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Abstract +{ + /** + * @var array + */ + protected $_options = array( + 'interval' => 1, + ); + + /** + * Transform the facet into an ES syntax compliant array. + * + * @return array + */ + public function getFacetQuery() + { + return array('histogram' => $this->_options); + } + + /** + * Parse the response to extract facet items. + * + * @param array $response Query response data. + * + * @return array + */ + public function getItems($response) + { + $result = array(); + + if (isset($response['entries'])) { + foreach ($response['entries'] as $value) { + $result[$value['key']] = $value['count']; + } + } + return $result; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/QueryGroup.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/QueryGroup.php new file mode 100644 index 00000000..7645a419 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/QueryGroup.php @@ -0,0 +1,93 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_QueryGroup + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Abstract +{ + /** + * @var array + */ + protected $_options = array( + 'queries' => array(), + 'prefix' => 'group_' + ); + + /** + * Transform the facet into an ES syntax compliant array. + * + * @return array + */ + public function getFacetQuery() + { + $queries = array(); + $prefix = $this->getPrefix(); + foreach ($this->_options['queries'] as $facetName => $query) { + $realName = $prefix . $facetName; + $queries[$realName] = array( + 'query' => array('query_string' => array('query' => $query)) + ); + } + + return $queries; + } + + /** + * Set the facet as group of facet + * + * @return bool + */ + public function isGroup() + { + return true; + } + + /** + * Get facet prefix + * + * @return string + */ + public function getPrefix() + { + return $this->_options['prefix']; + } + + /** + * Parse the response to extract facet items. + * + * @param array $response Query response data. + * + * @return array + */ + public function getItems($response) + { + $result = array(); + $prefix = $this->getPrefix(); + foreach ($response as $facetName => $facet) { + if (strpos($facetName, $prefix) === 0) { + $key = str_replace($prefix, '', $facetName); + $result[$key] = $facet['count']; + } + } + /*if (isset($response['entries'])) { + foreach ($response['entries'] as $value) { + $result[$value['key']] = $value['count']; + } + }*/ + return $result; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Terms.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Terms.php new file mode 100644 index 00000000..755b48da --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Facet/Terms.php @@ -0,0 +1,58 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Terms + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Abstract +{ + /** + * @var array + */ + protected $_options = array( + 'size' => 10, + 'order' => 'count' + ); + + /** + * Transform the facet into an ES syntax compliant array. + * + * @return array + */ + public function getFacetQuery() + { + return array('terms' => $this->_options); + } + + /** + * Parse the response to extract facet items. + * + * @param array $response Query response data. + * + * @return array + */ + public function getItems($response) + { + $result = array(); + + if (isset($response['terms'])) { + foreach ($response['terms'] as $value) { + $result[$value['term']] = $value['count']; + } + } + return $result; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Abstract.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Abstract.php new file mode 100644 index 00000000..7320ddab --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Abstract.php @@ -0,0 +1,62 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +abstract class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Filter_Abstract +{ + /** + * @var array + */ + protected $_options = array(); + + /** + * @var Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + protected $_query = null; + + /** + * Init the filter with it's options + * + * @param array $options Filter options. + */ + public function __construct($options = null) + { + if (!is_null($options)) { + $this->_options = array_merge($this->_options, $options); + } + } + + /** + * Associate a query to the facet. + * + * @param Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query $query Query the facet belong to. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Facet_Abstract + */ + public function setQuery($query) + { + $this->_query = $query; + return $this; + } + + /** + * Transform the filter into an ES syntax compliant array. + * + * @return array + */ + abstract public function getFilterQuery(); +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/QueryString.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/QueryString.php new file mode 100644 index 00000000..0a0cdfec --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/QueryString.php @@ -0,0 +1,32 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Filter_QueryString + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Filter_Abstract +{ + /** + * Transform the filter into an ES syntax compliant array. + * + * @return array + */ + public function getFilterQuery() + { + $query = array('query_string' => array('query' => $this->_options['query_string'])); + return array('fquery' => array('query' => $query, '_cache' => true)); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Range.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Range.php new file mode 100644 index 00000000..d5be9ce7 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Range.php @@ -0,0 +1,31 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Filter_Range + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Filter_Abstract +{ + /** + * Transform the filter into an ES syntax compliant array. + * + * @return array + */ + public function getFilterQuery() + { + return array('range' => $this->_options); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Terms.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Terms.php new file mode 100644 index 00000000..78a8da08 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Elasticsearch/Query/Filter/Terms.php @@ -0,0 +1,47 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Filter_Terms + extends Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query_Filter_Abstract +{ + protected $_parsedFilter = false; + + /** + * Transform the filter into an ES syntax compliant array. + * + * @return array + */ + public function getFilterQuery() + { + if ($this->_parsedFilter === false) { + foreach ($this->_options as $field => &$values) { + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as &$values) { + $values = $this->_query->prepareFilterQueryText($values); + } + } + + $this->_parsedFilter = true; + } + + return array('terms' => $this->_options); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Index.php b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Index.php new file mode 100644 index 00000000..9768133b --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/Model/Resource/Engine/Index.php @@ -0,0 +1,254 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_Model_Resource_Engine_Index extends Mage_CatalogSearch_Model_Resource_Fulltext +{ + /** + * @var array + */ + protected $_defaultRatingIdByStore = array(); + + /** + * @var array + */ + protected $_suggestFieldNames = array(); + + /** + * Init the suggest field name by store during construct + * + * @return void + */ + public function __construct() + { + foreach (Mage::app()->getStores(true) as $store) { + $this->_suggestFieldNames[$store->getId()] = Mage::helper('smile_elasticsearch')->getSuggestFieldName($store); + } + + parent::__construct(); + } + + + /** + * Adds advanced index data. + * + * @param array $index Data indexed + * @param int $storeId Store id to reindex + * @param array $productIds Product ids to reindex + * + * @return mixed + */ + public function addAdvancedIndex($index, $storeId, $productIds = null) + { + if (is_null($productIds) || !is_array($productIds)) { + $productIds = array(); + foreach ($index as $productData) { + $productIds[] = $productData['entity_id']; + } + } + + $suggestionFiledName = $this->_suggestFieldNames[$storeId]; + + $categoryData = $this->_getCatalogCategoryData($storeId, $productIds); + $priceData = $this->_getCatalogProductPriceData($productIds); + + $ratingData = $this->_getRatingData($storeId, $productIds); + + foreach ($index as $productId => &$productData) { + + if (isset($categoryData[$productId]) && isset($priceData[$productId])) { + $productData += $categoryData[$productId]; + $productData += $priceData[$productId]; + } else { + $productData += array( + 'categories' => array(), + 'show_in_categories' => array(), + 'visibility' => 0 + ); + } + + if (isset($ratingData[$productId])) { + $productData += $ratingData[$productId]; + } + } + + return $index; + } + + + /** + * Returns first rating that can be applied for a given store + * + * @param int $storeId The store id we want the default rating for + * + * @return false|int + */ + protected function _getDefaultRatingId($storeId) + { + if (!isset($this->_defaultRatingIdByStore[$storeId])) { + $ratingId = false; + $ratings = Mage::getResourceModel('rating/rating_collection') + ->setStoreFilter($storeId); + + if ($ratings->getSize() > 0) { + $ratingId = $ratings->getFirstItem()->getId(); + } + $this->_defaultRatingIdByStore[$storeId] = $ratingId; + } + + return $this->_defaultRatingIdByStore[$storeId]; + } + + /** + * Retrieve product ratings per store for the product list + * + * @param int $storeId Store id + * @param array $productIds Product ids + * + * @return array + */ + function _getRatingData($storeId, $productIds) + { + $adapter = $this->_getWriteAdapter(); + $indexedRatingId = $this->_getDefaultRatingId($storeId); + + $result = array(); + if ($indexedRatingId !== false) { + $select = $adapter->select() + ->from(array('r' => $this->getTable('rating/rating_vote_aggregated'))) + ->where('r.entity_pk_value IN (?)', $productIds) + ->where('r.rating_id = ?', $indexedRatingId) + ->where('store_id = ?', $storeId); + + foreach ($adapter->fetchAll($select) as $row) { + $productId = $row['entity_pk_value']; + if (!isset($result[$productId])) { + $result[$productId] = array(); + } + $result[$productId]['rating_filter'] = (float) $row['percent']; + } + } + + + return $result; + } + + /** + * Retrieves category data for advanced index. + * + * @param int $storeId Store id to reindex + * @param array $productIds Product ids to reindex + * @param bool $visibility Index product visibiliy into category + * + * @return array + */ + protected function _getCatalogCategoryData($storeId, $productIds, $visibility = true) + { + $adapter = $this->_getWriteAdapter(); + + $columns = array('product_id' => 'product_id'); + + if ($visibility) { + $columns[] = 'visibility'; + } + + $nameAttr = Mage::getModel('eav/entity_attribute')->loadByCode('catalog_category', 'name'); + $joinCond = $adapter->quoteInto( + 'cat.category_id = name.entity_id AND name.attribute_id = ? AND name.store_id IN(0, cat.store_id)', + $nameAttr->getAttributeId() + ); + + $select = $adapter->select() + ->from(array('cat' => $this->getTable('catalog/category_product_index')), $columns) + ->join(array('name' => $nameAttr->getBackendTable()), $joinCond, array()) + ->where('product_id IN (?)', $productIds) + ->where('cat.store_id = ?', $storeId) + ->group('product_id'); + + $helper = Mage::getResourceHelper('core'); + $helper->addGroupConcatColumn($select, 'parents', 'category_id', ' ', ',', 'is_parent = 1'); + $helper->addGroupConcatColumn($select, 'anchors', 'category_id', ' ', ',', 'is_parent = 0'); + $helper->addGroupConcatColumn($select, 'positions', array('category_id', 'position'), ' ', '_'); + $helper->addGroupConcatColumn($select, 'category_name', new Zend_Db_Expr('IF(cat.category_id = 2, "", name.value)'), '|'); + + $select = $helper->getQueryUsingAnalyticFunction($select); + + $result = array(); + foreach ($adapter->fetchAll($select) as $row) { + $data = array( + 'categories' => array_values(array_filter(explode(' ', $row['parents']))), + 'show_in_categories' => array_values(array_filter(explode(' ', $row['anchors']))), + 'category_name' => array_values(array_filter(explode('|', $row['category_name']))), + ); + + foreach (explode(' ', $row['positions']) as $value) { + list($categoryId, $position) = explode('_', $value); + $key = sprintf('position_category_%d', $categoryId); + $data[$key] = $position; + } + if ($visibility) { + $data['visibility'] = $row['visibility']; + } + + $result[$row['product_id']] = $data; + } + + return $result; + } + + /** + * Retrieves product price data for advanced index. + * + * @param array $productIds Product ids to reindex + * + * @return array + */ + protected function _getCatalogProductPriceData($productIds = null) + { + $adapter = $this->_getWriteAdapter(); + + $select = $adapter->select() + ->from( + $this->getTable('catalog/product_index_price'), + array( + 'entity_id', + 'customer_group_id', + 'website_id', + 'min_price', + 'has_discount' => new Zend_Db_Expr('COALESCE((price - min_price) > 0, 0)') + ) + ); + + if ($productIds) { + $select->where('entity_id IN (?)', $productIds); + } + + $result = array(); + foreach ($adapter->fetchAll($select) as $row) { + if (!isset($result[$row['entity_id']])) { + $result[$row['entity_id']] = array(); + } + $priceKey = sprintf('price_%s_%s', $row['customer_group_id'], $row['website_id']); + $result[$row['entity_id']][$priceKey] = round($row['min_price'], 2); + + $discountKey = sprintf('has_discount_%s_%s', $row['customer_group_id'], $row['website_id']); + $result[$row['entity_id']][$discountKey] = $row['has_discount']; + } + + return $result; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/controllers/AjaxController.php b/src/app/code/community/Smile/ElasticSearch/controllers/AjaxController.php new file mode 100644 index 00000000..399aef9f --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/controllers/AjaxController.php @@ -0,0 +1,55 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +require 'Mage/CatalogSearch/controllers/AjaxController.php'; + +/** + * Autocomplete controller + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Smile Searchandising Suite to newer + * versions in the future. + * + * This work is a fork of Johann Reinke previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_ElasticSearch_AjaxController extends Mage_CatalogSearch_AjaxController +{ + /** + * Execute autocomplete + * + * @return Mage_Core_Controller_Front_Action Self reference + */ + public function suggestAction() + { + if (Mage::helper('smile_elasticsearch/elasticsearch')->isActiveEngine()) { + $this->loadLayout(); + $this->renderLayout(); + } else { + parent::suggestAction(); + } + return $this; + } +} diff --git a/src/app/code/community/Smile/ElasticSearch/etc/config.xml b/src/app/code/community/Smile/ElasticSearch/etc/config.xml new file mode 100644 index 00000000..7611b1c0 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/etc/config.xml @@ -0,0 +1,241 @@ + + + + + + 1.1.1 + + + + + + Smile_ElasticSearch_Model + smile_elasticsearch_resource + + + Smile_ElasticSearch_Model_Resource + + + + Smile_ElasticSearch_Model_Index_Action_Fulltext_Refresh + Smile_ElasticSearch_Model_Index_Action_Fulltext_Refresh_Row + Smile_ElasticSearch_Model_Index_Action_Fulltext_Refresh_Changelog + + + + + + Smile_ElasticSearch_Helper + + + + + Smile_ElasticSearch_Block + + + + + + Smile_ElasticSearch + Mage_Catalog_Model_Resource_Setup + + + + + + + smile_elasticsearch/indexer_fulltext + + smile_elasticsearch/index_action_fulltext_refresh_changelog + smile_elasticsearch/index_action_fulltext_refresh + + + + + + + + + smile_elasticsearch/observer + requireCatalogsearchReindex + + + + + + + smile_elasticsearch/observer + reindexCategoryAfterSave + + + + + + + smile_elasticsearch/observer + cleanCategoryAfterDelete + + + + + + + smile_elasticsearch/observer + reindexProductOnPartialCategoryReindex + + + + + + + smile_elasticsearch/observer + processShellFulltextReindexEvent + + + + + + + + + + + + + + + + + smile_elasticsearch/engine_elasticsearch_mapping_product + + + smile_elasticsearch/engine_elasticsearch_mapping_category + + + + + + + + + + Smile_ElasticSearch_Adminhtml + + + + + + + + + + smile/elasticsearch.xml + + + + + + + + smile_elasticsearch/observer + eavAttributeEditFormInit + + + + + + + + + Smile_ElasticSearch.csv + + + + + + + + + + smile/elasticsearch.xml + + + + + + + + smile_elasticsearch/observer + resetCurrentCatalogLayer + + + + + + + + smile_elasticsearch/observer + resetCurrentSearchLayer + + + + + + + smile_elasticsearch/observer + resetCurrentSearchLayer + + + + + + + + + Smile_ElasticSearch + + + + + + + + + 0 + 127.0.0.1:9200 + 30 + magento + {{YYYYMMdd}}-{{HHmmss}} + 1 + 0 + 50 + 1 + 0 + 1 + 0.7 + 0 + 10 + 1.0 + 3 + + + + diff --git a/src/app/code/community/Smile/ElasticSearch/etc/system.xml b/src/app/code/community/Smile/ElasticSearch/etc/system.xml new file mode 100644 index 00000000..fbd55b87 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/etc/system.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + select + smile_elasticsearch/adminhtml_system_config_backend_engine + smile_elasticsearch/adminhtml_system_config_source_engine + 19 + 1 + 0 + 0 + + + + select + adminhtml/system_config_source_yesno + If set yo yes, will display potential error messages in frontend. + 50 + 1 + 1 + 1 + smile_elasticsearch/engine_elasticsearch + + + + text + host:port separated by comma. + 51 + 1 + 1 + 1 + required-entry + smile_elasticsearch/engine_elasticsearch + + + + Number of seconds after a timeout occurs for every request. If using indexing of file, large value necessary. + text + 55 + 1 + 0 + 0 + required-entry validate-greater-than-zero validate-number + smile_elasticsearch/engine_elasticsearch + + + + text + Without starting and trailing slashes. + 56 + 1 + 1 + 1 + required-entry validate-code + smile_elasticsearch/engine_elasticsearch + + + + text + Having more shards enhances the indexing performance and allows to distribute a big index across machines. + 57 + 1 + 0 + 0 + required-entry validate-greater-than-zero validate-digits + smile_elasticsearch/engine_elasticsearch + + + + text + Be careful when modifying this parameter. Write consistency (one, quorum or all) must be considered in order to avoid timeout write action. More info here: http://www.elasticsearch.org/guide/reference/api/bulk.html and https://github.com/elasticsearch/elasticsearch/issues/444]]> + Default write consistency is quorum (active shards > replicas / 2 + 1).
For example, in a N shards with 2 replicas index, there will have to be at least 2 active shards within the relevant partition (quorum) for the operation to succeed. In a N shards with 1 replica scenario, there will need to be a single shard active (in this case, one and quorum is the same).]]>
+ 58 + 1 + 0 + 0 + required-entry validate-digits + smile_elasticsearch/engine_elasticsearch +
+ + + text + Max number of values returned by a facet query. + 59 + 1 + 1 + 1 + required-entry validate-greater-than-zero validate-digits + smile_elasticsearch/engine_elasticsearch + + + + select + adminhtml/system_config_source_yesno + If enabled, will also search on product options labels. + 60 + 1 + 1 + 1 + smile_elasticsearch/engine_elasticsearch + + + + select + adminhtml/system_config_source_yesno + Needs ICU plugin installation: https://github.com/elasticsearch/elasticsearch-analysis-icu + 70 + 1 + 0 + 0 + smile_elasticsearch/engine_elasticsearch + + + + select + adminhtml/system_config_source_yesno + Enables approximative search: http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html + 71 + 1 + 1 + 1 + smile_elasticsearch/engine_elasticsearch + + + + text + 0 to 1 (1 excluded). Low value affects query performance. Default value in Elasticsearch: 0.5. + 72 + 1 + 1 + 1 + required-entry validate-number validate-number-range number-range-0-0.99 + + smile_elasticsearch/engine_elasticsearch + 1 + + + + + text + Length of required common prefix on variant terms. Default value in Elasticsearch: 0. + 73 + 1 + 1 + 1 + required-entry validate-digits + + smile_elasticsearch/engine_elasticsearch + 1 + + + + + text + High value affects query performance. Default value in Elasticsearch: 25. + 74 + 1 + 1 + 1 + required-entry validate-greater-than-zero validate-digits + + smile_elasticsearch/engine_elasticsearch + 1 + + + + + text + Sets the boost value of the query. Default value in Elasticsearch: 1. + 75 + 1 + 1 + 1 + required-entry validate-greater-than-zero validate-number + + smile_elasticsearch/engine_elasticsearch + 1 + + + + catalogsearch/fulltext_engine + + + catalogsearch/fulltext_engine + +
+
+
+
+
+
diff --git a/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/install-1.0.0.php b/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/install-1.0.0.php new file mode 100644 index 00000000..218c6ac5 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/install-1.0.0.php @@ -0,0 +1,35 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + +$installer = $this; +$installer->startSetup(); + +try { + $installer->getConnection()->addColumn( + $installer->getTable('catalog/eav_attribute'), + 'search_weight', + "tinyint(1) unsigned NOT NULL DEFAULT '1' after `is_searchable`" + ); +} catch (Exception $e) { + Mage::logException($e); +} + +$installer->endSetup(); \ No newline at end of file diff --git a/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/upgrade-1.0.0-1.1.0.php b/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/upgrade-1.0.0-1.1.0.php new file mode 100644 index 00000000..ea9553e3 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/upgrade-1.0.0-1.1.0.php @@ -0,0 +1,65 @@ + using a "virtual attribute" + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Smile Searchandising Suite to newer + * versions in the future. + * + * This work is a fork of Johann Reinke previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + +/** + * @var Mage_Catalog_Model_Resource_Setup + */ + +$installer = $this; +$installer->startSetup(); + +$productEntityTypeId = $installer->getEntityTypeId('catalog_product'); +$defaultAttributeSetId = $this->getDefaultAttributeSetId($productEntityTypeId); +$defaultGroupId = $this->getDefaultAttributeGroupId($productEntityTypeId); + +$installer->addAttribute( + $productEntityTypeId, + 'rating_filter', + array( + 'type' => 'decimal', + 'label' => 'Rating filter', + 'enabled' => true, + 'is_enabled' => true, + 'input' => 'hidden', + 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE, + 'required' => false, + 'visible' => 1, + 'searchable' => 1, + 'filterable_in_search' => 1, + 'visible_in_advanced_search'=> 0, + 'filterable' => 1, + 'comparable' => 0, + 'is_configurable' => 0, + 'used_in_product_listing' => 0, + 'user_defined' => 0, + 'visible_on_front' => 1, + 'is_html_allowed_on_front' => 0, + 'is_used_for_price_rules' => 0, + 'used_for_promo_rules' => 0, + 'used_for_sort_by' => 1, + 'is_configurable' => 0, + 'position' => 0, + ) +); + +$installer->addAttributeToSet($productEntityTypeId, $defaultAttributeSetId, $defaultGroupId, 'rating_filter', 200); + +$installer->endSetup(); diff --git a/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/upgrade-1.1.0-1.1.1.php b/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/upgrade-1.1.0-1.1.1.php new file mode 100644 index 00000000..23373a94 --- /dev/null +++ b/src/app/code/community/Smile/ElasticSearch/sql/smile_elasticsearch_setup/upgrade-1.1.0-1.1.1.php @@ -0,0 +1,30 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + +/** + * @var Mage_Catalog_Model_Resource_Setup + */ + +$installer = $this; +$installer->startSetup(); + +$installer->updateAttribute(Mage_Catalog_Model_Category::ENTITY, 'is_anchor', 'frontend_input', 'hidden'); +$installer->updateAttribute(Mage_Catalog_Model_Category::ENTITY, 'is_anchor', 'default_value', 1); + +$installer->endSetup(); diff --git a/src/app/code/community/Smile/SearchandisingSuite/Helper/Data.php b/src/app/code/community/Smile/SearchandisingSuite/Helper/Data.php new file mode 100644 index 00000000..2aec3e98 --- /dev/null +++ b/src/app/code/community/Smile/SearchandisingSuite/Helper/Data.php @@ -0,0 +1,32 @@ + +* @copyright 2013 Smile +* @license Apache License Version 2.0 +*/ +class Smile_SearchandisingSuite_Helper_Data extends Mage_Core_Helper_Abstract +{ + /** + * @var string Config path for site id. + */ + const CONFIG_SITE_ID_XPATH = 'smile_searchandisingsuite_general/website/site_id'; + + /** + * Retrieve site id from the configuration. + * + * @return string + */ + public function getSiteId() + { + return (string) Mage::getStoreConfig(self::CONFIG_SITE_ID_XPATH); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/SearchandisingSuite/etc/adminhtml.xml b/src/app/code/community/Smile/SearchandisingSuite/etc/adminhtml.xml new file mode 100644 index 00000000..bf6f0eec --- /dev/null +++ b/src/app/code/community/Smile/SearchandisingSuite/etc/adminhtml.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + Smile Searchandising General Section + + + + + + + + + + diff --git a/src/app/code/community/Smile/SearchandisingSuite/etc/config.xml b/src/app/code/community/Smile/SearchandisingSuite/etc/config.xml new file mode 100644 index 00000000..e04c2839 --- /dev/null +++ b/src/app/code/community/Smile/SearchandisingSuite/etc/config.xml @@ -0,0 +1,55 @@ + + + + + + + 1.0.0 + + + + + + + Smile_SearchandisingSuite_Helper + + + + + + + + + + Smile_SearchandisingSuite.csv + + + + + + + + + + + 1 + + + + + diff --git a/src/app/code/community/Smile/SearchandisingSuite/etc/system.xml b/src/app/code/community/Smile/SearchandisingSuite/etc/system.xml new file mode 100644 index 00000000..6e9db87a --- /dev/null +++ b/src/app/code/community/Smile/SearchandisingSuite/etc/system.xml @@ -0,0 +1,59 @@ + + + + + + + 200 + + + + + + separator-top + + smile_searchandisingsuite + text + 40 + 1 + 1 + 1 + + + + text + 100 + 1 + 1 + 1 + + + + text + 1 + 1 + 1 + 1 + + + + + + + + \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Config.php b/src/app/code/community/Smile/Tracker/Block/Config.php new file mode 100644 index 00000000..3abc4024 --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Config.php @@ -0,0 +1,96 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Config extends Mage_Core_Block_Template +{ + + /** + * Append the tracking scripts to the head only if the module is enabled. + * + * @return Mage_Core_Block_Abstract Self reference + */ + // @codingStandardsIgnoreStart + public function _prepareLayout() + { + if ($this->isEnabled() && $this->getLayout()->getBlock('head')) { + $this->getLayout()->getBlock('head')->setIsSmileTrackerEnabled(true); + } + return $this; + } + // @codingStandardsIgnoreEnd + + /** + * Is tracker enabled. + * + * @return bool + */ + public function isEnabled() + { + return Mage::helper('smile_tracker')->isEnabled(); + } + + /** + * Return the hit HTTP URL. + * If not set from confi, returns an internal URL that is visible into server access logs. + * + * @return string + */ + public function getBeaconUrl() + { + return Mage::helper('smile_tracker')->getBaseUrl(); + } + + /** + * This URL is the root of Boomerang bandwidth measures URLs. + * + * @return string + */ + public function getBwBaseUrl() + { + return Mage::getBaseUrl('js') . 'smile/tracker/boomerang/images/'; + } + + /** + * Return the tracked site id. + * + * @return string + */ + public function getSiteId() + { + return Mage::helper('smile_searchandisingsuite')->getSiteId(); + } + + /** + * Return the tracked store id. + * + * @return int + */ + public function getStoreId() + { + return Mage::app()->getStore()->getId(); + } + + /** + * Return the session cookie configuration (names and lifetimes) + * for cookies used by the tracker (visit/session and visitor). + * + * @return array + */ + public function getCookieConfig() + { + $config = Mage::helper('smile_tracker')->getCookieConfig(); + return $config; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Abstract.php b/src/app/code/community/Smile/Tracker/Block/Variables/Abstract.php new file mode 100644 index 00000000..9b4ad139 --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Abstract.php @@ -0,0 +1,43 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Abstract extends Mage_Core_Block_Template +{ + /** + * Indicate if the block is enabled or not + * + * @return Mage_Core_Block_Abstract Self reference + */ + public function isEnabled() + { + $mainBlock = $this->getLayout()->getBlock('smile.tracker.config'); + + return !is_null($mainBlock) && $mainBlock->isEnabled(); + } + + /** + * Display the block only if main block is present and enabled + * + * @return string Block rendering + */ + protected function _toHtml() + { + $html = ''; + if ($this->isEnabled()) { + $html = parent::_toHtml(); + } + return $html; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Page/Abstract.php b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Abstract.php new file mode 100644 index 00000000..0e58514e --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Abstract.php @@ -0,0 +1,42 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Page_Abstract extends Smile_Tracker_Block_Variables_Abstract +{ + /** + * Set the default template for page variable blocks + * + * @return void Nothing + */ + // @codingStandardsIgnoreStart + public function _construct() + { + $this->setTemplate('smile/tracker/variables/page.phtml'); + } + // @codingStandardsIgnoreEnd + + /** + * List of the variables added to the tracker + * Array keys are variable name + * + * @return array + */ + public function getVariables() + { + $variables = array(); + return array(); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Page/Base.php b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Base.php new file mode 100644 index 00000000..ac8637ed --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Base.php @@ -0,0 +1,120 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Page_Base extends Smile_Tracker_Block_Variables_Page_Abstract +{ + const PAGE_LABELS_BY_IDENTIFER_MAP_CACHE_ID = 'smile_tracker_page_label_map'; + + + /** + * Append the page type data to the tracked variables list + * + * @return array + */ + public function getVariables() + { + return $this->getPageTypeInformations();; + } + + /** + * List of the page type data + * + * @return array + */ + public function getPageTypeInformations() + { + return array( + 'type.identifier' => $this->getPageTypeIdentifier(), + 'type.label' => stripslashes($this->getPageTypeLabel()), + ); + } + + /** + * Page type identifier built from route (ex: catalog/product/view => catalog_product_view) + * + * @return string + */ + public function getPageTypeIdentifier() + { + $request = $this->getRequest(); + return $request->getModuleName() . '_' . $request->getControllerName() . '_' . $request->getActionName(); + } + + /** + * Human readable version of the page + * + * @return string + */ + public function getPageTypeLabel() + { + if (!$this->getData('page_type_label')) { + $label = ''; + $identifier = $this->getPageTypeIdentifier(); + $labelByIdentifier = $this->_getPageTypeLabelMap(); + + if (isset($labelByIdentifier[$identifier])) { + $label = $labelByIdentifier[$identifier]; + } + + $this->setData('page_type_label', $label); + } + + return $this->getData('page_type_label'); + } + + /** + * Return the array of page labels from layout indexed by handle names. + * + * @return array + */ + protected function _getPageTypeLabelMap() + { + $labelByIdentifier = array(); + $cacheKey = self::PAGE_LABELS_BY_IDENTIFER_MAP_CACHE_ID . '_' . Mage::app()->getStore()->getId(); + $cache = Mage::app()->loadCache($cacheKey); + + if ($cache === false) { + + // Retrieve informations from design + $design = Mage::getDesign(); + $area = $design->getArea(); + $package = $design->getPackageName(); + $theme = $design->getTheme('layout'); + + // Retrieve Layout Informations + $layoutHandles = $this->getLayout()->getUpdate()->getFileLayoutUpdatesXml($area, $package, $theme); + $layoutHandlesArr = $layoutHandles->xpath('/*/*/label/..'); + + if ($layoutHandlesArr) { + foreach ($layoutHandlesArr as $node) { + $identifier = $node->getName(); + $helper = Mage::helper(Mage_Core_Model_Layout::findTranslationModuleName($node)); + $labelByIdentifier[$identifier] = $this->helper('core')->jsQuoteEscape($helper->__((string)$node->label)); + } + } + + $cacheTags = array(Mage_Core_Model_Layout_Update::LAYOUT_GENERAL_CACHE_TAG); + Mage::app()->saveCache( + serialize($labelByIdentifier), $cacheKey, $cacheTags, 7200 + ); + + } else { + $labelByIdentifier = unserialize($cache); + } + + return $labelByIdentifier; + } + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Page/Catalog.php b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Catalog.php new file mode 100644 index 00000000..dd37a6dc --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Catalog.php @@ -0,0 +1,121 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Page_Catalog extends Smile_Tracker_Block_Variables_Page_Abstract +{ + /** + * Returnn the list of catalog related variables. + * + * @return array + */ + public function getVariables() + { + $variables = array_merge( + $this->getCategoryVariables(), + $this->getProductVariables(), + $this->getLayerVariables() + ); + + return $variables; + } + + /** + * Returns categories variables (id, name and path). + * + * @return array + */ + public function getCategoryVariables() + { + $variables = array(); + + if (Mage::registry('current_category')) { + $category = Mage::registry('current_category'); + $variables['category.id'] = $category->getId(); + $variables['category.label'] = $category->getName(); + $variables['category.path'] = $category->getPath(); + } + + return $variables; + } + + /** + * Return list of the product relatedd variables (id, label, sku) + * + * @return array + */ + public function getProductVariables() + { + $variables = array(); + + if (Mage::registry('current_product')) { + $product = Mage::registry('current_product'); + $variables['product.id'] = $product->getId(); + $variables['product.label'] = $product->getName(); + $variables['product.sku'] = $product->getSku(); + } + return $variables; + } + + /** + * Return list of product list variables (pages, sort, display mode, filters) + * + * @return array + */ + public function getLayerVariables() + { + $variables = array(); + + $productListBlock = $this->getLayout()->getBlock('product_list_toolbar'); + + if ($productListBlock && $productListBlock->getCollection()) { + $variables['product_list.page_count'] = $productListBlock->getLastPageNum(); + $variables['product_list.product_count'] = $productListBlock->getTotalNum(); + $variables['product_list.current_page'] = $productListBlock->getCurrentPage(); + $variables['product_list.sort_order'] = $productListBlock->getCurrentOrder(); + $variables['product_list.sort_direction'] = $productListBlock->getCurrentDirection(); + $variables['product_list.display_mode'] = $productListBlock->getCurrentMode(); + } + + $layer = Mage::registry('current_layer'); + + if ($layer) { + $filters = array(); + $layerState = $layer->getState(); + foreach ($layerState->getFilters() as $currentFilter) { + $currentFilterBase = $currentFilter->getFilter() ? $currentFilter->getFilter() : $currentFilter; + $identifier = $currentFilter->getRequestVar(); + + if ($currentFilter->getFilter()) { + $identifier = $currentFilter->getFilter()->getRequestVar(); + } + + $filterValue = $this->getRequest()->getParam($identifier, ''); + + if (is_array($filterValue)) { + $filterValue = implode('|', $filterValue); + } + + $variables['product_list.filters.' . $identifier] = $filterValue; + } + } + + return $variables; + } + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Page/Cms.php b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Cms.php new file mode 100644 index 00000000..ab48671b --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Cms.php @@ -0,0 +1,35 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Page_Cms extends Smile_Tracker_Block_Variables_Page_Abstract +{ + /** + * Append the CMS page viewed identifier and title to the list of tracked variables + * + * @return array + */ + public function getVariables() + { + $currentPage = Mage::getSingleton('cms/page'); + + return array( + 'cms.identifier' => $currentPage->getIdentifier(), + 'cms.title' => $currentPage->getTitle() + ); + } + + + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Page/Order.php b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Order.php new file mode 100644 index 00000000..2db2d0b1 --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Order.php @@ -0,0 +1,74 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Page_Order extends Smile_Tracker_Block_Variables_Page_Abstract +{ + /** + * Return order and it's item related variables + * + * @return array + */ + public function getVariables() + { + $variables = array(); + + $order = $this->getLastOrder(); + + if ($order) { + $variables['order.id'] = $order->getIncrementId(); + $variables['order.subtotal'] = $order->getBaseSubtotalInclTax(); + $variables['order.discount_total'] = $order->getDiscountAmount(); + $variables['order.shipping_total'] = $order->getShippingAmount(); + $variables['order.grand_total'] = $order->getBaseGrandTotal(); + $variables['order.shipping_method'] = $order->getShippingMethod(); + $variables['order.payment_method'] = $order->getPayment()->getMethod(); + $variables['order.salesrules'] = $order->getAppliedRuleIds(); + + foreach ($order->getAllItems() as $item) { + if (!$item->isDummy()) { + $itemId = $item->getId(); + $prefix = "order.items.$itemId"; + $variables[$prefix . '.sku'] = $item->getSku(); + $variables[$prefix . '.product_id'] = $item->getProductId(); + $variables[$prefix . '.qty'] = $item->getQtyOrdered(); + $variables[$prefix . '.price'] = $item->getBasePrice(); + $variables[$prefix . '.row_total'] = $item->getRowTotal(); + $variables[$prefix . '.label'] = $item->getName(); + $variables[$prefix . '.salesrules'] = $item->getAppliedRuleIds(); + } + } + } + + return $variables; + } + + /** + * Return the order placed by the customer + * + * @return Mage_Sales_Model_Order + */ + public function getLastOrder() + { + $orderId = Mage::getSingleton('checkout/session')->getLastOrderId(); + $order = Mage::getModel('sales/order')->load($orderId); + + if (!$order->getId()) { + $order = false; + } + + return $order; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Page/Search.php b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Search.php new file mode 100644 index 00000000..febae707 --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Page/Search.php @@ -0,0 +1,30 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Page_Search extends Smile_Tracker_Block_Variables_Page_Abstract +{ + /** + * Append the user fulltext query to the tracked variables list + * + * @return array + */ + public function getVariables() + { + $variables = array( + 'search.query' => Mage::helper('catalogsearch')->getEscapedQueryText() + ); + return $variables; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Block/Variables/Session/Customer.php b/src/app/code/community/Smile/Tracker/Block/Variables/Session/Customer.php new file mode 100644 index 00000000..544b0b34 --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Block/Variables/Session/Customer.php @@ -0,0 +1,98 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Block_Variables_Session_Customer extends Smile_Tracker_Block_Variables_Abstract +{ + /** + * Set the default template for page variable blocks + * + * @return void Nothing + */ + // @codingStandardsIgnoreStart + public function _construct() + { + $this->setTemplate('smile/tracker/variables/session.phtml'); + } + // @codingStandardsIgnoreEnd + + + /** + * Return the customer related variables to be tracked including : + * - customer id + * - all customer attributes set into smile_tracker/session/customer_attributes + * - all customer address attributes (primary billing address is used) + * set into smile_tracker/session/customer_address_attributes + * + * @return array + */ + public function getVariables() + { + $variables = array(); + + $customer = $this->getCustomer(); + + if ($customer && $customer->getId()) { + + $variables['customer.id'] = $customer->getId(); + + foreach ($this->getCustomerTrackedAttributes() as $attributeCode) { + if ($customer->getData($attributeCode)) { + $variables['customer.' . $attributeCode] = $customer->getData($attributeCode); + } + } + + if ($customer->getPrimaryBillingAddress()) { + $address = $customer->getPrimaryBillingAddress(); + foreach ($this->getCustomerAddressTrackedAttributes() as $attributeCode) { + if ($address->getData($attributeCode)) { + $variables['customer.address.' . $attributeCode] = $address->getData($attributeCode); + } + } + } + } + + return $variables; + } + + /** + * Return the list of customer attributes added to the tracking. + * + * @return array + */ + public function getCustomerTrackedAttributes() + { + return array_keys(Mage::getStoreConfig('smile_tracker/session/customer_attributes')); + } + + /** + * Return the list of customer address attributes added to the tracking. + * + * @return array + */ + public function getCustomerAddressTrackedAttributes() + { + return array_keys(Mage::getStoreConfig('smile_tracker/session/customer_address_attributes')); + } + + /** + * Return the current customer from the session + * + * @return Mage_Customer_Model_Customer + */ + public function getCustomer() + { + return Mage::getSingleton('customer/session')->getCustomer(); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/Helper/Data.php b/src/app/code/community/Smile/Tracker/Helper/Data.php new file mode 100644 index 00000000..a131c33c --- /dev/null +++ b/src/app/code/community/Smile/Tracker/Helper/Data.php @@ -0,0 +1,71 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_Tracker_Helper_Data extends Mage_Core_Helper_Abstract +{ + /** + * Module status configuration path + * @var string + */ + const CONFIG_IS_ENABLED_XPATH = 'smile_tracker/general/enabled'; + + /** + * Tracking URL configuration path + * @var string + */ + const CONFIG_BASE_URL_XPATH = 'smile_tracker/general/base_url'; + + /** + * Coookie configuration configuration path + * @var string + */ + const CONFIG_COOKIE = 'smile_tracker/session'; + + /** + * Return the module activation status + * + * @return bool + */ + public function isEnabled() + { + return (bool) Mage::getStoreConfig(self::CONFIG_IS_ENABLED_XPATH); + } + + /** + * Return the tracking base URL (params are added later) + * + * @return string + */ + public function getBaseUrl() + { + $result = Mage::getStoreConfig(self::CONFIG_BASE_URL_XPATH); + + if (!$result) { + $result = Mage::getBaseUrl('js') . 'smile/tracker/hit.png'; + } + + return $result; + } + + /** + * Return an array containing the cookie configuration + * + * @return array + */ + public function getCookieConfig () + { + return Mage::getStoreConfig(self::CONFIG_COOKIE); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/Tracker/doc/INSTALL.txt b/src/app/code/community/Smile/Tracker/doc/INSTALL.txt new file mode 100644 index 00000000..cc1822e7 --- /dev/null +++ b/src/app/code/community/Smile/Tracker/doc/INSTALL.txt @@ -0,0 +1,114 @@ +Basic installation : +==================== + +First make sure you have the SmileSearchandising Suite Module installed. +Then, just install the module as usual. + + +Tracking URL default configuration : +==================================== + +By default the module is using the built-in image as a beacon. +You should be able to filter tracking into your apache access logs with the following pattern : + + js/smile/tracker/hit.png + +This configuration is not adviced into a production environment since it mess up normal access logs and tracking ones. + + +Custom tracking URL : +==================== + +You can set up a custom tracking URL into "System > Configuration > Tracking > Tracking Base URL". +You should prefer URL not including the protocol to allow SSL page tagging. + + Example: //hit.mysite.com/hit.png + + + +Use a different vhost: +---------------------- + + This is the first way to install a tracking allowing to keep separate Apache access logs from tracking logs. + You will need a secondary domain for the tracking (eg. hit.mysite.com). + + + Create log target folder : + -------------------------- + + Even if not mandatory, it is strongly adviced that you create a seperated directory to store the logs produced by the tracker : + + > mkdir -p /var/log/smile_searchandising_suite/apache_raw_events + + Following instructions need to be adapted if you don't use the same path as described upon. + + + + Install the vhost : + ------------------- + + The following virtual host allows tracking : + + + ServerName + + DocumentRoot /js/smile/tracker/ + + /js/smile/tracker/> + AllowOverride None + Order allow,deny + Allow from all + + + RewriteEngine on + RewriteRule .* /hit.png + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined + CustomLog /var/log/smile_searchandising_suite/apache_raw_events/event.log combined + + + + Notes : + - You need to replace with the root of your Magento deployment and then reload Apache + + - ServerName by the FQDN of the tracker + + - Be careful about the port into the vhosts. Usually it should be 81 since you will have varnish in front of Magento. + You should also take care to bypass Varnish for the tracking domain (pass). + + - If tracker code is not deployed yet, reloading Apache will fail. You can fix it with + + mkdir -p /js/smile/tracker + + Configure log retention policy : + -------------------------------- + + Configure logrotate by putting this into /etc/logrotate.d/smile-tracker-log + + /var/log/smile_searchandising_suite/apache_raw_events/*.log { + daily + dateext + missingok + rotate 7 + compress + notifempty + create 640 root adm + sharedscripts + postrotate + /etc/init.d/apache2 reload > /dev/null + endscript + prerotate + if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ + run-parts /etc/logrotate.d/httpd-prerotate; \ + fi; \ + endscript + } + + This allow a daily log rotation and gzip and a seven days retention. + + +Use fluentd : +------------- + +Another great option to proceed to tracking, relay is to use fluentd (proxied by Apache) and espcially with the http-enhanced plugin. +Fluentd can also be used to relay Apache logs to another server used to process the events. diff --git a/src/app/code/community/Smile/Tracker/etc/adminhtml.xml b/src/app/code/community/Smile/Tracker/etc/adminhtml.xml new file mode 100644 index 00000000..92c1021c --- /dev/null +++ b/src/app/code/community/Smile/Tracker/etc/adminhtml.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + Smile Tracker Section + + + + + + + + + + diff --git a/src/app/code/community/Smile/Tracker/etc/config.xml b/src/app/code/community/Smile/Tracker/etc/config.xml new file mode 100644 index 00000000..6db25895 --- /dev/null +++ b/src/app/code/community/Smile/Tracker/etc/config.xml @@ -0,0 +1,84 @@ + + + + + + 1.0.0 + + + + + + + Smile_Tracker_Block + + + + + Smile_Tracker_Helper + + + + + + + + + smile/tracker.xml + + + + + + + + + + + Smile_Tracker.csv + + + + + + + + + + 1 + + + STUID + 3600 + 365 + STVID + + + + + + + + + + + + + + + diff --git a/src/app/code/community/Smile/Tracker/etc/system.xml b/src/app/code/community/Smile/Tracker/etc/system.xml new file mode 100644 index 00000000..17e58f6e --- /dev/null +++ b/src/app/code/community/Smile/Tracker/etc/system.xml @@ -0,0 +1,108 @@ + + + + + + + + smile_searchandisingsuite + text + 40 + 1 + 1 + 1 + + + + + text + 100 + 1 + 1 + 1 + + + + select + adminhtml/system_config_source_yesno + 1 + 1 + 0 + 0 + + + + text + 10 + 1 + 1 + 1 + 1 + + + + + + text + 200 + 1 + 1 + 1 + + + + text + 10 + 1 + 0 + 0 + + + + text + 11 + 1 + 0 + 0 + Without any activity under this delay we start a new visit.]]> + + + + text + 20 + 1 + 0 + 0 + + + + text + 21 + 1 + 0 + 0 + This cookie will be stick to the customer to allow multiple session aggregation.]]> + + + + + + + + + \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Catalog/Category/Tab/Product.php b/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Catalog/Category/Tab/Product.php new file mode 100644 index 00000000..a3a98ce1 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Catalog/Category/Tab/Product.php @@ -0,0 +1,155 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Block_Adminhtml_Catalog_Category_Tab_Product extends Mage_Adminhtml_Block_Catalog_Form +{ + /** + * Get the current edit category. + * + * @return Mage_Catalog_Model_Category + */ + public function getCategory() + { + if (!$this->_category) { + $this->_category = Mage::registry('category'); + } + return $this->_category; + } + + /** + * Create the form + * + * @return Smile_VirtualCategories_Block_Adminhtml_Catalog_Category_Tab_Product + */ + protected function _prepareForm() + { + $form = new Varien_Data_Form(); + $form->setHtmlIdPrefix('virtual_'); + + $this->_prepareCategoryTypeSelector($form) + ->_prepareVirtualRuleFieldset($form) + ->_prepareLegacyProductSelector($form); + + $form->setFieldNameSuffix('general'); + $form->addValues($this->getCategory()->getData()); + + $this->setForm($form); + + $this->setTemplate('smile/virtualcategories/category/product_select_form.phtml'); + + return parent::_prepareForm(); + } + + /** + * Create the category type selector fieldset. + * + * @param Varien_Data_Form $form Current form. + * + * @return Smile_VirtualCategories_Block_Adminhtml_Catalog_Category_Tab_Product + */ + private function _prepareCategoryTypeSelector(Varien_Data_Form $form) + { + $fieldset = $form->addFieldset( + 'base_fieldset', + array('legend' => $this->__('Category type'), 'class' => 'fieldset-wide') + ); + + $typeSelectorFieldConfiguration = array( + 'name' => 'is_virtual', + 'label' => $this->__('Enable virtual category'), + 'title' => $this->__('Enable virtual category'), + 'required' => true, + 'options' => array('0' => $this->__('No'), '1' => $this->__('Yes')) + ); + + $typeSelector = $fieldset->addField('is_virtual', 'select', $typeSelectorFieldConfiguration); + + $this->setSelectorHtmlId($typeSelector->getHtmlId()); + + return $this; + } + + /** + * Create the category rule admin fieldset. + * + * @param Varien_Data_Form $form Current form. + * + * @return Smile_VirtualCategories_Block_Adminhtml_Catalog_Category_Tab_Product + */ + private function _prepareVirtualRuleFieldset(Varien_Data_Form $form) + { + $url = $this->getUrl('*/promo_catalog/newConditionHtml', array('form' => 'virtual_virtual_fieldset')); + $renderer = Mage::getBlockSingleton('adminhtml/widget_form_renderer_fieldset') + ->setTemplate('smile/virtualcategories/category/rule_fieldset.phtml') + ->setNewChildUrl($url); + + $fieldset = $form->addFieldset( + 'virtual_fieldset', + array('legend' => $this->__('Virtual condition'), 'class' => 'fieldset-wide') + )->setRenderer($renderer); + + $field = $fieldset->addField( + 'conditions', + 'text', + array( + 'name' => 'conditions', + 'label' => Mage::helper('catalogrule')->__('Conditions'), + 'title' => Mage::helper('catalogrule')->__('Conditions'), + 'required' => true, + ) + ); + + $this->setVirtualRuleFieldsetHtmlId($fieldset->getHtmlId()); + + $rule = Mage::getModel('smile_virtualcategories/rule'); + + if ($this->getCategory()->getVirtualRule()) { + $rule = $this->getCategory()->getVirtualRule(); + } + + $rule->setForm($form); + $rule->getConditions()->setJsFormObject('virtual_virtual_fieldset'); + + $field->setRule($rule) + ->setRenderer(Mage::getBlockSingleton('rule/conditions')); + + return $this; + } + + /** + * Append the category product grid. + * + * @param Varien_Data_Form $form Current form. + * + * @return Smile_VirtualCategories_Block_Adminhtml_Catalog_Category_Tab_Product + */ + private function _prepareLegacyProductSelector(Varien_Data_Form $form) + { + $fieldset = $form->addFieldset( + 'product_selection', + array('legend' => $this->__('Product selection'), 'class' => 'fieldset-wide') + ); + + $fieldset->addField('pgold', 'hidden', array('name' => 'pgold')) + ->setAfterElementHtml($this->getProductsGrid()); + + $this->setProductFieldsetHtmlId($fieldset->getHtmlId()); + + return $this; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Override/Catalog/Category/Tabs.php b/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Override/Catalog/Category/Tabs.php new file mode 100644 index 00000000..24ed0c87 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Override/Catalog/Category/Tabs.php @@ -0,0 +1,39 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Block_Adminhtml_Override_Catalog_Category_Tabs extends Mage_Adminhtml_Block_Catalog_Category_Tabs +{ + /** + * Replace the content of the standard table with the new one. + * + * @return Smile_VirtualCategories_Block_Adminhtml_Override_Catalog_Category_Tabs + */ + protected function _prepareLayout() + { + parent::_prepareLayout(); + + $tab = $this->_tabs['products']; + $blockName = 'smile_virtualcategories/adminhtml_catalog_category_tab_product'; + $newTab = $this->getLayout() + ->createBlock($blockName, 'category.products.tab', array('products_grid' => $this->getTabContent($tab))); + + $tab->setContent($newTab->toHtml()); + + return $this; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Override/Catalog/Category/Tree.php b/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Override/Catalog/Category/Tree.php new file mode 100644 index 00000000..05b73c51 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Block/Adminhtml/Override/Catalog/Category/Tree.php @@ -0,0 +1,124 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Block_Adminhtml_Override_Catalog_Category_Tree extends Mage_Adminhtml_Block_Catalog_Category_Tree +{ + /** + * Retrieve product collection + * + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Collection + */ + public function getCategoryCollection() + { + $collection = $this->getData('category_collection'); + if (is_null($collection)) { + $collection = Mage::getResourceModel('smile_virtualcategories/catalog_virtualCategory_collection'); + + /* @var $collection Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Collection */ + $collection->addAttributeToSelect('name') + ->addAttributeToSelect(array('is_active', 'virtual_category')) + ->setProductStoreId($this->getStoreId()) + ->setLoadProductCount($this->_withProductCount) + ->setStoreId($this->getStoreId()); + + $this->setData('category_collection', $collection); + } + return $collection; + } + + /** + * Indicates if Magento is running multiple stores. + * + * @return boolean + */ + protected function _isMultipleStore() + { + return count(Mage::app()->getStores()) > 1; + } + + /** + * Return default store id. + * + * @return int + */ + protected function _getDefaultStoreId() + { + $currentStore = current(Mage::app()->getStores()); + return $currentStore->getId(); + } + + /** + * Return current store id. + * + * @return int + */ + public function getStoreId() + { + $storeId = $this->getRequest()->getParam('store'); + + if ($storeId == 0 && $this->_isMultipleStore()) { + // Product count is not relevant on multiple stores with virtual categories + // instance since attributes may vary from one store to another + // Store must be be selected at first + $this->_withProductCount = 0; + } else if ($storeId == 0) { + $storeId = $this->_getDefaultStoreId(); + } + return $storeId; + } + + + /** + * Get JSON of array of categories, that are breadcrumbs for specified category path + * + * @param string $path Category path. + * @param string $javascriptVarName Name of the variable the JSON should be placed in. + * + * @return string + */ + public function getBreadcrumbsJavascript($path, $javascriptVarName) + { + $result = ''; + + if (!empty($path)) { + $categories = Mage::getResourceModel('smile_virtualcategories/catalog_virtualCategory_collection'); + $categories->addAttributeToSelect('name') + ->addAttributeToSelect(array('is_active', 'virtual_category')) + ->addIdFilter(explode('/', $path)) + ->setProductStoreId($this->getStoreId()) + ->setStoreId($this->getStoreId()) + ->setLoadProductCount($this->_withProductCount); + + $categoriesNodes = array(); + foreach ($categories as $category) { + $categoriesNodes[$category->getId()] = $this->_getNodeJson($category->getData()); + } + + if (!empty($categories)) { + $result = ''; + } + } + + return $result; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Helper/Data.php b/src/app/code/community/Smile/VirtualCategories/Helper/Data.php new file mode 100644 index 00000000..ef9f5e82 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Helper/Data.php @@ -0,0 +1,22 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Helper_Data extends Mage_Core_Helper_Data +{ + +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Model/Category/Attributes/Backend/Virtual.php b/src/app/code/community/Smile/VirtualCategories/Model/Category/Attributes/Backend/Virtual.php new file mode 100644 index 00000000..ef017266 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Model/Category/Attributes/Backend/Virtual.php @@ -0,0 +1,93 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Model_Category_Attributes_Backend_Virtual extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract +{ + /** + * Serializes the virtual category configuration before it will be saved. + * + * @param Mage_Catalog_Model_Category $object Category saved. + * + * @return Smile_VirtualCategories_Model_Category_Attributes_Backend_Virtual + */ + public function beforeSave($object) + { + + $attributeCode = $this->getAttribute()->getName(); + $savedValue = $this->_defaultValue; + + $savedValue['is_virtual'] = (bool) $object->getIsVirtual(); + + if ($object->getVirtualCategoryRule()) { + $savedValue['rule_serialized'] = $object->getVirtualCategoryRule()->getConditions()->asArray(); + } + + $object->setData($attributeCode, serialize($savedValue)); + + return $this; + } + + /** + * Unserializes the virtual category configuration after it has been loaded. + * + * @param Mage_Catalog_Model_Category $object Category saved. + * + * @return Smile_VirtualCategories_Model_Category_Attributes_Backend_Virtual + */ + public function afterLoad($object) + { + $attributeCode = $this->getAttribute()->getName(); + $data = $object->getData($attributeCode); + + if ($data && is_string($data) && strlen($data)) { + $data = unserialize($data); + } else { + $data = $this->_defaultValue; + } + + $virtualCategoryRule = Mage::getModel('smile_virtualcategories/rule'); + + if (isset($data['rule_serialized'])) { + $virtualCategoryRule->getConditions() + ->setConditions(array()) + ->loadArray($data['rule_serialized']); + } + + $virtualCategoryRule->setCategory($object); + + $object->setData('is_virtual', $data['is_virtual']); + $object->setData('virtual_rule', $virtualCategoryRule); + + return $this; + } + + + /** + * Get attribute instance + * + * @return Mage_Eav_Model_Entity_Attribute_Abstract + */ + public function getAttribute() + { + if (is_null($this->_attribute)) { + $attribute = Mage::getModel('eav/entity_attribute')->loadByCode('catalog_category', 'virtual_category'); + $this->setAttribute($attribute); + } + return parent::getAttribute(); + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Model/Observer.php b/src/app/code/community/Smile/VirtualCategories/Model/Observer.php new file mode 100644 index 00000000..bab5070b --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Model/Observer.php @@ -0,0 +1,92 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Model_Observer +{ + /** + * Handling rule from the request when saving categories. + * + * @param Varien_Event_Observer $observer Event data. + * + * @return Smile_VirtualCategories_Model_Observer + */ + public function prepareCategorySave(Varien_Event_Observer $observer) + { + $rule = $observer->getRequest()->getParam('rule', false); + $category = $observer->getCategory(); + if ($rule !== false) { + $ruleInstance = Mage::getModel('smile_virtualcategories/rule')->loadPost($rule); + $category->setVirtualCategoryRule($ruleInstance); + } + + return $this; + } + + /** + * Install category filter into categories + * + * @param Varien_Event_Observer $observer Event data. + * + * @return Smile_VirtualCategories_Model_Observer + */ + public function prepareCategoryFilter(Varien_Event_Observer $observer) + { + // Retrieve filter and category from event + $filter = $observer->getFilter(); + $category = $observer->getCategory(); + + // Retrieve query associated with the filter + $query = $filter->getLayer()->getProductCollection()->getSearchEngineQuery(); + + // Append the query string for the virtual categories + $qs = $category->getVirtualRule()->getSearchQuery(); + $query->addFilter('query', array('query_string' => $qs)); + + // Mark filter as installed (avoid default filter behavior) + $filter->setProductCollectionFilterSet(true); + + return $this; + } + + /** + * Install category facet into categories + * + * @param Varien_Event_Observer $observer Event data. + * + * @return Smile_VirtualCategories_Model_Observer + */ + public function prepareCategoryFacet(Varien_Event_Observer $observer) + { + // Retrieve filter and category from event + $filter = $observer->getFilter(); + $category = $observer->getCategory(); + + // Retrieve query associated with the filter + $query = $filter->getLayer()->getProductCollection()->getSearchEngineQuery(); + + // Prepare facet query group + $queries = $category->getVirtualRule()->getChildrenCategoryQueries(); + $options = array('queries' => $queries, 'prefix' => 'categories_'); + $query->addFacet('categories', 'queryGroup', $options); + + $filter->setProductCollectionFacetSet(true); + + return $this; + } +} + diff --git a/src/app/code/community/Smile/VirtualCategories/Model/Resource/Catalog/VirtualCategory/Collection.php b/src/app/code/community/Smile/VirtualCategories/Model/Resource/Catalog/VirtualCategory/Collection.php new file mode 100644 index 00000000..2e27550a --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Model/Resource/Catalog/VirtualCategory/Collection.php @@ -0,0 +1,95 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Model_Resource_Catalog_VirtualCategory_Collection extends Mage_Catalog_Model_Resource_Category_Collection +{ + /** + * Init virtual category attributes using the backend model when category load. + * + * @return Mage_Catalog_Model_Resource_Category_Collection + */ + protected function _afterLoad() + { + parent::_afterLoad(); + + if (array_key_exists('virtual_category', $this->_selectAttributes)) { + $virtualCategoryBackendModel = Mage::getModel('smile_virtualcategories/category_attributes_backend_virtual'); + foreach ($this->_items as $item) { + $virtualCategoryBackendModel->afterLoad($item); + } + } + + return $this; + } + + /** + * Load product count for specified items + * + * @param array $items Items the product count should be loaded for. + * @param boolean $countRegular Get product count for regular (non-anchor) categories. + * @param boolean $countAnchor Get product count for anchor categories. + * + * @return Mage_Catalog_Model_Resource_Category_Collection + */ + public function loadProductCount($items, $countRegular = true, $countAnchor = true) + { + $query = $this->getQuery(); + + if ($query !== false) { + + $query->setPageParams(0, 0); + $queries = array(); + + foreach ($items as $item) { + $queries[$item->getId()] = $item->getVirtualRule()->getSearchQuery(); + } + + $options = array('queries' => $queries, 'prefix' => 'categories_'); + $query->addFacet('categories', 'queryGroup', $options); + + $response = $query->search(); + + foreach ($items as $item) { + $item->setProductCount($response['faceted_data']['categories'][$item->getId()]); + } + } + + return $this; + } + + /** + * Init a new ES query used to run a facet queries query to count product per category. + * + * @return false|Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Query + */ + public function getQuery() + { + $query = false; + $engine = Mage::helper('catalogsearch')->getEngine(); + + if ($engine instanceof Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch) { + $query = $engine->createQuery('product'); + } + + $query->addFilter('terms', array('store_id' => $this->getProductStoreId())); //)); + + + return $query; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Model/Rule.php b/src/app/code/community/Smile/VirtualCategories/Model/Rule.php new file mode 100644 index 00000000..2e3e8246 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Model/Rule.php @@ -0,0 +1,194 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Model_Rule extends Mage_Rule_Model_Rule +{ + /** + * + */ + const CACHE_KEY_PREFIX = 'SMILE_VIRTUALCATEGORIES_RULES'; + + /** + * @var array + */ + private $_queryCache = array(); + + /** + * @var array + */ + private $_usedCategories = array(); + + /** + * Retrieve list of the category ids used to build the condition + * + * @return array + */ + public function getUsedCategoryIds() + { + return $this->_usedCategories; + } + + /** + * Append category id(s) to the list of categories used to build the condition. + * + * @param array|int $categoryIds Category to add. + * + * @return Smile_VirtualCategories_Model_Rule + */ + public function addUsedCategoryIds($categoryIds) + { + if (!is_array($categoryIds)) { + $categoryIds = array($categoryIds); + } + + $categoryIds = array_filter($categoryIds); + + $this->_usedCategories = array_unique(array_merge($this->_usedCategories, $categoryIds)); + + return $this; + } + + /** + * Getter for rule conditions collection + * + * @return Mage_CatalogRule_Model_Rule_Condition_Combine + */ + public function getConditionsInstance() + { + return Mage::getModel('smile_virtualcategories/rule_condition_combine'); + } + + /** + * Local caching of queries. Used when a category query is retrieved several times during the same request. + * + * @param int $categoryId Id of the category. + * + * @return NULL|string + */ + public function getQueryFromCache($categoryId) + { + $cacheInstance = Mage::getSingleton('smile_virtualcategories/rule'); + $data = false; + + if (isset($cacheInstance->_queryCache[$categoryId])) { + $data = $cacheInstance->_queryCache[$categoryId]; + } + + if ($data === false && $cacheData = Mage::app()->loadCache(self::CACHE_KEY_PREFIX . '_' .$categoryId)) { + $data = unserialize($cacheData); + } + + return $data; + } + + /** + * Store category query into the local cache. + * + * @param int $categoryId Id of the category. + * @param string $data Data to cache [query, used_categories]. + * + * @return Smile_VirtualCategories_Model_Rule + */ + public function cacheQuery($categoryId, $data) + { + $cacheInstance = Mage::getSingleton('smile_virtualcategories/rule'); + $cacheInstance->_queryCache[$categoryId] = $data; + + $cacheTags = array(); + foreach ($data[1] as $usedCategoryId) { + $cacheTags[] = Mage_Catalog_Model_Category::CACHE_TAG . '_' . $usedCategoryId; + } + + $cacheId = self::CACHE_KEY_PREFIX . '_' .$categoryId; + + Mage::app()->saveCache(serialize($data), $cacheId, $cacheTags, Mage_Core_Model_Cache::DEFAULT_LIFETIME); + + return $this; + } + + /** + * Build product filter for a category. + * + * @param array $excludedCategories Indicates if some categories should be excluded (avoid infinite loops) + * + * @return string + */ + public function getSearchQuery($excludedCategories = array()) + { + $category = $this->getCategory(); + + $cacheData = $this->getQueryFromCache($category->getId() . $category->getStoreId()); + $query = ''; + + if (!$cacheData || (!empty($excludedCategories))) { + $this->_usedCategories = array(); + $this->addUsedCategoryIds($category->getId()); + if ($category->getIsVirtual()) { + $query = $this->getConditions()->getSearchQuery($excludedCategories); + } else { + $query = array('categories:' . $category->getId()); + $childrenQueries = $this->getChildrenCategoryQueries($excludedCategories); + $query = implode(' OR ', array_merge($query, $childrenQueries)); + } + + if (empty($excludedCategories)) { + $this->cacheQuery($category->getId() . $category->getStoreId(), array($query, $this->_usedCategories)); + } + } else { + list($query, $this->_usedCategories) = $cacheData; + } + + return $query; + } + + /** + * Get all ES queries for children categories of the current categories : + * + * - Used to build category facet + * - Compute inhereted products queries + * + * @param array $excludedCategories Indicates if some categories should be excluded (avoid infinite loops) + * + * @return array + */ + public function getChildrenCategoryQueries($excludedCategories = array()) + { + $queries = array(); + + $rootCategory = $this->getCategory(); + $childrenIds = explode(',', $rootCategory->getChildren()); + $childrenIds = array_diff($childrenIds, $excludedCategories); + + $categories = Mage::getResourceModel('smile_virtualcategories/catalog_virtualCategory_collection') + ->setStoreId($rootCategory->getStoreId()) + ->addIsActiveFilter() + ->addIdFilter($childrenIds) + ->addAttributeToSelect('virtual_category'); + + foreach ($categories as $currentCategory) { + $virtualRule = $currentCategory->getVirtualRule(); + $query = $virtualRule->getSearchQuery($excludedCategories); + if ($query) { + $queries[$currentCategory->getId()] = '(' . $query . ')'; + $this->addUsedCategoryIds($virtualRule->getUsedCategoryIds()); + } + } + + return array_filter($queries); + } +} diff --git a/src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Combine.php b/src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Combine.php new file mode 100644 index 00000000..cd4e4e48 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Combine.php @@ -0,0 +1,91 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Model_Rule_Condition_Combine extends Mage_CatalogRule_Model_Rule_Condition_Combine +{ + /** + * List all available rules under a combine. + * + * @return array + */ + public function getNewChildSelectOptions() + { + $productCondition = Mage::getModel('smile_virtualcategories/rule_condition_product'); + $productAttributes = $productCondition->loadAttributeOptions()->getAttributeOption(); + $attributes = array(); + + foreach ($productAttributes as $code=>$label) { + $attributes[] = array('value' => 'smile_virtualcategories/rule_condition_product|'.$code, 'label' => $label); + } + + $conditions = array( + array( + 'value' => '', + 'label' => Mage::helper('rule')->__('Please choose a condition to add...') + ), + array( + 'value' => 'smile_virtualcategories/rule_condition_combine', + 'label' => Mage::helper('catalogrule')->__('Conditions Combination') + ), + array( + 'value' => $attributes, + 'label' => Mage::helper('catalogrule')->__('Product Attribute') + ) + ); + + return $conditions; + } + + /** + * Build search query for the rule. + * + * @param string $excludedCategories Categories that should not beein used during query building. + * + * @return string + */ + public function getSearchQuery($excludedCategories = array()) + { + $operator = 'must'; + + $ruleOperator = $this->getAggregator(); + $ruleValue = $this->getValue(); + + $conditions = array(); + + foreach ($this->getConditions() as $condition) { + $conditions[] = $condition->getSearchQuery($excludedCategories); + } + + $conditions = array_filter($conditions); + $query = false; + + if (!empty($conditions)) { + if ($ruleOperator == 'any' && $ruleValue == '1') { + $query = implode(' OR ', $conditions); + } elseif ($ruleOperator == 'any' && $ruleValue = '0') { + $query = '-(' . implode(' AND ', $conditions) . ')'; + } elseif ($ruleOperator == 'all' && $ruleValue = '1') { + $query = implode(' AND ', $conditions); + } elseif ($ruleOperator == 'all' && $ruleValue = '0') { + $query = '-(' . implode(' OR ', $conditions) . ')'; + } + } + + return $query; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Product.php b/src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Product.php new file mode 100644 index 00000000..e7d45a77 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Product.php @@ -0,0 +1,353 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +class Smile_VirtualCategories_Model_Rule_Condition_Product extends Mage_CatalogRule_Model_Rule_Condition_Product +{ + /** + * Attribute data key that indicates whether it should be used for rules + * + * @var string + */ + protected $_isUsedForRuleProperty = array('is_filterable', 'is_filterable_in_search'); + + /** + * Query templates for building Lucene queries from rule operators + * + * @var array + */ + protected $_queryTemplates = array( + '==' => '#{field}:"#{value}"', + '!=' => '-(#{field}:"#{value}")', + '>=' => '#{field}:[#{value} TO *]', + '<=' => '#{field}:[* TO #{value}]', + '>' => '#{field}:{#{value} TO *]', + '<' => '#{field}:[* TO #{value}}', + '{}' => '#{field}:#{value}*', + '!{}' => '#{field}:#{value}*' + ); + + /** + * Default operator input by type map getter + * + * @return array + */ + public function getDefaultOperatorInputByType() + { + if (null === $this->_defaultOperatorInputByType) { + parent::getDefaultOperatorInputByType(); + $this->_defaultOperatorInputByType['multiselect'] = array('()', '!()'); + } + + return $this->_defaultOperatorInputByType; + } + + /** + * Load attribute options + * + * @return Mage_CatalogRule_Model_Rule_Condition_Product + */ + public function loadAttributeOptions() + { + $productAttributes = Mage::getResourceSingleton('catalog/product') + ->loadAllAttributes() + ->getAttributesByCode(); + + $attributes = array(); + foreach ($productAttributes as $attribute) { + foreach ($this->_isUsedForRuleProperty as $usedField) { + if (!$attribute->isAllowedForRuleCondition() || !$attribute->getDataUsingMethod($usedField)) { + continue; + } + $attributes[$attribute->getAttributeCode()] = $attribute->getFrontendLabel(); + } + } + + $this->_addSpecialAttributes($attributes); + + asort($attributes); + $this->setAttributeOption($attributes); + + return $this; + } + + /** + * Build search query for the rule. + * + * @param string $excludedCategories Categories that should not beein used during query building. + * + * @return string + */ + public function getSearchQuery($excludedCategories) + { + return $this->_getSearchQuery($this->getAttribute(), $this->getEscapedValue(), $this->getOperator(), $excludedCategories); + } + + /** + * Build search query for the rule (category field implementation) + * + * @param string $value Filtered value. + * @param boolean $not Negative filter : select product not being into categories. + * @param string $excludedCategories Categories that should not beein used during query building. + * + * @return string + */ + protected function _getCategoriesSearchQuery($value, $not = false, $excludedCategories = array()) + { + if ($this->getRule()->getCategory() && $this->getRule()->getCategory()->getId()) { + $excludedCategories[] = $this->getRule()->getCategory()->getId(); + } + $query = false; + if (strpos($value, ',') !== false) { + $query = array(); + $values = explode(',', $value); + foreach ($values as $currentValue) { + $subQuery = $this->_getCategoriesSearchQuery($currentValue, false, $excludedCategories); + if (is_array($subQuery)) { + $query = array_merge($query, $subQuery); + } else { + $query[] = $subQuery; + } + } + if (!empty($query)) { + $query = '(' . implode(' OR ', $query) . ')'; + $query = $not == true ? '-' . $query : $query; + } + } else { + $category = Mage::getModel('catalog/category')->load($value); + if ($category->getId() && !in_array($value, $excludedCategories)) { + $virtualRule = $category->getVirtualRule(); + $query = '(' . $virtualRule->getSearchQuery($excludedCategories) . ')'; + $this->getRule()->addUsedCategoryIds($virtualRule->getUsedCategoryIds()); + } + } + + return $query; + } + + /** + * Create query for has_image filter. + * + * @param array $excludedCategories Categories that should not beein used during query building. + * + * @return string + */ + protected function _getHasImageQuery($excludedCategories) + { + $value = 'no_selection'; + $attribute = 'image'; + $operator = '!='; + return $this->_getSearchQuery($attribute, $value, $operator, $excludedCategories); + } + + /** + * Create query for is_new filter. + * + * @param array $excludedCategories Categories that should not beein used during query building. + * + * @return string + */ + protected function _getIsNewQuery($excludedCategories) + { + $today = Mage::getSingleton('core/date')->gmtDate(Varien_Date::DATE_PHP_FORMAT); + $parts = array( + "(news_from_date:[* TO *] OR news_to_date:[* TO *])", + "((-news_from_date:[* TO *]) OR news_from_date:[* TO $today])", + "((-news_to_date:[* TO *]) OR news_to_date:[$today TO *])" + ); + return '(' . implode(' AND ', $parts) . ')'; + } + + /** + * Build search query for the rule (category field implementation) + * + * @param string $attribute Attribute to filter. + * @param string $value Filtered value. + * @param string $operator Comparaison operator. + * @param string $excludedCategories Categories that should not beein used during query building. + * + * @return string + */ + protected function _getSearchQuery($attribute, $value, $operator, $excludedCategories) + { + $query = false; + if ($attribute == 'category_ids') { + $query = $this->_getCategoriesSearchQuery($value, substr($operator, 0, 1) == '!', $excludedCategories); + } elseif ($attribute == 'has_image') { + if ($value == 1 && $operator == "==") { + $query = $this->_getHasImageQuery($excludedCategories); + } + } elseif ($attribute == 'is_new') { + if ($value == 1 && $operator == "==") { + $query = $this->_getIsNewQuery($excludedCategories); + } + } elseif ($attribute == 'has_discount') { + if ($value == 1 && $operator == "==") { + $attribute = $this->getFilterField($attribute); + $query = $this->_getSearchQuery($attribute, $value, $operator, $excludedCategories); + } + } else if ($operator == '()' || $operator == '!()') { + $attribute = $this->getFilterField($attribute); + $template = $this->_queryTemplates['==']; + $query = array(); + $values = is_array($value) ? $value : explode(',', $value); + foreach ($values as $currentValue) { + $query[] = $this->_getSearchQuery($attribute, $currentValue, "==", $excludedCategories); + } + if (!empty($query)) { + $query = '(' . implode(' OR ', $query) . ')'; + + if ($operator == '!()') { + $query = "(-${query})"; + } + } + + } else { + $template = $this->_queryTemplates[$operator]; + $query = str_replace(array('#{field}', '#{value}'), array($attribute, $value), $template); + } + + return $query; + } + + /** + * Escape value to be used into queries + * + * @return string + */ + public function getEscapedValue() + { + $result = $this->getValue(); + $chars = array('\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '/'); + foreach ($chars as $char) { + $result = str_replace($char, '\\' . $char, $result); + } + return $result; + } + + /** + * Add special attributes + * + * @param array &$attributes List of existing attributes + * + * @return void + */ + protected function _addSpecialAttributes(array &$attributes) + { + $attributes['category_ids'] = Mage::helper('catalogrule')->__('Category'); + $attributes['in_stock'] = Mage::helper('smile_virtualcategories')->__('Only in stock products'); + $attributes['has_image'] = Mage::helper('smile_virtualcategories')->__('Only products with images'); + $attributes['has_discount'] = Mage::helper('smile_virtualcategories')->__('Only discounted products'); + $attributes['is_new'] = Mage::helper('smile_virtualcategories')->__('Only new products'); + } + + /** + * Return the ES field name to build filter. + * + * @return string + */ + public function getFilterField() + { + $fieldName = $this->getMapping()->getFieldName($this->getAttribute(), $this->getLocaleCode(), 'filter'); + + if ($this->getAttribute() == 'price' || $this->getAttribute() == 'has_discount') { + $websiteId = Mage::app()->getStore()->getWebsiteId(); + $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId(); + $fieldName = $this->getAttribute() . '_' . $customerGroupId . '_' . $websiteId; + } + + return $fieldName; + } + + /** + * Input type for the current attribute. + * + * @return string + */ + public function getInputType() + { + $specialAttributes = array('in_stock', 'has_image', 'has_discount', 'is_new'); + if (in_array($this->getAttribute(), $specialAttributes)) { + return 'select'; + } + return parent::getInputType(); + } + + /** + * Input type for the current attribute. + * + * @return string + */ + public function getValueElementType() + { + $specialAttributes = array('in_stock', 'has_image', 'has_discount', 'is_new'); + if (in_array($this->getAttribute(), $specialAttributes)) { + return 'select'; + } + return parent::getValueElementType(); + } + + /** + * Attributes options + * + * @return Smile_VirtualCategories_Model_Rule_Condition_Product + */ + protected function _prepareValueOptions() + { + $specialAttributes = array('in_stock', 'has_image', 'has_discount', 'is_new'); + if (in_array($this->getAttribute(), $specialAttributes)) { + $this->setData( + 'value_select_options', + array( + array('value' => '1', 'label' => Mage::helper('adminhtml')->__('Yes')) + ) + ); + + $this->setData( + 'value_option', + array('1' => Mage::helper('adminhtml')->__('Yes')) + ); + } else { + parent::_prepareValueOptions(); + } + + return $this; + } + + /** + * Retrieve the product mapping. + * + * @return Smile_ElasticSearch_Model_Resource_Engine_Elasticsearch_Mapping_Product + */ + public function getMapping() + { + $currentIndex = Mage::helper('catalogsearch')->getEngine()->getCurrentIndex(); + return $currentIndex->getMapping('product'); + } + + /** + * Return locale code for the current store. + * + * @return string + */ + public function getLocaleCode() + { + $store = Mage::app()->getStore(); + $languageCode = Mage::helper('smile_elasticsearch')->getLanguageCodeByStore($store); + return $languageCode; + } +} \ No newline at end of file diff --git a/src/app/code/community/Smile/VirtualCategories/etc/config.xml b/src/app/code/community/Smile/VirtualCategories/etc/config.xml new file mode 100644 index 00000000..0e8c0e0a --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/etc/config.xml @@ -0,0 +1,128 @@ + + + + + + 1.0.0 + + + + + + Smile_VirtualCategories_Model + smile_virtualcategories_resource + + + Smile_VirtualCategories_Model_Resource + + + + + Smile_VirtualCategories_Helper + + + + + Smile_VirtualCategories_Block + + + + Smile_VirtualCategories_Block_Adminhtml_Override_Catalog_Category_Tabs + Smile_VirtualCategories_Block_Adminhtml_Override_Catalog_Category_Tree + + + + + + + Smile_VirtualCategories + Mage_Catalog_Model_Resource_Setup + + + + + + + + + + Smile_VirtualCategories_Adminhtml + + + + + + + + + + + smile_virtualcategories/observer + prepareCategorySave + + + + + + + + smile/virtualcategories.xml + + + + + + + + Smile_VirtualCategories.csv + + + + + + + + + + smile/virtualcategories.xml + + + + + + + + smile_virtualcategories/observer + prepareCategoryFilter + + + + + + + smile_virtualcategories/observer + prepareCategoryFacet + + + + + + diff --git a/src/app/code/community/Smile/VirtualCategories/sql/smile_virtualcategories_setup/install-1.0.0.php b/src/app/code/community/Smile/VirtualCategories/sql/smile_virtualcategories_setup/install-1.0.0.php new file mode 100644 index 00000000..9b8f9c73 --- /dev/null +++ b/src/app/code/community/Smile/VirtualCategories/sql/smile_virtualcategories_setup/install-1.0.0.php @@ -0,0 +1,48 @@ + previous module + * available at https://github.com/jreinke/magento-elasticsearch + * + * @category Smile + * @package Smile_VirtualCategories + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + +/** + * @var Mage_Catalog_Model_Resource_Setup + */ +$installer = $this; +$installer->startSetup(); + +$entityTypeId = $installer->getEntityTypeId('catalog_category'); +$defaultAttributeSetId = $this->getDefaultAttributeSetId($entityTypeId); +$defaultGroup = $this->getAttributeGroup($entityTypeId, $defaultAttributeSetId, 'General Information'); + +$installer->addAttribute( + $entityTypeId, + 'virtual_category', + array( + 'type' => 'text', + 'label' => 'Virtual category configuration', + 'enabled' => true, + 'is_enabled' => true, + 'input' => 'hidden', + 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, + 'required' => false, + 'visible' => true, + 'backend' => 'smile_virtualcategories/category_attributes_backend_virtual' + ) +); + +$installer->addAttributeToSet($entityTypeId, $defaultAttributeSetId, $defaultGroup['attribute_group_id'], 'virtual_category', 200); + +$installer->endSetup(); diff --git a/src/app/design/adminhtml/default/default/layout/smile/elasticsearch.xml b/src/app/design/adminhtml/default/default/layout/smile/elasticsearch.xml new file mode 100644 index 00000000..586e502e --- /dev/null +++ b/src/app/design/adminhtml/default/default/layout/smile/elasticsearch.xml @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/src/app/design/adminhtml/default/default/layout/smile/searchoptimizer.xml b/src/app/design/adminhtml/default/default/layout/smile/searchoptimizer.xml new file mode 100644 index 00000000..6f96b23f --- /dev/null +++ b/src/app/design/adminhtml/default/default/layout/smile/searchoptimizer.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + 1 + + + + + + + diff --git a/src/app/design/adminhtml/default/default/layout/smile/virtualcategories.xml b/src/app/design/adminhtml/default/default/layout/smile/virtualcategories.xml new file mode 100644 index 00000000..0687f3a2 --- /dev/null +++ b/src/app/design/adminhtml/default/default/layout/smile/virtualcategories.xml @@ -0,0 +1,24 @@ + + + + + + 1 + + + \ No newline at end of file diff --git a/src/app/design/adminhtml/default/default/template/smile/elasticsearch/catalog/product/attribute/js.phtml b/src/app/design/adminhtml/default/default/template/smile/elasticsearch/catalog/product/attribute/js.phtml new file mode 100644 index 00000000..2a2f5d2c --- /dev/null +++ b/src/app/design/adminhtml/default/default/template/smile/elasticsearch/catalog/product/attribute/js.phtml @@ -0,0 +1,326 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> + diff --git a/src/app/design/adminhtml/default/default/template/smile/virtualcategories/category/product_select_form.phtml b/src/app/design/adminhtml/default/default/template/smile/virtualcategories/category/product_select_form.phtml new file mode 100644 index 00000000..97c7e44d --- /dev/null +++ b/src/app/design/adminhtml/default/default/template/smile/virtualcategories/category/product_select_form.phtml @@ -0,0 +1,50 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +
+ getFormHtml();?> +
+getChildHtml('form_after');?> + + \ No newline at end of file diff --git a/src/app/design/adminhtml/default/default/template/smile/virtualcategories/category/rule_fieldset.phtml b/src/app/design/adminhtml/default/default/template/smile/virtualcategories/category/rule_fieldset.phtml new file mode 100644 index 00000000..8c431a4e --- /dev/null +++ b/src/app/design/adminhtml/default/default/template/smile/virtualcategories/category/rule_fieldset.phtml @@ -0,0 +1,33 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +getElement() ?> +
+
+

getLegend() ?>

+
+
serialize(array('class')) ?>> + getComment()): ?> +

escapeHtml($_element->getComment()) ?>

+ + getChildrenHtml() ?> +
+
+ diff --git a/src/app/design/frontend/base/default/layout/smile/elasticsearch.xml b/src/app/design/frontend/base/default/layout/smile/elasticsearch.xml new file mode 100644 index 00000000..6331ed2d --- /dev/null +++ b/src/app/design/frontend/base/default/layout/smile/elasticsearch.xml @@ -0,0 +1,107 @@ + + + + + + + + css/smile/elasticsearch.css + + + + + + + + + + + + price + rating_filter + + + + + + + + + + + + + + price + rating_filter + + + + + + + + + + + + + empty6 + one_column5 + two_columns_left4 + two_columns_right4 + three_columns3 + product_list_toolbar + three_columns + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/design/frontend/base/default/layout/smile/tracker.xml b/src/app/design/frontend/base/default/layout/smile/tracker.xml new file mode 100644 index 00000000..708269a7 --- /dev/null +++ b/src/app/design/frontend/base/default/layout/smile/tracker.xml @@ -0,0 +1,66 @@ + + + + + + + jssmile/tracker/boomerang/boomerang.jsis_smile_tracker_enabled + jssmile/tracker/tracking.jsis_smile_tracker_enabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/autocomplete.phtml b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/autocomplete.phtml new file mode 100644 index 00000000..963ce30c --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/autocomplete.phtml @@ -0,0 +1,18 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +
+ getChildHtml('complete_list'); ?> +
\ No newline at end of file diff --git a/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/form.mini.phtml b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/form.mini.phtml new file mode 100644 index 00000000..ad6f6a8c --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/form.mini.phtml @@ -0,0 +1,30 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +helper('catalogsearch'); +?> +
+ +
diff --git a/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/suggest/category.phtml b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/suggest/category.phtml new file mode 100644 index 00000000..e1b55681 --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/suggest/category.phtml @@ -0,0 +1,26 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + ?> + +isActive()) : ?> + getCategoryCollection(); ?> + getSize() > 0) : ?> +
__('Category'); ?>
+ +
getOutputText(); ?>
+ + + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + ?> + +isActive()) : ?> + getProductCollection(); ?> + getSize() > 0) : ?> +
__('Products'); ?>
+ getProductCollection() as $product) : ?> +
getName(); ?>
+ + + \ No newline at end of file diff --git a/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/suggest/terms.phtml b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/suggest/terms.phtml new file mode 100644 index 00000000..0a97c7cf --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/elasticsearch/autocomplete/suggest/terms.phtml @@ -0,0 +1,24 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +getSuggestData(); ?> + + 0): ?> +
__('Popular searches')?>
+ + escapeHtml($suggestion['title']); ?> +
+ + diff --git a/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter.phtml b/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter.phtml new file mode 100644 index 00000000..d4b14a30 --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter.phtml @@ -0,0 +1,30 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +
    +getItems() as $_item): ?> +
  1. + + getIsMultipleSelect()) : ?> + getSelected()) : ?>checked onclick="this.parentNode.click();"/> + + + + shouldDisplayProductCount()): ?> + (getCount() ?>) + +
  2. + +
diff --git a/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter/price.phtml b/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter/price.phtml new file mode 100644 index 00000000..95c516f4 --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter/price.phtml @@ -0,0 +1,143 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +
+
+ + +
+
+
+
+
+
+
+ +
+
+ + \ No newline at end of file diff --git a/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter/rating.phtml b/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter/rating.phtml new file mode 100644 index 00000000..5ca15f35 --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/elasticsearch/catalog/layer/filter/rating.phtml @@ -0,0 +1,35 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +
    +getItems() as $_item): ?> +
  1. + getCount() > 0): ?> + +
    +
    +
    + getLabel() < 100) : ?> + __('and more')?> + +
    + getLabel() ?> + + shouldDisplayProductCount()): ?> + (getCount() ?>) + +
  2. + +
diff --git a/src/app/design/frontend/base/default/template/smile/tracker/config.phtml b/src/app/design/frontend/base/default/template/smile/tracker/config.phtml new file mode 100644 index 00000000..0008b8ff --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/tracker/config.phtml @@ -0,0 +1,31 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> + +isEnabled()) : ?> + + \ No newline at end of file diff --git a/src/app/design/frontend/base/default/template/smile/tracker/variables/checkout.phtml b/src/app/design/frontend/base/default/template/smile/tracker/variables/checkout.phtml new file mode 100644 index 00000000..30ed291d --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/tracker/variables/checkout.phtml @@ -0,0 +1,21 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> + + diff --git a/src/app/design/frontend/base/default/template/smile/tracker/variables/page.phtml b/src/app/design/frontend/base/default/template/smile/tracker/variables/page.phtml new file mode 100644 index 00000000..0922a5ef --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/tracker/variables/page.phtml @@ -0,0 +1,26 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +getVariables(); ?> + + + + diff --git a/src/app/design/frontend/base/default/template/smile/tracker/variables/session.phtml b/src/app/design/frontend/base/default/template/smile/tracker/variables/session.phtml new file mode 100644 index 00000000..35c7fee3 --- /dev/null +++ b/src/app/design/frontend/base/default/template/smile/tracker/variables/session.phtml @@ -0,0 +1,26 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +getVariables(); ?> + + + + diff --git a/src/app/design/frontend/rwd/default/layout/smile/elasticsearch.xml b/src/app/design/frontend/rwd/default/layout/smile/elasticsearch.xml new file mode 100644 index 00000000..631840f3 --- /dev/null +++ b/src/app/design/frontend/rwd/default/layout/smile/elasticsearch.xml @@ -0,0 +1,112 @@ + + + + + + + + css/smile/elasticsearch.css + + + + + + + + + + + + + price + rating_filter + + + + + + + + + + + + + + + price + rating_filter + + + + + + + + + + + + + + + + empty6 + one_column5 + two_columns_left4 + two_columns_right4 + three_columns3 + product_list_toolbar + three_columns + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/design/frontend/rwd/default/template/smile/elasticsearch/catalog/layer/filter.phtml b/src/app/design/frontend/rwd/default/template/smile/elasticsearch/catalog/layer/filter.phtml new file mode 100644 index 00000000..fd7c3055 --- /dev/null +++ b/src/app/design/frontend/rwd/default/template/smile/elasticsearch/catalog/layer/filter.phtml @@ -0,0 +1,31 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> + +
    +getItems() as $_item): ?> +
  1. + + getIsMultipleSelect()) : ?> + getSelected()) : ?>checked onclick="this.parentNode.click();"/> + + + shouldDisplayProductCount()): ?> + (getCount() ?>) + + +
  2. + +
\ No newline at end of file diff --git a/src/app/design/frontend/rwd/default/template/smile/elasticsearch/catalog/layer/filter/rating.phtml b/src/app/design/frontend/rwd/default/template/smile/elasticsearch/catalog/layer/filter/rating.phtml new file mode 100644 index 00000000..b52774e0 --- /dev/null +++ b/src/app/design/frontend/rwd/default/template/smile/elasticsearch/catalog/layer/filter/rating.phtml @@ -0,0 +1,35 @@ + + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */?> +
    +getItems() as $_item): ?> +
  1. + getCount() > 0): ?> + +
    +
    +
    + getLabel() < 100) : ?> + __('and up')?> + + shouldDisplayProductCount()): ?> + (getCount() ?>) + +
    + getLabel() ?> + +
  2. + +
diff --git a/src/app/etc/modules/Smile_SearchandisingSuite.xml b/src/app/etc/modules/Smile_SearchandisingSuite.xml new file mode 100644 index 00000000..f630e7e1 --- /dev/null +++ b/src/app/etc/modules/Smile_SearchandisingSuite.xml @@ -0,0 +1,60 @@ + + + + + + + false + core + + + + + + + true + community + + + + true + community + + + + + + + true + community + + + + + + + + true + community + + + + + + + diff --git a/src/app/locale/en_US/Smile_ElasticSearch.csv b/src/app/locale/en_US/Smile_ElasticSearch.csv new file mode 100644 index 00000000..69d0ab83 --- /dev/null +++ b/src/app/locale/en_US/Smile_ElasticSearch.csv @@ -0,0 +1,32 @@ +"Smile Searchandising Suite","Smile Searchandising Suite" +"Search Weight","Search Weight" +"Search Engine","Search Engine", +"Enable Debug Mode","Enable Debug Mode" +"If set yo yes, will display potential error messages in frontend.","If set yo yes, will display potential error messages in frontend." +"Servers","Servers" +"host:port separated by comma.","host:port separated by comma." +"Server Timeout","Server Timeout" +"Number of seconds after a timeout occurs for every request. If using indexing of file, large value necessary","Number of seconds after a timeout occurs for every request. If using indexing of file, large value necessary" +"Alias Name","Alias Name" +"Without starting and trailing slashes.","Without starting and trailing slashes." +"Number of Shards","Number of Shards" +"Having more shards enhances the indexing performance and allows to distribute a big index across machines.","Having more shards enhances the indexing performance and allows to distribute a big index across machines." +"Number of Replicas","Number of Replicas" +"The number of replicas each shard has. Having more replicas enhances the search performance and improves the cluster availability.
Be careful when modifying this parameter. Write consistency (one, quorum or all) must be considered in order to avoid timeout write action. More info here: http://www.elasticsearch.org/guide/reference/api/bulk.html and https://github.com/elasticsearch/elasticsearch/issues/444","The number of replicas each shard has. Having more replicas enhances the search performance and improves the cluster availability.
Be careful when modifying this parameter. Write consistency (one, quorum or all) must be considered in order to avoid timeout write action. More info here: http://www.elasticsearch.org/guide/reference/api/bulk.html and https://github.com/elasticsearch/elasticsearch/issues/444" +"Default write consistency is quorum (active shards > replicas / 2 + 1).
For example, in a N shards with 2 replicas index, there will have to be at least 2 active shards within the relevant partition (quorum) for the operation to succeed. In a N shards with 1 replica scenario, there will need to be a single shard active (in this case, one and quorum is the same).","Default write consistency is quorum (active shards > replicas / 2 + 1).
For example, in a N shards with 2 replicas index, there will have to be at least 2 active shards within the relevant partition (quorum) for the operation to succeed. In a N shards with 1 replica scenario, there will need to be a single shard active (in this case, one and quorum is the same)." +"Facets Max Size","Facets Max Size" +"Max number of values returned by a facet query.","Max number of values returned by a facet query." +"Enable Search on Options Labels","Enable Search on Options Labels" +"If enabled, will also search on product options labels.","If enabled, will also search on product options labels." +"Enable ICU Folding Token Filter","Enable ICU Folding Token Filter" +"Needs ICU plugin installation: https://github.com/elasticsearch/elasticsearch-analysis-icu","Needs ICU plugin installation: https://github.com/elasticsearch/elasticsearch-analysis-icu" +"Enable Fuzzy Query","Enable Fuzzy Query" +"Enables approximative search: http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html","Enables approximative search: http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html" +"Fuzzy Min Similarity","Fuzzy Min Similarity" +"0 to 1 (1 excluded). Low value affects query performance. Default value in Elasticsearch: 0.5.","0 to 1 (1 excluded). Low value affects query performance. Default value in Elasticsearch: 0.5." +"Fuzzy Prefix Length","Fuzzy Prefix Length" +"Length of required common prefix on variant terms. Default value in Elasticsearch: 0.","Length of required common prefix on variant terms. Default value in Elasticsearch: 0." +"Fuzzy Max Expansions","Fuzzy Max Expansions" +"High value affects query performance. Default value in Elasticsearch: 25.","High value affects query performance. Default value in Elasticsearch: 25." +"Fuzzy Query Boost","Fuzzy Query Boost" +"Sets the boost value of the query. Default value in Elasticsearch: 1.","Sets the boost value of the query. Default value in Elasticsearch: 1." \ No newline at end of file diff --git a/src/app/locale/en_US/Smile_SearchandisingSuite.csv b/src/app/locale/en_US/Smile_SearchandisingSuite.csv new file mode 100644 index 00000000..9aad9b00 --- /dev/null +++ b/src/app/locale/en_US/Smile_SearchandisingSuite.csv @@ -0,0 +1,5 @@ +"Smile Searchandising General Section","Smile Searchandising General Section" +"Smile Searchandasing Suite","Smile Searchandasing Suite" +"General","General" +"Site configuration","Site configuration" +"Site Id","Site Id" diff --git a/src/app/locale/en_US/Smile_Tracker.csv b/src/app/locale/en_US/Smile_Tracker.csv new file mode 100644 index 00000000..e010e36c --- /dev/null +++ b/src/app/locale/en_US/Smile_Tracker.csv @@ -0,0 +1,11 @@ +"Smile Tracker Section","Smile Tracker Section" +"Tracking","Tracking" +"Global Configuration","Global Configuration" +"Tracking base URL","Tracking base URL" +"Session","Session" +"Visit cookie name","Visit cookie name" +"Visit cookie lifetime","Visit cookie lifetime" +"Visitor cookie name","Visitor cookie name" +"Visitor cookie lifetime","Visitor cookie lifetime" +"In seconds (default is 3600 sec.).
Without any activity under this delay we start a new visit.","In seconds (default is 3600 sec.).
Without any activity under this delay we start a new visit." +"In day (default is 365 days).
This cookie will be stick to the customer to allow multiple session aggregation.","In day (default is 365 sec.).
This cookie will be stick to the customer to allow multiple session aggregation." \ No newline at end of file diff --git a/src/app/locale/fr_FR/Smile_ElasticSearch.csv b/src/app/locale/fr_FR/Smile_ElasticSearch.csv new file mode 100644 index 00000000..52f72f6e --- /dev/null +++ b/src/app/locale/fr_FR/Smile_ElasticSearch.csv @@ -0,0 +1,32 @@ +"Smile Searchandising Suite","Smile Searchandising Suite" +"Search Weight","Pondération dans la recherche" +"Search Engine","Moteur de recherche", +"Enable Debug Mode","Activer le mode débogage" +"If set yo yes, will display potential error messages in frontend.","Si placer sur oui, affiche les messages d'erreur en front-office." +"Servers","Serveurs" +"host:port separated by comma.","host:port séparés par des virgules." +"Server Timeout","Timeout" +"Number of seconds after a timeout occurs for every request. If using indexing of file, large value necessary","Nombre de seconces après lesquelles un timeout se produit. Utiliser des valeurs élevées si vous indexez des fichiers." +"Alias Name","Nom de l'alias" +"Without starting and trailing slashes.","Ne pas utiser de / au début ni à la fin." +"Number of Shards","Nombres de shards" +"Having more shards enhances the indexing performance and allows to distribute a big index across machines.","Utiliser plus de shards permet d'améliorer les performances d'indexation et de répartir l'index sur plusieurs machines." +"Number of Replicas","Nombre de réplicas" +"The number of replicas each shard has. Having more replicas enhances the search performance and improves the cluster availability.
Be careful when modifying this parameter. Write consistency (one, quorum or all) must be considered in order to avoid timeout write action. More info here: http://www.elasticsearch.org/guide/reference/api/bulk.html and https://github.com/elasticsearch/elasticsearch/issues/444","Le nombre de réplicas de chaque shards. Un nombre plus important de réplicas améliore les performances de recherche ainsi que la tolérance à la panne.
Soyez prudent si vous modifiez ce paramètre. Le paramétrage de la cohérence en écriture (one, quorum or all) doit être pris en compte pour éviter les problèmes de timeout lors de l'indexation. Plus d'informations : http://www.elasticsearch.org/guide/reference/api/bulk.html et https://github.com/elasticsearch/elasticsearch/issues/444" +"Default write consistency is quorum (active shards > replicas / 2 + 1).
For example, in a N shards with 2 replicas index, there will have to be at least 2 active shards within the relevant partition (quorum) for the operation to succeed. In a N shards with 1 replica scenario, there will need to be a single shard active (in this case, one and quorum is the same).","Le paramétrage par défault de la cohérence en écriture est quorum (active shards > replicas / 2 + 1).
Par exemple, pour un index avec N shards et 2 replicas, il doit y avoir au moins deux shars actifs pour (quorum) pour que l'opération soit un succès. Dans un scénario avec N shards et 1 replica, vous avez besoin d'un seul shard actif (dans ce cas, one et quorum sont équivalents)." +"Facets Max Size","Taille maximale des facettes" +"Max number of values returned by a facet query.","Nombre maximal de valeurs retournées par une requête de facette" +"Enable Search on Options Labels","Activer la recherche sur les labels des options" +"If enabled, will also search on product options labels.","Si activé, la recherche sera aussi effectuée sur les labels des options." +"Enable ICU Folding Token Filter","Activer le plugin ICU" +"Needs ICU plugin installation: https://github.com/elasticsearch/elasticsearch-analysis-icu","Le plugin ICU doit être installé: https://github.com/elasticsearch/elasticsearch-analysis-icu" +"Enable Fuzzy Query","Activer la recherche approchante" +"Enables approximative search: http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html","Plus d'informations : http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html" +"Fuzzy Min Similarity","Similarité minimale pour la recherche approchante" +"0 to 1 (1 excluded). Low value affects query performance. Default value in Elasticsearch: 0.5.","Entre 0 et 1 (1 exclus). Les valeurs faibles réduisent la pertinence. Valeur par défaut d'Elasticsearch: 0.5." +"Fuzzy Prefix Length","Prefixe de la recherche approchante" +"Length of required common prefix on variant terms. Default value in Elasticsearch: 0.","Longueur minimale du prefix commun des termes approchants. Valeur par défaut d'Elasticsearch: 1." +"Fuzzy Max Expansions","Nombre d'expansions de la recherche approchante" +"High value affects query performance. Default value in Elasticsearch: 25.","Les valeurs élevées réduisent la pertinence. Valeur par défaut d'Elasticsearch: 25." +"Fuzzy Query Boost","Boost de la recherche approchante" +"Sets the boost value of the query. Default value in Elasticsearch: 1.","Valeur du boost de la recherche approchante. Valeur par défaut d'Elasticsearch: 1." \ No newline at end of file diff --git a/src/app/locale/fr_FR/Smile_SearchandisingSuite.csv b/src/app/locale/fr_FR/Smile_SearchandisingSuite.csv new file mode 100644 index 00000000..e524d5c2 --- /dev/null +++ b/src/app/locale/fr_FR/Smile_SearchandisingSuite.csv @@ -0,0 +1,5 @@ +"Smile Searchandising General Section","Section générale de Smile Searchandasing Suite" +"Smile Searchandasing Suite","Smile Searchandasing Suite" +"General","Général" +"Site configuration","Configuration du site" +"Site Id","Id du site" diff --git a/src/app/locale/fr_FR/Smile_Tracker.csv b/src/app/locale/fr_FR/Smile_Tracker.csv new file mode 100644 index 00000000..cfc5d56f --- /dev/null +++ b/src/app/locale/fr_FR/Smile_Tracker.csv @@ -0,0 +1,11 @@ +"Smile Tracker Section","Section tracking de Smile Searchandising Suite" +"Tracking","Tracking" +"Global Configuration","Configuation générale" +"Tracking base URL","URL de base du tracking" +"Session","Session" +"Visit cookie name","Nom du cookie de visite" +"Visit cookie lifetime","Durée de vie du cookie de visite" +"Visitor cookie name","Nom du cookie visiteur" +"Visitor cookie lifetime","Durée de vie du cookie visiteur" +"In seconds (default is 3600 sec.).
Without any activity under this delay we start a new visit.","En secondes (Valeur par défaut 3600 s.).
Sans activité durant ce délai une nouvelle visite est prise en compte." +"In day (default is 365 days).
This cookie will be stick to the customer to allow multiple session aggregation.","En jours (Valeur par défaut 365 jours.).
Ce cookie permet de consolider les multiples visites d'une même personne." \ No newline at end of file diff --git a/src/js/smile/elasticsearch/search.js b/src/js/smile/elasticsearch/search.js new file mode 100644 index 00000000..b62ceed1 --- /dev/null +++ b/src/js/smile/elasticsearch/search.js @@ -0,0 +1,101 @@ +/** + * ElasticSearch features javascript + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Smile Searchandising Suite to newer + * versions in the future. + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + +Es = {}; + +Es.searchForm = Class.create(Varien.searchForm, { + initAutocomplete : function(url, destinationElement) { + new MultipleAutoCompleter(this.field, destinationElement, url, { + paramName : this.field.name, + method : 'get', + minChars : 2, + updateElement : this._selectAutocompleteItem.bind(this), + onShow : function(element, update) { + if (!update.style.position + || update.style.position == 'absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight : false, + offsetTop : element.offsetHeight + }); + } + Effect.Appear(update, { + duration : 0 + }); + }, + autoSelect : false + }); + }, + _selectAutocompleteItem : function(element) { + if (element.hasAttribute('href')) { + window.location = element.getAttribute('href'); + } else { + if (element.title) { + this.field.value = element.title; + } + this.form.submit(); + } + } +}); + +MultipleAutoCompleter = Class.create(Ajax.Autocompleter, { + getEntry : function(index) { + return this.update.firstChild.select('dd')[index]; + }, + updateChoices : function(choices) { + if (!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if (this.update.firstChild && this.update.firstChild.select('dd')) { + this.entryCount = this.update.firstChild.select('dd').length; + for ( var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + + // Avoid automatic first suggestion selection + this.index = -1; + + if (this.entryCount == 1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + onHover : function(event) { + var element = Event.findElement(event, 'DD'); + this.index = element.autocompleteIndex; + this.render(); + Event.stop(event); + }, + + onClick : function(event) { + var element = Event.findElement(event, 'DD'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + } +}); \ No newline at end of file diff --git a/src/js/smile/tracker/boomerang/boomerang.js b/src/js/smile/tracker/boomerang/boomerang.js new file mode 100644 index 00000000..54221991 --- /dev/null +++ b/src/js/smile/tracker/boomerang/boomerang.js @@ -0,0 +1,1403 @@ +/* + * Copyright (c) 2011, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the BSD License. See the accompanying LICENSE.txt file for terms. + */ + +/** +\file boomerang.js +boomerang measures various performance characteristics of your user's browsing +experience and beacons it back to your server. + +\details +To use this you'll need a web site, lots of users and the ability to do +something with the data you collect. How you collect the data is up to +you, but we have a few ideas. +*/ + +// Measure the time the script started +// This has to be global so that we don't wait for the entire +// BOOMR function to download and execute before measuring the +// time. We also declare it without `var` so that we can later +// `delete` it. This is the only way that works on Internet Explorer +BOOMR_start = new Date().getTime(); + +// beaconing section +// the parameter is the window +(function(w) { + +var impl, boomr, k, d=w.document; + +// Short namespace because I don't want to keep typing BOOMERANG +if(typeof BOOMR === "undefined") { + BOOMR = {}; +} +// don't allow this code to be included twice +if(BOOMR.version) { + return; +} + +BOOMR.version = "0.9.1383147459"; + + +// impl is a private object not reachable from outside the BOOMR object +// users can set properties by passing in to the init() method +impl = { + // properties + beacon_url: "", + // strip out everything except last two parts of hostname. + // This doesn't work well for domains that end with a country tld, + // but we allow the developer to override site_domain for that. + site_domain: w.location.hostname. + replace(/.*?([^.]+\.[^.]+)\.?$/, '$1'). + toLowerCase(), + //! User's ip address determined on the server. Used for the BA cookie + user_ip: '', + + events: { + "page_ready": [], + "page_unload": [], + "visibility_changed": [], + "before_beacon": [] + }, + + vars: {}, + + disabled_plugins: {}, + + fireEvent: function(e_name, data) { + var i, h, e; + if(!this.events.hasOwnProperty(e_name)) { + return false; + } + + e = this.events[e_name]; + + for(i=0; i= 0 ) { + i += name.length; + cookies = cookies.substring(i, cookies.indexOf(';', i)); + return cookies; + } + + return null; + }, + + setCookie: function(name, subcookies, max_age, path, domain, sec) { + var value = "", + k, nameval, c, + exp = ""; + + if(!name) { + return false; + } + + for(k in subcookies) { + if(subcookies.hasOwnProperty(k)) { + value += '&' + encodeURIComponent(k) + + '=' + encodeURIComponent(subcookies[k]); + } + } + value = value.replace(/^&/, ''); + + if(max_age) { + exp = new Date(); + exp.setTime(exp.getTime() + max_age*1000); + exp = exp.toGMTString(); + } + + nameval = name + '=' + value; + c = nameval + + ((max_age) ? "; expires=" + exp : "" ) + + ((path) ? "; path=" + path : "") + + ((typeof domain !== "undefined") ? "; domain=" + + (domain !== null ? domain : impl.site_domain ) : "") + + ((sec) ? "; secure" : ""); + + if ( nameval.length < 4000 ) { + d.cookie = c; + // confirm cookie was set (could be blocked by user's settings, etc.) + return ( value === this.getCookie(name) ); + } + + return false; + }, + + getSubCookies: function(cookie) { + var cookies_a, + i, l, kv, + cookies={}; + + if(!cookie) { + return null; + } + + cookies_a = cookie.split('&'); + + if(cookies_a.length === 0) { + return null; + } + + for(i=0, l=cookies_a.length; i0); + } + }, + + init: function(config) { + var i, k, + properties = ["beacon_url", "site_domain", "user_ip"]; + + if(!config) { + config = {}; + } + + for(i=0; i -1)?'&':'?') + + 'page.u=' + encodeURIComponent(d.URL.replace(/#.*/, '')); + // use d.URL instead of location.href because of a safari bug + + for(k in impl.vars) { + if(impl.vars.hasOwnProperty(k)) { + var paramName = k; + if (!k.startsWith('page') && !k .startsWith('session')) { + paramName = 'page.rum.' + k; + } + nparams++; + url += "&" + paramName + + "=" + + ( + impl.vars[k]===undefined || impl.vars[k]===null + ? '' + : encodeURIComponent(impl.vars[k]) + ); + } + } + + // only send beacon if we actually have something to beacon back + if(nparams) { + img = new Image(); + img.src=url; + } + + return this; + } + +}; + +delete BOOMR_start; + +var make_logger = function(l) { + return function(m, s) { + this.log(m, l, "boomerang" + (s?"."+s:"")); return this; + }; +}; + +boomr.debug = make_logger("debug"); +boomr.info = make_logger("info"); +boomr.warn = make_logger("warn"); +boomr.error = make_logger("error"); + +if(w.YAHOO && w.YAHOO.widget && w.YAHOO.widget.Logger) { + boomr.log = w.YAHOO.log; +} +else if(typeof w.Y !== "undefined" && typeof w.Y.log !== "undefined") { + boomr.log = w.Y.log; +} +else if(typeof console !== "undefined" && typeof console.log !== "undefined") { + boomr.log = function(m,l,s) { console.log(s + ": [" + l + "] ", m); }; +} + + +for(k in boomr) { + if(boomr.hasOwnProperty(k)) { + BOOMR[k] = boomr[k]; + } +} + +BOOMR.plugins = BOOMR.plugins || {}; + +}(window)); + + +// end of boomerang beaconing section +// Now we start built in plugins. + + +// This is the Round Trip Time plugin. Abbreviated to RT +// the parameter is the window +(function(w) { + +var d=w.document; + +BOOMR = BOOMR || {}; +BOOMR.plugins = BOOMR.plugins || {}; + +// private object +var impl = { + complete: false, //! Set when this plugin has completed + + timers: {}, //! Custom timers that the developer can use + // Format for each timer is { start: XXX, end: YYY, delta: YYY-XXX } + cookie: 'RT', //! Name of the cookie that stores the start time and referrer + cookie_exp:600, //! Cookie expiry in seconds + strict_referrer: true, //! By default, don't beacon if referrers don't match. + // If set to false, beacon both referrer values and let + // the back end decide + + navigationType: 0, + navigationStart: undefined, + responseStart: undefined, + + // The start method is fired on page unload. It is called with the scope + // of the BOOMR.plugins.RT object + start: function() { + var t_end, t_start = new Date().getTime(); + + // Disable use of RT cookie by setting its name to a falsy value + if(!this.cookie) { + return this; + } + + // We use document.URL instead of location.href because of a bug in safari 4 + // where location.href is URL decoded + if(!BOOMR.utils.setCookie(this.cookie, + { s: t_start, r: d.URL.replace(/#.*/, '') }, + this.cookie_exp, + "/", null) + ) { + BOOMR.error("cannot set start cookie", "rt"); + return this; + } + + t_end = new Date().getTime(); + if(t_end - t_start > 50) { + // It took > 50ms to set the cookie + // The user Most likely has cookie prompting turned on so + // t_start won't be the actual unload time + // We bail at this point since we can't reliably tell t_done + BOOMR.utils.removeCookie(this.cookie); + + // at some point we may want to log this info on the server side + BOOMR.error("took more than 50ms to set cookie... aborting: " + + t_start + " -> " + t_end, "rt"); + } + + return this; + }, + + initNavTiming: function() { + var ti, p, source; + + if(this.navigationStart) { + return; + } + + // Get start time from WebTiming API see: + // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html + // http://blogs.msdn.com/b/ie/archive/2010/06/28/measuring-web-page-performance.aspx + // http://blog.chromium.org/2010/07/do-you-know-how-slow-your-web-page-is.html + p = w.performance || w.msPerformance || w.webkitPerformance || w.mozPerformance; + + if(p && p.navigation) { + this.navigationType = p.navigation.type; + } + + if(p && p.timing) { + ti = p.timing; + } + else if(w.chrome && w.chrome.csi && w.chrome.csi().startE) { + // Older versions of chrome also have a timing API that's sort of documented here: + // http://ecmanaut.blogspot.com/2010/06/google-bom-feature-ms-since-pageload.html + // source here: + // http://src.chromium.org/viewvc/chrome/trunk/src/chrome/renderer/loadtimes_extension_bindings.cc?view=markup + ti = { + navigationStart: w.chrome.csi().startE + }; + source = "csi"; + } + else if(w.gtbExternal && w.gtbExternal.startE()) { + // The Google Toolbar exposes navigation start time similar to old versions of chrome + // This would work for any browser that has the google toolbar installed + ti = { + navigationStart: w.gtbExternal.startE() + }; + source = 'gtb'; + } + + if(ti) { + // Always use navigationStart since it falls back to fetchStart + // If not set, we leave t_start alone so that timers that depend + // on it don't get sent back. Never use requestStart since if + // the first request fails and the browser retries, it will contain + // the value for the new request. + BOOMR.addVar("rt.start", source || "navigation"); + this.navigationStart = ti.navigationStart || undefined; + this.responseStart = ti.responseStart || undefined; + + // bug in Firefox 7 & 8 https://bugzilla.mozilla.org/show_bug.cgi?id=691547 + if(navigator.userAgent.match(/Firefox\/[78]\./)) { + this.navigationStart = ti.unloadEventStart || ti.fetchStart || undefined; + } + } + else { + BOOMR.warn("This browser doesn't support the WebTiming API", "rt"); + } + + return; + } +}; + +BOOMR.plugins.RT = { + // Methods + + init: function(config) { + impl.complete = false; + impl.timers = {}; + + BOOMR.utils.pluginConfig(impl, config, "RT", + ["cookie", "cookie_exp", "strict_referrer"]); + + BOOMR.subscribe("page_ready", this.done, null, this); + BOOMR.subscribe("page_unload", impl.start, null, impl); + + if(BOOMR.t_start) { + // How long does it take Boomerang to load up and execute + this.startTimer('boomerang', BOOMR.t_start); + this.endTimer('boomerang', BOOMR.t_end); // t_end === null defaults to current time + + // How long did it take till Boomerang started + this.endTimer('boomr_fb', BOOMR.t_start); + } + + return this; + }, + + startTimer: function(timer_name, time_value) { + if(timer_name) { + if (timer_name === 't_page') { + this.endTimer('t_resp', time_value); + } + impl.timers[timer_name] = {start: (typeof time_value === "number" ? time_value : new Date().getTime())}; + impl.complete = false; + } + + return this; + }, + + endTimer: function(timer_name, time_value) { + if(timer_name) { + impl.timers[timer_name] = impl.timers[timer_name] || {}; + if(!("end" in impl.timers[timer_name])) { + impl.timers[timer_name].end = + (typeof time_value === "number" ? time_value : new Date().getTime()); + } + } + + return this; + }, + + setTimer: function(timer_name, time_delta) { + if(timer_name) { + impl.timers[timer_name] = { delta: time_delta }; + } + + return this; + }, + + // Called when the page has reached a "usable" state. This may be when the + // onload event fires, or it could be at some other moment during/after page + // load when the page is usable by the user + done: function() { + var t_start, r, r2, + subcookies, basic_timers = { t_done: 1, t_resp: 1, t_page: 1}, + ntimers = 0, t_name, timer, t_other=[]; + + if(impl.complete) { + return this; + } + + impl.initNavTiming(); + + if( + (d.webkitVisibilityState && d.webkitVisibilityState === "prerender") + || + (d.msVisibilityState && d.msVisibilityState === 3) + ) { + // This means that onload fired through a pre-render. We'll capture this + // time, but wait for t_done until after the page has become either visible + // or hidden (ie, it moved out of the pre-render state) + // http://code.google.com/chrome/whitepapers/pagevisibility.html + // http://www.w3.org/TR/2011/WD-page-visibility-20110602/ + // http://code.google.com/chrome/whitepapers/prerender.html + + this.startTimer("t_load", impl.navigationStart); + this.endTimer("t_load"); // this will measure actual onload time for a prerendered page + this.startTimer("t_prerender", impl.navigationStart); + this.startTimer("t_postrender"); // time from prerender to visible or hidden + + BOOMR.subscribe("visibility_changed", this.done, null, this); + + return this; + } + + // If the dev has already called endTimer, then this call will do nothing + // else, it will stop the page load timer + this.endTimer("t_done"); + + if(impl.responseStart) { + // Use NavTiming API to figure out resp latency and page time + // t_resp will use the cookie if available or fallback to NavTiming + this.endTimer("t_resp", impl.responseStart); + if(impl.timers.t_load) { + this.setTimer("t_page", impl.timers.t_load.end - impl.responseStart); + } + else { + this.setTimer("t_page", new Date().getTime() - impl.responseStart); + } + } + else if(impl.timers.hasOwnProperty('t_page')) { + // If the dev has already started t_page timer, we can end it now as well + this.endTimer("t_page"); + } + + // If a prerender timer was started, we can end it now as well + if(impl.timers.hasOwnProperty('t_postrender')) { + this.endTimer("t_postrender"); + this.endTimer("t_prerender"); + } + + // A beacon may be fired automatically on page load or if the page dev fires + // it manually with their own timers. It may not always contain a referrer + // (eg: XHR calls). We set default values for these cases + + r = r2 = d.referrer.replace(/#.*/, ''); + + // If impl.cookie is not set, the dev does not want to use cookie time + if(impl.cookie) { + subcookies = BOOMR.utils.getSubCookies(BOOMR.utils.getCookie(impl.cookie)); + BOOMR.utils.removeCookie(impl.cookie); + + if(subcookies && subcookies.s && subcookies.r) { + r = subcookies.r; + if(!impl.strict_referrer || r === r2) { + t_start = parseInt(subcookies.s, 10); + } + } + } + + if(t_start && impl.navigationType != 2) { // 2 is TYPE_BACK_FORWARD but the constant may not be defined across browsers + BOOMR.addVar("rt.start", "cookie"); // if the user hit the back button, referrer will match, and cookie will match + } // but will have time of previous page start, so t_done will be wrong + else { + t_start = impl.navigationStart; + } + + // make sure old variables don't stick around + BOOMR.removeVar('t_done', 't_page', 't_resp', 'r', 'r2', 'rt.bstart', 'rt.end'); + + BOOMR.addVar('rt.bstart', BOOMR.t_start); + BOOMR.addVar('rt.end', impl.timers.t_done.end); + + for(t_name in impl.timers) { + if(!impl.timers.hasOwnProperty(t_name)) { + continue; + } + + timer = impl.timers[t_name]; + + // if delta is a number, then it was set using setTimer + // if not, then we have to calculate it using start & end + if(typeof timer.delta !== "number") { + if(typeof timer.start !== "number") { + timer.start = t_start; + } + timer.delta = timer.end - timer.start; + } + + // If the caller did not set a start time, and if there was no start cookie + // then timer.delta will be NaN, in which case we discard it. + if(isNaN(timer.delta)) { + continue; + } + + if(basic_timers.hasOwnProperty(t_name)) { + BOOMR.addVar(t_name, timer.delta); + } + else { + t_other.push(t_name + '|' + timer.delta); + } + ntimers++; + } + + if(ntimers) { + BOOMR.addVar("page.r", r); + + if(r2 !== r) { + BOOMR.addVar("page.r2", r2); + } + + if(t_other.length) { + BOOMR.addVar("t_other", t_other.join(',')); + } + } + + impl.timers = {}; + impl.complete = true; + + BOOMR.sendBeacon(); // we call sendBeacon() anyway because some other plugin + // may have blocked waiting for RT to complete + return this; + }, + + is_complete: function() { return impl.complete; } + +}; + +}(window)); + +// End of RT plugin + +// This is the Bandwidth & Latency plugin abbreviated to BW +// the parameter is the window +(function(w) { + +var d=w.document; + +BOOMR = BOOMR || {}; +BOOMR.plugins = BOOMR.plugins || {}; + +// We choose image sizes so that we can narrow down on a bandwidth range as +// soon as possible the sizes chosen correspond to bandwidth values of +// 14-64kbps, 64-256kbps, 256-1024kbps, 1-2Mbps, 2-8Mbps, 8-30Mbps & 30Mbps+ +// Anything below 14kbps will probably timeout before the test completes +// Anything over 60Mbps will probably be unreliable since latency will make up +// the largest part of download time. If you want to extend this further to +// cover 100Mbps & 1Gbps networks, use image sizes of 19,200,000 & 153,600,000 +// bytes respectively +// See https://spreadsheets.google.com/ccc?key=0AplxPyCzmQi6dDRBN2JEd190N1hhV1N5cHQtUVdBMUE&hl=en_GB +// for a spreadsheet with the details +var images=[ + { name: "image-0.png", size: 11483, timeout: 1400 }, + { name: "image-1.png", size: 40658, timeout: 1200 }, + { name: "image-2.png", size: 164897, timeout: 1300 }, + { name: "image-3.png", size: 381756, timeout: 1500 }, + { name: "image-4.png", size: 1234664, timeout: 1200 }, + { name: "image-5.png", size: 4509613, timeout: 1200 }, + { name: "image-6.png", size: 9084559, timeout: 1200 } +]; + +images.end = images.length; +images.start = 0; + +// abuse arrays to do the latency test simply because it avoids a bunch of +// branches in the rest of the code. +// I'm sorry Douglas +images.l = { name: "image-l.gif", size: 35, timeout: 1000 }; + +// private object +var impl = { + // properties + base_url: 'images/', + timeout: 15000, + nruns: 5, + latency_runs: 10, + user_ip: '', + cookie_exp: 7*86400, + cookie: 'BA', + + // state + results: [], + latencies: [], + latency: null, + runs_left: 0, + aborted: false, + complete: false, + running: false, + + // methods + + // numeric comparator. Returns negative number if a < b, positive if a > b and 0 if they're equal + // used to sort an array numerically + ncmp: function(a, b) { return (a-b); }, + + // Calculate the interquartile range of an array of data points + iqr: function(a) + { + var l = a.length-1, q1, q3, fw, b = [], i; + + q1 = (a[Math.floor(l*0.25)] + a[Math.ceil(l*0.25)])/2; + q3 = (a[Math.floor(l*0.75)] + a[Math.ceil(l*0.75)])/2; + + fw = (q3-q1)*1.5; + + l++; + + for(i=0; i q1-fw) { + b.push(a[i]); + } + } + + return b; + }, + + calc_latency: function() + { + var i, n, + sum=0, sumsq=0, + amean, median, + std_dev, std_err, + lat_filtered; + + // We first do IQR filtering and use the resulting data set + // for all calculations + lat_filtered = this.iqr(this.latencies.sort(this.ncmp)); + n = lat_filtered.length; + + BOOMR.debug(lat_filtered, "bw"); + + // First we get the arithmetic mean, standard deviation and standard error + // We ignore the first since it paid the price of DNS lookup, TCP connect + // and slow start + for(i=1; i=0 && nimgs<3; j--) { + // if we hit an undefined image time, we skipped everything before this + if(!r[j]) { + break; + } + if(r[j].t === null) { + continue; + } + + n++; + nimgs++; + + // multiply by 1000 since t is in milliseconds and not seconds + bw = images[j].size*1000/r[j].t; + bandwidths.push(bw); + + bw_c = images[j].size*1000/(r[j].t - this.latency.mean); + bandwidths_corrected.push(bw_c); + } + } + + BOOMR.debug('got ' + n + ' readings', "bw"); + + BOOMR.debug('bandwidths: ' + bandwidths, "bw"); + BOOMR.debug('corrected: ' + bandwidths_corrected, "bw"); + + // First do IQR filtering since we use the median here + // and should use the stddev after filtering. + if(bandwidths.length > 3) { + bandwidths = this.iqr(bandwidths.sort(this.ncmp)); + bandwidths_corrected = this.iqr(bandwidths_corrected.sort(this.ncmp)); + } else { + bandwidths = bandwidths.sort(this.ncmp); + bandwidths_corrected = bandwidths_corrected.sort(this.ncmp); + } + + BOOMR.debug('after iqr: ' + bandwidths, "bw"); + BOOMR.debug('corrected: ' + bandwidths_corrected, "bw"); + + // Now get the mean & median. + // Also get corrected values that eliminate latency + n = Math.max(bandwidths.length, bandwidths_corrected.length); + for(i=0; i= images.end-1 + || typeof this.results[this.nruns-run].r[i+1] !== "undefined" + ) { + BOOMR.debug(this.results[this.nruns-run], "bw"); + // First run is a pilot test to decide what the largest image + // that we can download is. All following runs only try to + // download this image + if(run === this.nruns) { + images.start = i; + } + this.defer(this.iterate); + } else { + this.load_img(i+1, run, this.img_loaded); + } + }, + + finish: function() + { + if(!this.latency) { + this.latency = this.calc_latency(); + } + var bw = this.calc_bw(), + o = { + bw: bw.median_corrected, + bw_err: parseFloat(bw.stderr_corrected, 10), + lat: this.latency.mean, + lat_err: parseFloat(this.latency.stderr, 10), + bw_time: Math.round(new Date().getTime()/1000) + }; + + BOOMR.addVar(o); + + // If we have an IP address we can make the BA cookie persistent for a while + // because we'll recalculate it if necessary (when the user's IP changes). + if(!isNaN(o.bw)) { + BOOMR.utils.setCookie(this.cookie, + { + ba: Math.round(o.bw), + be: o.bw_err, + l: o.lat, + le: o.lat_err, + ip: this.user_ip, + t: o.bw_time + }, + (this.user_ip ? this.cookie_exp : 0), + "/", + null + ); + } + + this.complete = true; + BOOMR.sendBeacon(); + this.running = false; + }, + + iterate: function() + { + if(this.aborted) { + return false; + } + + if(!this.runs_left) { + this.finish(); + } + else if(this.latency_runs) { + this.load_img('l', this.latency_runs--, this.lat_loaded); + } + else { + this.results.push({r:[]}); + this.load_img(images.start, this.runs_left--, this.img_loaded); + } + }, + + setVarsFromCookie: function(cookies) { + var ba = parseInt(cookies.ba, 10), + bw_e = parseFloat(cookies.be, 10), + lat = parseInt(cookies.l, 10) || 0, + lat_e = parseFloat(cookies.le, 10) || 0, + c_sn = cookies.ip.replace(/\.\d+$/, '0'), // Note this is IPv4 only + t = parseInt(cookies.t, 10), + p_sn = this.user_ip.replace(/\.\d+$/, '0'), + + // We use the subnet instead of the IP address because some people + // on DHCP with the same ISP may get different IPs on the same subnet + // every time they log in + + t_now = Math.round((new Date().getTime())/1000); // seconds + + // If the subnet changes or the cookie is more than 7 days old, + // then we recheck the bandwidth, else we just use what's in the cookie + if(c_sn === p_sn && t >= t_now - this.cookie_exp) { + this.complete = true; + BOOMR.addVar({ + 'bw': ba, + 'lat': lat, + 'bw_err': bw_e, + 'lat_err': lat_e + }); + + return true; + } + + return false; + } + +}; + +BOOMR.plugins.BW = { + init: function(config) { + var cookies; + + BOOMR.utils.pluginConfig(impl, config, "BW", + ["base_url", "timeout", "nruns", "cookie", "cookie_exp"]); + + if(config && config.user_ip) { + impl.user_ip = config.user_ip; + } + + images.start = 0; + impl.runs_left = impl.nruns; + impl.latency_runs = 10; + impl.results = []; + impl.latencies = []; + impl.latency = null; + impl.complete = false; + impl.aborted = false; + + BOOMR.removeVar('ba', 'ba_err', 'lat', 'lat_err'); + + cookies = BOOMR.utils.getSubCookies(BOOMR.utils.getCookie(impl.cookie)); + + if(!cookies || !cookies.ba || !impl.setVarsFromCookie(cookies)) { + BOOMR.subscribe("page_ready", this.run, null, this); + } + + return this; + }, + + run: function() { + if(impl.running || impl.complete) { + return this; + } + + if(w.location.protocol === 'https:') { + // we don't run the test for https because SSL stuff will mess up b/w + // calculations we could run the test itself over HTTP, but then IE + // will complain about insecure resources, so the best is to just bail + // and hope that the user gets the cookie from some other page + + BOOMR.info("HTTPS detected, skipping bandwidth test", "bw"); + impl.complete = true; + BOOMR.sendBeacon(); + return this; + } + + impl.running = true; + + setTimeout(this.abort, impl.timeout); + + impl.defer(impl.iterate); + + return this; + }, + + abort: function() { + impl.aborted = true; + if (impl.running) { + impl.finish(); // we don't defer this call because it might be called from + // onunload and we want the entire chain to complete + // before we return + } + return this; + }, + + is_complete: function() { return impl.complete; } +}; + +}(window)); + +// End of BW plugin + + + +/*jslint white: false, devel: true, onevar: true, browser: true, undef: true, nomen: true, regexp: false, continue: true, plusplus: false, bitwise: false, newcap: true, maxerr: 50, indent: 4 */ +/* + * Copyright (c), Buddy Brewer. + */ + +/** +\file navtiming.js +Plugin to collect metrics from the W3C Navigation Timing API. For more information about Navigation Timing, +see: http://www.w3.org/TR/navigation-timing/ +*/ + +// w is the window object +(function(w) { + +// First make sure BOOMR is actually defined. It's possible that your plugin is loaded before boomerang, in which case +// you'll need this. +BOOMR = BOOMR || {}; +BOOMR.plugins = BOOMR.plugins || {}; + +// A private object to encapsulate all your implementation details +var impl = { + complete: false, + done: function() { + var p, pn, pt, data; + p = w.performance || w.msPerformance || w.webkitPerformance || w.mozPerformance; + if(p && p.timing && p.navigation) { + BOOMR.info("This user agent supports NavigationTiming.", "nt"); + pn = w.performance.navigation; + pt = w.performance.timing; + data = { + nt_red_cnt: pn.redirectCount, + nt_nav_type: pn.type, + nt_nav_st: pt.navigationStart, + nt_red_st: pt.redirectStart, + nt_red_end: pt.redirectEnd, + nt_fet_st: pt.fetchStart, + nt_dns_st: pt.domainLookupStart, + nt_dns_end: pt.domainLookupEnd, + nt_con_st: pt.connectStart, + nt_con_end: pt.connectEnd, + nt_req_st: pt.requestStart, + nt_res_st: pt.responseStart, + nt_res_end: pt.responseEnd, + nt_domloading: pt.domLoading, + nt_domint: pt.domInteractive, + nt_domcontloaded_st: pt.domContentLoadedEventStart, + nt_domcontloaded_end: pt.domContentLoadedEventEnd, + nt_domcomp: pt.domComplete, + nt_load_st: pt.loadEventStart, + nt_load_end: pt.loadEventEnd, + nt_unload_st: pt.unloadEventStart, + nt_unload_end: pt.unloadEventEnd + }; + if (pt.secureConnectionStart) { + // secureConnectionStart is OPTIONAL in the spec + data.nt_ssl_st = pt.secureConnectionStart; + } + BOOMR.addVar(data); + } + this.complete = true; + BOOMR.sendBeacon(); + } +}; + +BOOMR.plugins.NavigationTiming = { + init: function() { + BOOMR.subscribe("page_ready", impl.done, null, impl); + return this; + }, + + is_complete: function() { + return impl.complete; + } +}; + +}(window)); + + +BOOMR.t_end = new Date().getTime(); diff --git a/src/js/smile/tracker/boomerang/dns.js b/src/js/smile/tracker/boomerang/dns.js new file mode 100644 index 00000000..ea82e96b --- /dev/null +++ b/src/js/smile/tracker/boomerang/dns.js @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2011, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the BSD License. See the accompanying LICENSE.txt file for terms. + */ + +/** +\file dns.js +Plugin to measure DNS latency. +This code is based on Carlos Bueno's guide to DNS on the YDN blog: +http://developer.yahoo.net/blog/archives/2009/11/guide_to_dns.html +*/ + +// w is the window object +(function(w) { + +BOOMR = BOOMR || {}; +BOOMR.plugins = BOOMR.plugins || {}; + +var impl = { + complete: false, + base_url: "", + t_start: null, + t_dns: null, + t_http: null, + img: null, + + gen_url: "", + + start: function() { + var random = Math.floor(Math.random()*(2147483647)).toString(36), + cache_bust = "" + (new Date().getTime()) + (Math.random()); + + this.gen_url = this.base_url.replace(/\*/, random); + + impl.img = new Image(); + impl.img.onload = impl.A_loaded; + + impl.t_start = new Date().getTime(); + impl.img.src = this.gen_url + "image-l.gif?t=" + cache_bust; + }, + + A_loaded: function() { + var cache_bust; + impl.t_dns = new Date().getTime() - impl.t_start; + + cache_bust = "" + (new Date().getTime()) + (Math.random()); + + impl.img = new Image(); + impl.img.onload = impl.B_loaded; + + impl.t_start = new Date().getTime(); + impl.img.src = impl.gen_url + "image-l.gif?t=" + cache_bust; + }, + + B_loaded: function() { + impl.t_http = new Date().getTime() - impl.t_start; + + impl.img = null; + impl.done(); + }, + + done: function() { + // DNS time is the time to load the image with uncached DNS + // minus the time to load the image with cached DNS + + var dns = impl.t_dns - impl.t_http; + + BOOMR.addVar("dns", dns); + this.complete = true; + BOOMR.sendBeacon(); + }, + + read_timing_api: function(t) { + if(typeof t.domainLookupStart === "undefined" + || typeof t.domainLookupEnd === "undefined") { + return false; + } + + // This will be 0 if we read DNS from cache, but that's what + // we want because it's what the user experiences + BOOMR.addVar("dns", t.domainLookupEnd - t.domainLookupStart); + + impl.complete = true; + + return true; + } +}; + +BOOMR.plugins.DNS = { + init: function(config) { + BOOMR.utils.pluginConfig(impl, config, "DNS", ["base_url"]); + + // If this browser supports the WebTiming API, then we just + // use that and don't bother doing the test + if(w.performance && w.performance.timing) { + if(impl.read_timing_api(w.performance.timing)) { + return this; + } + } + + if(!impl.base_url) { + BOOMR.warn("DNS.base_url is not set. Cannot run DNS test.", "dns"); + impl.complete = true; // set to true so that is_complete doesn't + // block other plugins + return this; + } + + // make sure that dns test images use the same protocol as the host page + if(w.location.protocol === 'https:') { + impl.base_url = impl.base_url.replace(/^http:/, 'https:'); + } + else { + impl.base_url = impl.base_url.replace(/^https:/, 'http:'); + } + + BOOMR.subscribe("page_ready", impl.start, null, this); + + return this; + }, + + is_complete: function() { + return impl.complete; + } +}; + +}(window)); + diff --git a/src/js/smile/tracker/boomerang/images/image-0.png b/src/js/smile/tracker/boomerang/images/image-0.png new file mode 100644 index 00000000..86c598f4 Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-0.png differ diff --git a/src/js/smile/tracker/boomerang/images/image-1.png b/src/js/smile/tracker/boomerang/images/image-1.png new file mode 100644 index 00000000..64ccf0d6 Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-1.png differ diff --git a/src/js/smile/tracker/boomerang/images/image-2.png b/src/js/smile/tracker/boomerang/images/image-2.png new file mode 100644 index 00000000..5ffc6de8 Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-2.png differ diff --git a/src/js/smile/tracker/boomerang/images/image-3.png b/src/js/smile/tracker/boomerang/images/image-3.png new file mode 100644 index 00000000..e09efdd4 Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-3.png differ diff --git a/src/js/smile/tracker/boomerang/images/image-4.png b/src/js/smile/tracker/boomerang/images/image-4.png new file mode 100644 index 00000000..0beed9fe Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-4.png differ diff --git a/src/js/smile/tracker/boomerang/images/image-5.png b/src/js/smile/tracker/boomerang/images/image-5.png new file mode 100644 index 00000000..a09e61da Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-5.png differ diff --git a/src/js/smile/tracker/boomerang/images/image-6.png b/src/js/smile/tracker/boomerang/images/image-6.png new file mode 100644 index 00000000..b229adc4 Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-6.png differ diff --git a/src/js/smile/tracker/boomerang/images/image-l.gif b/src/js/smile/tracker/boomerang/images/image-l.gif new file mode 100644 index 00000000..b506624a Binary files /dev/null and b/src/js/smile/tracker/boomerang/images/image-l.gif differ diff --git a/src/js/smile/tracker/boomerang/ipv6.js b/src/js/smile/tracker/boomerang/ipv6.js new file mode 100644 index 00000000..032bf5db --- /dev/null +++ b/src/js/smile/tracker/boomerang/ipv6.js @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2011, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the BSD License. See the accompanying LICENSE.txt file for terms. + */ + +/** +\file ipv6.js +Plugin to measure various ipv6 related metrics. +This plugin tries to do a few things: +- Check if the client can connect to an ipv6 address +- Check if the client can resolve DNS that points to an ipv6 address +- Check latency of connecting to an ipv6 address +- Check avg latency of doing dns lookup to an ipv6 address (not worstcase) + +You'll need a server that has an ipv6 address, and a DNS name to point to it. +Additionally, this server needs to be configured to serve content requested +from the IPv6 address and should not require a virtual host name. This means +that you probably cannot use shared hosting that puts multiple hosts on the +same IP address. + +All beacon parameters are prefixed with ipv6_ + +Beacon parameters: +- ipv6_latency: Latency in milliseconds of getting data from an ipv6 host when + connecting to the IP. Set to NA if the client cannot connect + to the ipv6 host. +- ipv6_lookup: Latency of getting data from a hostname that resolves to an + ipv6 address. Set to NA if the client cannot resolve or connect + to the ipv6 host. +*/ + +(function(w) { + +BOOMR = BOOMR || {}; +BOOMR.plugins = BOOMR.plugins || {}; + +/* +Algorithm: + +1. Try to load a sizeless image from an IPv6 host + - onerror, flag no IPv6 connect support and end + - onload, measure load time +2. Try to load a sizeless image from a hostname that resolves to an IPv6 address + - onerror, flag no IPv6 DNS resolver and end + - onload, measure load time +*/ +var impl = { + complete: false, + ipv6_url: "", + host_url: "", + timeout: 1200, + + timers: { + ipv6: { start: null, end: null }, + host: { start: null, end: null } + }, + + start: function() { + this.load_img('ipv6', 'host'); + }, + + load_img: function() { + var img, + rnd = "?t=" + (new Date().getTime()) + Math.random(), + timer=0, error = null, + that = this, + which = Array.prototype.shift.call(arguments), + a = arguments; + + // Terminate if we've reached end of test list + if(!which || !(which in this.timers)) { + this.done(); + return false; + } + + // Skip if URL wasn't set for this test + if(!this[which + '_url']) { + return this.load_img.apply(this, a); + } + + img = new Image(); + + img.onload = function() { + that.timers[which].end = new Date().getTime(); + clearTimeout(timer); + img.onload = img.onerror = null; + img = null; + + that.load_img.apply(that, a); + that = a = null; + }; + + error = function() { + that.timers[which].supported = false; + clearTimeout(timer); + img.onload = img.onerror = null; + img = null; + + that.done(); + that = a = null; + }; + + img.onerror = error; + timer = setTimeout(error, this.timeout); + this.timers[which].start = new Date().getTime(); + img.src = this[which + '_url'] + rnd; + + return true; + }, + + done: function() { + if(this.complete) { + return; + } + + BOOMR.removeVar('ipv6_latency', 'ipv6_lookup'); + if(this.timers.ipv6.end !== null) { + BOOMR.addVar('ipv6_latency', this.timers.ipv6.end - this.timers.ipv6.start); + } + else { + BOOMR.addVar('ipv6_latency', 'NA'); + } + + if(this.timers.host.end !== null) { + BOOMR.addVar('ipv6_lookup', this.timers.host.end - this.timers.host.start); + } + else { + BOOMR.addVar('ipv6_lookup', 'NA'); + } + + this.complete = true; + BOOMR.sendBeacon(); + } +}; + +BOOMR.plugins.IPv6 = { + init: function(config) { + BOOMR.utils.pluginConfig(impl, config, "IPv6", ["ipv6_url", "host_url", "timeout"]); + + if(!impl.ipv6_url) { + BOOMR.warn("IPv6.ipv6_url is not set. Cannot run IPv6 test.", "ipv6"); + impl.complete = true; // set to true so that is_complete doesn't + // block other plugins + return this; + } + + if(!impl.host_url) { + BOOMR.warn("IPv6.host_url is not set. Will skip hostname test.", "ipv6"); + } + + // make sure that test images use the same protocol as the host page + if(w.location.protocol === 'https:') { + impl.ipv6_url = impl.ipv6_url.replace(/^http:/, 'https:'); + impl.host_url = impl.host_url.replace(/^http:/, 'https:'); + } + else { + impl.ipv6_url = impl.ipv6_url.replace(/^https:/, 'http:'); + impl.host_url = impl.host_url.replace(/^https:/, 'http:'); + } + + BOOMR.subscribe("page_ready", impl.start, null, impl); + + return this; + }, + + is_complete: function() { + return impl.complete; + } +}; + +}(window)); + diff --git a/src/js/smile/tracker/boomerang/navtiming.js b/src/js/smile/tracker/boomerang/navtiming.js new file mode 100644 index 00000000..b4559ffb --- /dev/null +++ b/src/js/smile/tracker/boomerang/navtiming.js @@ -0,0 +1,76 @@ +/* + * Copyright (c), Buddy Brewer. + */ + +/** +\file navtiming.js +Plugin to collect metrics from the W3C Navigation Timing API. For more information about Navigation Timing, +see: http://www.w3.org/TR/navigation-timing/ +*/ + +// w is the window object +(function(w) { + +// First make sure BOOMR is actually defined. It's possible that your plugin is loaded before boomerang, in which case +// you'll need this. +BOOMR = BOOMR || {}; +BOOMR.plugins = BOOMR.plugins || {}; + +// A private object to encapsulate all your implementation details +var impl = { + complete: false, + done: function() { + var p, pn, pt, data; + p = w.performance || w.msPerformance || w.webkitPerformance || w.mozPerformance; + if(p && p.timing && p.navigation) { + BOOMR.info("This user agent supports NavigationTiming.", "nt"); + pn = w.performance.navigation; + pt = w.performance.timing; + data = { + nt_red_cnt: pn.redirectCount, + nt_nav_type: pn.type, + nt_nav_st: pt.navigationStart, + nt_red_st: pt.redirectStart, + nt_red_end: pt.redirectEnd, + nt_fet_st: pt.fetchStart, + nt_dns_st: pt.domainLookupStart, + nt_dns_end: pt.domainLookupEnd, + nt_con_st: pt.connectStart, + nt_con_end: pt.connectEnd, + nt_req_st: pt.requestStart, + nt_res_st: pt.responseStart, + nt_res_end: pt.responseEnd, + nt_domloading: pt.domLoading, + nt_domint: pt.domInteractive, + nt_domcontloaded_st: pt.domContentLoadedEventStart, + nt_domcontloaded_end: pt.domContentLoadedEventEnd, + nt_domcomp: pt.domComplete, + nt_load_st: pt.loadEventStart, + nt_load_end: pt.loadEventEnd, + nt_unload_st: pt.unloadEventStart, + nt_unload_end: pt.unloadEventEnd + }; + if (pt.secureConnectionStart) { + // secureConnectionStart is OPTIONAL in the spec + data.nt_ssl_st = pt.secureConnectionStart; + } + BOOMR.addVar(data); + } + this.complete = true; + BOOMR.sendBeacon(); + } +}; + +BOOMR.plugins.NavigationTiming = { + init: function() { + BOOMR.subscribe("page_ready", impl.done, null, impl); + return this; + }, + + is_complete: function() { + return impl.complete; + } +}; + +}(window)); + diff --git a/src/js/smile/tracker/boomerang/plugin.js b/src/js/smile/tracker/boomerang/plugin.js new file mode 100644 index 00000000..7574fa07 --- /dev/null +++ b/src/js/smile/tracker/boomerang/plugin.js @@ -0,0 +1,52 @@ +/** +\file plugin.js +Skeleton template for all boomerang plugins. Use this code as a starting point for your +own plugins. +*/ + +////////////////////////////////////////////////////////// +// DO NOT INCLUDE THIS FILE IN YOUR HTML DOCUMENT // +// THIS IS A SAMPLE PLUGIN // +////////////////////////////////////////////////////////// + +// w is the window object +(function(w) { + +var d=w.document; + +// First make sure BOOMR is actually defined. It's possible that your plugin is loaded before boomerang, in which case +// you'll need this. +BOOMR = BOOMR || {}; +BOOMR.plugins = BOOMR.plugins || {}; + +// A private object to encapsulate all your implementation details +// This is optional, but the way we recommend you do it. +var impl = { +}; + +BOOMR.plugins.MyPlugin = { + init: function(config) { + var i, properties = ["prop1", "prop2"]; // list of user configurable properties in O + + // This block is only needed if you actually have user configurable properties + BOOMR.utils.pluginConfig(impl, config, "MyPlugin", properties); + + // Other initialisation code here + + // Subscribe to any BOOMR events here. + // Unless your code will explicitly be called by the developer + // or by another plugin, you must to do this. + + return this; + }, + + // Any other public methods would be defined here + + is_complete: function() { + // This method should determine if the plugin has completed doing what it + /// needs to do and return true if so or false otherwise + } +}; + +}(window)); + diff --git a/src/js/smile/tracker/hit.png b/src/js/smile/tracker/hit.png new file mode 100644 index 00000000..35ef9769 Binary files /dev/null and b/src/js/smile/tracker/hit.png differ diff --git a/src/js/smile/tracker/tracking.js b/src/js/smile/tracker/tracking.js new file mode 100644 index 00000000..5ddc62ac --- /dev/null +++ b/src/js/smile/tracker/tracking.js @@ -0,0 +1,133 @@ +/** + * Smile tracker implementation + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Smile Searchandising Suite to newer + * versions in the future. + * + * @category Smile + * @package Smile_Tracker + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ +(function () { + + var stCookies = {}; + + function _uuid() { + + var uuid = "", i, random; + + for (i = 0; i < 32; i++) { + random = Math.random() * 16 | 0; + + if (i == 8 || i == 12 || i == 16 || i == 20) { + uuid += "-" + } + + uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16); + } + + return uuid; + } + + function _decodeCookies() { + // Decode cookies + document.cookie.split('; ').map(function(value) { + var parts = value.split("="); + if (parts.length == 2) { + stCookies[parts[0]] = parts[1]; + } + }); + } + + function _getCookieTrackingId(cookieName, expiresAt, path) { + + var trackingId = false; + + if (!path) { + path = '/'; + } + + if (stCookies[cookieName]) { + trackingId = stCookies[cookieName]; + } + + if (!trackingId) { + trackingId = _uuid(); + } + + document.cookie = cookieName + '=' + trackingId + "; expires=" + expiresAt.toUTCString() + '; path=' + path; + + return trackingId; + } + + + SmileTracker = { + + init : function(config) { + SmileTracker.config = config; + BOOMR.init({ + beacon_url: config.beaconUrl, + BW: { enabled: false, base_url: config.bwBaseUrl } + }); + SmileTracker.initSession(); + }, + + initSession : function() { + _decodeCookies(); + var expireAt = new Date(); + var config = SmileTracker.config.sessionConfig; + + expireAt.setSeconds(expireAt.getSeconds() + parseInt(config['visit_cookie_lifetime'])); + SmileTracker.addSessionVar('uid', _getCookieTrackingId(config['visit_cookie_name'], expireAt)); + + expireAt.setDate(expireAt.getDate() + parseInt(config['visitor_cookie_lifetime'])); + SmileTracker.addSessionVar('vid', _getCookieTrackingId(config['visitor_cookie_name'], expireAt)); + + BOOMR.addVar('t', Math.round(new Date().getTime() / 1000)); + }, + + addSessionVar : function (varName, value) { + BOOMR.addVar(this.transformVarName(varName, 'session'), value); + }, + + addPageVar : function (varName, value) { + + BOOMR.addVar(this.transformVarName(varName , 'page'), value); + }, + + transformVarName : function(varName, prefix) { + return prefix + "." + varName; + }, + + enableCheckoutTracking : function () + { + Checkout.prototype.superGotoSection = Checkout.prototype.gotoSection; + Checkout.prototype.gotoSection = function (section, reloadProgressBlock) { + if (!this.timerRunning) { + BOOMR.plugins.RT.startTimer('t_done'); + BOOMR.addVar('page.opc.server_loading', 0); + } + BOOMR.addVar('page[opc][step]', section); + this.superGotoSection(section, reloadProgressBlock); + BOOMR.plugins.RT.done(); + this.timerRunning = false; + BOOMR.removeVar('page.opc.step'); + BOOMR.removeVar('page.opc.server_loading'); + } + + + Checkout.prototype.superSetLoadWaiting = Checkout.prototype.setLoadWaiting; + Checkout.prototype.setLoadWaiting = function(step, keepDisabled) { + BOOMR.plugins.RT.startTimer('t_done'); + BOOMR.addVar('page.opc.server_loading', 1); + BOOMR.plugins.RT.startTimer('p'); + this.timerRunning = true; + this.superSetLoadWaiting(step, keepDisabled); + } + } + } +})(); \ No newline at end of file diff --git a/src/lib/.gitignore b/src/lib/.gitignore new file mode 100644 index 00000000..17fb1431 --- /dev/null +++ b/src/lib/.gitignore @@ -0,0 +1 @@ +/composer.lock diff --git a/src/lib/composer.json b/src/lib/composer.json new file mode 100644 index 00000000..d371d72a --- /dev/null +++ b/src/lib/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "elasticsearch/elasticsearch": "~1.2.2" + } +} diff --git a/src/lib/vendor/autoload.php b/src/lib/vendor/autoload.php new file mode 100644 index 00000000..83dcdc7a --- /dev/null +++ b/src/lib/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0 class loader + * + * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + + public function getPrefixes() + { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-0 base directories + * @param bool $prepend Whether to prepend the directories + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + */ + public function setPsr4($prefix, $paths) { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php'; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php'; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + // Remember that this class does not exist. + return $this->classMap[$class] = false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/src/lib/vendor/composer/autoload_classmap.php b/src/lib/vendor/composer/autoload_classmap.php new file mode 100644 index 00000000..7a91153b --- /dev/null +++ b/src/lib/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + array($vendorDir . '/symfony/event-dispatcher'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log'), + 'Pimple' => array($vendorDir . '/pimple/pimple/src'), + 'Guzzle\\Stream' => array($vendorDir . '/guzzle/stream'), + 'Guzzle\\Parser' => array($vendorDir . '/guzzle/parser'), + 'Guzzle\\Http' => array($vendorDir . '/guzzle/http'), + 'Guzzle\\Common' => array($vendorDir . '/guzzle/common'), + 'Elasticsearch\\Tests' => array($vendorDir . '/elasticsearch/elasticsearch/tests'), + 'Elasticsearch\\Benchmarks' => array($vendorDir . '/elasticsearch/elasticsearch/benchmarks'), + 'Elasticsearch' => array($vendorDir . '/elasticsearch/elasticsearch/src'), +); diff --git a/src/lib/vendor/composer/autoload_psr4.php b/src/lib/vendor/composer/autoload_psr4.php new file mode 100644 index 00000000..97bc5b2c --- /dev/null +++ b/src/lib/vendor/composer/autoload_psr4.php @@ -0,0 +1,10 @@ + array($vendorDir . '/monolog/monolog/src/Monolog'), +); diff --git a/src/lib/vendor/composer/autoload_real.php b/src/lib/vendor/composer/autoload_real.php new file mode 100644 index 00000000..f7011846 --- /dev/null +++ b/src/lib/vendor/composer/autoload_real.php @@ -0,0 +1,53 @@ + $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + + $loader->register(true); + + return $loader; + } +} + +function composerRequireaed18b5e3ce417e776e83987f8ca1e53($file) +{ + require $file; +} diff --git a/src/lib/vendor/composer/installed.json b/src/lib/vendor/composer/installed.json new file mode 100644 index 00000000..3d181c87 --- /dev/null +++ b/src/lib/vendor/composer/installed.json @@ -0,0 +1,484 @@ +[ + { + "name": "psr/log", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "time": "2012-12-21 11:40:51", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ] + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.5.4", + "version_normalized": "2.5.4.0", + "target-dir": "Symfony/Component/EventDispatcher", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "8faf5cc7e80fde74a650a36e60d32ce3c3e0457b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/8faf5cc7e80fde74a650a36e60d32ce3c3e0457b", + "reference": "8faf5cc7e80fde74a650a36e60d32ce3c3e0457b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0", + "symfony/dependency-injection": "~2.0", + "symfony/stopwatch": "~2.2" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "time": "2014-07-28 13:20:46", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "http://symfony.com" + }, + { + "name": "guzzle/common", + "version": "v3.9.2", + "version_normalized": "3.9.2.0", + "target-dir": "Guzzle/Common", + "source": { + "type": "git", + "url": "https://github.com/guzzle/common.git", + "reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/common/zipball/2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc", + "reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "symfony/event-dispatcher": ">=2.1" + }, + "time": "2014-08-11 04:32:36", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Common": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Common libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "collection", + "common", + "event", + "exception" + ] + }, + { + "name": "guzzle/stream", + "version": "v3.9.2", + "version_normalized": "3.9.2.0", + "target-dir": "Guzzle/Stream", + "source": { + "type": "git", + "url": "https://github.com/guzzle/stream.git", + "reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/stream/zipball/60c7fed02e98d2c518dae8f97874c8f4622100f0", + "reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0", + "shasum": "" + }, + "require": { + "guzzle/common": "self.version", + "php": ">=5.3.2" + }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, + "time": "2014-05-01 21:36:02", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Stream": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle stream wrapper component", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "component", + "stream" + ] + }, + { + "name": "guzzle/parser", + "version": "v3.9.2", + "version_normalized": "3.9.2.0", + "target-dir": "Guzzle/Parser", + "source": { + "type": "git", + "url": "https://github.com/guzzle/parser.git", + "reference": "6874d171318a8e93eb6d224cf85e4678490b625c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/parser/zipball/6874d171318a8e93eb6d224cf85e4678490b625c", + "reference": "6874d171318a8e93eb6d224cf85e4678490b625c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "time": "2014-02-05 18:29:46", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Parser": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Interchangeable parsers used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "URI Template", + "cookie", + "http", + "message", + "url" + ] + }, + { + "name": "guzzle/http", + "version": "v3.9.2", + "version_normalized": "3.9.2.0", + "target-dir": "Guzzle/Http", + "source": { + "type": "git", + "url": "https://github.com/guzzle/http.git", + "reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/http/zipball/1e8dd1e2ba9dc42332396f39fbfab950b2301dc5", + "reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5", + "shasum": "" + }, + "require": { + "guzzle/common": "self.version", + "guzzle/parser": "self.version", + "guzzle/stream": "self.version", + "php": ">=5.3.2" + }, + "suggest": { + "ext-curl": "*" + }, + "time": "2014-08-11 04:32:36", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Http": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "HTTP libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "client", + "curl", + "http", + "http client" + ] + }, + { + "name": "pimple/pimple", + "version": "v2.1.1", + "version_normalized": "2.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/fabpot/Pimple.git", + "reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fabpot/Pimple/zipball/ea22fb2880faf7b7b0e17c9809c6fe25b071fd76", + "reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2014-07-24 07:10:08", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ] + }, + { + "name": "monolog/monolog", + "version": "1.10.0", + "version_normalized": "1.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "25b16e801979098cb2f120e697bfce454b18bf23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/25b16e801979098cb2f120e697bfce454b18bf23", + "reference": "25b16e801979098cb2f120e697bfce454b18bf23", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.4, >2.4.8", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "phpunit/phpunit": "~3.7.0", + "raven/raven": "~0.5", + "ruflin/elastica": "0.90.*" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "time": "2014-06-04 16:30:04", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be", + "role": "Developer" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ] + }, + { + "name": "elasticsearch/elasticsearch", + "version": "v1.2.2", + "version_normalized": "1.2.2.0", + "source": { + "type": "git", + "url": "https://github.com/elasticsearch/elasticsearch-php.git", + "reference": "3a677634a46d01882f57dc634eb9ac0e10adfb77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/elasticsearch/elasticsearch-php/zipball/3a677634a46d01882f57dc634eb9ac0e10adfb77", + "reference": "3a677634a46d01882f57dc634eb9ac0e10adfb77", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "guzzle/http": "~3.7", + "monolog/monolog": "~1.5", + "php": ">=5.3.9", + "pimple/pimple": "~2.1", + "psr/log": "~1.0" + }, + "require-dev": { + "athletic/athletic": "~0.1", + "cpliakas/git-wrapper": "~1.0", + "mikey179/vfsstream": "~1.2", + "mockery/mockery": "dev-master@dev", + "phpunit/phpunit": "3.7.*", + "satooshi/php-coveralls": "dev-master", + "symfony/yaml": "2.4.3 as 2.4.2", + "twig/twig": "1.*" + }, + "time": "2014-08-06 16:04:48", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Elasticsearch": "src/", + "Elasticsearch\\Tests": "tests/", + "Elasticsearch\\Benchmarks": "benchmarks/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache 2" + ], + "authors": [ + { + "name": "Zachary Tong" + } + ], + "description": "PHP Client for Elasticsearch", + "keywords": [ + "client", + "elasticsearch", + "search" + ] + } +] diff --git a/src/lib/vendor/elasticsearch/elasticsearch/.gitignore b/src/lib/vendor/elasticsearch/elasticsearch/.gitignore new file mode 100755 index 00000000..19404c9f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/.gitignore @@ -0,0 +1,20 @@ +#composer related +composer.lock +vendor/ +composer.phar + +#editor related +.idea + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db + +#generator related +generator/* \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/.gitmodules b/src/lib/vendor/elasticsearch/elasticsearch/.gitmodules new file mode 100644 index 00000000..e03c4467 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/.gitmodules @@ -0,0 +1,3 @@ +[submodule "util/elasticsearch"] + path = util/elasticsearch + url = https://github.com/elasticsearch/elasticsearch.git diff --git a/src/lib/vendor/elasticsearch/elasticsearch/.travis.yml b/src/lib/vendor/elasticsearch/elasticsearch/.travis.yml new file mode 100644 index 00000000..d6031fa3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/.travis.yml @@ -0,0 +1,21 @@ +language: php +php: + - "5.5" + - "5.4" + - "5.3" +env: + - ES_VERSION=0.90.0 ES_TEST_HOST=http://localhost:9200 + - ES_VERSION=0.90.1 ES_TEST_HOST=http://localhost:9200 + - ES_VERSION=0.90.2 ES_TEST_HOST=http://localhost:9200 + - ES_VERSION=0.90.3 ES_TEST_HOST=http://localhost:9200 + - ES_VERSION=0.90.4 ES_TEST_HOST=http://localhost:9200 + - ES_VERSION=0.90.5 ES_TEST_HOST=http://localhost:9200 + +before_script: + - composer install --dev + - mkdir -p build/logs + +script: ./run_travis_test.sh + +after_script: + - php vendor/bin/coveralls -v \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/CHANGELOG.md b/src/lib/vendor/elasticsearch/elasticsearch/CHANGELOG.md new file mode 100644 index 00000000..ed71d672 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/CHANGELOG.md @@ -0,0 +1,146 @@ +## Release 1.3.0 + - Changed the guzzle requirement to the HTTP component only [[aec04a2]](http://github.com/elasticsearch/elasticsearch-php/commit/aec04a27bf0382e7d2754effdfd641f0388eda83) + - comma fix [[8f623e2]](http://github.com/elasticsearch/elasticsearch-php/commit/8f623e2200e9c8346a43b4a8e645601d3e7df2fd) + - Remove usage of Pimple class with new Pimple\Container class, bump pimple version to 2.1 [[6470863]](http://github.com/elasticsearch/elasticsearch-php/commit/6470863bb1540bcce2431c95259f1b8248bf07b0) + - Update README.md [[f82569f]](http://github.com/elasticsearch/elasticsearch-php/commit/f82569f8ee85bb3c3a853b186ec23b1f94357eed) + - [DOCS] Add explanation of common JSON patterns in PHP [[36861fb]](http://github.com/elasticsearch/elasticsearch-php/commit/36861fb37e329cd060e741ec14a7f1643194706a) + - [DOCS] Add advanced example of creating an index [[8817599]](http://github.com/elasticsearch/elasticsearch-php/commit/88175990da7fd8467424d8aa574d7ba8797ac187) + - Fix casing of class [[0768b5e]](http://github.com/elasticsearch/elasticsearch-php/commit/0768b5ed85c61c5086dba8ac7b6517b94f11a085) + - [DOCS] Elasticsearch does not need to run in daemon mode for tests [[ee4c9a3]](http://github.com/elasticsearch/elasticsearch-php/commit/ee4c9a3f82d10cf103288ebb06b4a843188f8e89) + - [TEST] Add some logging to RestSpecRunner [[a9376d4]](http://github.com/elasticsearch/elasticsearch-php/commit/a9376d4b99a75b762614f625b209334e717e0335) + - Add Get/Put/Delete Script endpoints [[07ddc97]](http://github.com/elasticsearch/elasticsearch-php/commit/07ddc977cf47c4a2ac6b17eb451c517aa9f59b4f) + - ScriptLangNotSupported exception should extended BadRequest400 [[02784fd]](http://github.com/elasticsearch/elasticsearch-php/commit/02784fd4bce6d4d8281099a19e064d74c7968ee5) + - Add Get/Put/Delete Template endpoints [[f003010]](http://github.com/elasticsearch/elasticsearch-php/commit/f0030100bac400c7490600c9e49a3bb093e8db85) + - [TEST] Add timestamp to yaml runner [[b0d351f]](http://github.com/elasticsearch/elasticsearch-php/commit/b0d351f33b3a1b38990e64aa265e67d734843dd8) + +## Release 1.2.0 + - Add Snapshot/Status endpoint [[f88d7ca]](http://github.com/elasticsearch/elasticsearch-php/commit/f88d7ca1e8e50229862175aed418c4a6dc4352cd) + - Add Snapshot/Status implementation [[ed85658]](http://github.com/elasticsearch/elasticsearch-php/commit/ed85658c88f6e3542e6865b5f4394de40b400b07) + - [DOCS] Fix typo [[90aeea4]](http://github.com/elasticsearch/elasticsearch-php/commit/90aeea4dfcdac2a91ffb97c27d841413c6b1753b) + - [TEST] Reconfigure regex parsing/matching [[3d8cc12]](http://github.com/elasticsearch/elasticsearch-php/commit/3d8cc1298a8145bb4239f190dbbe43d482f9abe2) + - [TEST] Fix incorrect feature-skip behavior [[ad10df9]](http://github.com/elasticsearch/elasticsearch-php/commit/ad10df9e3fa5870fca9ed1c6bd60fe560e3157dc) + - Add Cat/Fielddata endpoint [[950fbaa]](http://github.com/elasticsearch/elasticsearch-php/commit/950fbaad0e6a0ae0301b91638a833b0c0c985d82) + - Fix Cat/Fielddata endpoint URI [[4ea7149]](http://github.com/elasticsearch/elasticsearch-php/commit/4ea7149cb8a808af0ab66067c4f700397ec20f1d) + - [TEST] Improve Regex debugging output [[f93837a]](http://github.com/elasticsearch/elasticsearch-php/commit/f93837a81122f3306738de55629f1946746415fd) + - Update CONTRIBUTING.md [[f3a39a7]](http://github.com/elasticsearch/elasticsearch-php/commit/f3a39a7389167c7b5c378fe0647431459b5dfc8d) + - Update Pimple to 2.0 [[e1cc94e]](http://github.com/elasticsearch/elasticsearch-php/commit/e1cc94e5e8275d59e448f66319553377edef84ad) + - Add 'create' param to Indices/PutTemplate API [[b06ed72]](http://github.com/elasticsearch/elasticsearch-php/commit/b06ed72d432354e72ad7496678b9fa55593a6b4a) + - Add metric param to Indices/Stats endpoint [[8dace3f]](http://github.com/elasticsearch/elasticsearch-php/commit/8dace3fc2f4041a982f7f7f3c0d33421ab5fc6c5) + - Fix logging of response errors [[7d91545]](http://github.com/elasticsearch/elasticsearch-php/commit/7d915455d3e14ef9ba68c82681040c8d91aad6c8) + +## Release 1.1.0 + - [DOCS] Add more examples of bulk indexing/updating [[6d25569]](http://github.com/elasticsearch/elasticsearch-php/commit/6d25569c74ef3cc9439a4078cc3ca478f137f41a) + - [DOCS] Add updateAlias example [[a75b7f2]](http://github.com/elasticsearch/elasticsearch-php/commit/a75b7f20210cda7dc54b3613b7d60c849caa8996) + - [DOCS] Add example of function_score and defining explicitly empty objects [[ed66d23]](http://github.com/elasticsearch/elasticsearch-php/commit/ed66d23c297a6ef823393e23b74fd9734f91f8a7) + - Add ability to get last request info [[f1092c5]](http://github.com/elasticsearch/elasticsearch-php/commit/f1092c5b05c1d05662afb7901d75dc8402572525) + - [TEST] Fix bug where skips in setup are ignored [[21c8698]](http://github.com/elasticsearch/elasticsearch-php/commit/21c86986a0753e3d6f104e8e3302feb4621a438b) + - Match function call with function signature [[9a9e95e]](http://github.com/elasticsearch/elasticsearch-php/commit/9a9e95ef9efa8a0b42ccefcd1b71d27eca3bc2e5) + - Add clearScroll method [[9b85c2d]](http://github.com/elasticsearch/elasticsearch-php/commit/9b85c2dfc931919d29d60fd47fa9ebd014832055) + - [TEST] Properly handle 5xx errors when `request` is being caught [[d299c61]](http://github.com/elasticsearch/elasticsearch-php/commit/d299c6143e6e87b3606c28f57b66d4c3a70a724e) + - Various exceptions should extend ServerErrorResponseException [[9022a9e]](http://github.com/elasticsearch/elasticsearch-php/commit/9022a9e2c97aadb31023987cf17e554033994ed4) + - Fixed missing ' in Bulk indexing example code [[b90b7d3]](http://github.com/elasticsearch/elasticsearch-php/commit/b90b7d3729f4b92da525f4f41bdf70fd22ec159f) + - Fix bug where scheme prefix always defaulted to HTTP [[4020db6]](http://github.com/elasticsearch/elasticsearch-php/commit/4020db6dfe1be099311c70a0cb3812859524c640) + - [TEST] Change array syntax to be PHP 5.3 compatible [[f884c54]](http://github.com/elasticsearch/elasticsearch-php/commit/f884c54b64da532a48685fe9364b679e28a14528) + - Added a Bool Query section [[7b0011f]](http://github.com/elasticsearch/elasticsearch-php/commit/7b0011f0e34a72e4d42977457bcddc5f7e65d9b3) + - Add SearchShards endpoint [[7d7b667]](http://github.com/elasticsearch/elasticsearch-php/commit/7d7b66781ea526f99ba79b3d053c7feeaa9474e0) + +## Release 1.0.2 + - Update IndicesNamespace.php [[8656c33]](http://github.com/elasticsearch/elasticsearch-php/commit/8656c332e818e7361cbcecda621270a1e75ab017) + - [YAML] Update ES dependency commit point [[d0b9526]](http://github.com/elasticsearch/elasticsearch-php/commit/d0b952667a2af4bc4b957a548b359c933e9a9a82) + - Add `explain` parameter to Cluster\Reroute Endpoint [[ec4fa60]](http://github.com/elasticsearch/elasticsearch-php/commit/ec4fa6063fe32a1cbc0e98ee2b8047eaedfa3628) + - [TEST] Temporarily disable test - waiting on fixed yaml parser [[bb389c0]](http://github.com/elasticsearch/elasticsearch-php/commit/bb389c047a135c27d5f9ab594fab06caaa65a204) + - Prevent exception when `connectionPoolParams` overwrite the defaults [[f164e10]](http://github.com/elasticsearch/elasticsearch-php/commit/f164e10f50c14674ff66f9337a27643d7c901e61) + - Update SniffingConnectionPool to use 1.0 endpoints [[19f9662]](http://github.com/elasticsearch/elasticsearch-php/commit/19f9662879cf1c876fb69e9cb99a4d9c3b91c5b3) + - [TEST]Update SniffingConnectionPool unit tests [[c6e6326]](http://github.com/elasticsearch/elasticsearch-php/commit/c6e6326e820055a589a5e47d4b28120ffdf165d7) + - Default port. [[3885e9b]](http://github.com/elasticsearch/elasticsearch-php/commit/3885e9b4cb31d142a8eb09430a9b98e8e47485be) + - Update port in unit tests [[e638eb0]](http://github.com/elasticsearch/elasticsearch-php/commit/e638eb0ae693f28bdce29c0dabc5d5f97faaf7c1) + - [YAML] Set yaml test for 1.0 branch [[f1b69cd]](http://github.com/elasticsearch/elasticsearch-php/commit/f1b69cdc09315824fe543b9949aca9a948926d45) + - [TEST] Make SniffingConnectionPool integration test compatible with jenkins [[a53f2be]](http://github.com/elasticsearch/elasticsearch-php/commit/a53f2bed33e5d4ac25c9a637e54d43670fae9776) + - [DOCS] Added some code formatting [[3af3188]](http://github.com/elasticsearch/elasticsearch-php/commit/3af3188ad7b79f5beebc18a700a919e7e4091b7f) + - Fix bug where retries were not being properly set [[cb2a6e8]](http://github.com/elasticsearch/elasticsearch-php/commit/cb2a6e8fa52ef9d6667893d2a3258d183d077682) + - Fix bug where retries count is set incorrectly [[d1e0b87]](http://github.com/elasticsearch/elasticsearch-php/commit/d1e0b8755100d83e6758b8e312f6adba25aa81cb) + - markAlive() and markDead() should also set lastPing time [[e57c952]](http://github.com/elasticsearch/elasticsearch-php/commit/e57c952285a7b868f6ae5cd6581bdb3182210bcc) + - [TEST] update mechanism to retrieve yaml tests [[e6d6e80]](http://github.com/elasticsearch/elasticsearch-php/commit/e6d6e809b28b6b88de676c9ab4b9a734f92c8e1c) + - [TEST] Fix integration test to use jenkins env vars [[182dacd]](http://github.com/elasticsearch/elasticsearch-php/commit/182dacd6aa2dd5329072c8450cb4bae3bd48265e) + - Fix broken composer.json [[374bcfc]](http://github.com/elasticsearch/elasticsearch-php/commit/374bcfc3b22fa33a40b9b14c666d17e2f6bd6680) + - [TEST] Use forked version of Symfony/Yaml [[1f6822b]](http://github.com/elasticsearch/elasticsearch-php/commit/1f6822b27f044c696bca4e4c8c1f3818a07242a6) + - Add Indices/Recovery Endpont [[a3a66b7]](http://github.com/elasticsearch/elasticsearch-php/commit/a3a66b79cb12285f63411c86d6355130060a25d7) + - Add SearchTemplate Endpont [[78cdf38]](http://github.com/elasticsearch/elasticsearch-php/commit/78cdf38a633dbf981a0bf906b4b560abacf56547) + - [TEST] Fix for unescaped regex in tests [[146397c]](http://github.com/elasticsearch/elasticsearch-php/commit/146397c1899e5f6ff3e0f96702b6486576446395) + - Add ability to configure URL Prefix [[00d28df]](http://github.com/elasticsearch/elasticsearch-php/commit/00d28dff801b13c57b1d8bfed78b06b303c1fdf5) + + +## Release 1.0.1 + - Add documentation about namespaces [[a34a021]](http://github.com/elasticsearch/elasticsearch-php/commit/a34a0210d85ef6dc3bd4070afded8334aaa8528e) + - Fix tables, because asciidoc !== markdown [[c5cac5c]](http://github.com/elasticsearch/elasticsearch-php/commit/c5cac5c83fa9ede9df0da584203c98b974af51ea) + - Update default configuration list [[d329b8d]](http://github.com/elasticsearch/elasticsearch-php/commit/d329b8d73b8846521354c6f959de0d0e2f78f846) + - Add documentation about serializers [[d7062e4]](http://github.com/elasticsearch/elasticsearch-php/commit/d7062e4f27c182ddebf96b5e58c91ee6d8ec114e) + - Cluster\Info endpoint should accept metric parameter [[d04d816]](http://github.com/elasticsearch/elasticsearch-php/commit/d04d81691d0dca181fe6883ad45feaa7d7796981) + + +## Release 1.0 + - Master tests should track Elasticsearch master [[6ae948a]](http://github.com/elasticsearch/elasticsearch-php/commit/6ae948a66f978fced22ce41da0797d9c3a44c733) + - Update readme with note about --no-dev [[0c7ab25]](http://github.com/elasticsearch/elasticsearch-php/commit/0c7ab25402c4076c95b3c37e0a5c731b408581c7) + - Update rest-spec dep [[bfd47f0]](http://github.com/elasticsearch/elasticsearch-php/commit/bfd47f0471f15e06f9e680ae79af55bf71ecc10f) + - Add rest-spec parser/generator [[b814211]](http://github.com/elasticsearch/elasticsearch-php/commit/b814211479cfc6981aff38e4adff12d227537127) + - Modify cluster-clearing behavior [[6738578]](http://github.com/elasticsearch/elasticsearch-php/commit/67385789d18310ea85dfd58839f7a04cd2520ad4) + - Yaml tests have curious definitions for 'truthy' and 'falsey [[67b29d3]](http://github.com/elasticsearch/elasticsearch-php/commit/67b29d3aa947585cc2e0d31aef09e7dfef46a8d0) + - Pass the testFile to executor for easier debugging [[f35d2f2]](http://github.com/elasticsearch/elasticsearch-php/commit/f35d2f28b989ba9e0b4d8cd64f38a3c5b7517e05) + - Add NodeNamespace and SnapshotNamespace [[7a59bd4]](http://github.com/elasticsearch/elasticsearch-php/commit/7a59bd4b6b36a7336846009b1ab7bc11943e0623) + - GetURI exception checks should throw RuntimeException [[3d81b00]](http://github.com/elasticsearch/elasticsearch-php/commit/3d81b004241afb4d166493de9f0b3c430bb43d30) + - Generated URI construction should use elseif's [[ec6f996]](http://github.com/elasticsearch/elasticsearch-php/commit/ec6f996d8f09f874fcc57baa4b4400c6f7310a87) + - Explicit check for bulk/msearch [[3cde301]](http://github.com/elasticsearch/elasticsearch-php/commit/3cde3010912485b08fcc36f8b2fbbc2aee4c9aaf) + - Add NodeNamespace and SnapshotNamespace to Client [[86c0c98]](http://github.com/elasticsearch/elasticsearch-php/commit/86c0c98a79e60d3a65bc7809d0ff0a618fc807e3) + - Update endpoints to be 1.0 compatible [[2453a7e]](http://github.com/elasticsearch/elasticsearch-php/commit/2453a7efc70f3b2a25e71e41a0a8823fdc99c75a) + - Setups should be run for every yaml "doc" [[e36b6df]](http://github.com/elasticsearch/elasticsearch-php/commit/e36b6df3771bc6dfe6c48a53d41ecf3c92aa2997) + - Add Cat and a few other new 1.0 endpoints [[73b72b0]](http://github.com/elasticsearch/elasticsearch-php/commit/73b72b082d9ff3dd02e8088f5d6f89c6f6fa5e2e) + - Add version matrix to Readme [[d33d234]](http://github.com/elasticsearch/elasticsearch-php/commit/d33d2347930e8494ec547c928abd2f65fedee2c1) + - Temporarily Remove Travis [[9770b23]](http://github.com/elasticsearch/elasticsearch-php/commit/9770b23fec7682de3beef61d17fa34a5f67e09dd) + - Provide response body when exceptions are ignored [[c0983eb]](http://github.com/elasticsearch/elasticsearch-php/commit/c0983eba9d607f5e63047977126472c78498e342) + - Add documentation about minimum PHP version requirement [[30a68d9]](http://github.com/elasticsearch/elasticsearch-php/commit/30a68d9b623ccccd3ccdae56a0c88234f5fed7e6) + - Update installation docs with version matrix [[ac6ece0]](http://github.com/elasticsearch/elasticsearch-php/commit/ac6ece0b06a52b5e7da3547ed471e38f93fa02a6) + - Fixed table layout in installation.asciidoc [[5153338]](http://github.com/elasticsearch/elasticsearch-php/commit/51533382e4e28e3a23298873944b5d6d9e5a1f6b) + - Unset value in extract method, not calling method [[55cd213]](http://github.com/elasticsearch/elasticsearch-php/commit/55cd213a7d5dabec7790a6c92b30bd4ecb4359c5) + - setBody should not check type [[0baf101]](http://github.com/elasticsearch/elasticsearch-php/commit/0baf10139bd71fe71b81373a03d5edd3b8172669) + - Allow yaml test runner to work with empty objects [[b817b07]](http://github.com/elasticsearch/elasticsearch-php/commit/b817b075467c86ded88f23962ea271050109605a) + - Fix installtion documentation formatting [[a352fc9]](http://github.com/elasticsearch/elasticsearch-php/commit/a352fc9c827431f68f5fca795c2f32c5c159b2d5) + - Fix documentation link to php version requirements page [[ff6dcce]](http://github.com/elasticsearch/elasticsearch-php/commit/ff6dcced74b71e96106fe53e16dce6a8aa959163) + - Add documentation about ignore parameter [[4afc6a8]](http://github.com/elasticsearch/elasticsearch-php/commit/4afc6a8a990c7135b2c616bee6ae04d60f725655) + - [Docs] Update default configuration list [[f239f9d]](http://github.com/elasticsearch/elasticsearch-php/commit/f239f9d724825080d69ede5a2873a5ad730be331) + - [Docs] Add version requirement page to index [[08cabbe]](http://github.com/elasticsearch/elasticsearch-php/commit/08cabbe2b65f9de876c41d264b80ac09df10f746) + - Update unit tests to be 1.0 compatible [[c386538]](http://github.com/elasticsearch/elasticsearch-php/commit/c386538ef5fa266b08a801c9230560f1e8d06218) + - /Cluster/Nodes endpoints should extend a base, abstract class [[e60bca2]](http://github.com/elasticsearch/elasticsearch-php/commit/e60bca214b63fb54d364c23fc546a968fda2e68c) + - /Indices/Warmer/Get should throw exception on bad argument combination [[c053208]](http://github.com/elasticsearch/elasticsearch-php/commit/c053208387bfa85872fbd93829641a4da901a819) + - If `type` is specified but not `index`, default to _all [[60e653c]](http://github.com/elasticsearch/elasticsearch-php/commit/60e653caa05cc8c2603351e537ca79b87bc488d3) + - [Docs] Add minimum PHP version requirement to Readme [[96f1b8b]](http://github.com/elasticsearch/elasticsearch-php/commit/96f1b8bae068d0fb7eb2c5eb44df3c7cc34c6527) + - Add support for skipped tests [[a9d3997]](http://github.com/elasticsearch/elasticsearch-php/commit/a9d39972f731522dc8fff9572aa7136bef91b75e) + - Stats endpoint was missing from Cluster namespace [[383e8af]](http://github.com/elasticsearch/elasticsearch-php/commit/383e8afe88b940065fef253b208d5654f04add73) + - Add ability to skip different feature types [[baf3701]](http://github.com/elasticsearch/elasticsearch-php/commit/baf3701c4fa4de2f4994c562bce24778e3337ecc) + - Rename to `PendingTasks` [[1968314]](http://github.com/elasticsearch/elasticsearch-php/commit/19683143886a0ba99c852b0ad49fc0525d58f8b0) + - Rename `setNode_Id` to `setNodeID` [[dd650ab]](http://github.com/elasticsearch/elasticsearch-php/commit/dd650ab01aef99ef9df458132e4e54c6e6fd361c) + - Add Cat\ThreadPool endpoint [[343fa38]](http://github.com/elasticsearch/elasticsearch-php/commit/343fa38bf0191c7e19a66ec21c819ef37b2ee397) + - Add Cat Namespace [[b069b40]](http://github.com/elasticsearch/elasticsearch-php/commit/b069b4031fddea01ae40da18c746d457f03322fe) + - Typehint for $snapshot should be SnapshotNamespace [[0bd36a7]](http://github.com/elasticsearch/elasticsearch-php/commit/0bd36a76bb2644c2f392455b668ce10008969555) + - Initialize cat namespace [[5ec9257]](http://github.com/elasticsearch/elasticsearch-php/commit/5ec9257907c481ef95e92461d0e9629d258b1116) + - Add SmartSerializer and make default [[8bb8769]](http://github.com/elasticsearch/elasticsearch-php/commit/8bb87692265a9f45c8f7e3d0f33c3e529df7c77a) + - Make SmartSerializer default [[58e11ba]](http://github.com/elasticsearch/elasticsearch-php/commit/58e11bae02fb424f66f1c2004dabcc7e21d1fcff) + - Endpoint should extract node_id, not nodeId [[f9dabd2]](http://github.com/elasticsearch/elasticsearch-php/commit/f9dabd2dcd10f874a760bcd9895c21ced67974d4) + - Cluster/State endpoint accepts a metric parameter [[c0a5d5d]](http://github.com/elasticsearch/elasticsearch-php/commit/c0a5d5da89d4d8b233c86425cb1b45b2cef1523e) + - Metric parameter can accept arrays [[3f7270b]](http://github.com/elasticsearch/elasticsearch-php/commit/3f7270b612393713de0efa02860d91339c215414) + - Fix method name to use proper camel case [[2f8b936]](http://github.com/elasticsearch/elasticsearch-php/commit/2f8b936d38d009b771bf8745bc34f82c313a30d6) + - Add regex assertion support to yaml test runner [[6d28b88]](http://github.com/elasticsearch/elasticsearch-php/commit/6d28b88fdf229474cfc25ec01401c13f0f7f234f) + - Cluster/State accepts `index_templates` parameter [[e674523]](http://github.com/elasticsearch/elasticsearch-php/commit/e674523acdbe0bd8218487e85804d36dc9bbb5ca) + - Temporarily add `indices.create/10_basic` to skip list [[c2b7b43]](http://github.com/elasticsearch/elasticsearch-php/commit/c2b7b43a193c970bc1126a33b1ca1e71cb799b02) + - Add MPercolate Endpoint [[90158a8]](http://github.com/elasticsearch/elasticsearch-php/commit/90158a838e53a01bb5a3e900a69a1ca0b3c5c636) + - Cluster/State accepts index parameter [[c5f30c8]](http://github.com/elasticsearch/elasticsearch-php/commit/c5f30c858f2c1c8d0c84ed97e0f98d83021f668d) + - MPercolate requires the "bulk" version DIC instantiation [[ce39316]](http://github.com/elasticsearch/elasticsearch-php/commit/ce3931645b12a0728663c117b2f4a0eb0c765138) + - Add MTermVectors Endpoint [[ebd3ff3]](http://github.com/elasticsearch/elasticsearch-php/commit/ebd3ff3738818a45d5d3b45f255263c992ebf877) + - Add CountPercolate Endpoint [[054e60a]](http://github.com/elasticsearch/elasticsearch-php/commit/054e60af61bdc1bc7c3d2bf9a2d1582953ce1a0e) + - Percolate endpoint accepts doc ID [[c232f56]](http://github.com/elasticsearch/elasticsearch-php/commit/c232f56b3b985a67c7cc059b9f09b0d2a72b557f) + - Add $id to Percolate URI construction [[35ad222]](http://github.com/elasticsearch/elasticsearch-php/commit/35ad222dbdb5d0634c852b621bd653a0a34576d2) + - Update Percolate parameters and body [[74da187]](http://github.com/elasticsearch/elasticsearch-php/commit/74da187a0472c63704667a1a9909618ffc6cc498) + - Add TermVector Endpoint [[c67c0dd]](http://github.com/elasticsearch/elasticsearch-php/commit/c67c0dd783dd87e511a15e99fde8bcf3eaadae7a) + - Tweak YamlRunner debug output [[d5e5118]](http://github.com/elasticsearch/elasticsearch-php/commit/d5e5118f8e0f42cd27339d983e617c9e3b604621) + - Update unit tests for new serializer interface [[1c206ac]](http://github.com/elasticsearch/elasticsearch-php/commit/1c206acaa03fc65fb30396fb64d7160f503d432b) + - Update Percolate unit tests [[efc7ea8]](http://github.com/elasticsearch/elasticsearch-php/commit/efc7ea84da31adf746e37f986fa134fcb7cebf58) + - Update documentation regarding 1.0 branch [[60fc559]](http://github.com/elasticsearch/elasticsearch-php/commit/60fc5599df4c88a52f0195ed2485e348f9aab5d8) \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/CONTRIBUTING.md b/src/lib/vendor/elasticsearch/elasticsearch/CONTRIBUTING.md new file mode 100644 index 00000000..14b8360f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/CONTRIBUTING.md @@ -0,0 +1,46 @@ +If you have a bugfix or new feature that you would like to contribute to elasticsearch-php, please find or open an issue about it first. Talk about what you would like to do. It may be that somebody is already working on it, or that there are particular issues that you should know about before implementing the change. + +We enjoy working with contributors to get their code accepted. There are many approaches to fixing a problem and it is important to find the best approach before writing too much code. + +The process for contributing to any of the Elasticsearch repositories is similar. + +1. Sign the contributor license agreement + + Please make sure you have signed the [Contributor License Agreement](http://www.elasticsearch.org/contributor-agreement/). We are not asking you to assign copyright to us, but to give us the right to distribute your code without restriction. We ask this of all contributors in order to assure our users of the origin and continuing existence of the code. You only need to sign the CLA once. + +2. Set up your fork for development + + $> git clone https://github.com/elasticsearch/elasticsearch-php.git + $> cd elasticsearch-php + $> git submodule update --init --recursive + $> curl -s http://getcomposer.org/installer | php + $> php composer.phar install --dev + +3. Ensure a version of Elasticsearch is running on your machine. Recommended "test" configuration is: + + $> bin/elasticsearch -Des.gateway.type=none -Des.http.port=9200 \ + -Des.index.store.type=memory -Des.discovery.zen.ping.multicast.enabled=false \ + -Des.node.bench=true -Des.script.disable_dynamic=false + +4. Run the unit and yaml integration tests to ensure your changes do not break existing code. The exported `TEST_BUILD_REF` should match the branch of Elasticsearch that is running on your machine (since tests are specific to the server version): + + $> export TEST_BUILD_REF='origin/1.x' + $> export ES_TEST_HOST='http://localhost:9200' + + Then proceed to initialize the REST yaml tests and run the package. **WARNING: the unit tests will clear your cluster + and data..._do not_ run the tests on a production cluster!** + + $> php util/RestSpecRunner.php + $> php phpunit.phar --bootstrap tests/bootstrap.php --no-configuration \ + --coverage-clover build/logs/clover.xml --exclude-group ignore tests + +4. Rebase your changes + + Update your local repository with the most recent code from the main elasticsearch-php repository, and rebase your branch on top of the latest master branch. We prefer your changes to be squashed into a single commit. + +5. Submit a pull request + + Push your local changes to your forked copy of the repository and submit a pull request. In the pull request, describe what your changes do and mention the number of the issue where discussion has taken place, eg “Closes #123″. Please consider adding or modifying tests related to your changes. + +Then sit back and wait. There will probably be discussion about the pull request and, if any changes are needed, we would love to work with you to get your pull request merged into elasticsearch-php. + diff --git a/src/lib/vendor/elasticsearch/elasticsearch/LICENSE b/src/lib/vendor/elasticsearch/elasticsearch/LICENSE new file mode 100644 index 00000000..67db8588 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/LICENSE @@ -0,0 +1,175 @@ + + 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. diff --git a/src/lib/vendor/elasticsearch/elasticsearch/NOTICE b/src/lib/vendor/elasticsearch/elasticsearch/NOTICE new file mode 100644 index 00000000..5311b67f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/NOTICE @@ -0,0 +1,13 @@ +Copyright 2013 Elasticsearch + +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. \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/README.md b/src/lib/vendor/elasticsearch/elasticsearch/README.md new file mode 100644 index 00000000..ea715174 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/README.md @@ -0,0 +1,196 @@ +elasticsearch-php +================= + +Official low-level client for Elasticsearch. Its goal is to provide common ground for all Elasticsearch-related code in PHP; because of this it tries to be opinion-free and very extendable. + +To maintain consistency across all the low-level clients (Ruby, Python, etc), clients accept simple associative arrays as parameters. All parameters, from the URI to the document body, are defined in the associative array. + + +Features +-------- + + - One-to-one mapping with REST API and other language clients + - Configurable, automatic discovery of cluster nodes + - Persistent, Keep-Alive connections (within the lifetime of the script) + - Load balancing (with pluggable selection strategy) across all available nodes. Defaults to round-robin + - Pluggable connection pools to offer different connection strategies + - Generalized, pluggable architecture - most components can be replaced with your own custom class if specialized behavior is required + +Version Matrix +-------------- +Since there are breaking changes in Elasticsearch 1.0, you need to match your version of Elasticsearch to the appropriate version of this library. +If you are using a version older than 1.0, you must install the `0.4` Elasticsearch-PHP branch. Otherwise, use the `1.0` branch. + +The master branch will always track Elasticsearch master, but it is not recommended to use `dev-master` in your production code. + +| Elasticsearch Version | Elasticsearch-PHP Branch | +| --------------------- | ------------------------ | +| >= 1.0 | 1.0 | +| <= 0.90.* | 0.4 | + +Documentation +-------------- +[Full documentation can be found here.](http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/index.html) Docs are stored within the repo under /docs/, so if you see a typo or problem, please submit a PR to fix it! + +Installation via Composer +------------------------- +The recommended method to install _Elasticsearch-PHP_ is through [Composer](http://getcomposer.org). + +1. Add ``elasticsearch/elasticsearch`` as a dependency in your project's ``composer.json`` file (change version to suit your version of Elasticsearch): + + ```json + { + "require": { + "elasticsearch/elasticsearch": "~1.0" + } + } + ``` + +2. Download and install Composer: + + ```bash + curl -s http://getcomposer.org/installer | php + ``` + +3. Install your dependencies: + + ```bash + php composer.phar install --no-dev + ``` + +4. Require Composer's autoloader + + Composer also prepares an autoload file that's capable of autoloading all of the classes in any of the libraries that it downloads. To use it, just add the following line to your code's bootstrap process: + + ```php + 'abc'); + $params['index'] = 'my_index'; + $params['type'] = 'my_type'; + $params['id'] = 'my_id'; + $ret = $client->index($params); +``` + +Get a document +----- + +Let's get the document that we just indexed: + +```php + $getParams = array(); + $getParams['index'] = 'my_index'; + $getParams['type'] = 'my_type'; + $getParams['id'] = 'my_id'; + $retDoc = $client->get($getParams); +``` + +Search for a document +----- + +Searching is a hallmark of elasticsearch (no surprise there!), so let's perform a basic search. We are going to use the Match query as a demonstration: + +```php + $searchParams['index'] = 'my_index'; + $searchParams['type'] = 'my_type'; + $searchParams['body']['query']['match']['testField'] = 'abc'; + $queryResponse = $client->search($searchParams); + + echo $queryResponse['hits']['hits'][0]['_id']; // Outputs 'abc' +``` + +Update a document +----- +Let's update a document we have indexed: + +```php + $updateParams['index'] = 'my_index'; + $updateParams['type'] = 'my_type'; + $updateParams['id'] = 'my_id'; + $updateParams['body']['doc'] = array('my_key' => 'new_value'); + + $retUpdate = $client->update($updateParams); +``` + +Delete a document +----- + +Alright, let's go ahead and delete the document that we added previously: + +```php + $deleteParams = array(); + $deleteParams['index'] = 'my_index'; + $deleteParams['type'] = 'my_type'; + $deleteParams['id'] = 'my_id'; + $retDelete = $client->delete($deleteParams); +``` + +Delete an index +----- + +Due to the dynamic nature of elasticsearch, the first document we added automatically built an index with some default settings. Let's delete that index because we want to specify our own settings later: + +```php + $deleteParams['index'] = 'my_index'; + $client->indices()->delete($deleteParams); +``` + +Create an index +----- + +Ok, now that we are starting fresh, let's add a new index with some custom settings: +```php + $indexParams['index'] = 'my_index'; + $indexParams['body']['settings']['number_of_shards'] = 2; + $indexParams['body']['settings']['number_of_replicas'] = 0; + $client->indices()->create($indexParams); +``` + +Wrap up +======= + +That was just a crash-course overview of the client and it's syntax. If you are familiar with elasticsearch, you'll notice that the methods are named just like REST endpoints. + +You'll also notice that the client is configured in a manner that facilitates easy discovery via the IDE. All core actions are available under the `$client` object (indexing, searching, getting, etc). Index and cluster management are located under the `$client->indices()` and `$client->cluster()` objects, respectively. + +Check out the rest of the [Documentation](http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/index.html) to see how the entire client works. + + +License +------- + +Copyright 2014 Elasticsearch + +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/src/lib/vendor/elasticsearch/elasticsearch/benchmarks/Elasticsearch/Benchmarks/IndexingEvent.php b/src/lib/vendor/elasticsearch/elasticsearch/benchmarks/Elasticsearch/Benchmarks/IndexingEvent.php new file mode 100644 index 00000000..22348700 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/benchmarks/Elasticsearch/Benchmarks/IndexingEvent.php @@ -0,0 +1,133 @@ + '\Elasticsearch\Connections\CurlMultiConnection' + ); + $this->client = new Client($curlParams); + + $guzzleParams = array( + 'connectionClass' => '\Elasticsearch\Connections\GuzzleConnection' + ); + $this->guzzleClient = new Client($guzzleParams); + + + $this->setupClient = new Client(); + $indexParams['index'] = 'benchmarking_index'; + $indexParams['body']['test']['_all']['enabled'] = false; + $indexParams['body']['test']['properties']['testField'] = array( + 'type' => 'string', + 'store' => 'no', + 'index' => 'no' + ); + + $this->setupClient->indices()->create($indexParams); + + $this->document = array(); + $this->document['body'] = array('testField' => 'abc'); + $this->document['index'] = 'benchmarking_index'; + $this->document['type'] = 'test'; + + $this->mediumDocument = array(); + $this->mediumDocument['body']['testField'] = str_repeat('a', 1000); + $this->mediumDocument['index'] = 'benchmarking_index'; + $this->mediumDocument['type'] = 'test'; + + $this->largeDocument = array(); + $this->largeDocument['body']['testField'] = str_repeat('a', 5000); + $this->largeDocument['index'] = 'benchmarking_index'; + $this->largeDocument['type'] = 'test'; + + } + + protected function classTearDown() + { + $indexParams['index'] = 'benchmarking_index'; + $this->setupClient->indices()->delete($indexParams); + } + + + /** + * @iterations 100 + * @group small + * @baseline + */ + public function curlMultiHandleSmall() + { + $this->client->index($this->document); + } + + /** + * @iterations 100 + * @group medium + * @baseline + */ + public function curlMultiHandleMedium() + { + $this->client->index($this->mediumDocument); + } + + /** + * @iterations 100 + * @group large + * @baseline + */ + public function curlMultiHandleLarge() + { + $this->client->index($this->largeDocument); + } + + /** + * @iterations 100 + * @group small + */ + public function guzzleSmall() + { + $this->guzzleClient->index($this->document); + } + + /** + * @iterations 100 + * @group medium + */ + public function guzzleMedium() + { + $this->guzzleClient->index($this->mediumDocument); + } + + + /** + * @iterations 100 + * @group large + */ + public function guzzleLarge() + { + $this->guzzleClient->index($this->largeDocument); + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/composer.json b/src/lib/vendor/elasticsearch/elasticsearch/composer.json new file mode 100644 index 00000000..7898d7e0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/composer.json @@ -0,0 +1,43 @@ +{ + "name": "elasticsearch/elasticsearch", + "description": "PHP Client for Elasticsearch", + "keywords": ["search","client", "elasticsearch"], + "type": "library", + "license": "Apache 2", + "authors": [ + { + "name": "Zachary Tong" + } + ], + "require": { + "php": ">=5.3.9", + "monolog/monolog": "~1.5", + "pimple/pimple": "~2.1", + "guzzle/http": "~3.7", + "psr/log": "~1.0", + "ext-curl": "*" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*", + "mockery/mockery": "dev-master@dev", + "athletic/athletic": "~0.1", + "symfony/yaml": "2.4.3 as 2.4.2", + "satooshi/php-coveralls": "dev-master", + "mikey179/vfsStream": "~1.2", + "twig/twig": "1.*", + "cpliakas/git-wrapper": "~1.0" + }, + "autoload": { + "psr-0": { + "Elasticsearch": "src/", + "Elasticsearch\\Tests" : "tests/", + "Elasticsearch\\Benchmarks" : "benchmarks/" + } + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/polyfractal/Yaml" + } + ] +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/configuration.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/configuration.asciidoc new file mode 100644 index 00000000..50d4e22d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/configuration.asciidoc @@ -0,0 +1,259 @@ + +== Configuration + +Almost every aspect of the client is configurable. The client is built around http://pimple.sensiolabs.org[Pimple] a light-weight dependency injection container. Most users will only need to configure a few parameters to suit their needs. + +However, since the container also controls all object instantiation, it is possible for users to completely change the internal components used by the client. A user could, for example, write a custom ConnectionPool class and use that instead of the default connection pools that ship with the client + +=== Example: Configuring the Hosts + +A common operation will be telling the client what nodes are in your cluster. By default, the client will connect to 'localhost:9200', which obviously doesn't work in many production environments. + +All configurations (both simple parameters and more advanced component-replacement) are injected into the constructor of the client. + +The client accepts an array of hosts that you would like to connect to. Each value in the array must be a string (either with or without the port number). SSL can be enabled by prefixing the host with 'https': + +[source,php] +---- +$params = array(); +$params['hosts'] = array ( + '192.168.1.1:9200', // IP + Port + '192.168.1.2', // Just IP + 'mydomain.server.com:9201', // Domain + Port + 'mydomain2.server.com', // Just Domain + 'https://localhost', // SSL to localhost + 'https://192.168.1.3:9200' // SSL to IP + Port +); + +$client = new Elasticsearch\Client($params); +---- + +This associative array holds all custom configurations that you may want to set. Often, you'll only need to configure the hosts, but if you need more advanced behavior, read on. + +=== Example: Configuring HTTP Basic Auth +HTTP basic authentication is a very common requirement. To enable Basic Auth in the client, simply set a parameter with the required auth parameters: + +[source,php] +---- +$params = array(); +$params['connectionParams']['auth'] = array( + 'username', + 'password', + 'Basic' <1> +); +$client = new Elasticsearch\Client($params); +---- +<1> Accepts four different options: `Basic`, `Digests`, `NTLM`, `Any` + +After being initialized with authentication credentials, all outgoing requests will automatically include the HTTP auth headers. + + +=== Example: Ignoring exceptions +The library attempts to throw exceptions for common problems. These exceptions +match the HTTP response code provided by Elasticsearch. For example, attempting to +GET a nonexistent document will throw a `MissingDocument404Exception`. + +Exceptions are a useful and consistent way to deal with problems like missing +documents, syntax errors, version conflicts, etc. But sometimes you want +to deal with the response body rather than catch exceptions (often useful +in test suites). + +If you need that behavior, you can configure an `ignore` parameter. The +following setting will ignore the `MissingDocument404Exception` exception and +instead return the JSON provided by Elasticsearch: + +[source,php] +---- +$client = new Client(); + +$params = array( + 'index' => 'test_missing', + 'type' => 'test', + 'id' => 1, + 'ignore' => 404 <1> +); +echo $client->get($params); + +> {"_index":"test_missing","_type":"test","_id":"1","found":false} + + +$params = array( + 'index' => 'test_missing', + 'type' => 'test', + 'ignore' => [400, 404] <2> +); +echo $client->get($params); + +> No handler found for uri [/test_missing/test/] and method [GET] + +---- +<1> This will ignore just the 404 missing exception +<2> `ignore` also accepts an array of exceptions to ignore. In this example, +the `BadRequest400Exception` is being ignored + +It should be noted that the response is simply a string, which may or may not +be encoded as JSON. In the first example, the response body was a complete +JSON object which could be decoded. In the second example, it was simply a string. + +Since the client has no way of knowing what the exception response will contain, +no attempts to decode it are taken. + + +=== Example: Configuring the Logger +By default, logging in the client is disabled for performance reasons. If you wish to enable logging, simply set the `logging` parameter to true: + +[source,php] +---- +$params = array(); +$params['logging'] = true; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + + +This will enable logging to a file called `elasticsearch.log` inside your project directory. The default logging level is `WARN`. This is a logging level +that only describes important events that should probably require action from you. + +Often, you'll want to change the logging location. To change this location, simply do the following: + +[source,php] +---- +$params = array(); +$params['logging'] = true; +$params['logPath'] = '/var/logs/elasticsearch/elasticsearch.log'; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + + +Not all parameters are strings. For example, we can change the logging level of the client: + +[source,php] +---- +$params = array(); +$params['logging'] = true; +$params['logPath'] = '/var/logs/elasticsearch/elasticsearch.log'; +$params['logLevel'] = Psr\Log\LogLevel::INFO; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + + +Easy, right? Let's get a little more complicated and specify a custom logger. By default, the client uses a file-based logger provided by the https://github.com/Seldaek/monolog[Monolog] framework. Monolog provides a variety of loggers. + +Let's log to the SysLog instead of a file: + +[source,php] +---- +use Monolog\Logger; + +// Build a Monolog logger that uses the SyslogHandler +$logger = new Logger('log'); +$handler = new SyslogHandler('my_user'); +$processor = new IntrospectionProcessor(); + +$logger->pushHandler($handler); +$logger->pushProcessor($processor); + +// Over-ride the client's logger object with your own +$params['logging'] = true; +$params['logObject'] = $logger; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + + +The client uses the generic https://github.com/php-fig/log[PSR\Log interface], which means that any PSR\Log compatible loggers will work just fine in the client. +Replacing the logger with another PSR\Log compatible logger is similar to the previous example of configuring a Monolog logger: + +[source,php] +---- +use Monolog\Logger; + +$logger = new MySpecialPSRLogger(); + + +$params['logging'] = true; +$params['logObject'] = $logger; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + + +=== Example: Configuring the Selector Class +When we changed the logger object, we provided a complete object that we wanted to over-ride the default with. There are many configurations where this won't work. For example, the Connection class must be instantiated repeatedly when new connections are made. + +Rather than provide an anonymous function or callback which builds new objects, the client simply accepts a class path which is used to build new objects. + +Let's configure the Selector class. By default, the client uses a Round-Robin selector (called RoundRobinSelector, unsurprisingly). This will select connections in a loop, evenly distributing requests against your whole cluster. + +Let's change it to a different Selector - the RandomSelector: + +[source,php] +---- +$params['selectorClass'] = '\Elasticsearch\ConnectionPool\Selectors\RandomSelector'; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + + +The client will now query random nodes. Let's go one step further and define our own selector, using custom business logic that is specific to your domain. Most configurable components in the client adhere to an interface, which makes it easy to swap them out for your own class. + +Let's make a selector that only chooses the first connection. This is obviously not a good selector (!!!), but it demonstrates the concept well: + +[source,php] +---- +namespace MyProject\Selectors; + +use Elasticsearch\Connections\ConnectionInterface; +use Elasticsearch\ConnectionPool\Selectors\SelectorInterface + +class FirstSelector implements SelectorInterface +{ + + /** + * Selects the first connection + * + * @param array $connections Array of Connection objects + * + * @return ConnectionInterface + */ + public function select($connections) + { + return $connections[0]; + } + +} +---- +{zwsp} + + +And now we can specify that when creating the client: + +[source,php] +---- +$params['selectorClass'] = '\MyProject\Selectors\FirstSelector'; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + + +=== Full list of configurations + +.Default Configurations +[source,php] +---- +$paramDefaults = array( + 'connectionClass' => '\Elasticsearch\Connections\GuzzleConnection', + 'connectionFactoryClass'=> '\Elasticsearch\Connections\ConnectionFactory', + 'connectionPoolClass' => '\Elasticsearch\ConnectionPool\StaticNoPingConnectionPool', + 'selectorClass' => '\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector', + 'serializerClass' => '\Elasticsearch\Serializers\SmartSerializer', + 'sniffOnStart' => false, + 'connectionParams' => array(), + 'logging' => false, + 'logObject' => null, + 'logPath' => 'elasticsearch.log', + 'logLevel' => Log\LogLevel::WARNING, + 'traceObject' => null, + 'tracePath' => 'elasticsearch.log', + 'traceLevel' => Log\LogLevel::WARNING, + 'guzzleOptions' => array(), + 'connectionPoolParams' => array( + 'randomizeHosts' => true + ), + 'retries' => null +); +---- diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/connection-pool.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/connection-pool.asciidoc new file mode 100644 index 00000000..0e84bc46 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/connection-pool.asciidoc @@ -0,0 +1,35 @@ + +== The Connection Pool + +The connection pool is an object inside the client that is responsible for maintaining the current list of nodes. Theoretically, nodes are either dead or alive. + +However, in the real world, things are never so clear. Nodes are sometimes in a gray-zone of _"probably dead but not confirmed"_, _"timed-out but unclear why"_ or _"recently dead but now alive"_. + +The connection pool's job is to manage this set of unruly connections and try to provide the best behavior to the client. There are currently two connection pool implementations: + + - `staticConnectionPool`: the user provides a static list of hosts and the connection pool simply tries to use these connections as required + - `sniffingConnectionPool`: the user provides a seed list of hosts, which the client uses to sniff the rest of the cluster using the Cluster State API + +=== PHP and connection pooling + +At first blush, the `sniffingConnectionPool` implementation seems superior. For many languages, it is. In PHP, the conversation is a bit more nuanced. + +Because PHP is a share-nothing architecture, there is no way to maintain a connection pool across script instances. This means that every script is responsible for creating, maintaining, and destroying connections on every instantiation. + +Sniffing is a relatively lightweight operation but it may be considered a non-negligible overhead for certain PHP applications. + +The average PHP script will likely load the client, execute a few queries and then close. Imagine this script being called 1000 times per second: the sniffing connection pool will perform the sniffing and pinging process 1000 times per second. + +In reality, if your script only executes a few queries, the sniffing concept is _too_ robust. It tends to be more useful in long-lived processes which potentially "out-live" a static list. + +For this reason the default connection pool is currently the `staticConnectionPool`. You can, of course, change this default - but we strong recommend you load test and verify that it does not negatively impact your performance. + +=== RoundRobinSelector vs StickyRoundRobinSelector + +In a similar vein as the connection pool, there is a PHP-specific selector that may be useful to some environments. + +The selector's job is to return a single connection from an array of connections. The default is a round-robin selector that operates on a randomized list of hosts. This ensures an even load of traffic across your cluster. Round-robin'ing happens on a per-request basis (e.g. sequential requests go to different nodes). + +Considering the nature of many PHP scripts, it is possible this is a sub-optimal strategy due to overhead of creating new connections. For that reason, there is a slightly modified `StickyRoundRobinSelector` class. + +This class prefers to use the same connection for every request, but if the node is dead (due to a previous connection failure) it will round-robin to the next node. Using the default `randomizeHosts = true` setting, this still ensures even distribution of load across the cluster. The load will simply be round-robin'ed on a per-script basis rather than a per-query basis. \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/index-operations.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/index-operations.asciidoc new file mode 100644 index 00000000..59ce8500 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/index-operations.asciidoc @@ -0,0 +1,255 @@ + +== Index Operations + +This section will walk you through the various index APIs that are exposed through the client. Index operations include anything that manages an index itself (e.g. create an index, delete, change mappings, etc). + +We'll walk through a few common operations with detailed code snippets, then list the rest of the methods in a table. The parameters are identical to the REST api, so it should be easy to perform the operation you need. + +=== Create an index + +The index operations are all contained under a distinct namespace, separated from other methods that are on the root client object. As an example, let's create a new index: + +[source,php] +---- +$client = new Elasticsearch\Client(); +$indexParams['index'] = 'my_index'; //index + +$client->indices()->create($indexParams); +---- +{zwsp} + + +You can, of course, specify any parameters that would normally be included in a new index creation API. All parameters that would normally go in the request body are located in the 'body' associative array: + +[source,php] +---- +$client = new Elasticsearch\Client(); +$indexParams['index'] = 'my_index'; + +// Index Settings +$indexParams['body']['settings']['number_of_shards'] = 3; +$indexParams['body']['settings']['number_of_replicas'] = 2; + +// Example Index Mapping +$myTypeMapping = array( + '_source' => array( + 'enabled' => true + ), + 'properties' => array( + 'first_name' => array( + 'type' => 'string', + 'analyzer' => 'standard' + ), + 'age' => array( + 'type' => 'integer' + ) + ) +); +$indexParams['body']['mappings']['my_type'] = $myTypeMapping; + +// Create the index +$client->indices()->create($indexParams); +---- +{zwsp} + + +=== Create an index (advanced example) + +This is a more complicated example of creating an index, showing how to define analyzers, tokenizers, filters and index settings. +Although essentially the same as the previous example, the more complicated example can be helpful for "real world" usage +of the client, since this particular syntax is easy to mess up. + +For brevity, the example is presented using PHP 5.4+ short array syntax (`[]` as opposed to `array()`). + +[source,php] +---- +$params = [ + 'index' => 'reuters', + 'body' => [ + 'settings' => [ <1> + 'number_of_shards' => 1, + 'number_of_replicas' => 0, + 'analysis' => [ <2> + 'filter' => [ + 'shingle' => [ + 'type' => 'shingle' + ] + ], + 'char_filter' => [ + 'pre_negs' => [ + 'type' => 'pattern_replace', + 'pattern' => '(\\w+)\\s+((?i:never|no|nothing|nowhere|noone|none|not|havent|hasnt|hadnt|cant|couldnt|shouldnt|wont|wouldnt|dont|doesnt|didnt|isnt|arent|aint))\\b', + 'replacement' => '~$1 $2' + ], + 'post_negs' => [ + 'type' => 'pattern_replace', + 'pattern' => '\\b((?i:never|no|nothing|nowhere|noone|none|not|havent|hasnt|hadnt|cant|couldnt|shouldnt|wont|wouldnt|dont|doesnt|didnt|isnt|arent|aint))\\s+(\\w+)', + 'replacement' => '$1 ~$2' + ] + ], + 'analyzer' => [ + 'reuters' => [ + 'type' => 'custom', + 'tokenizer' => 'standard', + 'filter' => ['lowercase', 'stop', 'kstem'] + ] + ] + ] + ], + 'mappings' => [ <3> + '_default_' => [ <4> + 'properties' => [ + 'title' => [ + 'type' => 'string', + 'analyzer' => 'reuters', + 'term_vector' => 'yes', + 'copy_to' => 'combined' + ], + 'body' => [ + 'type' => 'string', + 'analyzer' => 'reuters', + 'term_vector' => 'yes', + 'copy_to' => 'combined' + ], + 'combined' => [ + 'type' => 'string', + 'analyzer' => 'reuters', + 'term_vector' => 'yes' + ], + 'topics' => [ + 'type' => 'string', + 'index' => 'not_analyzed' + ], + 'places' => [ + 'type' => 'string', + 'index' => 'not_analyzed' + ] + ] + ], + 'my_type' => [ <5> + 'properties' => [ + 'my_field' => [ + 'type' => 'string' + ] + ] + ] + ] + ] +]; +$client->indices()->create($params); +---- +<1> The top level `settings` contains config about the index (# of shards, etc) as well as analyzers +<2> `analysis` is nested inside of `settings`, and contains tokenizers, filters, char filters and analyzers +<3> `mappings` is another element nested inside of `settings`, and contains the mappings for various types +<4> The `_default_` type is a dynamic template that is applied to all fields that don't have an explicit mapping +<5> The `my_type` type is an example of a user-defined type that holds a single field, `my_field` + + +=== Delete an index + +Deleting an index is very simple: + +[source,php] +---- +$deleteParams['index'] = 'my_index'; +$client->indices()->delete($deleteParams); +---- +{zwsp} + + +=== Put Settings API +The Put Settings API allows you to modify any index setting that is dynamic: + +[source,php] +---- +$params['index'] = 'my_index'; +$params['body']['index']['number_of_replicas'] = 0; +$params['body']['index']['refresh_interval'] = -1; + +$ret = $client->indices()->putSettings($params); +---- +{zwsp} + + +=== Get Settings API + +Get Settings API will show you the currently configured settings for one or more indexes: + +[source,php] +---- +// Get settings for one index +$params['index'] = 'my_index'; +$ret = $client->indices()->getSettings($params); + +// Get settings for several indexes +$params['index'] = array('my_index', 'my_index2'); +$ret = $client->indices()->getSettings($params); +---- +{zwsp} + + +=== Put Mappings API + +The Put Mappings API allows you to modify or add to an existing index's mapping. + +[source,php] +---- +// Set the index and type +$params['index'] = 'my_index'; +$params['type'] = 'my_type2'; + +// Adding a new type to an existing index +$myTypeMapping2 = array( + '_source' => array( + 'enabled' => true + ), + 'properties' => array( + 'first_name' => array( + 'type' => 'string', + 'analyzer' => 'standard' + ), + 'age' => array( + 'type' => 'integer' + ) + ) +); +$params['body']['my_type2'] = $myTypeMapping2; + +// Update the index mapping +$client->indices()->putMapping($params); +---- +{zwsp} + + +=== Get Mappings API + +The Get Mappings API will return the mapping details about your indexes and types. Depending on the mappings that you wish to retrieve, you can specify a number of combinations of index and type: + +[source,php] +---- +// Get mappings for all indexes and types +$ret = $client->indices()->getMapping(); + +// Get mappings for all types in 'my_index' +$params['index'] = 'my_index'; +$ret = $client->indices()->getMapping($params); + +// Get mappings for all types of 'my_type', regardless of index +$params['type'] = 'my_type'; +$ret = $client->indices()->getMapping($params); + +// Get mapping 'my_type' in 'my_index' +$params['index'] = 'my_index'; +$params['type'] = 'my_type' +$ret = $client->indices()->getMapping($params); + +// Get mappings for two indexes +$params['index'] = array('my_index', 'my_index2'); +$ret = $client->indices()->getMapping($params); +---- +{zwsp} + + +=== Other APIs in the Indices Namespace +There are a number of other APIs in the indices namespace that allow you to manage your elasticsearch indexes (add/remove templates, flush segments, close indexes, etc). + +If you use an IDE with autocompletion, you should be able to easily explore the indices namespace by typing: + +[source,php] +---- +$client->indices()-> +---- +And perusing the list of available methods. Alternatively, browsing the `\Elasticsearch\Namespaces\Indices.php` file will show you the full list of available method calls (as well as parameter lists in the comments for each method). diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/index.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/index.asciidoc new file mode 100644 index 00000000..7784d9af --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/index.asciidoc @@ -0,0 +1,26 @@ + += Elasticsearch-PHP + +include::overview.asciidoc[] + +include::quickstart.asciidoc[] + +include::installation.asciidoc[] + +include::configuration.asciidoc[] + +include::php_json_objects.asciidoc[] + +include::index-operations.asciidoc[] + +include::indexing-operations.asciidoc[] + +include::search-operations.asciidoc[] + +include::namespaces.asciidoc[] + +include::connection-pool.asciidoc[] + +include::serializers.asciidoc[] + +include::php-version-requirement.asciidoc[] \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/indexing-operations.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/indexing-operations.asciidoc new file mode 100644 index 00000000..803bf590 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/indexing-operations.asciidoc @@ -0,0 +1,144 @@ +== Indexing Operations + +Indexing is very easy in the client. Since associative arrays can easily be converted into JSON documents, indexing documents is simply a matter of providing the correctly structured associative array and calling a method. + +=== Single document indexing + +When indexing a document, you can either provide an ID or let elasticsearch generate one for you. + +{zwsp} + + +.Providing an ID value +[source,php] +---- +$params = array(); +$params['body'] = array('testField' => 'abc'); + +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; +$params['id'] = 'my_id'; + +// Document will be indexed to my_index/my_type/my_id +$ret = $client->index($params); +---- +{zwsp} + + +.Omitting an ID value +[source,php] +---- +$params = array(); +$params['body'] = array('testField' => 'abc'); + +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; + +// Document will be indexed to my_index/my_type/ +$ret = $client->index($params); +---- +{zwsp} + + +Like most of the other APIs, there are a number of other parameters that can be specified. They are specified in the parameter array just like `index` or `type`. For example, let's set the routing and timestamp of this new document: + +.Additional parameters +[source,php] +---- +$params = array(); +$params['body'] = array('testField' => 'xyz'); + +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; +$params['routing'] = 'company_xyz'; +$params['timestamp'] = strtotime("-1d"); + +$ret = $client->index($params); +---- +{zwsp} + + +=== Bulk Indexing + +Elasticsearch also supports bulk indexing of documents. The client provides an interface to bulk index too, but it is less user-friendly. In the future we will be adding "helper" methods that simplify this process. + +The bulk API method expects a bulk body identical to the kind elasticsearch expects: JSON action/metadata pairs separated by new lines. A common bulk-creation +pattern is as follows: + +.Bulk indexing with PHP arrays +[source,php] +---- +for($i = 0; $i < 100; $i++) { + $params['body'][] = array( + 'index' => array( + '_id' => $i + ) + ); + + $params['body'][] = array( + 'doc' => array( + 'my_field' => 'my_value', + 'second_field' => 'some more values' + ) + ); +} + +$responses = $client->bulk($params); +---- + +You can of course use any of the available bulk methods. Here is an example of using upserts: + +.Bulk upserting with PHP arrays +[source,php] +---- +for($i = 0; $i < 100; $i++) { + $params['body'][] = array( + 'update' => array( + '_id' => $i + ) + ); + + $params['body'][] = array( + 'doc_as_upsert' => 'true', + 'doc' => array( + 'my_field' => 'my_value', + 'second_field' => 'some more values' + ) + ); +} + +$responses = $client->bulk($params); +---- + + +==== Bulk updating with Nowdocs + +If you are specifying bulks manually or extracting them from an existing JSON file, http://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.nowdoc:[Nowdocs] are probably the best method. Otherwise, when you construct them algorithmically, take care to ensure newlines ("\n") separates all lines...including the last! + +.Bulk indexing +[source,php] +---- +$params = array(); +$params['body'] = <<<'EOT' +{ "index" : { "_index" : "my_index", "_type" : "my_type", "_id" : "1" } } +{ "field1" : "value1" } + +EOT; + +$ret = $client->bulk($params); +---- +{zwsp} + + +Like the Bulk API, if you specify the index/type in the parameters, you can omit it from the bulk request itself (which often saves a lot of space and redundant data transfer): + +.Bulk indexing w/ explicit index/type +[source,php] +---- +$params = array(); +$params['body'] = <<<'EOT' +{ "index" : { "_id" : "1" } } +{ "field1" : "value1" } + +EOT; + +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; + +$ret = $client->bulk($params); +---- diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/installation.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/installation.asciidoc new file mode 100644 index 00000000..b76813fc --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/installation.asciidoc @@ -0,0 +1,65 @@ +== Installation + +Elasticsearch-php only has a three requirements that you need to worry about: + +* PHP 5.3.9 or higher (link:_php_version_requirement.html[see here for more details]) +* http://getcomposer.org[Composer] +* http://php.net/manual/en/book.curl.php[ext-curl]: the Libcurl extension for PHP + +The rest of the dependencies will automatically be downloaded and installed by Composer. Composer is a package and dependency manager for PHP. Installing elasticsearch-php with Composer is very easy + +=== Version Matrix + +Since there are breaking changes in Elasticsearch 1.0, you need to match your version of Elasticsearch to the appropriate version of this library. +If you are using a version older than 1.0, you must install the `0.4` Elasticsearch-PHP branch. Otherwise, use the `1.0` branch. + +The master branch will always track Elasticsearch master, but it is not recommended to use `dev-master` in your production code. + +[width="40%",options="header",frame="topbot"] +|============================ +|Elasticsearch Version | Elasticsearch-PHP Branch +| >= 1.0 | `1.0` +| <= 0.90.* | `0.4` +|============================ + +=== Composer Installation + +* Include elasticsearch-php in your `composer.json` file. If you are starting a new project, simply paste the following JSON snippet into a new file called `composer.json`. If you have an existing project, include this requirement under the rest of requirements already present: ++ +[source,json] +-------------------------- +{ + "require": { + "elasticsearch/elasticsearch": "~1.0" + } +} +-------------------------- + +* Install the client with composer. The first command download the `composer.phar` PHP package, and the second command invokes the installation. Composer will automatically download any required dependencies, store them in a /vendor/ directory and build an autoloader.: ++ +[source,shell] +-------------------------- +curl -s http://getcomposer.org/installer | php +php composer.phar install --no-dev +-------------------------- + +* Finally, include the generated autoloader in your main project. If your project is already based on Composer, the autoloader is likely already included somewhere and you don't need to add it again. Finally, instantiate a new client: ++ +[source,php] +-------------------------- +require 'vendor/autoload.php'; + +$client = new Elasticsearch\Client(); +-------------------------- + +More information about http://getcomposer.org/[Composer can be found at their website]. + +=== --no-dev flag +You'll notice that the installation command specified `--no-dev`. This prevents Composer +from installing the various testing and development dependencies. For average users, there +is no need to install the test suite. In particular, the development dependencies include +a full copy of Elasticsearch so that tests can be run against the REST specifications This +is a rather large download for non-developers, hence the --no-dev flag + +If you wish to contribute to development of this library, just omit the `--no-dev` flag to +be able to run tests. diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/namespaces.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/namespaces.asciidoc new file mode 100644 index 00000000..c24a52db --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/namespaces.asciidoc @@ -0,0 +1,82 @@ + +== Namespaces + +The client has a number of "namespaces", which generally expose administrative +functionality. The namespaces correspond to the various administrative endpoints +in Elasticsearch. This is a complete list of namespaces: + + +[width="40%",options="header",frame="topbot"] +|============================ +| Namespace | Functionality +| `indices()` | Index-centric stats and info +| `nodes()` | Node-centric stats and info +| `cluster()` | Cluster-centric stats and info +| `snapshot()` | Methods to snapshot/restore your cluster and indices +| `cat()` | Access to the Cat API (which is generally used standalone from the command line +|============================ + +Some methods are available in several different namespaces, which give you +the same information but grouped into different contexts. To see how these +namespaces work, let's look at the `_stats` output: + + +[source,php] +---- +$client = new Elasticsearch\Client(); + +// Index Stats +// Corresponds to curl -XGET localhost:9200/_stats +$response = $client->indices()->stats(); + +// Node Stats +// Corresponds to curl -XGET localhost:9200/_nodes/stats +$response = $client->nodes()->stats(); + +// Cluster Stats +// Corresponds to curl -XGET localhost:9200/_cluster/stats +$response = $client->cluster()->stats(); +---- +{zwsp} + + +As you can see, the same `stats()` call is made through three different +namespaces. Sometimes the methods require parameters. These parameters work +just like any other method in the library. + +For example, we can requests index stats about a specific index, or multiple +indices: + +[source,php] +---- +$client = new Elasticsearch\Client(); + +// Corresponds to curl -XGET localhost:9200/my_index/_stats +$params['index'] = 'my_index'; +$response = $client->indices()->stats($params); + +// Corresponds to curl -XGET localhost:9200/my_index1,my_index2/_stats +$params['index'] = array('my_index1', 'my_index2'); +$response = $client->indices()->stats($params); +---- +{zwsp} + + +As another example, here is how you might add an alias to an existing index: + +[source,php] +---- +$params['body'] = array( + 'actions' => array( + array( + 'add' => array( + 'index' => 'myindex', + 'alias' => 'myalias' + ) + ) + ) +); +$client->indices()->updateAliases($params); +---- + +Notice how both the `stats` calls and the updateAlias took a variety of parameters, +each according to what the particular API requires. The `stats` API only requires +an index name(s), while the `updateAlias` requires a body of actions. \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/overview.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/overview.asciidoc new file mode 100644 index 00000000..f2dda5ae --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/overview.asciidoc @@ -0,0 +1,8 @@ +== Overview + +This is the official PHP client for Elasticsearch. It is designed to be a very low-level client that does not stray from the REST API. + +All methods closely match the REST API, and furthermore, match the method structure of other language clients (ruby, python, etc). We hope that this consistency makes it easy to get started with a client, and to seamlessly switch from one language to the next with minimal effort. + +The client is designed to be "unopinionated". There are a few universal niceties added to the client (cluster state sniffing, round-robin requests, etc) but largely it is very barebones. This was intentional. We want a common base that more sophisticated libraries can build on top of. + diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/php-version-requirement.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/php-version-requirement.asciidoc new file mode 100644 index 00000000..dba261c1 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/php-version-requirement.asciidoc @@ -0,0 +1,64 @@ +== PHP Version Requirement + +Elasticsearch-php requires PHP version 5.3.9 or higher. There are two bugs in PHP +below 5.3.9 which cause problems for this library. + +=== Bug #54367 + +https://bugs.php.net/bug.php?id=54367[Bug #54367 (Use of closure causes Problem in Array Access)] +prevents closures from working if they implement ArrayAccess. Pimple, the dependency +injection container used in this library, makes heavy use of ArrayAccess. In several +places, Elasticsearch-php closes over the pimple object itself +to return a new function (providing a lightweight factory type method, without +actually creating dedicated factory objects). + +For example, this code would trigger bug #54367: + +[source,php] +-------------------------- +private function setConnectionObj() +{ + $this->dic['connection'] = function ($dicParams) { + return function ($host, $port = null) use ($dicParams) { // <--- This is the problem + return new $dicParams['connectionClass']( + $host, + $port, + $dicParams['connectionParamsShared'], + $dicParams['logObject'], + $dicParams['traceObject'] + ); + }; + }; +} +-------------------------- + +Notice how `return function ($host, $port = null) use ($dicParams)` captures +`$dicParams` (which is a Pimple object) in the closure. + +=== Bug #43200 +Bug #54367 was fixed in PHP 5.3.7, but we run into a different bug now. +https://bugs.php.net/bug.php?id=43200[Bug #43200 (Interface implementation / inheritence not possible in abstract classes)] +now becomes a problem. In short, this bug occurs when you combine interfaces with concrete +functions that are implemented in an abstract class. + +Elasticsearch-php uses both interfaces and abstract classes in this manner. The interfaces +provide a contract which all implementing objects must follow. This is important +so that users can provide their own implementations for custom logic. By implementing +the interface, they are guaranteed that their code will work correctly with the library. + +Abstract classes are used to provide common functionality between different classes. +For example, many Elasticsearch endpoints (search, get, index, etc) use similar +URI parameters such as `index` and `type`. Instead of duplicating the code between all +these classes, a single abstract class provides concrete implementations of the +methods. + +This means that the library runs into bug #43200 and is unusable until 5.3.9 +when it was fixed. + +=== Conclusion +In summary, PHP version 5.3.9 is the lowest compatible version. There are currently +no plans to refactor the code to work around these two bugs. + +PHP 5.3.9 is nearly two years old, and two new major versions (5.4, 5.5) have been +released since then. It is highly advised to upgrade to a newer major version, as +a large number of bugs and performance improvements have been made during that time. \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/php_json_objects.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/php_json_objects.asciidoc new file mode 100644 index 00000000..ac8b1421 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/php_json_objects.asciidoc @@ -0,0 +1,161 @@ + +== Dealing with JSON Arrays and Objects in PHP + +A common source of confusion with the client revolves around JSON arrays and objects, and how to specify them in PHP. +In particular, problems are caused by empty objects and arrays of objects. This page will show you some common patterns +used in Elasticsearch JSON API, and how to convert that to a PHP representation + +=== Empty Objects + +The Elasticsearch API uses empty JSON objects in several locations, and this can cause problems for PHP. Unlike other +languages, PHP does not have a "short" notation for empty objects and so many developers are unaware how to specify +an empty object. + +Consider adding a Highlight to a query: + +[source,json] +---- +{ + "query" : { + "match" : { + "content" : "quick brown fox" + } + }, + "highlight" : { + "fields" : { + "content" : {} <1> + } + } +} +---- +<1> This empty JSON object is what causes problems. + +The problem is that PHP will automatically convert `"content" : {}` into `"content" : []`, which is no longer valid +Elasticsearch DSL. We need to tell PHP that the empty object is explicitly an object, not an array. To define this +query in PHP, you would do: + +[source,json] +---- +$params['body'] = array( + 'query' => array( + 'match' => array( + 'content' => 'quick brown fox' + ) + ), + 'highlight' => array( + 'fields' => array( + 'content' => new \stdClass() <1> + ) + ) +); +$results = $client->search($params); +---- +<1> We use the generic PHP stdClass object to represent an empty object. The JSON will now encode correctly. + +By using an explicit stdClass object, we can force the `json_encode` parser to correctly output an empty object, instead +of an empty array. Sadly, this verbose solution is the only way to acomplish the goal in PHP...there is no "short" +version of an empty object. + +=== Arrays of Objects + +Another common pattern in Elasticsearch DSL is an array of objects. For example, consider adding a sort to your query: + +[source,json] +---- +{ + "query" : { + "match" : { "content" : "quick brown fox" } + }, + "sort" : [ <1> + {"time" : {"order" : "desc"}}, + {"popularity" : {"order" : "desc"}} + ] +} +---- +<1> "sort" contains an array of JSON objects + +This arrangement is *very* common, but the construction in PHP can be tricky since it requires nesting arrays. The +verbosity of PHP tends to obscure what is actually going on. To construct an array of objects, you actually need +an array of arrays: + +[source,json] +---- +$params['body'] = array( + 'query' => array( + 'match' => array( + 'content' => 'quick brown fox' + ) + ), + 'sort' => array( <1> + array('time' => array('order' => 'desc')), <2> + array('popularity' => array('order' => 'desc')) <3> + ) +); +$results = $client->search($params); +---- +<1> This array encodes the `"sort" : []` array +<2> This array encodes the `{"time" : {"order" : "desc"}}` object +<3> This array encodes the `{"popularity" : {"order" : "desc"}}` object + +If you are on PHP 5.4+, I would strongly encourage you to use the short array syntax. It makes these nested arrays +much simpler to read: + +[source,json] +---- +$params['body'] = [ + 'query' => [ + 'match' => [ + 'content' => 'quick brown fox' + ] + ], + 'sort' => [ + ['time' => ['order' => 'desc']], + ['popularity' => ['order' => 'desc']] + ] +]; +$results = $client->search($params); +---- + +=== Arrays of empty objects + +Occasionally, you'll encounter DSL that requires both of the previous patterns. The function score query is a good +example, it sometimes requires an array of objects, and some of those objects might be empty JSON objects. + +Given this query: +[source,json] +---- +{ + "query":{ + "function_score":{ + "functions":[ + { + "random_score":{} + } + ], + "boost_mode":"replace" + } + } +} +---- + +We can build it using the following PHP code: + + +[source,json] +---- +$params['body'] = array( + 'query' => array( + 'function_score' => array( + 'functions' => array( <1> + array( <2> + 'random_score' => new \stdClass() <3> + ) + ) + ) + ) +); +$results = $client->search($params); +---- +<1> This encodes the array of objects: `"functions" : []` +<2> This encodes an object inside the array: `{ "random_score": {} }` +<3> This encodes the empty JSON object: `"random_score": {}` \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/quickstart.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/quickstart.asciidoc new file mode 100644 index 00000000..ab0b278d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/quickstart.asciidoc @@ -0,0 +1,122 @@ + +== Quickstart + +This section will give you a quick overview of the client and how the major functions work. + +=== Installation + +* Include elasticsearch-php in your `composer.json` file: ++ +[source,json] +---------------------------- +{ + "require": { + "elasticsearch/elasticsearch": "~1.0" + } +} +---------------------------- + +* Install the client with composer: ++ +[source,shell] +---------------------------- +curl -s http://getcomposer.org/installer | php +php composer.phar install +---------------------------- + +* Include the autoloader in your main project (if you haven't already), and instantiate a new client : ++ +[source,php] +---------------------------- +require 'vendor/autoload.php'; + +$client = new Elasticsearch\Client(); +---------------------------- + + +=== Index a document + +In elasticsearch-php, almost everything is configured by associative arrays. The REST endpoint, document and optional parameters - everything is an associative array. + +To index a document, we simply specify a `body` that contains the document that we wish to index. Each field in the document is represented by a different key/value pair in the associative array. + +The index, type and ID are also specified in the parameters assoc. array: + +[source,php] +---------------------------- +$params = array(); +$params['body'] = array('testField' => 'abc'); +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; +$params['id'] = 'my_id'; +$ret = $client->index($params); +---------------------------- + +=== Get a document + +Let's get the document that we just indexed: + +[source,php] +---------------------------- +$getParams = array(); +$getParams['index'] = 'my_index'; +$getParams['type'] = 'my_type'; +$getParams['id'] = 'my_id'; +$retDoc = $client->get($getParams); +---- + +=== Search for a document + +Searching is a hallmark of elasticsearch, so let's perform a search. We are going to use the Match query as a demonstration: + +[source,php] +---------------------------- +$searchParams['index'] = 'my_index'; +$searchParams['type'] = 'my_type'; +$searchParams['body']['query']['match']['testField'] = 'abc'; +$retDoc = $client->search($searchParams); +---------------------------- + +=== Delete a document + +Alright, let's go ahead and delete the document that we added previously: + +[source,php] +---------------------------- +$deleteParams = array(); +$deleteParams['index'] = 'my_index'; +$deleteParams['type'] = 'my_type'; +$deleteParams['id'] = 'my_id'; +$retDelete = $client->delete($deleteParams); +---------------------------- + +=== Delete an index + +Due to the dynamic nature of elasticsearch, the first document we added automatically built an index with some default settings. Let's delete that index because we want to specify our own settings later: + +[source,php] +---------------------------- +$deleteParams['index'] = 'my_index'; +$client->indices()->delete($deleteParams); +---------------------------- + +=== Create an index + +Ok, now that we are starting fresh, let's add a new index with some custom settings: + +[source,php] +---------------------------- +$indexParams['index'] = 'my_index'; +$indexParams['body']['settings']['number_of_shards'] = 2; +$indexParams['body']['settings']['number_of_replicas'] = 0; +$client->indices()->create($indexParams); +---------------------------- + +=== Wrap up + +That was just a crash-course overview of the client and it's syntax. If you are familiar with elasticsearch, you'll notice that the methods are named just like REST endpoints. + +You'll also notice that the client is configured in a manner that facilitates easy discovery via your IDE. All core actions are available under the `$client` object (indexing, searching, getting, etc). Index and cluster management are located under the `$client->indices()` and `$client->cluster()` objects, respectively. + +Check out the rest of the Documentation to see how the entire client works. + diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/search-operations.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/search-operations.asciidoc new file mode 100644 index 00000000..3664da7e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/search-operations.asciidoc @@ -0,0 +1,225 @@ +== Search Operations + +Well...it isn't called elasticsearch for nothing! Let's talk about search operations in the PHP client. + +The client gives you full access to every query and parameter exposed by the REST API, following the naming scheme as much as possible. Let's look at a few examples so you can become familiar with the syntax. + +=== Match Query + +Here is a standard curl for a Match query: + +[source,shell] +---- +curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{ + "query" : { + "match" : { + "testField" : "abc" + } + } +}' +---- +{zwsp} + + +And here is the same query constructed in the client: + +[source,php] +---- +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; +$params['body']['query']['match']['testField'] = 'abc'; + +$results = $client->search($params); +---- +{zwsp} + + + +.Using Raw JSON +**** +As you can see, the translation between JSON and query is very straightforward. You could serialize JSON directly into the body, or even provide the raw JSON string. The client will handle it just fine: + +[source,php] +---- +$json = '{ + "query" : { + "match" : { + "testField" : "abc" + } + } +}'; + +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; +$params['body'] = $json; + +$results = $client->search($params); +---- +**** +{zwsp} + + +The search results that come back are simply elasticsearch response elements serialized into an array. Working with the search results is as simple as iterating over the array values: + +[source,php] +---- +$milliseconds = $results['took']; +$maxScore = $results['hits']['max_score']; + +$score = $results['hits']['hits'][0]['_score']; +$doc = $results['hits']['hits'][0]['_source']; +---- +{zwsp} + + +=== Bool Queries + +Bool queries can be easily constructed using the client. For example, this query: +[source,shell] +---- +curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{ + "query" : { + "bool" : { + "must": { + "match" : { + "testField" : "abc" + }, + "match" : { + "anotherTestField" : "xyz" + } + } + } + } +}' +---- +{zwsp} + + +Would be structured like this (Note the position of the square brackets): +[source,php] +---- +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; +$params['body']['query']['bool']['must'][]['match']['testField'] = 'abc'; +$params['body']['query']['bool']['must'][]['match']['anotherTestField'] = 'xyz'; + +$results = $client->search($params); +---- +{zwsp} + + + +=== A more complicated example + +Let's construct a slightly more complicated example: a filtered query that contains both a filter and a query. This is a very common activity in elasticsearch queries, so it will be a good demonstration. + +The curl version of the query: + +[source,shell] +---- +curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{ + "query" : { + "filtered" : { + "filter" : { + "term" : { + "my_field" : "abc" + } + }, + "query" : { + "match" : { + "my_other_field" : "xyz" + } + } + } + } +}' +---- +{zwsp} + + +And in PHP: + +[source,php] +---- +$params['index'] = 'my_index'; +$params['type'] = 'my_type'; + +$filter = array(); +$filter['term']['my_field'] = 'abc'; + +$query = array(); +$query['match']['my_other_field'] = 'xyz'; + +$params['body']['query']['filtered'] = array( + "filter" => $filter, + "query" => $query +); + +$results = $client->search($params); +---- +{zwsp} + + +For clarity and ease of readability, the filter and query sections were allocated individually as variables and then composed together later. This is often a good design pattern for applications, since it lets you treat the queries and filters as building blocks that can be passed around your application. + +Of course, at the end of the day, it is built into a single array. You could easily build the entire array in one definition of nested array blocks, or build them line-by-line. + +All the client requires is an associative array with a structure that matches the JSON query structure. + +=== Function_Score query +A special note needs to be made about the `function_score` query. Due to the way PHP handles JSON encoding, everything is converted to an array of one for or another. +This is usually not a problem, since most places in the Elasticsearch API accept arrays or empty objects interchangeably. + +However, the `function_score` is a little different and needs to differentiate between empty arrays and empty objects. For example, consider this query: + +[source,json] +---- +{ + "query":{ + "function_score":{ + "functions":[ + { + "random_score":{} + } + ], + "boost_mode":"replace", + "query":{ + "match_all":{} + } + } + } +} +---- + +The `function_score` defines an array of objects, and the `random_score` key has an empty object as it's value. PHP's json_encode will convert that query to this: + +[source,json] +---- +{ + "query":{ + "function_score":{ + "functions":[ + { + "random_score":[] + } + ], + "boost_mode":"replace", + "query":{ + "match_all":[] + } + } + } +} +---- + +Which will result in a parse exception from Elasticsearch. What we need to do is tell PHP that `random_score` contains an empty *object*, not an array. To do so, +we need to specify an explicitly empty object: + +[source,json] +---- +$params['body'] = array( + 'query' => array( + 'function_score' => array( + 'functions' => array( + array("random_score" => new \stdClass()) + ), + 'query' => array('match_all' => array()) + ) + ) +); +$results = $client->search($params); +---- + +Now, the JSON will be encoded properly and your query will no longer generate a parser exception. diff --git a/src/lib/vendor/elasticsearch/elasticsearch/docs/serializers.asciidoc b/src/lib/vendor/elasticsearch/elasticsearch/docs/serializers.asciidoc new file mode 100644 index 00000000..f6bfc977 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/docs/serializers.asciidoc @@ -0,0 +1,112 @@ + +== Serializers + +The client has three serializers available. You will most likely never need +to change the serializer, unless you have special requirements or are +implementing a new protocol. + +The job of the serializer is to encode the outgoing request body and decode +the incoming response body. In 99% of cases, this is a simple conversion +to/from JSON. + +The default serializer is the `SmartSerializer` + +=== SmartSerializer +==== Serialize() +The `SmartSerializer` inspects the data to be encoded. If the request body +is provided as a string, it is passed directly to Elasticsearch as a string. +This allows users to provide raw JSON, or raw strings for certain endpoints that +dont have structure (such as the Analyze endpoint). + +If the data is an array, it is converted to json. If the data provided was an +empty array, the serializer manually converts the JSON from an empty array (`[]`) +to an empty object (`{}`) so that it is valid JSON for Elasticsearch request +bodies. + +==== Deserialize() +When decoding the response body, the `SmartSerializer` introspects the +`content_type` headers to determine the appropriate encoding. If the data is +encoded as JSON, it is decoded into an array using `json_decode`. Otherwise, +it is returned as a string. + +This functionality is required to cooperate with endpoints such as the `Cat` +endpoints, which return tabular text instead of JSON. + +=== ArrayToJSONSerializer +==== Serialize() +The `ArrayToJSONSerializer` inspects the data to be encoded. If the request body +is provided as a string, it is passed directly to Elasticsearch as a string. +This allows users to provide raw JSON, or raw strings for certain endpoints that +dont have structure (such as the Analyze endpoint). + +If the data is an array, it is converted to json. If the data provided was an +empty array, the serializer manually converts the JSON from an empty array (`[]`) +to an empty object (`{}`) so that it is valid JSON for Elasticsearch request +bodies. + +==== Deserialize() +When decoding the response body, everything is decoded to JSON from JSON. If +the data is not valid JSON, `null` will be returned. + +=== EverythingToJSONSerializer +==== Serialize() +The `EverythingToJSONSerializer` tries to convert everything to JSON. + +If the data provided was an empty array, the serializer manually converts the +JSON from an empty array (`[]`) to an empty object (`{}`) so that it is valid +JSON for Elasticsearch request bodies. + +If the data was not an array and/or not convertible to JSON, the method returns +`null`. + +==== Deserialize() +When decoding the response body, everything is decoded to JSON from JSON. If +the data is not valid JSON, `null` will be returned. + + +=== Implementing your own Serializer +If you want to use your own custom serializer, you need to implement the +`SerializerInterface` interface: + + +[source,php] +---- +class MyCustomSerializer implements SerializerInterface +{ + + /** + * Serialize request body + * + * @param string|array $data Request body + * + * @return string + */ + public function serialize($data) + { + // code here + } + + /** + * Deserialize response body + * + * @param string $data Response body + * @param array $headers Response Headers + * + * @return array|string + */ + public function deserialize($data, $headers) + { + // code here + } +} +---- +{zwsp} + + +To use it, you simply provide the class path in the configuration parameters: + +[source,php] +---- +$params['serializerClass'] = '\MyProject\Serializers\MyCustomSerializer'; +$client = new Elasticsearch\Client($params); +---- +{zwsp} + \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/run_travis_test.sh b/src/lib/vendor/elasticsearch/elasticsearch/run_travis_test.sh new file mode 100755 index 00000000..24c31c70 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/run_travis_test.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +if [ -z $ES_VERSION ]; then + echo "No ES_VERSION specified"; + exit 1; +fi; + +ES_DIR="elasticsearch-$ES_VERSION" + +killall java 2>/dev/null + +if [ ! -d $ES_DIR ]; then + echo "Downloading Elasticsearch v${ES_VERSION}" + ES_URL="https://download.elasticsearch.org/elasticsearch/elasticsearch/${ES_DIR}.zip" + curl -O $ES_URL + unzip "${ES_DIR}.zip" +fi; + +echo "Starting Elasticsearch v${ES_VERSION}" +./${ES_DIR}/bin/elasticsearch \ + -Des.network.host=localhost \ + -Des.discovery.zen.ping.multicast.enabled=false \ + -Des.discovery.zen.ping_timeout=1 + +sleep 3 + +phpunit --bootstrap tests/bootstrap.php --no-configuration --coverage-clover build/logs/clover.xml --exclude-group ignore tests \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Client.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Client.php new file mode 100644 index 00000000..64af8069 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Client.php @@ -0,0 +1,1569 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class Client +{ + + /** + * @var Transport + */ + public $transport; + + /** + * @var \Pimple\Container + */ + protected $params; + + /** + * @var IndicesNamespace + */ + protected $indices; + + /** + * @var ClusterNamespace + */ + protected $cluster; + + /** + * @var NodesNamespace + */ + protected $nodes; + + /** + * @var SnapshotNamespace + */ + protected $snapshot; + + /** + * @var CatNamespace + */ + protected $cat; + + /** @var callback */ + protected $dicEndpoints; + + + /** + * Client constructor + * + * @param array $params Array of injectable parameters + */ + public function __construct($params = array()) + { + $this->setParams($params); + $this->setLogging(); + $this->transport = $this->params['transport']; + $this->indices = $this->params['indicesNamespace']; + $this->cluster = $this->params['clusterNamespace']; + $this->nodes = $this->params['nodesNamespace']; + $this->snapshot = $this->params['snapshotNamespace']; + $this->cat = $this->params['catNamespace']; + $this->dicEndpoints = $this->params['endpoint']; + } + + + /** + * + * + * @return array + */ + public function info() + { + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Info $endpoint */ + $endpoint = $endpointBuilder('Info'); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + public function ping() + { + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Ping $endpoint */ + $endpoint = $endpointBuilder('Ping'); + + try { + $response = $endpoint->performRequest(); + } catch (Missing404Exception $exception) { + return false; + } + + if (isset($response['status']) === true && $response['status'] === 200) { + return true; + } else { + return false; + } + } + + + /** + * $params['id'] = (string) The document ID (Required) + * ['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (use `_all` to fetch the first document matching the ID across all types) (Required) + * ['ignore_missing'] = ?? + * ['fields'] = (list) A comma-separated list of fields to return in the response + * ['parent'] = (string) The ID of the parent document + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['realtime'] = (boolean) Specify whether to perform the operation in realtime or search mode + * ['refresh'] = (boolean) Refresh the shard containing the document before performing the operation + * ['routing'] = (string) Specific routing value + * ['_source'] = (list) True or false to return the _source field or not, or a list of fields to return + * ['_source_exclude'] = (list) A list of fields to exclude from the returned _source field + * ['_source_include'] = (list) A list of fields to extract and return from the _source field + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function get($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Get $endpoint */ + $endpoint = $endpointBuilder('Get'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['id'] = (string) The document ID (Required) + * ['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (use `_all` to fetch the first document matching the ID across all types) (Required) + * ['ignore_missing'] = ?? + * ['parent'] = (string) The ID of the parent document + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['realtime'] = (boolean) Specify whether to perform the operation in realtime or search mode + * ['refresh'] = (boolean) Refresh the shard containing the document before performing the operation + * ['routing'] = (string) Specific routing value + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getSource($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Get $endpoint */ + $endpoint = $endpointBuilder('Get'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type) + ->returnOnlySource(); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['id'] = (string) The document ID (Required) + * ['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (Required) + * ['consistency'] = (enum) Specific write consistency setting for the operation + * ['parent'] = (string) ID of parent document + * ['refresh'] = (boolean) Refresh the index after performing the operation + * ['replication'] = (enum) Specific replication type + * ['routing'] = (string) Specific routing value + * ['timeout'] = (time) Explicit operation timeout + * ['version_type'] = (enum) Specific version type + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function delete($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Delete $endpoint */ + $endpoint = $endpointBuilder('Delete'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * + * $params[''] @todo finish the rest of these params + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param array $params + * + * @return array + */ + public function deleteByQuery($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\DeleteByQuery $endpoint */ + $endpoint = $endpointBuilder('DeleteByQuery'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of indices to restrict the results + * ['type'] = (list) A comma-separated list of types to restrict the results + * ['min_score'] = (number) Include only documents with a specific `_score` value in the result + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['routing'] = (string) Specific routing value + * ['source'] = (string) The URL-encoded query definition (instead of using the request body) + * ['body'] = (array) A query to restrict the results (optional) + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function count($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Count $endpoint */ + $endpoint = $endpointBuilder('Count'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['index'] = (list) A comma-separated list of indices to restrict the results + * ['type'] = (list) A comma-separated list of types to restrict the results + * ['id'] = (string) ID of document + * ['ignore_unavailable'] = (boolean) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['routing'] = (string) Specific routing value + * ['allow_no_indices'] = (boolean) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['body'] = (array) A query to restrict the results (optional) + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['percolate_index'] = (string) The index to count percolate the document into. Defaults to index. + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * ['version'] = (number) Explicit version number for concurrency control + * ['version_type'] = (enum) Specific version type + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function countPercolate($params = array()) + { + $index = $this->extractArgument($params, 'index'); + $type = $this->extractArgument($params, 'type'); + $id = $this->extractArgument($params, 'id'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\CountPercolate $endpoint */ + $endpoint = $endpointBuilder('CountPercolate'); + $endpoint->setIndex($index) + ->setType($type) + ->setID($id) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index with a registered percolator query (Required) + * ['type'] = (string) The document type (Required) + * ['prefer_local'] = (boolean) With `true`, specify that a local shard should be used if available, with `false`, use a random shard (default: true) + * ['body'] = (array) The document (`doc`) to percolate against registered queries; optionally also a `query` to limit the percolation to specific registered queries + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function percolate($params) + { + $index = $this->extractArgument($params, 'index'); + $type = $this->extractArgument($params, 'type'); + $id = $this->extractArgument($params, 'id'); + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Percolate $endpoint */ + $endpoint = $endpointBuilder('Percolate'); + $endpoint->setIndex($index) + ->setType($type) + ->setID($id) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) Default index for items which don't provide one + * ['type'] = (string) Default document type for items which don't provide one + * ['ignore_unavailable'] = (boolean) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (boolean) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function mpercolate($params = array()) + { + $index = $this->extractArgument($params, 'index'); + $type = $this->extractArgument($params, 'type'); + $body = $this->extractArgument($params, 'body'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\MPercolate $endpoint */ + $endpoint = $endpointBuilder('MPercolate'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) Default index for items which don't provide one + * ['type'] = (string) Default document type for items which don't provide one + * ['term_statistics'] = (boolean) Specifies if total term frequency and document frequency should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['field_statistics'] = (boolean) Specifies if document count, sum of document frequencies and sum of total term frequencies should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['fields'] = (list) A comma-separated list of fields to return. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['offsets'] = (boolean) Specifies if term offsets should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['positions'] = (boolean) Specifies if term positions should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['payloads'] = (boolean) Specifies if term payloads should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) .Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * ['routing'] = (string) Specific routing value. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * ['parent'] = (string) Parent id of documents. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function termvector($params = array()) + { + $index = $this->extractArgument($params, 'index'); + $type = $this->extractArgument($params, 'type'); + $id = $this->extractArgument($params, 'id'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\TermVector $endpoint */ + $endpoint = $endpointBuilder('TermVector'); + $endpoint->setIndex($index) + ->setType($type) + ->setID($id) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) Default index for items which don't provide one + * ['type'] = (string) Default document type for items which don't provide one + * ['ids'] = (list) A comma-separated list of documents ids. You must define ids as parameter or set \"ids\" or \"docs\" in the request body + * ['term_statistics'] = (boolean) Specifies if total term frequency and document frequency should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['field_statistics'] = (boolean) Specifies if document count, sum of document frequencies and sum of total term frequencies should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['fields'] = (list) A comma-separated list of fields to return. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['offsets'] = (boolean) Specifies if term offsets should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['positions'] = (boolean) Specifies if term positions should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\"." + * ['payloads'] = (boolean) Specifies if term payloads should be returned. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) .Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * ['routing'] = (string) Specific routing value. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * ['parent'] = (string) Parent id of documents. Applies to all returned documents unless otherwise specified in body \"params\" or \"docs\". + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function mtermvectors($params = array()) + { + $index = $this->extractArgument($params, 'index'); + $type = $this->extractArgument($params, 'type'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\MTermVectors $endpoint */ + $endpoint = $endpointBuilder('MTermVectors'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['id'] = (string) The document ID (Required) + * ['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (use `_all` to fetch the first document matching the ID across all types) (Required) + * ['parent'] = (string) The ID of the parent document + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['realtime'] = (boolean) Specify whether to perform the operation in realtime or search mode + * ['refresh'] = (boolean) Refresh the shard containing the document before performing the operation + * ['routing'] = (string) Specific routing value + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function exists($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Exists $endpoint */ + $endpoint = $endpointBuilder('Exists'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type); + $endpoint->setParams($params); + + try { + $response = $endpoint->performRequest(); + } catch (Missing404Exception $exception) { + return false; + } catch (RoutingMissingException $exception) { + return false; + } + + + if ($response['status'] === 200) { + return true; + } else { + return false; + } + } + + + /** + * $params['id'] = (string) The document ID (Required) + * ['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (use `_all` to fetch the first document matching the ID across all types) (Required) + * ['boost_terms'] = (number) The boost factor + * ['max_doc_freq'] = (number) The word occurrence frequency as count: words with higher occurrence in the corpus will be ignored + * ['max_query_terms'] = (number) The maximum query terms to be included in the generated query + * ['max_word_len'] = (number) The minimum length of the word: longer words will be ignored + * ['min_doc_freq'] = (number) The word occurrence frequency as count: words with lower occurrence in the corpus will be ignored + * ['min_term_freq'] = (number) The term frequency as percent: terms with lower occurrence in the source document will be ignored + * ['min_word_len'] = (number) The minimum length of the word: shorter words will be ignored + * ['mlt_fields'] = (list) Specific fields to perform the query against + * ['percent_terms_to_match'] = (number) How many terms have to match in order to consider the document a match (default: 0.3) + * ['routing'] = (string) Specific routing value + * ['search_from'] = (number) The offset from which to return results + * ['search_indices'] = (list) A comma-separated list of indices to perform the query against (default: the index containing the document) + * ['search_query_hint'] = (string) The search query hint + * ['search_scroll'] = (string) A scroll search request definition + * ['search_size'] = (number) The number of documents to return (default: 10) + * ['search_source'] = (string) A specific search request definition (instead of using the request body) + * ['search_type'] = (string) Specific search type (eg. `dfs_then_fetch`, `count`, etc) + * ['search_types'] = (list) A comma-separated list of types to perform the query against (default: the same type as the document) + * ['stop_words'] = (list) A list of stop words to be ignored + * ['body'] = (array) A specific search request definition + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function mlt($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Mlt $endpoint */ + $endpoint = $endpointBuilder('Mlt'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index + * ['type'] = (string) The type of the document + * ['fields'] = (list) A comma-separated list of fields to return in the response + * ['parent'] = (string) The ID of the parent document + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['realtime'] = (boolean) Specify whether to perform the operation in realtime or search mode + * ['refresh'] = (boolean) Refresh the shard containing the document before performing the operation + * ['routing'] = (string) Specific routing value + * ['body'] = (array) Document identifiers; can be either `docs` (containing full document information) or `ids` (when index and type is provided in the URL. + * ['_source'] = (list) True or false to return the _source field or not, or a list of fields to return + * ['_source_exclude'] = (list) A list of fields to exclude from the returned _source field + * ['_source_include'] = (list) A list of fields to extract and return from the _source field + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function mget($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Mget $endpoint */ + $endpoint = $endpointBuilder('Mget'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to use as default + * ['type'] = (list) A comma-separated list of document types to use as default + * ['search_type'] = (enum) Search operation type + * ['body'] = (array|string) The request definitions (metadata-search request definition pairs), separated by newlines + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function msearch($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Msearch $endpoint */ + $endpoint = $endpointBuilder('Msearch'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (Required) + * ['id'] = (string) Specific document ID (when the POST method is used) + * ['consistency'] = (enum) Explicit write consistency setting for the operation + * ['parent'] = (string) ID of the parent document + * ['percolate'] = (string) Percolator queries to execute while indexing the document + * ['refresh'] = (boolean) Refresh the index after performing the operation + * ['replication'] = (enum) Specific replication type + * ['routing'] = (string) Specific routing value + * ['timeout'] = (time) Explicit operation timeout + * ['timestamp'] = (time) Explicit timestamp for the document + * ['ttl'] = (duration) Expiration time for the document + * ['version'] = (number) Explicit version number for concurrency control + * ['version_type'] = (enum) Specific version type + * ['body'] = (array) The document + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function create($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Index $endpoint */ + $endpoint = $endpointBuilder('Index'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type) + ->setBody($body) + ->createIfAbsent(); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) Default index for items which don't provide one + * ['type'] = (string) Default document type for items which don't provide one + * ['consistency'] = (enum) Explicit write consistency setting for the operation + * ['refresh'] = (boolean) Refresh the index after performing the operation + * ['replication'] = (enum) Explicitly set the replication type + * ['body'] = (string) Default document type for items which don't provide one + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function bulk($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Bulk $endpoint */ + $endpoint = $endpointBuilder('Bulk'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (Required) + * ['id'] = (string) Specific document ID (when the POST method is used) + * ['consistency'] = (enum) Explicit write consistency setting for the operation + * ['op_type'] = (enum) Explicit operation type + * ['parent'] = (string) ID of the parent document + * ['percolate'] = (string) Percolator queries to execute while indexing the document + * ['refresh'] = (boolean) Refresh the index after performing the operation + * ['replication'] = (enum) Specific replication type + * ['routing'] = (string) Specific routing value + * ['timeout'] = (time) Explicit operation timeout + * ['timestamp'] = (time) Explicit timestamp for the document + * ['ttl'] = (duration) Expiration time for the document + * ['version'] = (number) Explicit version number for concurrency control + * ['version_type'] = (enum) Specific version type + * ['body'] = (array) The document + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function index($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Index $endpoint */ + $endpoint = $endpointBuilder('Index'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices + * ['ignore_indices'] = (enum) When performed on multiple indices, allows to ignore `missing` ones + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['routing'] = (string) Specific routing value + * ['source'] = (string) The URL-encoded request definition (instead of using request body) + * ['body'] = (array) The request definition + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function suggest($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Suggest $endpoint */ + $endpoint = $endpointBuilder('Suggest'); + $endpoint->setIndex($index) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['id'] = (string) The document ID (Required) + * ['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (Required) + * ['analyze_wildcard'] = (boolean) Specify whether wildcards and prefix queries in the query string query should be analyzed (default: false) + * ['analyzer'] = (string) The analyzer for the query string query + * ['default_operator'] = (enum) The default operator for query string query (AND or OR) + * ['df'] = (string) The default field for query string query (default: _all) + * ['fields'] = (list) A comma-separated list of fields to return in the response + * ['lenient'] = (boolean) Specify whether format-based query failures (such as providing text to a numeric field) should be ignored + * ['lowercase_expanded_terms'] = (boolean) Specify whether query terms should be lowercased + * ['parent'] = (string) The ID of the parent document + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['q'] = (string) Query in the Lucene query string syntax + * ['routing'] = (string) Specific routing value + * ['source'] = (string) The URL-encoded query definition (instead of using the request body) + * ['_source'] = (list) True or false to return the _source field or not, or a list of fields to return + * ['_source_exclude'] = (list) A list of fields to exclude from the returned _source field + * ['_source_include'] = (list) A list of fields to extract and return from the _source field + * ['body'] = (string) The URL-encoded query definition (instead of using the request body) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function explain($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Explain $endpoint */ + $endpoint = $endpointBuilder('Explain'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices + * ['type'] = (list) A comma-separated list of document types to search; leave empty to perform the operation on all types + * ['analyzer'] = (string) The analyzer to use for the query string + * ['analyze_wildcard'] = (boolean) Specify whether wildcard and prefix queries should be analyzed (default: false) + * ['default_operator'] = (enum) The default operator for query string query (AND or OR) + * ['df'] = (string) The field to use as default where no field prefix is given in the query string + * ['explain'] = (boolean) Specify whether to return detailed information about score computation as part of a hit + * ['fields'] = (list) A comma-separated list of fields to return as part of a hit + * ['from'] = (number) Starting offset (default: 0) + * ['ignore_indices'] = (enum) When performed on multiple indices, allows to ignore `missing` ones + * ['indices_boost'] = (list) Comma-separated list of index boosts + * ['lenient'] = (boolean) Specify whether format-based query failures (such as providing text to a numeric field) should be ignored + * ['lowercase_expanded_terms'] = (boolean) Specify whether query terms should be lowercased + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['q'] = (string) Query in the Lucene query string syntax + * ['routing'] = (list) A comma-separated list of specific routing values + * ['scroll'] = (duration) Specify how long a consistent view of the index should be maintained for scrolled search + * ['search_type'] = (enum) Search operation type + * ['size'] = (number) Number of hits to return (default: 10) + * ['sort'] = (list) A comma-separated list of : pairs + * ['source'] = (string) The URL-encoded request definition using the Query DSL (instead of using request body) + * ['_source'] = (list) True or false to return the _source field or not, or a list of fields to return + * ['_source_exclude'] = (list) A list of fields to exclude from the returned _source field + * ['_source_include'] = (list) A list of fields to extract and return from the _source field + * ['stats'] = (list) Specific 'tag' of the request for logging and statistical purposes + * ['suggest_field'] = (string) Specify which field to use for suggestions + * ['suggest_mode'] = (enum) Specify suggest mode + * ['suggest_size'] = (number) How many suggestions to return in response + * ['suggest_text'] = (text) The source text for which the suggestions should be returned + * ['timeout'] = (time) Explicit operation timeout + * ['version'] = (boolean) Specify whether to return document version as part of a hit + * ['body'] = (array|string) The search definition using the Query DSL + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function search($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Search $endpoint */ + $endpoint = $endpointBuilder('Search'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['index'] = (list) A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices + * ['type'] = (list) A comma-separated list of document types to search; leave empty to perform the operation on all types + * ['preference'] = (string) Specify the node or shard the operation should be performed on (default: random) + * ['routing'] = (string) Specific routing value + * ['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function searchShards($params = array()) + { + $index = $this->extractArgument($params, 'index'); + $type = $this->extractArgument($params, 'type'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\SearchShards $endpoint */ + $endpoint = $endpointBuilder('SearchShards'); + $endpoint->setIndex($index) + ->setType($type); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices + * ['type'] = (list) A comma-separated list of document types to search; leave empty to perform the operation on all types + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function searchTemplate($params = array()) + { + $index = $this->extractArgument($params, 'index'); + $type = $this->extractArgument($params, 'type'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Search $endpoint */ + $endpoint = $endpointBuilder('SearchTemplate'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['scroll_id'] = (string) The scroll ID for scrolled search + * ['scroll'] = (duration) Specify how long a consistent view of the index should be maintained for scrolled search + * ['body'] = (string) The scroll ID for scrolled search + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function scroll($params = array()) + { + $scrollID = $this->extractArgument($params, 'scroll_id'); + + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Scroll $endpoint */ + $endpoint = $endpointBuilder('Scroll'); + $endpoint->setScrollID($scrollID) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['scroll_id'] = (string) The scroll ID for scrolled search + * ['scroll'] = (duration) Specify how long a consistent view of the index should be maintained for scrolled search + * ['body'] = (string) The scroll ID for scrolled search + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function clearScroll($params = array()) + { + $scrollID = $this->extractArgument($params, 'scroll_id'); + + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Scroll $endpoint */ + $endpoint = $endpointBuilder('Scroll'); + $endpoint->setScrollID($scrollID) + ->setBody($body) + ->setClearScroll(true); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['id'] = (string) Document ID (Required) + * ['index'] = (string) The name of the index (Required) + * ['type'] = (string) The type of the document (Required) + * ['consistency'] = (enum) Explicit write consistency setting for the operation + * ['fields'] = (list) A comma-separated list of fields to return in the response + * ['lang'] = (string) The script language (default: mvel) + * ['parent'] = (string) ID of the parent document + * ['percolate'] = (string) Perform percolation during the operation; use specific registered query name, attribute, or wildcard + * ['refresh'] = (boolean) Refresh the index after performing the operation + * ['replication'] = (enum) Specific replication type + * ['retry_on_conflict'] = (number) Specify how many times should the operation be retried when a conflict occurs (default: 0) + * ['routing'] = (string) Specific routing value + * ['script'] = () The URL-encoded script definition (instead of using request body) + * ['timeout'] = (time) Explicit operation timeout + * ['timestamp'] = (time) Explicit timestamp for the document + * ['ttl'] = (duration) Expiration time for the document + * ['version_type'] = (number) Explicit version number for concurrency control + * ['body'] = (array) The request definition using either `script` or partial `doc` + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function update($params) + { + $id = $this->extractArgument($params, 'id'); + + + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Update $endpoint */ + $endpoint = $endpointBuilder('Update'); + $endpoint->setID($id) + ->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['id'] = (string) The script ID (Required) + * ['lang'] = (string) The script language (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getScript($params) + { + $id = $this->extractArgument($params, 'id'); + $lang = $this->extractArgument($params, 'lang'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Script\Get $endpoint */ + $endpoint = $endpointBuilder('Script\Get'); + $endpoint->setID($id) + ->setLang($lang); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['id'] = (string) The script ID (Required) + * ['lang'] = (string) The script language (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function deleteScript($params) + { + $id = $this->extractArgument($params, 'id'); + $lang = $this->extractArgument($params, 'lang'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Script\Delete $endpoint */ + $endpoint = $endpointBuilder('Script\Delete'); + $endpoint->setID($id) + ->setLang($lang); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['id'] = (string) The script ID (Required) + * ['lang'] = (string) The script language (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putScript($params) + { + $id = $this->extractArgument($params, 'id'); + $lang = $this->extractArgument($params, 'lang'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Script\Put $endpoint */ + $endpoint = $endpointBuilder('Script\Put'); + $endpoint->setID($id) + ->setLang($lang) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['id'] = (string) The search template ID (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getTemplate($params) + { + $id = $this->extractArgument($params, 'id'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Template\Get $endpoint */ + $endpoint = $endpointBuilder('Template\Get'); + $endpoint->setID($id); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['id'] = (string) The search template ID (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function deleteTemplate($params) + { + $id = $this->extractArgument($params, 'id'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Template\Delete $endpoint */ + $endpoint = $endpointBuilder('Template\Delete'); + $endpoint->setID($id); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['id'] = (string) The search template ID (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putTemplate($params) + { + $id = $this->extractArgument($params, 'id'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Template\Put $endpoint */ + $endpoint = $endpointBuilder('Template\Put'); + $endpoint->setID($id) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + + /** + * Operate on the Indices Namespace of commands + * + * @return IndicesNamespace + */ + public function indices() + { + return $this->indices; + } + + + /** + * Operate on the Cluster namespace of commands + * + * @return ClusterNamespace + */ + public function cluster() + { + return $this->cluster; + } + + + /** + * Operate on the Nodes namespace of commands + * + * @return NodesNamespace + */ + public function nodes() + { + return $this->nodes; + } + + + /** + * Operate on the Snapshot namespace of commands + * + * @return SnapshotNamespace + */ + public function snapshot() + { + return $this->snapshot; + } + + + /** + * Operate on the Cat namespace of commands + * + * @return CatNamespace + */ + public function cat() + { + return $this->cat; + } + + + /** + * Sets up the DIC parameter object + * + * Merges user-specified parameters into the default list, then + * builds a DIC to house all the information + * + * @param array $params Array of user settings + * + * @internal param array $hosts Array of hosts + * @return void + */ + private function setParams($params) + { + + if (isset($params['hosts']) === true) { + $hosts = $this->buildHostsFromSeed($params['hosts']); + unset($params['hosts']); + } else { + $hosts = $this->getDefaultHost(); + } + + if (isset($params['dic']) !== true) { + $dicBuilder = new DICBuilder($hosts, $params); + } else { + $dicBuilder = $params['dic']($hosts, $params); + unset($params['dic']); + } + + /** @var DICBuilder $dicBuilder */ + + $this->params = $dicBuilder->getDIC(); + + } + + + /** + * Sets up the logging object + * If a user-defined logger is not available, builds a default file logger + * + * @return void + */ + private function setLogging() + { + if ($this->params['logging'] !== true) { + $this->setEmptyLogger(); + return; + } + + if ($this->params['logObject'] === null) { + $this->setDefaultLogger(); + } + + if ($this->params['traceObject'] === null) { + $this->setDefaultTracer(); + } + + } + + private function setEmptyLogger() + { + $this->params['logObject'] = new EmptyLogger(); + $this->params['traceObject'] = new EmptyLogger(); + } + + private function setDefaultLogger() + { + $log = new Logger('log'); + $handler = new StreamHandler( + $this->params['logPath'], + $this->params['logLevel'] + ); + $processor = new IntrospectionProcessor(); + + $log->pushHandler($handler); + $log->pushProcessor($processor); + + $this->params['logObject'] = $log; + } + + private function setDefaultTracer() + { + $trace = new Logger('trace'); + $traceHandler = new StreamHandler( + $this->params['tracePath'], + $this->params['traceLevel'] + ); + + $trace->pushHandler($traceHandler); + + $this->params['traceObject'] = $trace; + } + + + /** + * @return array + */ + private function getDefaultHost() + { + return array(array('host' => 'localhost', 'port' => 9200)); + } + + + /** + * @param array $hosts + * + * @return array + * @throws Common\Exceptions\InvalidArgumentException + */ + private function buildHostsFromSeed($hosts) + { + if (is_array($hosts) === false) { + throw new Exceptions\InvalidArgumentException('Hosts parameter must be an array of strings'); + } + + $finalHosts = array(); + foreach ($hosts as $host) { + $host = $this->prependMissingScheme($host); + $finalHosts[] = $this->extractURIParts($host); + } + + return $finalHosts; + } + + + /** + * @param array $host + * + * @return array + * @throws Common\Exceptions\InvalidArgumentException + */ + private function extractURIParts($host) + { + + $parts = parse_url($host); + + if ($parts === false) { + throw new Exceptions\InvalidArgumentException("Could not parse URI"); + } + + if (isset($parts['port']) !== true) { + $parts['port'] = 9200; + } + + return $parts; + } + + + /** + * @param string $host + * + * @return string + */ + private function prependMissingScheme($host) { + if (!filter_var($host, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED)) { + $host = 'http://' . $host; + } + return $host; + } + + /** + * @param array $params + * @param string $arg + * + * @return null|mixed + */ + public function extractArgument(&$params, $arg) + { + if (is_object($params) === true) { + $params = (array)$params; + } + + if (isset($params[$arg]) === true) { + $val = $params[$arg]; + unset($params[$arg]); + return $val; + } else { + return null; + } + } + + +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/AbstractFactory.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/AbstractFactory.php new file mode 100644 index 00000000..e17fe8a0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/AbstractFactory.php @@ -0,0 +1,25 @@ +container = $container; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/DICBuilder.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/DICBuilder.php new file mode 100644 index 00000000..ef87cbdf --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/DICBuilder.php @@ -0,0 +1,359 @@ + '\Elasticsearch\Connections\GuzzleConnection', + 'connectionFactoryClass'=> '\Elasticsearch\Connections\ConnectionFactory', + 'connectionPoolClass' => '\Elasticsearch\ConnectionPool\StaticNoPingConnectionPool', + 'selectorClass' => '\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector', + 'serializerClass' => '\Elasticsearch\Serializers\SmartSerializer', + 'sniffOnStart' => false, + 'connectionParams' => array(), + 'logging' => false, + 'logObject' => null, + 'logPath' => 'elasticsearch.log', + 'logLevel' => Log\LogLevel::WARNING, + 'traceObject' => null, + 'tracePath' => 'elasticsearch.log', + 'traceLevel' => Log\LogLevel::WARNING, + 'guzzleOptions' => array(), + 'connectionPoolParams' => array( + 'randomizeHosts' => true + ), + 'retries' => null + ); + + + /** + * Constructor + * + * @param array $hosts Array of hosts + * @param array $params Array of user settings + * + * @throws Exceptions\InvalidArgumentException + * @throws Exceptions\UnexpectedValueException + */ + public function __construct($hosts, $params) + { + + if (isset($params) === false || is_array($params) !== true) { + throw new Exceptions\InvalidArgumentException( + 'Parameters must be an array' + ); + } + + $this->checkParamWhitelist($params); + $this->createDICObject($hosts, $params); + + } + + + /** + * Get the Dependency injection container + * + * @return Pimple + */ + public function getDIC() + { + return $this->dic; + + } + + + /** + * Verify that all parameters are whitelisted + * + * @param array $params Array of params + * + * @throws Exceptions\UnexpectedValueException + * @return void + */ + private function checkParamWhitelist($params) + { + // Verify that all provided parameters are 'white-listed'. + foreach ($params as $key => $value) { + if (array_key_exists($key, $this->paramDefaults) === false) { + throw new Exceptions\UnexpectedValueException( + $key . ' is not a recognized parameter' + ); + } + } + + } + + + /** + * Create the Pimple DIC object, build the dep tree + * + * @param array $hosts Array of hosts + * @param array $params Array of user params + * + * @return void + */ + private function createDICObject($hosts, $params) + { + $this->dic = new Pimple(); + + $this->setDICParams($params); + $this->setNonSharedDICObjects(); + $this->setSharedDICObjects($hosts); + $this->setEndpointDICObjects(); + + } + + + /** + * Set the user params inside the DIC object + * + * @param array $params Array of user params + * + * @return void + */ + private function setDICParams($params) + { + $params = array_merge($this->paramDefaults, $params); + + foreach ($params as $key => $value) { + $this->dic[$key] = $value; + } + } + + + /** + * NonShared DIC objects return a new obj each time + * they are accessed + */ + private function setNonSharedDICObjects() + { + $this->setConnectionObj(); + $this->setConnectionFactoryObj(); + $this->setSelectorObj(); + $this->setSerializerObj(); + $this->setConnectionPoolObj(); + } + + + /** + * Shared DIC objects reuse the same obj each time + * they are accessed + * + * @param array $hosts Array of hosts + */ + private function setSharedDICObjects($hosts) + { + $this->setTransportObj($hosts); + $this->setClusterNamespaceObj(); + $this->setIndicesNamespaceObj(); + $this->setNodesNamespaceObj(); + $this->setCatNamespaceObj(); + $this->setSnapshotNamespaceObj(); + $this->setSharedConnectionParamsObj(); + $this->setCurlMultihandle(); + $this->setGuzzleClient(); + } + + private function setEndpointDICObjects() + { + $this->setEndpoint(); + } + + + private function setConnectionObj() + { + $this->dic['connection'] = function ($dicParams) { + return function ($hostDetails) use ($dicParams) { + return new $dicParams['connectionClass']( + $hostDetails, + $dicParams['connectionParamsShared'], + $dicParams['logObject'], + $dicParams['traceObject'] + ); + }; + }; + } + + private function setConnectionFactoryObj() + { + $this->dic['connectionFactory'] = function ($dicParams) { + return new $dicParams['connectionFactoryClass']($dicParams); + }; + } + + + private function setSelectorObj() + { + $this->dic['selector'] = function ($dicParams) { + return new $dicParams['selectorClass'](); + }; + } + + + private function setSerializerObj() + { + $this->dic['serializer'] = function ($dicParams) { + return new $dicParams['serializerClass'](); + }; + } + + + private function setConnectionPoolObj() + { + $this->dic['connectionPool'] = function ($dicParams) { + return function ($connections) use ($dicParams) { + return new $dicParams['connectionPoolClass']( + $connections, + $dicParams['selector'], + $dicParams['connectionFactory'], + $dicParams['connectionPoolParams'] + ); + }; + }; + } + + + private function setTransportObj($hosts) + { + $this->dic['transport'] = function ($dicParams) use ($hosts) { + return new Transport($hosts, $dicParams, $dicParams['logObject']); + }; + } + + + private function setClusterNamespaceObj() + { + $this->dic['clusterNamespace'] = function ($dicParams) { + /** @var Pimple $dicParams */ + return new ClusterNamespace($dicParams['transport'], $dicParams['endpoint']); + }; + } + + + private function setIndicesNamespaceObj() + { + $this->dic['indicesNamespace'] = function ($dicParams) { + /** @var Pimple $dicParams */ + return new IndicesNamespace($dicParams['transport'], $dicParams['endpoint']); + }; + } + + private function setNodesNamespaceObj() + { + $this->dic['nodesNamespace'] = function ($dicParams) { + /** @var Pimple $dicParams */ + return new NodesNamespace($dicParams['transport'], $dicParams['endpoint']); + }; + } + + + private function setSnapshotNamespaceObj() + { + $this->dic['snapshotNamespace'] = function ($dicParams) { + /** @var Pimple $dicParams */ + return new SnapshotNamespace($dicParams['transport'], $dicParams['endpoint']); + }; + } + + private function setCatNamespaceObj() + { + $this->dic['catNamespace'] = function ($dicParams) { + /** @var Pimple $dicParams */ + return new CatNamespace($dicParams['transport'], $dicParams['endpoint']); + }; + } + + + private function setSharedConnectionParamsObj() + { + // This will inject a shared object into all connections. + // Allows users to inject shared resources, similar to the multi-handle + // shared above (but in their own code). + $this->dic['connectionParamsShared'] = function ($dicParams) { + $connectionParams = $dicParams['connectionParams']; + + // Multihandle connections need a "static", shared curl multihandle. + if ($dicParams['connectionClass'] === '\Elasticsearch\Connections\CurlMultiConnection') { + $connectionParams = array_merge( + $connectionParams, + array('curlMultiHandle' => $dicParams['curlMultiHandle']) + ); + } elseif ($dicParams['connectionClass'] === '\Elasticsearch\Connections\GuzzleConnection') { + $connectionParams = array_merge( + $connectionParams, + array('guzzleClient' => $dicParams['guzzleClient']) + ); + } + + return $connectionParams; + }; + } + + + private function setCurlMultihandle() + { + // Only used by some connections - won't be instantiated until used. + $this->dic['curlMultiHandle'] = function () { + if (extension_loaded('curl') !== true) { + throw new RuntimeException('Curl library/extension is required for CurlMultiConnection.'); + } + return curl_multi_init(); + }; + } + + private function setGuzzleClient() + { + // Only used by Guzzle connections - won't be instantiated until used. + $this->dic['guzzleClient'] = function ($dicParams) { + $guzzleOptions = array(); + $guzzleOptions['curl.options']['body_as_string'] = true; + + if (isset($dicParams['connectionParams']['auth']) === true) { + $guzzleOptions['request.options']['auth'] = $dicParams['connectionParams']['auth']; + } + + $guzzleOptions = array_merge($guzzleOptions, $dicParams['guzzleOptions']); + $guzzle = new \Guzzle\Http\Client(null, $guzzleOptions); + + return $guzzle; + }; + } + + private function setEndpoint() + { + $dicParams = $this->dic; + $this->dic['endpoint'] = $this->dic->protect(function ($class) use ($dicParams) { + $fullPath = '\\Elasticsearch\\Endpoints\\'.$class; + if ($class === 'Bulk' || $class === 'Msearch' || $class === 'MPercolate') { + return new $fullPath($dicParams['transport'], $dicParams['serializer']); + } else { + return new $fullPath($dicParams['transport']); + } + }); + } +}//end class diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/EmptyLogger.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/EmptyLogger.php new file mode 100644 index 00000000..b3eff494 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/EmptyLogger.php @@ -0,0 +1,27 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class AlreadyExpiredException extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/BadMethodCallException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/BadMethodCallException.php new file mode 100644 index 00000000..7409c8bc --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/BadMethodCallException.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * BadMethodCallException + * Denote problems with a method call (e.g. incorrect number of arguments) + */ +class BadMethodCallException extends \BadMethodCallException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/BadRequest400Exception.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/BadRequest400Exception.php new file mode 100644 index 00000000..4cd9b8f8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/BadRequest400Exception.php @@ -0,0 +1,16 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class BadRequest400Exception extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ClientErrorResponseException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ClientErrorResponseException.php new file mode 100644 index 00000000..cab60cd3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ClientErrorResponseException.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * Class ClientErrorResponseException + * @package Elasticsearch\Common\Exceptions + */ +class ClientErrorResponseException extends TransportException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Conflict409Exception.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Conflict409Exception.php new file mode 100644 index 00000000..fd464f2c --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Conflict409Exception.php @@ -0,0 +1,16 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class Conflict409Exception extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Curl/CouldNotConnectToHost.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Curl/CouldNotConnectToHost.php new file mode 100644 index 00000000..66ab2100 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Curl/CouldNotConnectToHost.php @@ -0,0 +1,19 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +namespace Elasticsearch\Common\Exceptions; + +/** + * Generic Exception interface + * + * @category Elasticsearch + * @package Elasticsearch\Common\Exceptions + * @author Zachary Tong + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +interface ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Forbidden403Exception.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Forbidden403Exception.php new file mode 100644 index 00000000..49d3892d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Forbidden403Exception.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class Forbidden403Exception extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/InvalidArgumentException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/InvalidArgumentException.php new file mode 100644 index 00000000..e8ad81ce --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * InvalidArgumentException + * Denote invalid or incorrect argument values + */ +class InvalidArgumentException extends \InvalidArgumentException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/MaxRetriesException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/MaxRetriesException.php new file mode 100644 index 00000000..a78d2d83 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/MaxRetriesException.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * BadMethodCallException + * Denote problems with a method call (e.g. incorrect number of arguments) + */ +class MaxRetriesException extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Missing404Exception.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Missing404Exception.php new file mode 100644 index 00000000..fd9fdbdd --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/Missing404Exception.php @@ -0,0 +1,27 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +namespace Elasticsearch\Common\Exceptions; + +/** + * Generic Exception interface + * + * @category Elasticsearch + * @package Elasticsearch\Common\Exceptions + * @author Zachary Tong + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class Missing404Exception extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoDocumentsToGetException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoDocumentsToGetException.php new file mode 100644 index 00000000..814296b3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoDocumentsToGetException.php @@ -0,0 +1,22 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class NoDocumentsToGetException extends ServerErrorResponseException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoNodesAvailableException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoNodesAvailableException.php new file mode 100644 index 00000000..d14fee7b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoNodesAvailableException.php @@ -0,0 +1,19 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * NoNodesAvailableException + */ +class NoNodesAvailableException extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoShardAvailableException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoShardAvailableException.php new file mode 100644 index 00000000..459cbd5b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/NoShardAvailableException.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class NoShardAvailableException extends ServerErrorResponseException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/RoutingMissingException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/RoutingMissingException.php new file mode 100644 index 00000000..b2c6b3ab --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/RoutingMissingException.php @@ -0,0 +1,22 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class RoutingMissingException extends ServerErrorResponseException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/RuntimeException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/RuntimeException.php new file mode 100644 index 00000000..144cc108 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/RuntimeException.php @@ -0,0 +1,22 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * RuntimeException + */ +class RuntimeException extends \RuntimeException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ScriptLangNotSupportedException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ScriptLangNotSupportedException.php new file mode 100644 index 00000000..f308b047 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ScriptLangNotSupportedException.php @@ -0,0 +1,22 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class ScriptLangNotSupportedException extends BadRequest400Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ServerErrorResponseException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ServerErrorResponseException.php new file mode 100644 index 00000000..58c2e7f0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/ServerErrorResponseException.php @@ -0,0 +1,20 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * ServerErrorResponseException + */ +class ServerErrorResponseException extends TransportException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/TransportException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/TransportException.php new file mode 100644 index 00000000..d1d8951c --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/TransportException.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * BadMethodCallException + * Denote problems with a method call (e.g. incorrect number of arguments) + */ +class TransportException extends \Exception implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/UnexpectedValueException.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/UnexpectedValueException.php new file mode 100644 index 00000000..463b66d1 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Common/Exceptions/UnexpectedValueException.php @@ -0,0 +1,21 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +namespace Elasticsearch\Common\Exceptions; + +/** + * UnexpectedValueException + * Denote a value that is outside the normally accepted values + */ +class UnexpectedValueException extends \UnexpectedValueException implements ElasticsearchException +{ +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/AbstractConnectionPool.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/AbstractConnectionPool.php new file mode 100644 index 00000000..85976759 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/AbstractConnectionPool.php @@ -0,0 +1,76 @@ +connections = $connections; + $this->seedConnections = $connections; + $this->selector = $selector; + $this->connectionPoolParams = $connectionPoolParams; + $this->connectionFactory = $factory; + + } + + + /** + * @param bool $force + * + * @return AbstractConnection + */ + abstract public function nextConnection($force = false); + + abstract public function scheduleCheck(); + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/RandomSelector.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/RandomSelector.php new file mode 100644 index 00000000..412f851e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/RandomSelector.php @@ -0,0 +1,39 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class RandomSelector implements SelectorInterface +{ + + + /** + * Select a random connection from the provided array + * + * @param array $connections Array of Connection objects + * + * @return ConnectionInterface + */ + public function select($connections) + { + return $connections[array_rand($connections)]; + + } + + +}//end class \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/RoundRobinSelector.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/RoundRobinSelector.php new file mode 100644 index 00000000..f534ac8c --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/RoundRobinSelector.php @@ -0,0 +1,47 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class RoundRobinSelector implements SelectorInterface +{ + + /** + * @var int + */ + private $current = 0; + + + /** + * Select the next connectioion in the sequence + * + * @param array $connections Array of connections to choose from + * + * @return ConnectionInterface + */ + public function select($connections) + { + $this->current += 1; + + return $connections[$this->current % count($connections)]; + + } + + +}//end class \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/SelectorInterface.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/SelectorInterface.php new file mode 100644 index 00000000..0ae03964 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/Selectors/SelectorInterface.php @@ -0,0 +1,13 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class StickyRoundRobinSelector implements SelectorInterface +{ + + /** + * @var int + */ + private $current = 0; + + /** @var int */ + private $currentCounter = 0; + + /** + * Use current connection unless it is dead, otherwise round-robin + * + * @param array $connections Array of connections to choose from + * + * @return ConnectionInterface + */ + public function select($connections) + { + /** @var ConnectionInterface[] $connections */ + if ($connections[$this->current]->isAlive()) { + return $connections[$this->current]; + } + + $this->currentCounter += 1; + $this->current = $this->currentCounter % count($connections); + + return $connections[$this->current]; + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/SniffingConnectionPool.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/SniffingConnectionPool.php new file mode 100644 index 00000000..cc751cd1 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/SniffingConnectionPool.php @@ -0,0 +1,166 @@ +setConnectionPoolParams($connectionPoolParams); + $this->nextSniff = time() + $this->sniffingInterval; + } + + + /** + * @param bool $force + * + * @return AbstractConnection + * @throws \Elasticsearch\Common\Exceptions\NoNodesAvailableException + */ + public function nextConnection($force = false) + { + $this->sniff($force); + + $size = count($this->connections); + while ($size--) { + /** @var AbstractConnection $connection */ + $connection = $this->selector->select($this->connections); + if ($connection->isAlive() === true || $connection->ping() === true) { + return $connection; + } + } + + if ($force === true) { + throw new NoNodesAvailableException("No alive nodes found in your cluster"); + } + + return $this->nextConnection(true); + + + } + + public function scheduleCheck() + { + $this->nextSniff = -1; + } + + + /** + * @param bool $force + */ + private function sniff($force = false) + { + if ($force === false && $this->nextSniff >= time()) { + return; + } + + $total = count($this->connections); + + while ($total--) { + /** @var AbstractConnection $connection */ + $connection = $this->selector->select($this->connections); + + if ($connection->isAlive() xor $force) { + continue; + } + + if ($this->sniffConnection($connection) === true) { + return; + } + } + + if ($force === true) { + return; + } + + foreach ($this->seedConnections as $connection) { + if ($this->sniffConnection($connection) === true) { + return; + } + } + } + + + /** + * @param AbstractConnection $connection + * @return bool + */ + private function sniffConnection(AbstractConnection $connection) + { + try { + $response = $connection->sniff(); + } catch (OperationTimeoutException $exception) { + return false; + } + + // TODO wire in the serializer? + $nodeInfo = json_decode($response['text'], true); + $nodes = $this->parseClusterState($connection->getTransportSchema(), $nodeInfo); + + if (count($nodes) === 0) { + return false; + } + + $this->connections = array(); + + foreach ($nodes as $node) { + $nodeDetails = array( + 'host' => $node['host'], + 'port' => $node['port'] + ); + $this->connections[] = $this->connectionFactory->create($nodeDetails); + } + + $this->nextSniff = time() + $this->sniffingInterval; + return true; + } + + + private function parseClusterState($transportSchema, $nodeInfo) + { + $pattern = '/\/([^:]*):([0-9]+)\]/'; + $schemaAddress = $transportSchema . '_address'; + $hosts = array(); + + foreach ($nodeInfo['nodes'] as $node) { + if (isset($node[$schemaAddress]) === true) { + if (preg_match($pattern, $node[$schemaAddress], $match) === 1) { + $hosts[] = array( + 'host' => $match[1], + 'port' => (int)$match[2], + ); + } + } + } + + return $hosts; + + } + + private function setConnectionPoolParams($connectionPoolParams) + { + if (isset($connectionPoolParams['sniffingInterval']) === true) { + $this->sniffingInterval = $connectionPoolParams['sniffingInterval']; + } + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/StaticConnectionPool.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/StaticConnectionPool.php new file mode 100644 index 00000000..c97e504c --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/StaticConnectionPool.php @@ -0,0 +1,90 @@ +scheduleCheck(); + } + + + /** + * @param bool $force + * + * @return AbstractConnection + * @throws \Elasticsearch\Common\Exceptions\NoNodesAvailableException + */ + public function nextConnection($force = false) + { + $skipped = array(); + + $total = count($this->connections); + while ($total--) { + /** @var AbstractConnection $connection */ + $connection = $this->selector->select($this->connections); + if ($connection->isAlive() === true) { + return $connection; + } + + if ($this->readyToRevive($connection) === true) { + if ($connection->ping() === true) { + return $connection; + } + } else { + $skipped[] = $connection; + } + } + + // All "alive" nodes failed, force pings on "dead" nodes + foreach ($skipped as $connection) { + if ($connection->ping() === true) { + return $connection; + } + } + + throw new NoNodesAvailableException("No alive nodes found in your cluster"); + } + + public function scheduleCheck() + { + foreach ($this->connections as $connection) { + $connection->markDead(); + } + } + + /** + * @param AbstractConnection $connection + * + * @return bool + */ + private function readyToRevive(AbstractConnection $connection) + { + $timeout = min( + $this->pingTimeout * pow(2, $connection->getPingFailures()), + $this->maxPingTimeout + ); + + if ($connection->getLastPing() + $timeout < time()) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/StaticNoPingConnectionPool.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/StaticNoPingConnectionPool.php new file mode 100644 index 00000000..7be0f9a2 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/ConnectionPool/StaticNoPingConnectionPool.php @@ -0,0 +1,73 @@ +connections); + while ($total--) { + /** @var AbstractConnection $connection */ + $connection = $this->selector->select($this->connections); + if ($connection->isAlive() === true) { + return $connection; + } + + if ($this->readyToRevive($connection) === true) { + return $connection; + } + } + + throw new NoNodesAvailableException("No alive nodes found in your cluster"); + } + + public function scheduleCheck() + { + + } + + /** + * @param AbstractConnection $connection + * + * @return bool + */ + private function readyToRevive(AbstractConnection $connection) + { + $timeout = min( + $this->pingTimeout * pow(2, $connection->getPingFailures()), + $this->maxPingTimeout + ); + + if ($connection->getLastPing() + $timeout < time()) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/AbstractConnection.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/AbstractConnection.php new file mode 100644 index 00000000..82d1d417 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/AbstractConnection.php @@ -0,0 +1,345 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +abstract class AbstractConnection implements ConnectionInterface +{ + /** + * @var string + */ + protected $transportSchema = 'http'; // TODO depreciate this default + + /** + * @var string + */ + protected $host; + + /** + * @var LoggerInterface + */ + protected $log; + + /** + * @var LoggerInterface + */ + protected $trace; + + /** + * @var array + */ + protected $connectionParams; + + /** @var bool */ + protected $isAlive = false; + + /** @var float */ + private $pingTimeout = 1; //TODO expose this + + /** @var int */ + private $lastPing = 0; + + /** @var int */ + private $failedPings = 0; + + /** + * @param $method + * @param $uri + * @param null $params + * @param null $body + * @param array $options + * + * @return mixed + */ + abstract public function performRequest($method, $uri, $params = null, $body = null, $options = array()); + + /** @return string */ + abstract public function getTransportSchema(); + + /** @return array */ + abstract public function getLastRequestInfo(); + + + /** + * Constructor + * + * @param array $hostDetails + * @param array $connectionParams Array of connection-specific parameters + * @param \Psr\Log\LoggerInterface $log Logger object + * @param \Psr\Log\LoggerInterface $trace + */ + public function __construct($hostDetails, $connectionParams, LoggerInterface $log, LoggerInterface $trace) + { + if (isset($hostDetails['scheme'])) { + $this->transportSchema = $hostDetails['scheme']; + } + + $host = $this->transportSchema.'://'.$hostDetails['host'].':'.$hostDetails['port']; + if (isset($hostDetails['path']) === true) { + $host .= $hostDetails['path']; + } + $this->host = $host; + $this->log = $log; + $this->trace = $trace; + $this->connectionParams = $connectionParams; + + } + + + /** + * Log a successful request + * + * @param string $method + * @param string $fullURI + * @param string $body + * @param array $headers + * @param string $statusCode + * @param string $response + * @param string $duration + * + * @return void + */ + public function logRequestSuccess($method, $fullURI, $body, $headers, $statusCode, $response, $duration) + { + $this->log->debug('Request Body', array($body)); + $this->log->info( + 'Request Success:', + array( + 'method' => $method, + 'uri' => $fullURI, + 'headers' => $headers, + 'HTTP code' => $statusCode, + 'duration' => $duration, + ) + ); + $this->log->debug('Response', array($response)); + + // Build the curl command for Trace. + $curlCommand = $this->buildCurlCommand($method, $fullURI, $body); + $this->trace->info($curlCommand); + $this->trace->debug( + 'Response:', + array( + 'response' => $response, + 'method' => $method, + 'uri' => $fullURI, + 'HTTP code' => $statusCode, + 'duration' => $duration, + ) + ); + + } + + + /** + * Log a a failed request + * + * @param string $method + * @param string $fullURI + * @param string $body + * @param array $headers + * @param string $duration + * @param null|string $statusCode + * @param null|string $response + * @param null|string $exception + * + * @return void + */ + public function logRequestFail( + $method, + $fullURI, + $body, + $headers, + $duration, + $statusCode = null, + $response = null, + $exception = null + ) { + $this->log->debug('Request Body', array($body)); + $this->log->warning( + 'Request Failure:', + array( + 'method' => $method, + 'uri' => $fullURI, + 'headers' => $headers, + 'HTTP code' => $statusCode, + 'duration' => $duration, + 'error' => $exception, + ) + ); + $this->log->warning('Response', array($response)); + + // Build the curl command for Trace. + $curlCommand = $this->buildCurlCommand($method, $fullURI, $body); + $this->trace->info($curlCommand); + $this->trace->debug( + 'Response:', + array( + 'response' => $response, + 'method' => $method, + 'uri' => $fullURI, + 'HTTP code' => $statusCode, + 'duration' => $duration, + ) + ); + + } + + + /** + * @return bool + */ + public function ping() + { + $options = array('timeout' => $this->pingTimeout); + try { + $response = $this->performRequest('HEAD', '', null, null, $options); + + } catch (TransportException $exception) { + $this->markDead(); + return false; + } + + + if ($response['status'] === 200) { + $this->markAlive(); + return true; + } else { + $this->markDead(); + return false; + } + } + + /** + * @return array + */ + public function sniff() + { + $options = array('timeout' => $this->pingTimeout); + return $this->performRequest('GET', '/_nodes/_all/clear', null, null, $options); + + } + + + /** + * @return bool + */ + public function isAlive() + { + return $this->isAlive; + } + + + public function markAlive() + { + $this->failedPings = 0; + $this->isAlive = true; + $this->lastPing = time(); + } + + public function markDead() + { + $this->isAlive = false; + $this->failedPings += 1; + $this->lastPing = time(); + } + + + /** + * @return int + */ + public function getLastPing() + { + return $this->lastPing; + } + + + /** + * @return int + */ + public function getPingFailures() + { + return $this->failedPings; + } + + + /** + * @return string + */ + public function getHost() + { + return $this->host; + } + + + /** + * @param $curlErrorNumber + * @param $message + * + * @throws \Elasticsearch\Common\Exceptions\TransportException + * @throws \Elasticsearch\Common\Exceptions\Curl\CouldNotResolveHostException + * @throws \Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost + */ + protected function throwCurlException($curlErrorNumber, $message) + { + switch ($curlErrorNumber) { + case 6: + throw new CouldNotResolveHostException($message); + case 7: + throw new CouldNotConnectToHost($message); + case 28: + throw new OperationTimeoutException($message); + default: + throw new TransportException($message); + } + } + + + /** + * Construct a string cURL command + * + * @param string $method HTTP method + * @param string $uri Full URI of request + * @param string $body Request body + * + * @return string + */ + private function buildCurlCommand($method, $uri, $body) + { + if (strpos($uri, '?') === false) { + $uri .= '?pretty=true'; + } else { + str_replace('?', '?pretty=true', $uri); + } + + $curlCommand = 'curl -X' . strtoupper($method); + $curlCommand .= " '" . $uri . "'"; + + if (isset($body) === true && $body !== '') { + $curlCommand .= " -d '" . $body . "'"; + } + + return $curlCommand; + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/ConnectionFactory.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/ConnectionFactory.php new file mode 100644 index 00000000..46d0e7c5 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/ConnectionFactory.php @@ -0,0 +1,28 @@ +container['connection']( + $hostDetails, + $this->container['connectionParamsShared'], + $this->container['logObject'], + $this->container['traceObject'] + ); + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/ConnectionInterface.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/ConnectionInterface.php new file mode 100644 index 00000000..c4a33dcf --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/ConnectionInterface.php @@ -0,0 +1,36 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +interface ConnectionInterface +{ + public function __construct($hostDetails, $connectionParams, LoggerInterface $log, LoggerInterface $trace); + + public function getTransportSchema(); + + public function isAlive(); + + public function markAlive(); + + public function markDead(); + + public function getLastRequestInfo(); + + public function performRequest($method, $uri, $params = null, $body = null); +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/CurlMultiConnection.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/CurlMultiConnection.php new file mode 100644 index 00000000..f5e2fae4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/CurlMultiConnection.php @@ -0,0 +1,454 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class CurlMultiConnection extends AbstractConnection implements ConnectionInterface +{ + + /** + * @var Resource + */ + private $multiHandle; + + private $headers; + + private $curlOpts; + + private $lastRequest = array(); + + + /** + * Constructor + * + * @param array $hostDetails + * @param array $connectionParams Array of connection parameters + * @param \Psr\Log\LoggerInterface $log logger object + * @param \Psr\Log\LoggerInterface $trace logger object (for curl traces) + * + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return CurlMultiConnection + */ + public function __construct($hostDetails, $connectionParams, LoggerInterface $log, LoggerInterface $trace) + { + if (extension_loaded('curl') !== true) { + $log->critical('Curl library/extension is required for CurlMultiConnection.'); + throw new RuntimeException('Curl library/extension is required for CurlMultiConnection.'); + } + + if (isset($connectionParams['curlMultiHandle']) !== true) { + $log->critical('curlMultiHandle must be set in connectionParams'); + throw new InvalidArgumentException('curlMultiHandle must be set in connectionParams'); + } + + if (isset($hostDetails['port']) !== true) { + $hostDetails['port'] = 9200; + } + + if (isset($hostDetails['scheme']) !== true) { + $hostDetails['scheme'] = 'http'; + } + + $connectionParams = $this->transformAuth($connectionParams); + $this->curlOpts = $this->generateCurlOpts($connectionParams); + + $this->multiHandle = $connectionParams['curlMultiHandle']; + return parent::__construct($hostDetails, $connectionParams, $log, $trace); + + } + + + /** + * Returns the transport schema + * + * @return string + */ + public function getTransportSchema() + { + return $this->transportSchema; + + } + + + /** + * Perform an HTTP request on the cluster + * + * @param string $method HTTP method to use for request + * @param string $uri HTTP URI to use for request + * @param null|string $params Optional URI parameters + * @param null|string $body Optional request body + * @param array $options Optional options + * + * @throws \Elasticsearch\Common\Exceptions\TransportException + * @throws \Elasticsearch\Common\Exceptions\ServerErrorResponseException + * @return array + */ + public function performRequest($method, $uri, $params = null, $body = null, $options = array()) + { + $uri = $this->getURI($uri, $params); + + $curlHandle = curl_init(); + + $opts = $this->curlOpts; + $opts[CURLOPT_URL] = $uri; + $opts[CURLOPT_CUSTOMREQUEST]= $method; + + if (count($options) > 0) { + $opts = $this->reconcileOptions($options) + $opts; + } + + if ($method === 'GET') { + //Force these since Curl won't reset by itself + $opts[CURLOPT_NOBODY] = false; + } else if ($method === 'HEAD') { + $opts[CURLOPT_NOBODY] = true; + } + + if (isset($body) === true) { + if ($method === 'GET'){ + $opts[CURLOPT_CUSTOMREQUEST] = 'POST'; + } + $opts[CURLOPT_POSTFIELDS] = $body; + } + + $this->log->debug("Curl Options:", $opts); + + $this->lastRequest = array('request' => + array( + 'uri' => $uri, + 'body' => $body, + 'options' => $options, + 'method' => $method + ) + ); + + curl_setopt_array($curlHandle, $opts); + curl_multi_add_handle($this->multiHandle, $curlHandle); + + $response = array(); + + + do { + + do { + $execrun = curl_multi_exec($this->multiHandle, $running); + } while ($execrun == CURLM_CALL_MULTI_PERFORM && $running === 1); + + if ($execrun !== CURLM_OK) { + $this->log->critical('Unexpected Curl error: ' . $execrun); + throw new TransportException('Unexpected Curl error: ' . $execrun); + } + + /* + Curl_multi_select not strictly necessary, since we are only + performing one request total. May be useful if we ever + implement batching + + From Guzzle: https://github.com/guzzle/guzzle/blob/master/src/Guzzle/Http/Curl/CurlMulti.php#L314 + Select the curl handles until there is any + activity on any of the open file descriptors. See: + https://github.com/php/php-src/blob/master/ext/curl/multi.c#L170 + */ + + if ($running === 1 && $execrun === CURLM_OK && curl_multi_select($this->multiHandle, 0.5) === -1) { + /* + Perform a usleep if a previously executed select returned -1 + @see https://bugs.php.net/bug.php?id=61141 + */ + + usleep(100); + } + + // A request was just completed. + while ($transfer = curl_multi_info_read($this->multiHandle)) { + $response['responseText'] = curl_multi_getcontent($transfer['handle']); + $response['errorNumber'] = curl_errno($transfer['handle']); + $response['error'] = curl_error($transfer['handle']); + $response['requestInfo'] = curl_getinfo($transfer['handle']); + curl_multi_remove_handle($this->multiHandle, $transfer['handle']); + + } + } while ($running === 1); + + // If there was an error response, something like a time-out or + // refused connection error occurred. + if ($response['error'] !== '') { + $this->processCurlError($method, $uri, $response); + } + + if ($response['requestInfo']['http_code'] >= 400 && $response['requestInfo']['http_code'] < 500) { + $this->process4xxError($method, $uri, $body, $response); + } else if ($response['requestInfo']['http_code'] >= 500) { + $this->process5xxError($method, $uri, $body, $response); + } + + $this->lastRequest['response']['body'] = $response['responseText']; + $this->lastRequest['response']['info'] = $response['requestInfo']; + $this->lastRequest['response']['status'] = $response['requestInfo']['http_code']; + + $this->logRequestSuccess( + $method, + $uri, + $body, + "", //TODO FIX THIS + $response['requestInfo']['http_code'], + $response['responseText'], + $response['requestInfo']['total_time'] + ); + + + + return array( + 'status' => $response['requestInfo']['http_code'], + 'text' => $response['responseText'], + 'info' => $response['requestInfo'], + ); + + } + + + /** + * @return array + */ + public function getLastRequestInfo() + { + return $this->lastRequest; + } + + + /** + * @param $method + * @param $uri + * @param $response + * + * @throws \Elasticsearch\Common\Exceptions\ScriptLangNotSupportedException + * @throws \Elasticsearch\Common\Exceptions\Forbidden403Exception + * @throws \Elasticsearch\Common\Exceptions\Conflict409Exception + * @throws \Elasticsearch\Common\Exceptions\Missing404Exception + * @throws \Elasticsearch\Common\Exceptions\AlreadyExpiredException + */ + private function process4xxError($method, $uri, $request, $response) + { + $this->logErrorDueToFailure($method, $uri, $request, $response); + + $statusCode = $response['requestInfo']['http_code']; + $exceptionText = $response['error']; + $responseBody = $response['responseText']; + + $exceptionText = "$statusCode Server Exception: $exceptionText\n$responseBody"; + + if ($statusCode === 400 && strpos($responseBody, "AlreadyExpiredException") !== false) { + throw new AlreadyExpiredException($responseBody, $statusCode); + } elseif ($statusCode === 403) { + throw new Forbidden403Exception($responseBody, $statusCode); + } elseif ($statusCode === 404) { + throw new Missing404Exception($responseBody, $statusCode); + } elseif ($statusCode === 409) { + throw new Conflict409Exception($responseBody, $statusCode); + } elseif ($statusCode === 400 && strpos($responseBody, 'script_lang not supported') !== false) { + throw new ScriptLangNotSupportedException($responseBody. $statusCode); + } elseif ($statusCode === 400) { + throw new BadRequest400Exception($responseBody, $statusCode); + } + } + + + /** + * @param $method + * @param $uri + * @param $response + * + * @throws \Elasticsearch\Common\Exceptions\RoutingMissingException + * @throws \Elasticsearch\Common\Exceptions\NoShardAvailableException + * @throws \Elasticsearch\Common\Exceptions\NoDocumentsToGetException + * @throws \Elasticsearch\Common\Exceptions\ServerErrorResponseException + */ + private function process5xxError($method, $uri, $request, $response) + { + $this->logErrorDueToFailure($method, $uri, $request, $response); + + $statusCode = $response['requestInfo']['http_code']; + $exceptionText = $response['error']; + $responseBody = $response['responseText']; + + $exceptionText = "$statusCode Server Exception: $exceptionText\n$responseBody"; + $this->log->error($exceptionText); + + if ($statusCode === 500 && strpos($responseBody, "RoutingMissingException") !== false) { + throw new RoutingMissingException($responseBody, $statusCode); + } elseif ($statusCode === 500 && preg_match('/ActionRequestValidationException.+ no documents to get/',$responseBody) === 1) { + throw new NoDocumentsToGetException($responseBody, $statusCode); + } elseif ($statusCode === 500 && strpos($responseBody, 'NoShardAvailableActionException') !== false) { + throw new NoShardAvailableException($responseBody, $statusCode); + } else { + throw new ServerErrorResponseException($responseBody, $statusCode); + } + + + } + + + /** + * @param $method + * @param $uri + * @param $response + */ + private function processCurlError($method, $uri, $response) + { + $error = 'Curl error: ' . $response['error']; + $this->log->error($error); + $this->throwCurlException($response['errorNumber'], $response['error']); + } + + + /** + * @param $method + * @param $uri + * @param $request + * @param $response + */ + private function logErrorDueToFailure($method, $uri, $request, $response) + { + $this->logRequestFail( + $method, + $uri, + $request, + $response['requestInfo']['http_code'], + $response['responseText'], + $response['error'], + $response + ); + } + + + + /** + * @param array $connectionParams + * @return array + */ + private function transformAuth($connectionParams) + { + if (isset($connectionParams['auth']) !== true) { + return $connectionParams; + } + + $username = $connectionParams['auth'][0]; + $password = $connectionParams['auth'][1]; + + switch ($connectionParams['auth'][2]) { + case 'Basic': + $connectionParams['connectionParams']['curlOpts'][CURLOPT_HTTPAUTH] = CURLAUTH_BASIC; + $this->headers['authorization'] = 'Basic '.base64_encode("$username:$password"); + unset($connectionParams['auth']); + return $connectionParams; + break; + + case 'Digest': + $connectionParams['connectionParams']['curlOpts'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST; + break; + + case 'NTLM': + $connectionParams['connectionParams']['curlOpts'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM; + break; + + case 'Any': + $connectionParams['connectionParams'][CURLOPT_HTTPAUTH] = CURLAUTH_ANY; + break; + } + + + $connectionParams['connectionParams'][CURLOPT_USERPWD] = "$username:$password"; + + unset($connectionParams['auth']); + return $connectionParams; + + } + + /** + * @param string $uri + * @param array $params + * + * @return string + */ + private function getURI($uri, $params) + { + $uri = $this->host . $uri; + + if (isset($params) === true) { + $uri .= '?' . http_build_query($params); + } + + return $uri; + } + + private function generateCurlOpts($connectionParams) + { + $opts = array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT_MS => 1000, + CURLOPT_CONNECTTIMEOUT_MS => 1000, + CURLOPT_HEADER => false, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYHOST => false, + CURLOPT_TCP_NODELAY => false + ); + + if (isset($this->headers) && count($this->headers) > 0) { + $opts[CURLOPT_HTTPHEADER] = $this->headers; + } + + if (isset($connectionParams['timeout']) === true) { + $opts[CURLOPT_TIMEOUT_MS] = $connectionParams['timeout']; + $opts[CURLOPT_CONNECTTIMEOUT_MS] = $connectionParams['timeout']; + } + + if (isset($connectionParams['connectionParams']['curlOpts'])) { + //MUST use union operator, array_merge rekeys numeric + $opts = $opts + $connectionParams['connectionParams']['curlOpts']; + } + + return $opts; + } + + private function reconcileOptions($options) + { + $opts = array(); + if (isset($options['timeout']) === true) { + $opts[CURLOPT_TIMEOUT_MS] = $options['timeout']; + $opts[CURLOPT_CONNECTTIMEOUT_MS] = $options['timeout']; + } + + return $opts; + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/GuzzleConnection.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/GuzzleConnection.php new file mode 100644 index 00000000..ed2690f6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/GuzzleConnection.php @@ -0,0 +1,334 @@ +critical('guzzleClient must be set in connectionParams'); + throw new InvalidArgumentException('guzzleClient must be set in connectionParams'); + } + + if (isset($hostDetails['port']) !== true) { + $hostDetails['port'] = 9200; + } + + if (isset($hostDetails['scheme']) !== true) { + $hostDetails['scheme'] = 'http'; + } + + $this->guzzle = $connectionParams['guzzleClient']; + + if (isset($connectionParams['connectionParams'])) { + $this->connectionOpts = $connectionParams['connectionParams']; + } + + return parent::__construct($hostDetails, $connectionParams, $log, $trace); + + } + + /** + * Returns the transport schema + * + * @return string + */ + public function getTransportSchema() + { + return $this->transportSchema; + } + + + /** + * Perform an HTTP request on the cluster + * + * @param string $method HTTP method to use for request + * @param string $uri HTTP URI to use for request + * @param null|string $params Optional URI parameters + * @param null|string $body Optional request body + * @param array $options + * + * @return array + */ + public function performRequest($method, $uri, $params = null, $body = null, $options = array()) + { + + $uri = $this->getURI($uri, $params); + + $options += $this->connectionOpts; + $request = $this->buildGuzzleRequest($method, $uri, $body, $options); + $response = $this->sendRequest($request, $body); + + return array( + 'status' => $response->getStatusCode(), + 'text' => $response->getBody(true), + 'info' => $response->getInfo(), + ); + + } + + + /** + * @return array + */ + public function getLastRequestInfo() + { + return $this->lastRequest; + } + + + /** + * @param string $uri + * @param array $params + * + * @return string + */ + private function getURI($uri, $params) + { + $uri = $this->host . $uri; + + if (isset($params) === true) { + $uri .= '?' . http_build_query($params); + } + + return $uri; + } + + + /** + * @param string $method + * @param string $uri + * @param string $body + * @param array $options + * + * @return Request + */ + private function buildGuzzleRequest($method, $uri, $body, $options = array()) + { + if ($method === 'GET' && isset($body) === true) { + $method = 'POST'; + } + + if (isset($body) === true) { + $this->lastRequest = array( 'request' => array( + 'uri' => $uri, + 'body' => $body, + 'options' => $options, + 'method' => $method + )); + $request = $this->guzzle->$method($uri, array(), $body, $options); + } else { + $this->lastRequest = array( 'request' => array( + 'uri' => $uri, + 'body' => null, + 'options' => $options, + 'method' => $method + )); + $request = $this->guzzle->$method($uri, array(), $options); + } + + return $request; + } + + + /** + * @param Request $request + * + * @param string $body + * + * @throws \Elasticsearch\Common\Exceptions\TransportException + * @return \Guzzle\Http\Message\Response + */ + private function sendRequest(Request $request, $body) + { + try { + $request->send(); + } catch (ServerErrorResponseException $exception) { + $this->process5xxError($request, $exception, $body); + + } catch (ClientErrorResponseException $exception) { + $this->process4xxError($request, $exception, $body); + + } catch (CurlException $exception) { + $this->processCurlError($exception); + + } catch (\Exception $exception) { + $error = 'Unexpected error: ' . $exception->getMessage(); + $this->log->critical($error); + throw new TransportException($error); + } + + $this->processSuccessfulRequest($request, $body); + return $request->getResponse(); + } + + + /** + * @param Request $request + * @param ServerErrorResponseException $exception + * @param string $body + * + * @throws \Elasticsearch\Common\Exceptions\RoutingMissingException + * @throws \Elasticsearch\Common\Exceptions\NoShardAvailableException + * @throws \Guzzle\Http\Exception\ServerErrorResponseException + * @throws \Elasticsearch\Common\Exceptions\NoDocumentsToGetException + */ + private function process5xxError(Request $request, ServerErrorResponseException $exception, $body) + { + $this->logErrorDueToFailure($request, $exception, $body); + + $statusCode = $request->getResponse()->getStatusCode(); + $exceptionText = $exception->getMessage(); + $responseBody = $request->getResponse()->getBody(true); + + $exceptionText = "$statusCode Server Exception: $exceptionText\n$responseBody"; + $this->log->error($exceptionText); + + if ($statusCode === 500 && strpos($responseBody, "RoutingMissingException") !== false) { + throw new RoutingMissingException($responseBody, $statusCode, $exception); + } elseif ($statusCode === 500 && preg_match('/ActionRequestValidationException.+ no documents to get/',$responseBody) === 1) { + throw new NoDocumentsToGetException($responseBody, $statusCode, $exception); + } elseif ($statusCode === 500 && strpos($responseBody, 'NoShardAvailableActionException') !== false) { + throw new NoShardAvailableException($responseBody, $statusCode, $exception); + } else { + throw new \Elasticsearch\Common\Exceptions\ServerErrorResponseException($responseBody, $statusCode, $exception); + } + + + } + + + private function process4xxError(Request $request, ClientErrorResponseException $exception, $body) + { + $this->logErrorDueToFailure($request, $exception, $body); + + $statusCode = $request->getResponse()->getStatusCode(); + $exceptionText = $exception->getMessage(); + $responseBody = $request->getResponse()->getBody(true); + + $exceptionText = "$statusCode Server Exception: $exceptionText\n$responseBody"; + + if ($statusCode === 400 && strpos($responseBody, "AlreadyExpiredException") !== false) { + throw new AlreadyExpiredException($responseBody, $statusCode, $exception); + } elseif ($statusCode === 403) { + throw new Forbidden403Exception($responseBody, $statusCode, $exception); + } elseif ($statusCode === 404) { + throw new Missing404Exception($responseBody, $statusCode, $exception); + } elseif ($statusCode === 409) { + throw new Conflict409Exception($responseBody, $statusCode, $exception); + } elseif ($statusCode === 400 && strpos($responseBody, 'script_lang not supported') !== false) { + throw new ScriptLangNotSupportedException($responseBody. $statusCode); + } elseif ($statusCode === 400) { + throw new BadRequest400Exception($responseBody, $statusCode, $exception); + } + } + + + /** + * @param Request $request + * @param \Exception $exception + * @param string $body + */ + private function logErrorDueToFailure(Request $request, \Exception $exception, $body) + { + $response = $request->getResponse(); + $headers = $request->getHeaders()->getAll(); + $info = $response->getInfo(); + $responseBody = $response->getBody(true); + $status = $response->getStatusCode(); + + $this->lastRequest['response']['body'] = $responseBody; + $this->lastRequest['response']['info'] = $info; + $this->lastRequest['response']['status'] = $status; + + $this->logRequestFail( + $request->getMethod(), + $request->getUrl(), + $body, + $headers, + $response->getStatusCode(), + $responseBody, + $exception->getMessage() + ); + } + + + /** + * @param CurlException $exception\ + */ + private function processCurlError(CurlException $exception) + { + $error = 'Curl error: ' . $exception->getMessage(); + $this->log->error($error); + $this->throwCurlException($exception->getErrorNo(), $exception->getError()); + } + + /** + * @param Request $request + * @param string $body + */ + private function processSuccessfulRequest(Request $request, $body) + { + $response = $request->getResponse(); + $headers = $request->getHeaders()->getAll(); + $responseBody = $response->getBody(true); + $status = $response->getStatusCode(); + + $this->lastRequest['response']['body'] = $responseBody; + $this->lastRequest['response']['status'] = $status; + + $this->logRequestSuccess( + $request->getMethod(), + $request->getUrl(), + $body, + $headers, + $status, + $responseBody, + $response->getInfo('total_time') + ); + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/AbstractEndpoint.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/AbstractEndpoint.php new file mode 100644 index 00000000..f3bb646f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/AbstractEndpoint.php @@ -0,0 +1,302 @@ +transport = $transport; + } + + + /** + * + * @throws \Exception + * @return array + */ + public function performRequest() + { + $result = array(); + + try { + $result = $this->transport->performRequest( + $this->getMethod(), + $this->getURI(), + $this->params, + $this->getBody() + ); + } catch (\Exception $exception) { + $code = $exception->getCode(); + if ($this->ignore === null) { + throw $exception; + } else if (array_search($code, $this->ignore) === false) { + throw $exception; + } else { + //TODO return null or dedicated object here instead? + return array('data' => $exception->getMessage()); + } + } + + return $result; + + } + + /** + * Set the parameters for this endpoint + * + * @param string[] $params Array of parameters + * @return $this + */ + public function setParams($params) + { + if (is_object($params) === true) { + $params = (array)$params; + } + + $this->checkUserParams($params); + $this->params = $this->convertArraysToStrings($params); + $this->extractIgnore(); + return $this; + } + + + /** + * @param string $index + * + * @return $this + */ + public function setIndex($index) + { + if ($index === null) { + return $this; + } + + if (is_array($index) === true) { + $index = implode(",", $index); + } + + $this->index = urlencode($index); + return $this; + } + + + /** + * @param string $type + * + * @return $this + */ + public function setType($type) + { + if ($type === null) { + return $this; + } + + if (is_array($type) === true) { + $type = implode(",", $type); + } + + $this->type = urlencode($type); + return $this; + } + + + /** + * @param int|string $docID + * + * @return $this + */ + public function setID($docID) + { + if ($docID === null) { + return $this; + } + + $this->id = urlencode($docID); + return $this; + } + + + /** + * @return array + */ + protected function getBody() + { + return $this->body; + } + + + /** + * @param string $endpoint + * + * @return string + */ + protected function getOptionalURI($endpoint) + { + $uri = array(); + $uri[] = $this->getOptionalIndex(); + $uri[] = $this->getOptionalType(); + $uri[] = $endpoint; + $uri = array_filter($uri); + + return '/' . implode('/', $uri); + } + + + /** + * @return string + */ + private function getOptionalIndex() + { + if (isset($this->index) === true){ + return $this->index; + } else { + return '_all'; + } + } + + + /** + * @return string + */ + private function getOptionalType() + { + if (isset($this->type) === true){ + return $this->type; + } else { + return ''; + } + } + + + + /** + * @param array $params + * + * @throws \Elasticsearch\Common\Exceptions\UnexpectedValueException + */ + private function checkUserParams($params) + { + try { + $this->ifParamsInvalidThrowException($params); + } catch (UnexpectedValueException $exception) { + throw $exception; + } + } + + /** + * Check if param is in whitelist + * + * @param array $params Assoc array of parameters + * + * @throws \Elasticsearch\Common\Exceptions\UnexpectedValueException + * + */ + private function ifParamsInvalidThrowException($params) + { + if (isset($params) !== true) { + return; //no params, just return. + } + + $whitelist = array_merge($this->getParamWhitelist(), array('ignore')); + + foreach ($params as $key => $value) { + if (array_search($key, $whitelist) === false) { + throw new UnexpectedValueException($key . ' is not a valid parameter'); + } + } + + } + + + private function extractIgnore() + { + if (isset($this->params['ignore']) === true) { + $this->ignore = explode(",", $this->params['ignore']); + unset($this->params['ignore']); + } + } + + + private function convertArraysToStrings($params) + { + foreach ($params as &$param) { + if (is_array($param) === true) { + if ($this->isNestedArray($param) !== true){ + $param = implode(",", $param); + } + + } + } + + return $params; + } + + private function isNestedArray($a) { + foreach ($a as $v) { + if (is_array($v)) { + return true; + } + } + return false; + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Bulk.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Bulk.php new file mode 100644 index 00000000..b8e8773b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Bulk.php @@ -0,0 +1,85 @@ +serializer = $serializer; + parent::__construct($transport); + } + + + /** + * @param string|array $body + * + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + if (is_array($body) === true) { + $bulkBody = ""; + foreach ($body as $item) { + $bulkBody .= $this->serializer->serialize($item)."\n"; + } + $body = $bulkBody; + } + + $this->body = $body; + return $this; + } + + /** + * @return string + */ + protected function getURI() + { + return $this->getOptionalURI('_bulk'); + + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'consistency', + 'refresh', + 'replication', + 'type', + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/BulkEndpointInterface.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/BulkEndpointInterface.php new file mode 100644 index 00000000..71ebbd59 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/BulkEndpointInterface.php @@ -0,0 +1,16 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Aliases extends AbstractEndpoint +{ + // A comma-separated list of alias names to return + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $name = $this->name; + $uri = "/_cat/aliases"; + + if (isset($name) === true) { + $uri = "/_cat/aliases/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Allocation.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Allocation.php new file mode 100644 index 00000000..a91d5ae1 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Allocation.php @@ -0,0 +1,84 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Allocation extends AbstractEndpoint +{ + // A comma-separated list of node IDs or names to limit the returned information + private $node_id; + + + /** + * @param $node_id + * + * @return $this + */ + public function setNodeId($node_id) + { + if (isset($node_id) !== true) { + return $this; + } + + $this->node_id = $node_id; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $node_id = $this->node_id; + $uri = "/_cat/allocation"; + + if (isset($node_id) === true) { + $uri = "/_cat/allocation/$node_id"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'bytes', + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Count.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Count.php new file mode 100644 index 00000000..1faf1a11 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Count.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Count extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_cat/count"; + + if (isset($index) === true) { + $uri = "/_cat/count/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Fielddata.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Fielddata.php new file mode 100644 index 00000000..b269083a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Fielddata.php @@ -0,0 +1,82 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Fielddata extends AbstractEndpoint +{ + private $fields; + + + /** + * @param $fields + * + * @return $this + */ + public function setFields($fields) + { + if (isset($fields) !== true) { + return $this; + } + + $this->fields = $fields; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $fields = $this->fields; + $uri = "/_cat/fielddata"; + + if (isset($fields) === true) { + $uri = "/_cat/fielddata/$fields"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Health.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Health.php new file mode 100644 index 00000000..bed26e72 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Health.php @@ -0,0 +1,60 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Health extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cat/health"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'ts', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Help.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Help.php new file mode 100644 index 00000000..69d6785b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Help.php @@ -0,0 +1,55 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Help extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cat"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'help', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Indices.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Indices.php new file mode 100644 index 00000000..b257ecff --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Indices.php @@ -0,0 +1,65 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Indices extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_cat/indices"; + + if (isset($index) === true) { + $uri = "/_cat/indices/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'bytes', + 'local', + 'master_timeout', + 'h', + 'help', + 'pri', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Master.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Master.php new file mode 100644 index 00000000..20cf05c6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Master.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Master extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cat/master"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Nodes.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Nodes.php new file mode 100644 index 00000000..46106e76 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Nodes.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Nodes extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cat/nodes"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/PendingTasks.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/PendingTasks.php new file mode 100644 index 00000000..c333f402 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/PendingTasks.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class PendingTasks extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cat/pending_tasks"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Recovery.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Recovery.php new file mode 100644 index 00000000..4ffa6522 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Recovery.php @@ -0,0 +1,64 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Recovery extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_cat/recovery"; + + if (isset($index) === true) { + $uri = "/_cat/recovery/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'bytes', + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Shards.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Shards.php new file mode 100644 index 00000000..599df4f4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/Shards.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Shards extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_cat/shards"; + + if (isset($index) === true) { + $uri = "/_cat/shards/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/ThreadPool.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/ThreadPool.php new file mode 100644 index 00000000..f77d9f24 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cat/ThreadPool.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class ThreadPool extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cat/thread_pool"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'h', + 'help', + 'v', + 'full_id', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/ClearScroll.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/ClearScroll.php new file mode 100644 index 00000000..d8ff16df --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/ClearScroll.php @@ -0,0 +1,84 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Clearscroll extends AbstractEndpoint +{ + // A comma-separated list of scroll IDs to clear + private $scroll_id; + + + /** + * @param $scroll_id + * + * @return $this + */ + public function setScroll_Id($scroll_id) + { + if (isset($scroll_id) !== true) { + return $this; + } + + $this->scroll_id = $scroll_id; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->scroll_id) !== true) { + throw new Exceptions\RuntimeException( + 'scroll_id is required for Clearscroll' + ); + } + $scroll_id = $this->scroll_id; + $uri = "/_search/scroll/$scroll_id"; + + if (isset($scroll_id) === true) { + $uri = "/_search/scroll/$scroll_id"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Health.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Health.php new file mode 100644 index 00000000..ddf387b3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Health.php @@ -0,0 +1,66 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Health extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_cluster/health"; + + if (isset($index) === true) { + $uri = "/_cluster/health/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'level', + 'local', + 'master_timeout', + 'timeout', + 'wait_for_active_shards', + 'wait_for_nodes', + 'wait_for_relocating_shards', + 'wait_for_status', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/AbstractNodesEndpoint.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/AbstractNodesEndpoint.php new file mode 100644 index 00000000..8ec0978e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/AbstractNodesEndpoint.php @@ -0,0 +1,44 @@ +nodeID = $nodeID; + return $this; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/HotThreads.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/HotThreads.php new file mode 100644 index 00000000..29f2f317 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/HotThreads.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class HotThreads extends AbstractNodesEndpoint +{ + + /** + * @return string + */ + protected function getURI() + { + $node_id = $this->nodeID; + $uri = "/_cluster/nodes/hotthreads"; + + if (isset($node_id) === true) { + $uri = "/_cluster/nodes/$node_id/hotthreads"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'interval', + 'snapshots', + 'threads', + 'type', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Info.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Info.php new file mode 100644 index 00000000..bf1dabb2 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Info.php @@ -0,0 +1,89 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Info extends AbstractNodesEndpoint +{ + + // A comma-separated list of metrics you wish returned. Leave empty to return all. + private $metric; + + /** + * @param $metric + * + * @return $this + */ + public function setMetric($metric) + { + if (isset($metric) !== true) { + return $this; + } + + if (is_array($metric) === true) { + $metric = implode(",", $metric); + } + + $this->metric = $metric; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $node_id = $this->nodeID; + $metric = $this->metric; + $uri = "/_nodes"; + + if (isset($node_id) === true && isset($metric) === true) { + $uri = "/_nodes/$node_id/$metric"; + } elseif (isset($metric) === true) { + $uri = "/_nodes/$metric"; + } elseif (isset($node_id) === true) { + $uri = "/_nodes/$node_id"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'flat_settings', + 'human', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Shutdown.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Shutdown.php new file mode 100644 index 00000000..ae02496d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Shutdown.php @@ -0,0 +1,61 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Shutdown extends AbstractNodesEndpoint +{ + + /** + * @return string + */ + protected function getURI() + { + $node_id = $this->nodeID; + $uri = "/_shutdown"; + + if (isset($node_id) === true) { + $uri = "/_cluster/nodes/$node_id/_shutdown"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'delay', + 'exit', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Stats.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Stats.php new file mode 100644 index 00000000..3627f691 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Nodes/Stats.php @@ -0,0 +1,122 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Stats extends AbstractNodesEndpoint +{ + // Limit the information returned to the specified metrics + private $metric; + + + // Limit the information returned for `indices` metric to the specific index metrics. Isn't used if `indices` (or `all`) metric isn't specified. + private $indexMetric; + + /** + * @param $metric + * + * @return $this + */ + public function setMetric($metric) + { + if (isset($metric) !== true) { + return $this; + } + + if (is_array($metric) === true) { + $metric = implode(",", $metric); + } + + $this->metric = $metric; + return $this; + } + + + /** + * @param $indexMetric + * + * @return $this + */ + public function setIndexMetric($indexMetric) + { + if (isset($indexMetric) !== true) { + return $this; + } + + if (is_array($indexMetric) === true) { + $indexMetric = implode(",", $indexMetric); + } + + $this->indexMetric = $indexMetric; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $metric = $this->metric; + $index_metric = $this->indexMetric; + $node_id = $this->nodeID; + $uri = "/_nodes/stats"; + + if (isset($node_id) === true && isset($metric) === true && isset($index_metric) === true) { + $uri = "/_nodes/$node_id/stats/$metric/$index_metric"; + } elseif (isset($metric) === true && isset($index_metric) === true) { + $uri = "/_nodes/stats/$metric/$index_metric"; + } elseif (isset($node_id) === true && isset($metric) === true) { + $uri = "/_nodes/$node_id/stats/$metric"; + } elseif (isset($metric) === true) { + $uri = "/_nodes/stats/$metric"; + } elseif (isset($node_id) === true) { + $uri = "/_nodes/$node_id/stats"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'completion_fields', + 'fielddata_fields', + 'fields', + 'groups', + 'human', + 'level', + 'types', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/PendingTasks.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/PendingTasks.php new file mode 100644 index 00000000..db9a60d5 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/PendingTasks.php @@ -0,0 +1,55 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class PendingTasks extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cluster/pending_tasks"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Reroute.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Reroute.php new file mode 100644 index 00000000..67e69fad --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Reroute.php @@ -0,0 +1,78 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Reroute extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cluster/reroute"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'dry_run', + 'filter_metadata', + 'master_timeout', + 'timeout', + 'explain' + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Settings/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Settings/Get.php new file mode 100644 index 00000000..126f255e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Settings/Get.php @@ -0,0 +1,57 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cluster/settings"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'flat_settings', + 'master_timeout', + 'timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Settings/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Settings/Put.php new file mode 100644 index 00000000..def2e151 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Settings/Put.php @@ -0,0 +1,74 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $uri = "/_cluster/settings"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'flat_settings', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/State.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/State.php new file mode 100644 index 00000000..5d20f849 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/State.php @@ -0,0 +1,89 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class State extends AbstractEndpoint +{ + // Limit the information returned to the specified metrics + private $metric; + + + /** + * @param $metric + * + * @return $this + */ + public function setMetric($metric) + { + if (isset($metric) !== true) { + return $this; + } + + if (is_array($metric) === true) { + $metric = implode(",", $metric); + } + + $this->metric = $metric; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $metric = $this->metric; + $uri = "/_cluster/state"; + + if (isset($metric) === true && isset($index) === true) { + $uri = "/_cluster/state/$metric/$index"; + } elseif (isset($metric) === true) { + $uri = "/_cluster/state/$metric"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + 'master_timeout', + 'flat_settings', + 'index_templates' + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Stats.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Stats.php new file mode 100644 index 00000000..2902e85e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Cluster/Stats.php @@ -0,0 +1,80 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Stats extends AbstractEndpoint +{ + // A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes + private $nodeID; + + + /** + * @param $node_id + * + * @return $this + */ + public function setNodeID($node_id) + { + if (isset($node_id) !== true) { + return $this; + } + + $this->nodeID = $node_id; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $node_id = $this->nodeID; + $uri = "/_cluster/stats"; + + if (isset($node_id) === true) { + $uri = "/_cluster/stats/nodes/$node_id"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'flat_settings', + 'human', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Count.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Count.php new file mode 100644 index 00000000..9df724d8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Count.php @@ -0,0 +1,89 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Count extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_count"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_count"; + } elseif (isset($type) === true) { + $uri = "/_all/$type/_count"; + } elseif (isset($index) === true) { + $uri = "/$index/_count"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'min_score', + 'preference', + 'routing', + 'source', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/CountPercolate.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/CountPercolate.php new file mode 100644 index 00000000..019621e5 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/CountPercolate.php @@ -0,0 +1,100 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class CountPercolate extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for CountPercolate' + ); + } + + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for CountPercolate' + ); + } + + $index = $this->index; + $type = $this->type; + $id = $this->id; + $uri = "/$index/$type/_percolate/count"; + + if (isset($id) === true) { + $uri = "/$index/$type/$id/_percolate/count"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'routing', + 'preference', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'percolate_index', + 'percolate_type', + 'version', + 'version_type' + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Delete.php new file mode 100644 index 00000000..9b27c4da --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Delete.php @@ -0,0 +1,84 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Delete' + ); + } + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Delete' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Delete' + ); + } + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/$id"; + + if (isset($index) === true && isset($type) === true && isset($id) === true) { + $uri = "/$index/$type/$id"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'consistency', + 'parent', + 'refresh', + 'replication', + 'routing', + 'timeout', + 'version', + 'version_type', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/DeleteByQuery.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/DeleteByQuery.php new file mode 100644 index 00000000..0b546f2a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/DeleteByQuery.php @@ -0,0 +1,98 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class DeleteByQuery extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Deletebyquery' + ); + } + $index = $this->index; + $type = $this->type; + $uri = "/$index/_query"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_query"; + } elseif (isset($index) === true) { + $uri = "/$index/_query"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'analyzer', + 'consistency', + 'default_operator', + 'df', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'replication', + 'q', + 'routing', + 'source', + 'timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Exists.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Exists.php new file mode 100644 index 00000000..4d566be3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Exists.php @@ -0,0 +1,81 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Exists extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Exists' + ); + } + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Exists' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Exists' + ); + } + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/$id"; + + if (isset($index) === true && isset($type) === true && isset($id) === true) { + $uri = "/$index/$type/$id"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'parent', + 'preference', + 'realtime', + 'refresh', + 'routing', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'HEAD'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Explain.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Explain.php new file mode 100644 index 00000000..1ecd319b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Explain.php @@ -0,0 +1,110 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Explain extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Explain' + ); + } + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Explain' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Explain' + ); + } + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/$id/_explain"; + + if (isset($index) === true && isset($type) === true && isset($id) === true) { + $uri = "/$index/$type/$id/_explain"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'analyze_wildcard', + 'analyzer', + 'default_operator', + 'df', + 'fields', + 'lenient', + 'lowercase_expanded_terms', + 'parent', + 'preference', + 'q', + 'routing', + 'source', + '_source', + '_source_exclude', + '_source_include', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Get.php new file mode 100644 index 00000000..05cb246d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Get.php @@ -0,0 +1,122 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + + /** @var bool */ + private $returnOnlySource = false; + + /** @var bool */ + private $checkOnlyExistance = false; + + + /** + * @return $this + */ + public function returnOnlySource() + { + $this->returnOnlySource = true; + return $this; + } + + /** + * @return $this + */ + public function checkOnlyExistance() + { + $this->checkOnlyExistance = true; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Get' + ); + } + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Get' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Get' + ); + } + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/$id"; + + if (isset($index) === true && isset($type) === true && isset($id) === true) { + $uri = "/$index/$type/$id"; + } + + if ($this->returnOnlySource === true) { + $uri .= '/_source'; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'fields', + 'parent', + 'preference', + 'realtime', + 'refresh', + 'routing', + '_source', + '_source_exclude', + '_source_include', + 'version', + 'version_type', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + if ($this->checkOnlyExistance === true) { + return 'HEAD'; + } else { + return 'GET'; + } + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Index.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Index.php new file mode 100644 index 00000000..f8fc4b9a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Index.php @@ -0,0 +1,142 @@ +body = $body; + return $this; + } + + + /** + * @return $this + */ + public function createIfAbsent() + { + $this->createIfAbsent = true; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Index' + ); + } + + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Index' + ); + } + + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type"; + + if (isset($id) === true) { + $uri = "/$index/$type/$id"; + } + + if ($this->createIfAbsent === true) { + $uri .= $this->addCreateFlag(); + } + + return $uri; + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'consistency', + 'op_type', + 'parent', + 'percolate', + 'refresh', + 'replication', + 'routing', + 'timeout', + 'timestamp', + 'ttl', + 'version', + 'version_type', + ); + } + + /** + * @return string + */ + protected function getMethod() + { + if (isset($this->id) === true) { + return 'PUT'; + } else { + return 'POST'; + } + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Document body must be set for index request'); + } else { + return $this->body; + } + } + + private function addCreateFlag() + { + if (isset($this->id) === true) { + return '/_create'; + } else { + $this->params['op_type'] = 'create'; + return ""; + } + + } +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/AbstractAliasEndpoint.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/AbstractAliasEndpoint.php new file mode 100644 index 00000000..2906e823 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/AbstractAliasEndpoint.php @@ -0,0 +1,41 @@ +name = urlencode($name); + return $this; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Delete.php new file mode 100644 index 00000000..de7519ff --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Delete.php @@ -0,0 +1,92 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + // A comma-separated list of aliases to delete (supports wildcards); use `_all` to delete all aliases for the specified indices. + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Delete' + ); + } + if (isset($this->name) !== true) { + throw new Exceptions\RuntimeException( + 'name is required for Delete' + ); + } + $index = $this->index; + $name = $this->name; + $uri = "/$index/_alias/$name"; + + if (isset($index) === true && isset($name) === true) { + $uri = "/$index/_alias/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Exists.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Exists.php new file mode 100644 index 00000000..44a0b591 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Exists.php @@ -0,0 +1,87 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Exists extends AbstractEndpoint +{ + // A comma-separated list of alias names to return + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $name = $this->name; + $uri = "/_alias/$name"; + + if (isset($index) === true && isset($name) === true) { + $uri = "/$index/_alias/$name"; + } elseif (isset($index) === true) { + $uri = "/$index/_alias"; + } elseif (isset($name) === true) { + $uri = "/_alias/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'HEAD'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Get.php new file mode 100644 index 00000000..36606319 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Get.php @@ -0,0 +1,87 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // A comma-separated list of alias names to return + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $name = $this->name; + $uri = "/_alias"; + + if (isset($index) === true && isset($name) === true) { + $uri = "/$index/_alias/$name"; + } else if (isset($index) === true) { + $uri = "/$index/_alias"; + } else if (isset($name) === true) { + $uri = "/_alias/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Put.php new file mode 100644 index 00000000..0db00cbf --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Alias/Put.php @@ -0,0 +1,108 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + // The name of the alias to be created or updated + private $name; + + + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->name) !== true) { + throw new Exceptions\RuntimeException( + 'name is required for Put' + ); + } + $index = $this->index; + $name = $this->name; + $uri = "/_alias/$name"; + + if (isset($index) === true && isset($name) === true) { + $uri = "/$index/_alias/$name"; + } elseif (isset($name) === true) { + $uri = "/_alias/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Aliases/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Aliases/Get.php new file mode 100644 index 00000000..8b4dc9d0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Aliases/Get.php @@ -0,0 +1,85 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // A comma-separated list of alias names to filter + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $name = $this->name; + $uri = "/_aliases"; + + if (isset($index) === true && isset($name) === true) { + $uri = "/$index/_aliases/$name"; + } elseif (isset($name) === true) { + $uri = "/_aliases/$name"; + } elseif (isset($index) === true) { + $uri = "/$index/_aliases"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Aliases/Update.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Aliases/Update.php new file mode 100644 index 00000000..6b169c01 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Aliases/Update.php @@ -0,0 +1,88 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Update extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $uri = "/_aliases"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Update Aliases'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Analyze.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Analyze.php new file mode 100644 index 00000000..1c84a78b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Analyze.php @@ -0,0 +1,85 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Analyze extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_analyze"; + + if (isset($index) === true) { + $uri = "/$index/_analyze"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'analyzer', + 'field', + 'filters', + 'index', + 'prefer_local', + 'text', + 'tokenizer', + 'format', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Cache/Clear.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Cache/Clear.php new file mode 100644 index 00000000..b3c93042 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Cache/Clear.php @@ -0,0 +1,63 @@ +index; + $uri = "/_cache/clear"; + + if (isset($index) === true) { + $uri = "/$index/_cache/clear"; + } + return $uri; + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'field_data', + 'fielddata', + 'fields', + 'filter', + 'filter_cache', + 'filter_keys', + 'id', + 'id_cache', + 'index', + 'recycler', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards' + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/ClearCache.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/ClearCache.php new file mode 100644 index 00000000..61493cbc --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/ClearCache.php @@ -0,0 +1,71 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class ClearCache extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_cache/clear"; + + if (isset($index) === true) { + $uri = "/$index/_cache/clear"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'field_data', + 'fielddata', + 'fields', + 'filter', + 'filter_cache', + 'filter_keys', + 'id', + 'id_cache', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'index', + 'recycler', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Close.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Close.php new file mode 100644 index 00000000..4907ab0f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Close.php @@ -0,0 +1,69 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Close extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Close' + ); + } + $index = $this->index; + $uri = "/$index/_close"; + + if (isset($index) === true) { + $uri = "/$index/_close"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Create.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Create.php new file mode 100644 index 00000000..e2f377f9 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Create.php @@ -0,0 +1,89 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Create extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Create' + ); + } + $index = $this->index; + $uri = "/$index"; + + if (isset($index) === true) { + $uri = "/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + if (isset($this->body['mappings']) === true) { + return 'POST'; + } else { + return 'PUT'; + } + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Delete.php new file mode 100644 index 00000000..3f7d9608 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Delete.php @@ -0,0 +1,60 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/$index"; + + if (isset($index) === true) { + $uri = "/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Exists.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Exists.php new file mode 100644 index 00000000..78f672e4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Exists.php @@ -0,0 +1,68 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Exists extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Exists' + ); + } + $index = $this->index; + $uri = "/$index"; + + if (isset($index) === true) { + $uri = "/$index"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'HEAD'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Exists/Types.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Exists/Types.php new file mode 100644 index 00000000..f16f9160 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Exists/Types.php @@ -0,0 +1,65 @@ +index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Types Exists' + ); + } + + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Types Exists' + ); + } + + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type"; + + return $uri; + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards' + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'HEAD'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Field/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Field/Get.php new file mode 100644 index 00000000..37055343 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Field/Get.php @@ -0,0 +1,97 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // A comma-separated list of fields + private $field; + + + /** + * @param $field + * + * @return $this + */ + public function setField($field) + { + if (isset($field) !== true) { + return $this; + } + + $this->field = $field; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->field) !== true) { + throw new Exceptions\RuntimeException( + 'field is required for Get' + ); + } + $index = $this->index; + $type = $this->type; + $field = $this->field; + $uri = "/_mapping/field/$field"; + + if (isset($index) === true && isset($type) === true && isset($field) === true) { + $uri = "/$index/_mapping/$type/field/$field"; + } elseif (isset($type) === true && isset($field) === true) { + $uri = "/_mapping/$type/field/$field"; + } elseif (isset($index) === true && isset($field) === true) { + $uri = "/$index/_mapping/field/$field"; + } elseif (isset($field) === true) { + $uri = "/_mapping/field/$field"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'include_defaults', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Flush.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Flush.php new file mode 100644 index 00000000..51d55068 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Flush.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Flush extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_flush"; + + if (isset($index) === true) { + $uri = "/$index/_flush"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'force', + 'full', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Gateway/Snapshot.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Gateway/Snapshot.php new file mode 100644 index 00000000..786826f0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Gateway/Snapshot.php @@ -0,0 +1,55 @@ +index; + $uri = "/_gateway/snapshot"; + + + if (isset($index) === true) { + $uri = "/$index/_gateway/snapshot"; + } + + return $uri; + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards' + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Delete.php new file mode 100644 index 00000000..e4c41cb6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Delete.php @@ -0,0 +1,71 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Delete' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Delete' + ); + } + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/_mapping"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_mapping"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Get.php new file mode 100644 index 00000000..9e95e0d0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Get.php @@ -0,0 +1,67 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_mapping"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/_mapping/$type"; + } elseif (isset($type) === true) { + $uri = "/_mapping/$type"; + } elseif (isset($index) === true) { + $uri = "/$index/_mapping"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/GetField.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/GetField.php new file mode 100644 index 00000000..07467952 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/GetField.php @@ -0,0 +1,83 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class GetField extends AbstractEndpoint +{ + /** @var string */ + private $field; + + + /** + * @param string|array $field + * + * @return $this + */ + public function setField($field) { + if (isset($field) !== true) { + return $this; + } + + if (is_array($field) === true) { + $field = implode(",", $field); + } + + $this->field = $field; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->field) !== true) { + throw new Exceptions\RuntimeException( + 'field is required for Get Field Mapping' + ); + } + $uri = $this->getOptionalURI('_mapping/field'); + + return $uri.'/'.$this->field; + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'include_defaults' + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Put.php new file mode 100644 index 00000000..a467f813 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Mapping/Put.php @@ -0,0 +1,105 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Put' + ); + } + $index = $this->index; + $type = $this->type; + $uri = "/_mapping/$type"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_mapping"; + } elseif (isset($type) === true) { + $uri = "/_mapping/$type"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_conflicts', + 'timeout', + 'master_timeout', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Put Mapping'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Open.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Open.php new file mode 100644 index 00000000..7f942354 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Open.php @@ -0,0 +1,69 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Open extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Open' + ); + } + $index = $this->index; + $uri = "/$index/_open"; + + if (isset($index) === true) { + $uri = "/$index/_open"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Optimize.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Optimize.php new file mode 100644 index 00000000..8da884d2 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Optimize.php @@ -0,0 +1,66 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Optimize extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_optimize"; + + if (isset($index) === true) { + $uri = "/$index/_optimize"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'flush', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'max_num_segments', + 'only_expunge_deletes', + 'operation_threading', + 'wait_for_merge', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Recovery.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Recovery.php new file mode 100644 index 00000000..64a7348a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Recovery.php @@ -0,0 +1,61 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Recovery extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_recovery"; + + if (isset($index) === true) { + $uri = "/$index/_recovery"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'detailed', + 'active_only', + 'human' + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Refresh.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Refresh.php new file mode 100644 index 00000000..eafb2ca2 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Refresh.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Refresh extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_refresh"; + + if (isset($index) === true) { + $uri = "/$index/_refresh"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'force', + 'operation_threading', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Segments.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Segments.php new file mode 100644 index 00000000..1183c7a2 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Segments.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Segments extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_segments"; + + if (isset($index) === true) { + $uri = "/$index/_segments"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'human', + 'operation_threading', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Settings/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Settings/Get.php new file mode 100644 index 00000000..2d6593eb --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Settings/Get.php @@ -0,0 +1,88 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // The name of the settings that should be included + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $name = $this->name; + $uri = "/_settings"; + + if (isset($index) === true && isset($name) === true) { + $uri = "/$index/_settings/$name"; + } elseif (isset($name) === true) { + $uri = "/_settings/$name"; + } elseif (isset($index) === true) { + $uri = "/$index/_settings"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'flat_settings', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Settings/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Settings/Put.php new file mode 100644 index 00000000..48ca3b7d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Settings/Put.php @@ -0,0 +1,95 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_settings"; + + if (isset($index) === true) { + $uri = "/$index/_settings"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'flat_settings', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Put Settings'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Snapshotindex.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Snapshotindex.php new file mode 100644 index 00000000..cf50af3b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Snapshotindex.php @@ -0,0 +1,61 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Snapshotindex extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_gateway/snapshot"; + + if (isset($index) === true) { + $uri = "/$index/_gateway/snapshot"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Stats.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Stats.php new file mode 100644 index 00000000..31bdefd7 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Stats.php @@ -0,0 +1,91 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Stats extends AbstractEndpoint +{ + // Limit the information returned the specific metrics. + private $metric; + + + /** + * @param $metric + * + * @return $this + */ + public function setMetric($metric) + { + if (isset($metric) !== true) { + return $this; + } + + $this->metric = $metric; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $metric = $this->metric; + $uri = "/_stats"; + + if (isset($index) === true && isset($metric) === true) { + $uri = "/$index/_stats/$metric"; + } elseif (isset($index) === true) { + $uri = "/$index/_stats"; + } elseif (isset($metric) === true) { + $uri = "/_stats/$metric"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'completion_fields', + 'fielddata_fields', + 'fields', + 'groups', + 'human', + 'level', + 'types', + 'metric' + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Status.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Status.php new file mode 100644 index 00000000..8b511dd6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Status.php @@ -0,0 +1,65 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Status extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_status"; + + if (isset($index) === true) { + $uri = "/$index/_status"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'human', + 'operation_threading', + 'recovery', + 'snapshot', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/AbstractTemplateEndpoint.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/AbstractTemplateEndpoint.php new file mode 100644 index 00000000..d7175239 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/AbstractTemplateEndpoint.php @@ -0,0 +1,29 @@ +name = $name; + return $this; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Delete.php new file mode 100644 index 00000000..301142fb --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Delete.php @@ -0,0 +1,86 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + // The name of the template + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->name) !== true) { + throw new Exceptions\RuntimeException( + 'name is required for Delete' + ); + } + $name = $this->name; + $uri = "/_template/$name"; + + if (isset($name) === true) { + $uri = "/_template/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'timeout', + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Exists.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Exists.php new file mode 100644 index 00000000..ca741da8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Exists.php @@ -0,0 +1,85 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Exists extends AbstractEndpoint +{ + // The name of the template + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->name) !== true) { + throw new Exceptions\RuntimeException( + 'name is required for Exists' + ); + } + $name = $this->name; + $uri = "/_template/$name"; + + if (isset($name) === true) { + $uri = "/_template/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'HEAD'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Get.php new file mode 100644 index 00000000..09008050 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Get.php @@ -0,0 +1,81 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // The name of the template + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + $name = $this->name; + $uri = "/_template"; + + if (isset($name) === true) { + $uri = "/_template/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'flat_settings', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Put.php new file mode 100644 index 00000000..46ce54e4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Template/Put.php @@ -0,0 +1,121 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + // The name of the template + private $name; + + + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->name) !== true) { + throw new Exceptions\RuntimeException( + 'name is required for Put' + ); + } + $name = $this->name; + $uri = "/_template/$name"; + + if (isset($name) === true) { + $uri = "/_template/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'order', + 'timeout', + 'master_timeout', + 'flat_settings', + 'create' + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Put Template'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Type/Exists.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Type/Exists.php new file mode 100644 index 00000000..bce4bbbb --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Type/Exists.php @@ -0,0 +1,74 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Exists extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Exists' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Exists' + ); + } + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'HEAD'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Validate/Query.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Validate/Query.php new file mode 100644 index 00000000..45ba4be5 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Validate/Query.php @@ -0,0 +1,66 @@ +body = $body; + return $this; + } + + /** + * @return string + */ + protected function getURI() + { + return $this->getOptionalURI('_validate/query'); + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'explain', + 'ignore_indices', + 'operation_threading', + 'source', + 'q' + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/ValidateQuery.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/ValidateQuery.php new file mode 100644 index 00000000..cbf877db --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/ValidateQuery.php @@ -0,0 +1,87 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class ValidateQuery extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_validate/query"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_validate/query"; + } elseif (isset($index) === true) { + $uri = "/$index/_validate/query"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'explain', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'operation_threading', + 'source', + 'q', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/AbstractWarmerEndpoint.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/AbstractWarmerEndpoint.php new file mode 100644 index 00000000..219d7527 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/AbstractWarmerEndpoint.php @@ -0,0 +1,53 @@ +name = $name; + return $this; + } + + + /** + * @return string + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getWarmerURI() + { + if (isset($this->index) !== true) { + throw new RuntimeException( + 'index is required for Delete' + ); + } + + $uri = $this->getOptionalURI('_warmer'); + + $name = $this->name; + if (isset($name) === true) { + $uri .= "/$name"; + } + + return $uri; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Delete.php new file mode 100644 index 00000000..08232378 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Delete.php @@ -0,0 +1,92 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + // A comma-separated list of warmer names to delete (supports wildcards); use `_all` to delete all warmers in the specified indices. You must specify a name either in the uri or in the parameters. + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Delete' + ); + } + if (isset($this->name) !== true) { + throw new Exceptions\RuntimeException( + 'name is required for Delete' + ); + } + $index = $this->index; + $name = $this->name; + $uri = "/$index/_warmer/$name"; + + if (isset($index) === true && isset($name) === true) { + $uri = "/$index/_warmer/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'name', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Get.php new file mode 100644 index 00000000..5c7055aa --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Get.php @@ -0,0 +1,93 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // The name of the warmer (supports wildcards); leave empty to get all warmers + private $name; + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + $index = $this->index; + $name = $this->name; + $type = $this->type; + $uri = "/_warmer"; + + if (isset($index) === true && isset($type) === true && isset($name) === true) { + $uri = "/$index/$type/_warmer/$name"; + } elseif (isset($index) === true && isset($name) === true) { + $uri = "/$index/_warmer/$name"; + } elseif (isset($index) === true && isset($type) === true) { + throw new Exceptions\RuntimeException('Invalid index/type/name combination. If index + type are defined, name must also be defined'); + } elseif (isset($index) === true) { + $uri = "/$index/_warmer"; + } elseif (isset($name) === true) { + $uri = "/_warmer/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Put.php new file mode 100644 index 00000000..d1b51a7a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Indices/Warmer/Put.php @@ -0,0 +1,126 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + // The name of the warmer + private $name; + + + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + if (isset($name) !== true) { + return $this; + } + + $this->name = $name; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->name) !== true) { + throw new Exceptions\RuntimeException( + 'name is required for Put' + ); + } + $index = $this->index; + $name = $this->name; + $type = $this->type; + $uri = "/_warmer/$name"; + + if (isset($index) === true && isset($type) === true && isset($name) === true) { + $uri = "/$index/$type/_warmer/$name"; + } elseif (isset($index) === true && isset($name) === true) { + $uri = "/$index/_warmer/$name"; + } elseif (isset($name) === true) { + $uri = "/_warmer/$name"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Put Warmer'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Info.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Info.php new file mode 100644 index 00000000..e0855416 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Info.php @@ -0,0 +1,54 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Info extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/MPercolate.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/MPercolate.php new file mode 100644 index 00000000..19aa9e2f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/MPercolate.php @@ -0,0 +1,84 @@ +serializer = $serializer; + parent::__construct($transport); + } + + + /** + * @param string|array $body + * + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + if (is_array($body) === true) { + $bulkBody = ""; + foreach ($body as $item) { + $bulkBody .= $this->serializer->serialize($item)."\n"; + } + $body = $bulkBody; + } + + $this->body = $body; + return $this; + } + + /** + * @return string + */ + protected function getURI() + { + return $this->getOptionalURI('_mpercolate'); + + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/MTermVectors.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/MTermVectors.php new file mode 100644 index 00000000..53503ab8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/MTermVectors.php @@ -0,0 +1,71 @@ +body = $body; + return $this; + } + + /** + * @return string + */ + protected function getURI() + { + return $this->getOptionalURI('_mtermvectors'); + + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ids', + 'term_statistics', + 'field_statistics', + 'fields', + 'offsets', + 'positions', + 'payloads', + 'preference', + 'routing', + 'parent' + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Mget.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Mget.php new file mode 100644 index 00000000..c75e5ffc --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Mget.php @@ -0,0 +1,102 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Mget extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_mget"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_mget"; + } elseif (isset($index) === true) { + $uri = "/$index/_mget"; + } elseif (isset($type) === true) { + $uri = "/_all/$type/_mget"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'fields', + 'preference', + 'realtime', + 'refresh', + '_source', + '_source_exclude', + '_source_include', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for MGet'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Mlt.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Mlt.php new file mode 100644 index 00000000..3e3c392d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Mlt.php @@ -0,0 +1,114 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Mlt extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Mlt' + ); + } + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Mlt' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Mlt' + ); + } + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/$id/_mlt"; + + if (isset($index) === true && isset($type) === true && isset($id) === true) { + $uri = "/$index/$type/$id/_mlt"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'boost_terms', + 'max_doc_freq', + 'max_query_terms', + 'max_word_length', + 'min_doc_freq', + 'min_term_freq', + 'min_word_length', + 'mlt_fields', + 'percent_terms_to_match', + 'routing', + 'search_from', + 'search_indices', + 'search_query_hint', + 'search_scroll', + 'search_size', + 'search_source', + 'search_type', + 'search_types', + 'stop_words', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Msearch.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Msearch.php new file mode 100644 index 00000000..b7dd7f42 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Msearch.php @@ -0,0 +1,117 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Msearch extends AbstractEndpoint +{ + + /** + * @param Transport $transport + * @param SerializerInterface $serializer + */ + public function __construct(Transport $transport, SerializerInterface $serializer) + { + $this->serializer = $serializer; + parent::__construct($transport); + } + + + /** + * @param array|string $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + if (is_array($body) === true) { + $bulkBody = ""; + foreach ($body as $item) { + $bulkBody .= $this->serializer->serialize($item)."\n"; + } + $body = $bulkBody; + } + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_msearch"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_msearch"; + } elseif (isset($index) === true) { + $uri = "/$index/_msearch"; + } elseif (isset($type) === true) { + $uri = "/_all/$type/_msearch"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'search_type', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for MSearch'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Percolate.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Percolate.php new file mode 100644 index 00000000..c9141452 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Percolate.php @@ -0,0 +1,109 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Percolate extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Percolate' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Percolate' + ); + } + $index = $this->index; + $type = $this->type; + $id = $this->id; + $uri = "/$index/$type/_percolate"; + + if (isset($id) === true) { + $uri = "/$index/$type/$id/_percolate"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'routing', + 'preference', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'percolate_index', + 'percolate_type', + 'version', + 'version_type', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Ping.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Ping.php new file mode 100644 index 00000000..dcd206e4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Ping.php @@ -0,0 +1,54 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Ping extends AbstractEndpoint +{ + /** + * @return string + */ + protected function getURI() + { + $uri = "/"; + + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'HEAD'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Delete.php new file mode 100644 index 00000000..a18d112d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Delete.php @@ -0,0 +1,85 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + /** @var String */ + private $lang; + + + /** + * @param $lang + * + * @return $this + */ + public function setLang($lang) + { + if (isset($lang) !== true) { + return $this; + } + + $this->lang = $lang; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->lang) !== true) { + throw new Exceptions\RuntimeException( + 'lang is required for Put' + ); + } + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for put' + ); + } + $id = $this->id; + $lang = $this->lang; + $uri = "/_scripts/$lang/$id"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array(); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Get.php new file mode 100644 index 00000000..989bf845 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Get.php @@ -0,0 +1,85 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + /** @var String */ + private $lang; + + + /** + * @param $lang + * + * @return $this + */ + public function setLang($lang) + { + if (isset($lang) !== true) { + return $this; + } + + $this->lang = $lang; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->lang) !== true) { + throw new Exceptions\RuntimeException( + 'lang is required for Put' + ); + } + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for put' + ); + } + $id = $this->id; + $lang = $this->lang; + $uri = "/_scripts/$lang/$id"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array(); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Put.php new file mode 100644 index 00000000..5d77bc9f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Script/Put.php @@ -0,0 +1,100 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + /** @var String */ + private $lang; + + /** + * @param $lang + * + * @return $this + */ + public function setLang($lang) + { + if (isset($lang) !== true) { + return $this; + } + + $this->lang = $lang; + return $this; + } + + + /** + * @param array $body + * + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + $this->body = $body; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->lang) !== true) { + throw new Exceptions\RuntimeException( + 'lang is required for Put' + ); + } + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for put' + ); + } + $id = $this->id; + $lang = $this->lang; + $uri = "/_scripts/$lang/$id"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array(); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Scroll.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Scroll.php new file mode 100644 index 00000000..6ae4c9e9 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Scroll.php @@ -0,0 +1,111 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Scroll extends AbstractEndpoint +{ + // The scroll ID + private $scroll_id; + + private $clear = false; + + + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + public function setClearScroll($clear) + { + $this->clear = $clear; + return $this; + } + + + /** + * @param $scroll_id + * + * @return $this + */ + public function setScrollId($scroll_id) + { + if (isset($scroll_id) !== true) { + return $this; + } + + $this->scroll_id = $scroll_id; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $scroll_id = $this->scroll_id; + $uri = "/_search/scroll"; + + if (isset($scroll_id) === true) { + $uri = "/_search/scroll/$scroll_id"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'scroll', + 'scroll_id', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + if ($this->clear == true) { + return 'DELETE'; + } + + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Search.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Search.php new file mode 100644 index 00000000..229422d6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Search.php @@ -0,0 +1,113 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Search extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_search"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_search"; + } elseif (isset($index) === true) { + $uri = "/$index/_search"; + } elseif (isset($type) === true) { + $uri = "/_all/$type/_search"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'analyzer', + 'analyze_wildcard', + 'default_operator', + 'df', + 'explain', + 'fields', + 'from', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'indices_boost', + 'lenient', + 'lowercase_expanded_terms', + 'preference', + 'q', + 'routing', + 'scroll', + 'search_type', + 'size', + 'sort', + 'source', + '_source', + '_source_exclude', + '_source_include', + 'stats', + 'suggest_field', + 'suggest_mode', + 'suggest_size', + 'suggest_text', + 'timeout', + 'version', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/SearchShards.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/SearchShards.php new file mode 100644 index 00000000..96d85964 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/SearchShards.php @@ -0,0 +1,72 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class SearchShards extends AbstractEndpoint +{ + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_search_shards"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_search_shards"; + } elseif (isset($index) === true) { + $uri = "/$index/_search_shards"; + } elseif (isset($type) === true) { + $uri = "/_all/$type/_search_shards"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'preference', + 'routing', + 'local', + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards' + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/SearchTemplate.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/SearchTemplate.php new file mode 100644 index 00000000..171f6f9d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/SearchTemplate.php @@ -0,0 +1,81 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class SearchTemplate extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $type = $this->type; + $uri = "/_search/template"; + + if (isset($index) === true && isset($type) === true) { + $uri = "/$index/$type/_search/template"; + } elseif (isset($index) === true) { + $uri = "/$index/_search/template"; + } elseif (isset($type) === true) { + $uri = "/_all/$type/_search/template"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array(); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Create.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Create.php new file mode 100644 index 00000000..12ba7544 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Create.php @@ -0,0 +1,131 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Create extends AbstractEndpoint +{ + // A repository name + private $repository; + + + // A snapshot name + private $snapshot; + + + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @param $snapshot + * + * @return $this + */ + public function setSnapshot($snapshot) + { + if (isset($snapshot) !== true) { + return $this; + } + + $this->snapshot = $snapshot; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->repository) !== true) { + throw new Exceptions\RuntimeException( + 'repository is required for Create' + ); + } + if (isset($this->snapshot) !== true) { + throw new Exceptions\RuntimeException( + 'snapshot is required for Create' + ); + } + $repository = $this->repository; + $snapshot = $this->snapshot; + $uri = "/_snapshot/$repository/$snapshot"; + + if (isset($repository) === true && isset($snapshot) === true) { + $uri = "/_snapshot/$repository/$snapshot"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'wait_for_completion', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Delete.php new file mode 100644 index 00000000..05d119b3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Delete.php @@ -0,0 +1,111 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + // A repository name + private $repository; + + + // A snapshot name + private $snapshot; + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @param $snapshot + * + * @return $this + */ + public function setSnapshot($snapshot) + { + if (isset($snapshot) !== true) { + return $this; + } + + $this->snapshot = $snapshot; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->repository) !== true) { + throw new Exceptions\RuntimeException( + 'repository is required for Delete' + ); + } + if (isset($this->snapshot) !== true) { + throw new Exceptions\RuntimeException( + 'snapshot is required for Delete' + ); + } + $repository = $this->repository; + $snapshot = $this->snapshot; + $uri = "/_snapshot/$repository/$snapshot"; + + if (isset($repository) === true && isset($snapshot) === true) { + $uri = "/_snapshot/$repository/$snapshot"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Get.php new file mode 100644 index 00000000..403ad479 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Get.php @@ -0,0 +1,111 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // A comma-separated list of repository names + private $repository; + + + // A comma-separated list of snapshot names + private $snapshot; + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @param $snapshot + * + * @return $this + */ + public function setSnapshot($snapshot) + { + if (isset($snapshot) !== true) { + return $this; + } + + $this->snapshot = $snapshot; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->repository) !== true) { + throw new Exceptions\RuntimeException( + 'repository is required for Get' + ); + } + if (isset($this->snapshot) !== true) { + throw new Exceptions\RuntimeException( + 'snapshot is required for Get' + ); + } + $repository = $this->repository; + $snapshot = $this->snapshot; + $uri = "/_snapshot/$repository/$snapshot"; + + if (isset($repository) === true && isset($snapshot) === true) { + $uri = "/_snapshot/$repository/$snapshot"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Create.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Create.php new file mode 100644 index 00000000..09e6377b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Create.php @@ -0,0 +1,118 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Create extends AbstractEndpoint +{ + // A repository name + private $repository; + + + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->repository) !== true) { + throw new Exceptions\RuntimeException( + 'repository is required for Create' + ); + } + $repository = $this->repository; + $uri = "/_snapshot/$repository"; + + if (isset($repository) === true) { + $uri = "/_snapshot/$repository"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'timeout', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Create Repository'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Delete.php new file mode 100644 index 00000000..d0efdc0c --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Delete.php @@ -0,0 +1,86 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + // A comma-separated list of repository names + private $repository; + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->repository) !== true) { + throw new Exceptions\RuntimeException( + 'repository is required for Delete' + ); + } + $repository = $this->repository; + $uri = "/_snapshot/$repository"; + + if (isset($repository) === true) { + $uri = "/_snapshot/$repository"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Get.php new file mode 100644 index 00000000..02b0647a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Repository/Get.php @@ -0,0 +1,80 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + // A comma-separated list of repository names + private $repository; + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @return string + */ + protected function getURI() + { + $repository = $this->repository; + $uri = "/_snapshot"; + + if (isset($repository) === true) { + $uri = "/_snapshot/$repository"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'local', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Restore.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Restore.php new file mode 100644 index 00000000..c72a33b7 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Restore.php @@ -0,0 +1,131 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Restore extends AbstractEndpoint +{ + // A repository name + private $repository; + + + // A snapshot name + private $snapshot; + + + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @param $snapshot + * + * @return $this + */ + public function setSnapshot($snapshot) + { + if (isset($snapshot) !== true) { + return $this; + } + + $this->snapshot = $snapshot; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->repository) !== true) { + throw new Exceptions\RuntimeException( + 'repository is required for Restore' + ); + } + if (isset($this->snapshot) !== true) { + throw new Exceptions\RuntimeException( + 'snapshot is required for Restore' + ); + } + $repository = $this->repository; + $snapshot = $this->snapshot; + $uri = "/_snapshot/$repository/$snapshot/_restore"; + + if (isset($repository) === true && isset($snapshot) === true) { + $uri = "/_snapshot/$repository/$snapshot/_restore"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + 'wait_for_completion', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Status.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Status.php new file mode 100644 index 00000000..feab5d81 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Snapshot/Status.php @@ -0,0 +1,108 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Status extends AbstractEndpoint +{ + // A comma-separated list of repository names + private $repository; + + // A comma-separated list of snapshot names + private $snapshot; + + + /** + * @param $repository + * + * @return $this + */ + public function setRepository($repository) + { + if (isset($repository) !== true) { + return $this; + } + + $this->repository = $repository; + return $this; + } + + + /** + * @param $snapshot + * + * @return $this + */ + public function setSnapshot($snapshot) + { + if (isset($snapshot) !== true) { + return $this; + } + + $this->snapshot = $snapshot; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->snapshot) === true && isset($this->repository) !== true) { + throw new Exceptions\RuntimeException( + 'Repository param must be provided if snapshot param is set' + ); + } + + $repository = $this->repository; + $snapshot = $this->snapshot; + $uri = "/_snapshot/_status"; + + if (isset($repository) === true) { + $uri = "/_snapshot/$repository/_status"; + } elseif (isset($repository) === true && isset($snapshot) === true) { + $uri = "/_snapshot/$repository/$snapshot/_status"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'master_timeout', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Source/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Source/Get.php new file mode 100644 index 00000000..6b8bb258 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Source/Get.php @@ -0,0 +1,86 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Get' + ); + } + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Get' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Get' + ); + } + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/$id/_source"; + + if (isset($index) === true && isset($type) === true && isset($id) === true) { + $uri = "/$index/$type/$id/_source"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'parent', + 'preference', + 'realtime', + 'refresh', + 'routing', + '_source', + '_source_exclude', + '_source_include', + 'version', + 'version_type', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Suggest.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Suggest.php new file mode 100644 index 00000000..9f2af6a8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Suggest.php @@ -0,0 +1,96 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Suggest extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @return string + */ + protected function getURI() + { + $index = $this->index; + $uri = "/_suggest"; + + if (isset($index) === true) { + $uri = "/$index/_suggest"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'ignore_unavailable', + 'allow_no_indices', + 'expand_wildcards', + 'preference', + 'routing', + 'source', + ); + } + + + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Suggest'); + } + return $this->body; + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Delete.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Delete.php new file mode 100644 index 00000000..a384505a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Delete.php @@ -0,0 +1,60 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Delete extends AbstractEndpoint +{ + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Delete' + ); + } + $templateId = $this->id; + $uri = "/_search/template/$templateId"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array(); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'DELETE'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Get.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Get.php new file mode 100644 index 00000000..dfea2081 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Get.php @@ -0,0 +1,60 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Get extends AbstractEndpoint +{ + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Get' + ); + } + $templateId = $this->id; + $uri = "/_search/template/$templateId"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array(); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'GET'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Put.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Put.php new file mode 100644 index 00000000..eb205b13 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Template/Put.php @@ -0,0 +1,77 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Put extends AbstractEndpoint +{ + + /** + * @param array $body + * + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + $this->body = $body; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Put' + ); + } + + $templateId = $this->id; + $uri = "/_search/template/$templateId"; + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array(); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'PUT'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/TermVector.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/TermVector.php new file mode 100644 index 00000000..6a55ad83 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/TermVector.php @@ -0,0 +1,93 @@ +body = $body; + return $this; + } + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for TermVector' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for TermVector' + ); + } + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for TermVector' + ); + } + + $index = $this->index; + $type = $this->type; + $id = $this->id; + $uri = "/$index/$type/$id/_termvector"; + + return $uri; + + } + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'term_statistics', + 'field_statistics', + 'fields', + 'offsets', + 'positions', + 'payloads', + 'preference', + 'routing', + 'parent' + ); + } + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Update.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Update.php new file mode 100644 index 00000000..4adbe279 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/Update.php @@ -0,0 +1,109 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class Update extends AbstractEndpoint +{ + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + + $this->body = $body; + return $this; + } + + + + /** + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + * @return string + */ + protected function getURI() + { + if (isset($this->id) !== true) { + throw new Exceptions\RuntimeException( + 'id is required for Update' + ); + } + if (isset($this->index) !== true) { + throw new Exceptions\RuntimeException( + 'index is required for Update' + ); + } + if (isset($this->type) !== true) { + throw new Exceptions\RuntimeException( + 'type is required for Update' + ); + } + $id = $this->id; + $index = $this->index; + $type = $this->type; + $uri = "/$index/$type/$id/_update"; + + if (isset($index) === true && isset($type) === true && isset($id) === true) { + $uri = "/$index/$type/$id/_update"; + } + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( + 'consistency', + 'fields', + 'lang', + 'parent', + 'refresh', + 'replication', + 'retry_on_conflict', + 'routing', + 'script', + 'timeout', + 'timestamp', + 'ttl', + 'version', + 'version_type', + ); + } + + + /** + * @return string + */ + protected function getMethod() + { + return 'POST'; + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/AbstractNamespace.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/AbstractNamespace.php new file mode 100644 index 00000000..e8526381 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/AbstractNamespace.php @@ -0,0 +1,65 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +abstract class AbstractNamespace +{ + /** @var \Elasticsearch\Transport */ + protected $transport; + + /** @var callback */ + protected $dicEndpoints; + + + /** + * Abstract constructor + * + * @param Transport $transport Transport object + * @param $dicEndpoints + */ + public function __construct($transport, $dicEndpoints) + { + $this->transport = $transport; + $this->dicEndpoints = $dicEndpoints; + } + + + /** + * @param array $params + * @param string $arg + * + * @return null|mixed + */ + public function extractArgument(&$params, $arg) + { + if (is_object($params) === true) { + $params = (array)$params; + } + + if (isset($params[$arg]) === true) { + $val = $params[$arg]; + unset($params[$arg]); + return $val; + } else { + return null; + } + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/CatNamespace.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/CatNamespace.php new file mode 100644 index 00000000..29f9a9b3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/CatNamespace.php @@ -0,0 +1,349 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class CatNamespace extends AbstractNamespace +{ + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function aliases($params = array()) + { + $name = $this->extractArgument($params, 'name'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Aliases $endpoint */ + $endpoint = $endpointBuilder('Cat\Aliases'); + $endpoint->setName($name); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * ['bytes'] = (enum) The unit in which to display byte values + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function allocation($params = array()) + { + $nodeID = $this->extractArgument($params, 'node_id'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Allocation $endpoint */ + $endpoint = $endpointBuilder('Cat\Allocation'); + $endpoint->setNodeID($nodeID); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function count($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Count $endpoint */ + $endpoint = $endpointBuilder('Cat\Count'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * ['ts'] = (bool) Set to false to disable timestamping + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function health($params = array()) + { + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Health $endpoint */ + $endpoint = $endpointBuilder('Cat\Health'); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['help'] = (bool) Return help information + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function help($params = array()) + { + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Help $endpoint */ + $endpoint = $endpointBuilder('Cat\Help'); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * ['bytes'] = (enum) The unit in which to display byte values + * ['pri'] = (bool) Set to true to return stats only for primary shards + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function indices($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Indices $endpoint */ + $endpoint = $endpointBuilder('Cat\Indices'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function master($params = array()) + { + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Master $endpoint */ + $endpoint = $endpointBuilder('Cat\Master'); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function nodes($params = array()) + { + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Nodes $endpoint */ + $endpoint = $endpointBuilder('Cat\Nodes'); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function pendingTasks($params = array()) + { + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\PendingTasks $endpoint */ + $endpoint = $endpointBuilder('Cat\PendingTasks'); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * ['bytes'] = (enum) The unit in which to display byte values + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function recovery($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Recovery $endpoint */ + $endpoint = $endpointBuilder('Cat\Recovery'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function shards($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Shards $endpoint */ + $endpoint = $endpointBuilder('Cat\Shards'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * ['full_id'] = (bool) Enables displaying the complete node ids + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function threadPool($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\ThreadPool $endpoint */ + $endpoint = $endpointBuilder('Cat\ThreadPool'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['h'] = (list) Comma-separated list of column names to display + * ['help'] = (bool) Return help information + * ['v'] = (bool) Verbose mode. Display column headers + * ['bytes'] = (enum) The unit in which to display byte values + * ['fields'] = (list) A comma-separated list of fields to return the fielddata size + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function fielddata($params = array()) + { + $fields = $this->extractArgument($params, 'fields'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cat\Fielddata $endpoint */ + $endpoint = $endpointBuilder('Cat\Fielddata'); + $endpoint->setFields($fields); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/ClusterNamespace.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/ClusterNamespace.php new file mode 100644 index 00000000..ea80bdc0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/ClusterNamespace.php @@ -0,0 +1,201 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class ClusterNamespace extends AbstractNamespace +{ + + /** + * $params['index'] = (string) Limit the information returned to a specific index + * ['level'] = (enum) Specify the level of detail for returned information + * ['local'] = (boolean) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['timeout'] = (time) Explicit operation timeout + * ['wait_for_active_shards'] = (number) Wait until the specified number of shards is active + * ['wait_for_nodes'] = (number) Wait until the specified number of nodes is available + * ['wait_for_relocating_shards'] = (number) Wait until the specified number of relocating shards is finished + * ['wait_for_status'] = (enum) Wait until cluster is in a specific state + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function health($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Health $endpoint */ + $endpoint = $endpointBuilder('Cluster\Health'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['dry_run'] = (boolean) Simulate the operation only and return the resulting state + * ['filter_metadata'] = (boolean) Don't return cluster state metadata (default: false) + * ['body'] = (boolean) Don't return cluster state metadata (default: false) + * ['explain'] = (boolean) Return an explanation of why the commands can or cannot be executed + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function reroute($params = array()) + { + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Reroute $endpoint */ + $endpoint = $endpointBuilder('Cluster\Reroute'); + $endpoint->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['filter_blocks'] = (boolean) Do not return information about blocks + * ['filter_index_templates'] = (boolean) Do not return information about index templates + * ['filter_indices'] = (list) Limit returned metadata information to specific indices + * ['filter_metadata'] = (boolean) Do not return information about indices metadata + * ['filter_nodes'] = (boolean) Do not return information about nodes + * ['filter_routing_table'] = (boolean) Do not return information about shard allocation (`routing_table` and `routing_nodes`) + * ['local'] = (boolean) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Specify timeout for connection to master + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function state($params = array()) + { + $index = $this->extractArgument($params, 'index'); + $metric = $this->extractArgument($params, 'metric'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\State $endpoint */ + $endpoint = $endpointBuilder('Cluster\State'); + $endpoint->setParams($params) + ->setIndex($index) + ->setMetric($metric); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['flat_settings'] = (boolean) Return settings in flat format (default: false) + * ['human'] = (boolean) Whether to return time and byte values in human-readable format. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function stats($params = array()) + { + $nodeID = $this->extractArgument($params, 'node_id'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Stats $endpoint */ + $endpoint = $endpointBuilder('Cluster\Stats'); + $endpoint->setNodeID($nodeID) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['body'] = () + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putSettings($params = array()) + { + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Settings\Put $endpoint */ + $endpoint = $endpointBuilder('Cluster\Settings\Put'); + $endpoint->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * @param array $params + * + * @return array + */ + public function getSettings($params = array()) + { + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Settings\Put $endpoint */ + $endpoint = $endpointBuilder('Cluster\Settings\Get'); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['master_timeout'] = (time) Specify timeout for connection to master + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function pendingTasks($params = array()) + { + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\PendingTasks $endpoint */ + $endpoint = $endpointBuilder('Cluster\PendingTasks'); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/IndicesNamespace.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/IndicesNamespace.php new file mode 100644 index 00000000..596514d4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/IndicesNamespace.php @@ -0,0 +1,1200 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class IndicesNamespace extends AbstractNamespace +{ + /** + * $params['index'] = (list) A comma-separated list of indices to check (Required) + * + * @param $params array Associative array of parameters + * + * @return bool + */ + public function exists($params) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Exists $endpoint */ + $endpoint = $endpointBuilder('Indices\Exists'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + + try { + $response = $endpoint->performRequest(); + } catch (Missing404Exception $exception) { + return false; + } + + + if ($response['status'] === 200) { + return true; + } else { + return false; + } + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * ['operation_threading'] = () TODO: ? + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function segments($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Segments $endpoint */ + $endpoint = $endpointBuilder('Indices\Segments'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['name'] = (string) The name of the template (Required) + * ['timeout'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function deleteTemplate($params) + { + $name = $this->extractArgument($params, 'name'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Template\Delete $endpoint */ + $endpoint = $endpointBuilder('Indices\Template\Delete'); + $endpoint->setName($name); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to register warmer for; use `_all` or empty string to perform the operation on all indices (Required) + * ['name'] = (string) The name of the warmer (supports wildcards); leave empty to delete all warmers + * ['type'] = (list) A comma-separated list of document types to register warmer for; use `_all` or empty string to perform the operation on all types + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function deleteWarmer($params) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Warmer\Delete $endpoint */ + $endpoint = $endpointBuilder('Indices\Warmer\Delete'); + $endpoint->setIndex($index) + ->setName($name) + ->setType($type); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of indices to delete; use `_all` or empty string to delete all indices + * ['timeout'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function delete($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Delete $endpoint */ + $endpoint = $endpointBuilder('Indices\Delete'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['fields'] = (boolean) A comma-separated list of fields for `fielddata` metric (supports wildcards) + * ['index'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * ['indexing_types'] = (list) A comma-separated list of document types to include in the `indexing` statistics + * ['metric_family'] = (enum) Limit the information returned to a specific metric + * ['search_groups'] = (list) A comma-separated list of search groups to include in the `search` statistics + * ['all'] = (boolean) Return all available information + * ['clear'] = (boolean) Reset the default level of detail + * ['docs'] = (boolean) Return information about indexed and deleted documents + * ['fielddata'] = (boolean) Return information about field data + * ['filter_cache'] = (boolean) Return information about filter cache + * ['flush'] = (boolean) Return information about flush operations + * ['get'] = (boolean) Return information about get operations + * ['groups'] = (boolean) A comma-separated list of search groups for `search` statistics + * ['id_cache'] = (boolean) Return information about ID cache + * ['ignore_indices'] = (enum) When performed on multiple indices, allows to ignore `missing` ones + * ['indexing'] = (boolean) Return information about indexing operations + * ['merge'] = (boolean) Return information about merge operations + * ['refresh'] = (boolean) Return information about refresh operations + * ['search'] = (boolean) Return information about search operations; use the `groups` parameter to include information for specific search groups + * ['store'] = (boolean) Return information about the size of the index + * ['warmer'] = (boolean) Return information about warmers + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function stats($params = array()) + { + $metric = $this->extractArgument($params, '$metric'); + + $index = $this->extractArgument($params, 'index'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Stats $endpoint */ + $endpoint = $endpointBuilder('Indices\Stats'); + $endpoint->setIndex($index) + ->setMetric($metric); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * ['body'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putSettings($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Settings\Put $endpoint */ + $endpoint = $endpointBuilder('Indices\Settings\Put'); + $endpoint->setIndex($index) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string for all indices + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function snapshotIndex($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Gateway\Snapshot $endpoint */ + $endpoint = $endpointBuilder('Indices\Gateway\Snapshot'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string for all indices + * ['type'] = (list) A comma-separated list of document types + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getMapping($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Mapping\Get $endpoint */ + $endpoint = $endpointBuilder('Indices\Mapping\Get'); + $endpoint->setIndex($index) + ->setType($type); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string for all indices + * ['type'] = (list) A comma-separated list of document types + * ['field'] = (list) A comma-separated list of document fields + * ['include_defaults'] = (bool) specifies default mapping values should be returned + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getFieldMapping($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + $type = $this->extractArgument($params, 'type'); + + $field = $this->extractArgument($params, 'field'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Mapping\GetField $endpoint */ + $endpoint = $endpointBuilder('Indices\Mapping\GetField'); + $endpoint->setIndex($index) + ->setType($type) + ->setField($field); + + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string for all indices + * ['force'] = (boolean) TODO: ? + * ['full'] = (boolean) TODO: ? + * ['refresh'] = (boolean) Refresh the index after performing the operation + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function flush($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Flush $endpoint */ + $endpoint = $endpointBuilder('Indices\Flush'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * ['operation_threading'] = () TODO: ? + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function refresh($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Refresh $endpoint */ + $endpoint = $endpointBuilder('Indices\Refresh'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string for all indices + * ['detailed'] = (bool) Whether to display detailed information about shard recovery + * ['active_only'] = (bool) Display only those recoveries that are currently on-going + * ['human'] = (bool) Whether to return time and byte values in human-readable format. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function recovery($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Flush $endpoint */ + $endpoint = $endpointBuilder('Indices\Recovery'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` to check the types across all indices (Required) + * ['type'] = (list) A comma-separated list of document types to check (Required) + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function existsType($params) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Type\Exists $endpoint */ + $endpoint = $endpointBuilder('Indices\Type\Exists'); + $endpoint->setIndex($index) + ->setType($type); + $endpoint->setParams($params); + + try { + $response = $endpoint->performRequest(); + } catch (Missing404Exception $exception) { + return false; + } + + + if ($response['status'] === 200) { + return true; + } else { + return false; + } + } + + + /** + * $params['index'] = (string) The name of the index with an alias + * ['name'] = (string) The name of the alias to be created or updated + * ['timeout'] = (time) Explicit timestamp for the document + * ['body'] = (time) Explicit timestamp for the document + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putAlias($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Alias\Put $endpoint */ + $endpoint = $endpointBuilder('Indices\Alias\Put'); + $endpoint->setIndex($index) + ->setName($name) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices (Required) + * ['name'] = (string) The name of the warmer (supports wildcards); leave empty to get all warmers + * ['type'] = (list) A comma-separated list of document types to restrict the operation; leave empty to perform the operation on all types + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getWarmer($params) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Warmer\Get $endpoint */ + $endpoint = $endpointBuilder('Indices\Warmer\Get'); + $endpoint->setIndex($index) + ->setName($name) + ->setType($type); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to register the warmer for; use `_all` or empty string to perform the operation on all indices (Required) + * ['name'] = (string) The name of the warmer (Required) + * ['type'] = (list) A comma-separated list of document types to register the warmer for; leave empty to perform the operation on all types + * ['body'] = (list) A comma-separated list of document types to register the warmer for; leave empty to perform the operation on all types + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putWarmer($params) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Warmer\Put $endpoint */ + $endpoint = $endpointBuilder('Indices\Warmer\Put'); + $endpoint->setIndex($index) + ->setName($name) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['name'] = (string) The name of the template (Required) + * ['order'] = (number) The order for this template when merging multiple matching ones (higher numbers are merged later, overriding the lower numbers) + * ['timeout'] = (time) Explicit operation timeout + * ['body'] = (time) Explicit operation timeout + * ['create'] = (bool) Whether the index template should only be added if new or can also replace an existing one + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putTemplate($params) + { + $name = $this->extractArgument($params, 'name'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Template\Put $endpoint */ + $endpoint = $endpointBuilder('Indices\Template\Put'); + $endpoint->setName($name) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices + * ['type'] = (list) A comma-separated list of document types to restrict the operation; leave empty to perform the operation on all types + * ['explain'] = (boolean) Return detailed information about the error + * ['ignore_indices'] = (enum) When performed on multiple indices, allows to ignore `missing` ones + * ['operation_threading'] = () TODO: ? + * ['source'] = (string) The URL-encoded query definition (instead of using the request body) + * ['body'] = (string) The URL-encoded query definition (instead of using the request body) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function validateQuery($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Validate\Query $endpoint */ + $endpoint = $endpointBuilder('Indices\Validate\Query'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['name'] = (list) A comma-separated list of alias names to return (Required) + * ['index'] = (list) A comma-separated list of index names to filter aliases + * ['ignore_indices'] = (enum) When performed on multiple indices, allows to ignore `missing` ones + * ['name'] = (list) A comma-separated list of alias names to return + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getAlias($params) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Alias\Get $endpoint */ + $endpoint = $endpointBuilder('Indices\Alias\Get'); + $endpoint->setIndex($index) + ->setName($name); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` to perform the operation on all indices (Required) + * ['type'] = (string) The name of the document type + * ['ignore_conflicts'] = (boolean) Specify whether to ignore conflicts while updating the mapping (default: false) + * ['timeout'] = (time) Explicit operation timeout + * ['body'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function putMapping($params) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + $body = $this->extractArgument($params, 'body'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Mapping\Put $endpoint */ + $endpoint = $endpointBuilder('Indices\Mapping\Put'); + $endpoint->setIndex($index) + ->setType($type) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` for all indices (Required) + * ['type'] = (string) The name of the document type to delete (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function deleteMapping($params) + { + $index = $this->extractArgument($params, 'index'); + + + $type = $this->extractArgument($params, 'type'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Mapping\Delete $endpoint */ + $endpoint = $endpointBuilder('Indices\Mapping\Delete'); + $endpoint->setIndex($index) + ->setType($type); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['name'] = (string) The name of the template (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getTemplate($params) + { + $name = $this->extractArgument($params, 'name'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Template\Get $endpoint */ + $endpoint = $endpointBuilder('Indices\Template\Get'); + $endpoint->setName($name); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['name'] = (string) The name of the template (Required) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function existsTemplate($params) + { + $name = $this->extractArgument($params, 'name'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Template\Exists $endpoint */ + $endpoint = $endpointBuilder('Indices\Template\Exists'); + $endpoint->setName($name); + $endpoint->setParams($params); + + try { + $response = $endpoint->performRequest(); + } catch (Missing404Exception $exception) { + return false; + } + + + if ($response['status'] === 200) { + return true; + } else { + return false; + } + } + + + /** + * $params['index'] = (string) The name of the index (Required) + * ['timeout'] = (time) Explicit operation timeout + * ['body'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function create($params) + { + $index = $this->extractArgument($params, 'index'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Create $endpoint */ + $endpoint = $endpointBuilder('Indices\Create'); + $endpoint->setIndex($index) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * ['flush'] = (boolean) Specify whether the index should be flushed after performing the operation (default: true) + * ['max_num_segments'] = (number) The number of segments the index should be merged into (default: dynamic) + * ['only_expunge_deletes'] = (boolean) Specify whether the operation should only expunge deleted documents + * ['operation_threading'] = () TODO: ? + * ['refresh'] = (boolean) Specify whether the index should be refreshed after performing the operation (default: true) + * ['wait_for_merge'] = (boolean) Specify whether the request should block until the merge process is finished (default: true) + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function optimize($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Optimize $endpoint */ + $endpoint = $endpointBuilder('Indices\Optimize'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index with an alias (Required) + * ['name'] = (string) The name of the alias to be deleted (Required) + * ['timeout'] = (time) Explicit timestamp for the document + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function deleteAlias($params) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Alias\Delete $endpoint */ + $endpoint = $endpointBuilder('Indices\Alias\Delete'); + $endpoint->setIndex($index) + ->setName($name); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index (Required) + * ['timeout'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function open($params) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Open $endpoint */ + $endpoint = $endpointBuilder('Indices\Open'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index to scope the operation + * ['analyzer'] = (string) The name of the analyzer to use + * ['field'] = (string) Use the analyzer configured for this field (instead of passing the analyzer name) + * ['filters'] = (list) A comma-separated list of filters to use for the analysis + * ['prefer_local'] = (boolean) With `true`, specify that a local shard should be used if available, with `false`, use a random shard (default: true) + * ['text'] = (string) The text on which the analysis should be performed (when request body is not used) + * ['tokenizer'] = (string) The name of the tokenizer to use for the analysis + * ['format'] = (enum) Format of the output + * ['body'] = (enum) Format of the output + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function analyze($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Analyze $endpoint */ + $endpoint = $endpointBuilder('Indices\Analyze'); + $endpoint->setIndex($index) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index name to limit the operation + * ['field_data'] = (boolean) Clear field data + * ['fielddata'] = (boolean) Clear field data + * ['fields'] = (list) A comma-separated list of fields to clear when using the `field_data` parameter (default: all) + * ['filter'] = (boolean) Clear filter caches + * ['filter_cache'] = (boolean) Clear filter caches + * ['filter_keys'] = (boolean) A comma-separated list of keys to clear when using the `filter_cache` parameter (default: all) + * ['id'] = (boolean) Clear ID caches for parent/child + * ['id_cache'] = (boolean) Clear ID caches for parent/child + * ['recycler'] = (boolean) Clear the recycler cache + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function clearCache($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Cache\Clear $endpoint */ + $endpoint = $endpointBuilder('Indices\Cache\Clear'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names to filter aliases + * ['timeout'] = (time) Explicit timestamp for the document + * ['body'] = (time) Explicit timestamp for the document + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function updateAliases($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $body = $this->extractArgument($params, 'body'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Aliases\Update $endpoint */ + $endpoint = $endpointBuilder('Indices\Aliases\Update'); + $endpoint->setIndex($index) + ->setBody($body); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['local'] = (bool) Return local information, do not retrieve the state from master node (default: false) + * ['timeout'] = (time) Explicit timestamp for the document + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getAliases($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Aliases\Get $endpoint */ + $endpoint = $endpointBuilder('Indices\Aliases\Get'); + $endpoint->setIndex($index) + ->setName($name); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['name'] = (list) A comma-separated list of alias names to return (Required) + * ['index'] = (list) A comma-separated list of index names to filter aliases + * ['ignore_unavailable'] = (bool) Whether specified concrete indices should be ignored when unavailable (missing or closed) + * ['allow_no_indices'] = (bool) Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * ['expand_wildcards'] = (enum) Whether to expand wildcard expression to concrete indices that are open, closed or both. + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function existsAlias($params) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Alias\Exists $endpoint */ + $endpoint = $endpointBuilder('Indices\Alias\Exists'); + $endpoint->setIndex($index) + ->setName($name); + $endpoint->setParams($params); + + try { + $response = $endpoint->performRequest(); + } catch (Missing404Exception $exception) { + return false; + } + + + if ($response['status'] === 200) { + return true; + } else { + return false; + } + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * ['ignore_indices'] = (enum) When performed on multiple indices, allows to ignore `missing` ones + * ['operation_threading'] = () TODO: ? + * ['recovery'] = (boolean) Return information about shard recovery + * ['snapshot'] = (boolean) TODO: ? + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function status($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Status $endpoint */ + $endpoint = $endpointBuilder('Indices\Status'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (list) A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getSettings($params = array()) + { + $index = $this->extractArgument($params, 'index'); + + + $name = $this->extractArgument($params, 'name'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Settings\Get $endpoint */ + $endpoint = $endpointBuilder('Indices\Settings\Get'); + $endpoint->setIndex($index) + ->setName($name); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['index'] = (string) The name of the index (Required) + * ['timeout'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function close($params) + { + $index = $this->extractArgument($params, 'index'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Indices\Close $endpoint */ + $endpoint = $endpointBuilder('Indices\Close'); + $endpoint->setIndex($index); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + + + +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/NodesNamespace.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/NodesNamespace.php new file mode 100644 index 00000000..219f38c3 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/NodesNamespace.php @@ -0,0 +1,144 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class NodesNamespace extends AbstractNamespace +{ + /** + * $params['fields'] = (list) A comma-separated list of fields for `fielddata` metric (supports wildcards) + * ['metric_family'] = (enum) Limit the information returned to a certain metric family + * ['metric'] = (enum) Limit the information returned for `indices` family to a specific metric + * ['node_id'] = (list) A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes + * ['all'] = (boolean) Return all available information + * ['clear'] = (boolean) Reset the default level of detail + * ['fs'] = (boolean) Return information about the filesystem + * ['http'] = (boolean) Return information about HTTP + * ['indices'] = (boolean) Return information about indices + * ['jvm'] = (boolean) Return information about the JVM + * ['network'] = (boolean) Return information about network + * ['os'] = (boolean) Return information about the operating system + * ['process'] = (boolean) Return information about the Elasticsearch process + * ['thread_pool'] = (boolean) Return information about the thread pool + * ['transport'] = (boolean) Return information about transport + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function stats($params = array()) + { + $nodeID = $this->extractArgument($params, 'node_id'); + + $metric = $this->extractArgument($params, 'metric'); + + $index_metric = $this->extractArgument($params, 'index_metric'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Nodes\Stats $endpoint */ + $endpoint = $endpointBuilder('Cluster\Nodes\Stats'); + $endpoint->setNodeID($nodeID) + ->setMetric($metric) + ->setIndexMetric($index_metric) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['node_id'] = (list) A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes + * ['metric'] = (list) A comma-separated list of metrics you wish returned. Leave empty to return all. + * ['flat_settings'] = (boolean) Return settings in flat format (default: false) + * ['human'] = (boolean) Whether to return time and byte values in human-readable format. + + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function info($params = array()) + { + $nodeID = $this->extractArgument($params, 'node_id'); + $metric = $this->extractArgument($params, 'metric'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Nodes\Info $endpoint */ + $endpoint = $endpointBuilder('Cluster\Nodes\Info'); + $endpoint->setNodeID($nodeID)->setMetric($metric); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['node_id'] = (list) A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes + * ['interval'] = (time) The interval for the second sampling of threads + * ['snapshots'] = (number) Number of samples of thread stacktrace (default: 10) + * ['threads'] = (number) Specify the number of threads to provide information for (default: 3) + * ['type'] = (enum) The type to sample (default: cpu) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function hotThreads($params = array()) + { + $nodeID = $this->extractArgument($params, 'node_id'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Nodes\HotThreads $endpoint */ + $endpoint = $endpointBuilder('Cluster\Nodes\HotThreads'); + $endpoint->setNodeID($nodeID); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['node_id'] = (list) A comma-separated list of node IDs or names to perform the operation on; use `_local` to perform the operation on the node you're connected to, leave empty to perform the operation on all nodes + * ['delay'] = (time) Set the delay for the operation (default: 1s) + * ['exit'] = (boolean) Exit the JVM as well (default: true) + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function shutdown($params = array()) + { + $nodeID = $this->extractArgument($params, 'node_id'); + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Cluster\Nodes\Shutdown $endpoint */ + $endpoint = $endpointBuilder('Cluster\Nodes\Shutdown'); + $endpoint->setNodeID($nodeID); + $endpoint->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/SnapshotNamespace.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/SnapshotNamespace.php new file mode 100644 index 00000000..fb570fbc --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Namespaces/SnapshotNamespace.php @@ -0,0 +1,227 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class SnapshotNamespace extends AbstractNamespace +{ + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['wait_for_completion'] = (bool) Should this request wait until the operation has completed before returning + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function create($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + $snapshot = $this->extractArgument($params, 'snapshot'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Create $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Create'); + $endpoint->setRepository($repository) + ->setSnapshot($snapshot) + ->setParams($params) + ->setBody($body); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['timeout'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function createRepository($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Repository\Create $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Repository\Create'); + $endpoint->setRepository($repository) + ->setBody($body) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function delete($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + $snapshot = $this->extractArgument($params, 'snapshot'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Delete $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Delete'); + $endpoint->setRepository($repository) + ->setSnapshot($snapshot) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['timeout'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function deleteRepository($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Repository\Delete $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Repository\Delete'); + $endpoint->setRepository($repository) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function get($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + $snapshot = $this->extractArgument($params, 'snapshot'); + + + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Get $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Get'); + $endpoint->setRepository($repository) + ->setSnapshot($snapshot) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['timeout'] = (time) Explicit operation timeout + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function getRepository($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Repository\Get $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Repository\Get'); + $endpoint->setRepository($repository) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * ['wait_for_completion'] = (bool) Should this request wait until the operation has completed before returning + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function restore($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + $snapshot = $this->extractArgument($params, 'snapshot'); + $body = $this->extractArgument($params, 'body'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Restore $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Restore'); + $endpoint->setRepository($repository) + ->setSnapshot($snapshot) + ->setParams($params) + ->setBody($body); + $response = $endpoint->performRequest(); + return $response['data']; + } + + /** + * $params['master_timeout'] = (time) Explicit operation timeout for connection to master node + * + * @param $params array Associative array of parameters + * + * @return array + */ + public function status($params = array()) + { + $repository = $this->extractArgument($params, 'repository'); + $snapshot = $this->extractArgument($params, 'snapshot'); + + /** @var callback $endpointBuilder */ + $endpointBuilder = $this->dicEndpoints; + + /** @var \Elasticsearch\Endpoints\Snapshot\Status $endpoint */ + $endpoint = $endpointBuilder('Snapshot\Status'); + $endpoint->setRepository($repository) + ->setSnapshot($snapshot) + ->setParams($params); + $response = $endpoint->performRequest(); + return $response['data']; + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/ArrayToJSONSerializer.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/ArrayToJSONSerializer.php new file mode 100644 index 00000000..efbfee97 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/ArrayToJSONSerializer.php @@ -0,0 +1,60 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class ArrayToJSONSerializer implements SerializerInterface +{ + + + /** + * Serialize assoc array into JSON string + * + * @param string|array $data Assoc array to encode into JSON + * + * @return string + */ + public function serialize($data) + { + if (is_string($data) === true) { + return $data; + } else { + $data = json_encode($data); + if ($data === '[]') { + return '{}'; + } else { + return $data; + } + } + + + } + + + /** + * Deserialize JSON into an assoc array + * + * @param string $data JSON encoded string + * @param array $headers Response Headers + * + * @return array + */ + public function deserialize($data, $headers) + { + return json_decode($data, true); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/EverythingToJSONSerializer.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/EverythingToJSONSerializer.php new file mode 100644 index 00000000..a1659b23 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/EverythingToJSONSerializer.php @@ -0,0 +1,52 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class EverythingToJSONSerializer implements SerializerInterface +{ + + /** + * Serialize assoc array into JSON string + * + * @param string|array $data Assoc array to encode into JSON + * + * @return string + */ + public function serialize($data) + { + $data = json_encode($data); + if ($data === '[]') { + return '{}'; + } else { + return $data; + } + } + + + /** + * Deserialize JSON into an assoc array + * + * @param string $data JSON encoded string + * @param array $headers Response headers + * + * @return array + */ + public function deserialize($data, $headers) + { + return json_decode($data, true); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/SerializerInterface.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/SerializerInterface.php new file mode 100644 index 00000000..1f2b0814 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Serializers/SerializerInterface.php @@ -0,0 +1,16 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class SmartSerializer implements SerializerInterface +{ + + + /** + * Serialize assoc array into JSON string + * + * @param string|array $data Assoc array to encode into JSON + * + * @return string + */ + public function serialize($data) + { + if (is_string($data) === true) { + return $data; + } else { + $data = json_encode($data); + if ($data === '[]') { + return '{}'; + } else { + return $data; + } + } + + + } + + + /** + * Deserialize by introspecting content_type. Tries to deserialize JSON, + * otherwise returns string + * + * @param string $data JSON encoded string + * @param array $headers Response Headers + * + * @return array + */ + public function deserialize($data, $headers) + { + if (isset($headers['content_type']) === true) { + if (strpos($headers['content_type'], 'json') !== false) { + return json_decode($data, true); + } else { + //Not json, return as string + return $data; + } + + } else { + //No content headers, assume json + return json_decode($data, true); + } + + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Transport.php b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Transport.php new file mode 100644 index 00000000..913b2666 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Transport.php @@ -0,0 +1,260 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class Transport +{ + /** + * @var \Pimple\Container + */ + private $params; + + /** + * @var AbstractConnectionPool + */ + private $connectionPool; + + /** + * @var array Array of seed nodes provided by the user + */ + private $seeds = array(); + + /** + * @var SerializerInterface + */ + private $serializer; + + /** + * @var LoggerInterface + */ + private $log; + + /** @var int */ + private $retryAttempts; + + /** @var AbstractConnection */ + private $lastConnection; + + + /** + * Transport class is responsible for dispatching requests to the + * underlying cluster connections + * + * @param array $hosts Array of hosts in cluster + * @param \Pimple\Container $params DIC containing dependencies + * @param \Psr\Log\LoggerInterface $log Monolog logger object + * + * @throws Common\Exceptions\InvalidArgumentException + */ + public function __construct($hosts, $params, LoggerInterface $log) + { + $this->log = $log; + + if (is_array($hosts) !== true) { + $this->log->critical('Hosts parameter must be an array'); + throw new Exceptions\InvalidArgumentException('Hosts parameter must be an array'); + } + + $this->params = $params; + $this->serializer = $params['serializer']; + + $this->seeds = $hosts; + $this->setConnections($hosts); + + if (isset($this->params['retries']) !== true || $this->params['retries'] === null) { + $this->params['retries'] = count($hosts) -1; + } + + if ($params['sniffOnStart'] === true) { + $this->log->notice('Sniff on Start.'); + $this->connectionPool->scheduleCheck(); + } + + } + + + /** + * Creates Connection objects and instantiates a ConnectionPool object + * + * @param array $hosts Assoc array of hosts to add to connection pool + * + * @return void + */ + public function setConnections($hosts) + { + // Merge in the initial seed list (union not array_merge). + $hosts = $hosts + $this->seeds; + + $connections = $this->hostsToConnections($hosts); + + $this->connectionPool = $this->params['connectionPool']($connections); + + } + + + /** + * Returns a single connection from the connection pool + * Potentially performs a sniffing step before returning + * + * @return ConnectionInterface Connection + */ + + public function getConnection() + { + return $this->connectionPool->nextConnection(); + } + + + /** + * Perform a request to the Cluster + * + * @param string $method HTTP method to use + * @param string $uri HTTP URI to send request to + * @param null $params Optional query parameters + * @param null $body Optional query body + * + * @throws Common\Exceptions\NoNodesAvailableException|\Exception + * @internal param null $maxRetries Optional number of retries + * + * @return array + */ + public function performRequest($method, $uri, $params = null, $body = null) + { + try { + $connection = $this->getConnection(); + } catch (Exceptions\NoNodesAvailableException $exception) { + $this->log->critical('No alive nodes found in cluster'); + throw $exception; + } + + $response = array(); + $caughtException = null; + $this->lastConnection = $connection; + + try { + if (isset($body) === true) { + $body = $this->serializer->serialize($body); + } + + $response = $connection->performRequest( + $method, + $uri, + $params, + $body + ); + + $connection->markAlive(); + $this->retryAttempts = 0; + + $data = $this->serializer->deserialize($response['text'], $response['info']); + + return array( + 'status' => $response['status'], + 'data' => $data, + 'info' => $response['info'], + ); + + } catch (Exceptions\Curl\OperationTimeoutException $exception) { + $this->connectionPool->scheduleCheck(); + $caughtException = $exception; + + } catch (Exceptions\ClientErrorResponseException $exception) { + throw $exception; //We need 4xx errors to go straight to the user, no retries + + } catch (Exceptions\ServerErrorResponseException $exception) { + throw $exception; //We need 5xx errors to go straight to the user, no retries + + } catch (TransportException $exception) { + $connection->markDead(); + $this->connectionPool->scheduleCheck(); + $caughtException = $exception; + } + + $shouldRetry = $this->shouldRetry($method, $uri, $params, $body); + if ($shouldRetry === true) { + return $this->performRequest($method, $uri, $params, $body); + } + + if ($caughtException !== null) { + throw $caughtException; + } + + return $response; + } + + + /** + * @param $method + * @param $uri + * @param $params + * @param $body + * + * @return bool + */ + public function shouldRetry($method, $uri, $params, $body) + { + if ($this->retryAttempts < $this->params['retries']) { + $this->retryAttempts += 1; + return true; + } + + return false; + } + + + /** + * Returns the last used connection so that it may be inspected. Mainly + * for debugging/testing purposes. + * + * @return AbstractConnection + */ + public function getLastConnection() + { + return $this->lastConnection; + } + + + /** + * Convert host arrays into connections + * + * @param array $hosts Assoc array of host values + * + * @return AbstractConnection[] + */ + private function hostsToConnections($hosts) + { + $connections = array(); + foreach ($hosts as $host) { + $connections[] = $this->params['connection']( + $host + ); + } + + return $connections; + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ClientTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ClientTest.php new file mode 100644 index 00000000..bc18cd5a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ClientTest.php @@ -0,0 +1,350 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class ClientTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() + { + m::close(); + } + + public function setUp() + { + $this->root = vfsStream::setup('root'); + } + + /** + * @expectedException \Elasticsearch\Common\Exceptions\InvalidArgumentException + */ + public function testConstructorStringHost() + { + // Hosts param must be an array. + $params = array('hosts' => 'localhost'); + $client = new Elasticsearch\Client($params); + + } + + + public function testOneGoodOneBadHostNoException() + { + $params = array('hosts' => array ( + '127.0.0.1:80', + $_SERVER['ES_TEST_HOST'], + )); + $client = new Elasticsearch\Client($params); + + // Perform three requests to make sure the bad host is tried at least once + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + + } + + + /** + * @expectedException Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost + */ + public function testOneGoodOneBadHostNoRetryException() + { + $params = array('hosts' => array ( + '127.0.0.1:1', + $_SERVER['ES_TEST_HOST'], + )); + $params['retries'] = 0; + $client = new Elasticsearch\Client($params); + + // Perform three requests to make sure the bad host is tried at least once + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + + } + + + /** + * @expectedException \Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost + */ + public function testBadHost() + { + $params = array('hosts' => array ( + '127.0.0.1:8200', + )); + $client = new Elasticsearch\Client($params); + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + + } + + + /** + * @expectedException \Elasticsearch\Common\Exceptions\InvalidArgumentException + */ + public function testConstructorIllegalPort() + { + $params = array( + 'hosts' => array('localhost:abc') + ); + $client = new Elasticsearch\Client($params); + + } + + /** + * @expectedException \Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost + */ + public function testZeroRetries() + { + $params = array( + 'retries' => 0, + 'hosts' => array('localhost:8000') + ); + $client = new Elasticsearch\Client($params); + $client->exists(array("index" => 'test', 'type' => 'test', 'id' => 'test')); + + } + + + public function testConstructorEmptyPort() + { + $mockPimple = m::mock('Pimple')->shouldReceive('offsetGet')->getMock()->shouldReceive('offsetSet')->getMock(); + $mockDIC = m::mock('DICBuilder')->shouldReceive('getDIC')->once()->andReturn($mockPimple)->getMock(); + + $that = $this; //hurp durp + + $params = array( + 'hosts' => array('localhost:'), + 'dic' => function ($hosts, $params) use ($mockDIC, $that) { + + $expected = array(array('scheme' => 'http', 'host' => 'localhost', 'port' => 9200)); + $that->assertEquals($expected, $hosts); + return $mockDIC; + } + ); + $client = new Elasticsearch\Client($params); + + } + + public function testConstructorNoPort() + { + $mockPimple = m::mock('Pimple')->shouldReceive('offsetGet')->getMock()->shouldReceive('offsetSet')->getMock(); + $mockDIC = m::mock('DICBuilder')->shouldReceive('getDIC')->once()->andReturn($mockPimple)->getMock(); + + $that = $this; //hurp durp + + $params = array( + 'hosts' => array('localhost'), + 'dic' => function ($hosts, $params) use ($mockDIC, $that) { + + $expected = array(array('scheme' => 'http', 'host' => 'localhost', 'port' => 9200)); + $that->assertEquals($expected, $hosts); + return $mockDIC; + } + ); + $client = new Elasticsearch\Client($params); + + } + + public function testConstructorWithPort() + { + $mockPimple = m::mock('Pimple')->shouldReceive('offsetGet')->getMock()->shouldReceive('offsetSet')->getMock(); + $mockDIC = m::mock('DICBuilder')->shouldReceive('getDIC')->once()->andReturn($mockPimple)->getMock(); + + $that = $this; //hurp durp + + $params = array( + 'hosts' => array('localhost:9200'), + 'dic' => function ($hosts, $params) use ($mockDIC, $that) { + + $expected = array(array('scheme' => 'http', 'host' => 'localhost', 'port' => 9200)); + $that->assertEquals($expected, $hosts); + return $mockDIC; + } + ); + $client = new Elasticsearch\Client($params); + + } + + public function testConstructorWithSchemeAndPort() + { + $mockPimple = m::mock('Pimple')->shouldReceive('offsetGet')->getMock()->shouldReceive('offsetSet')->getMock(); + $mockDIC = m::mock('DICBuilder')->shouldReceive('getDIC')->once()->andReturn($mockPimple)->getMock(); + + $that = $this; //hurp durp + + $params = array( + 'hosts' => array('http://localhost:9200'), + 'dic' => function ($hosts, $params) use ($mockDIC, $that) { + + $expected = array(array('scheme' => 'http', 'host' => 'localhost', 'port' => 9200)); + $that->assertEquals($expected, $hosts); + return $mockDIC; + } + ); + $client = new Elasticsearch\Client($params); + + } + + + + + /** + * + * @expectedException \Elasticsearch\Common\Exceptions\InvalidArgumentException + * + * @return void + */ + public function testConstructorStringParam() + { + // String parameter instead of an array. + $params = 'some arbitrary string'; + $client = new Elasticsearch\Client($params); + + }//end testConstructorStringParam() + + + /** + * + * @expectedException \Elasticsearch\Common\Exceptions\UnexpectedValueException + * + * @return void + */ + public function testConstructorInvalidParam() + { + // String parameter instead of an array. + $params = array('randomParam' => 'some arbitrary string'); + $client = new Elasticsearch\Client($params); + } + + + /** + * This test is rather hacky...better way to test than check headers in log? + * + * @group integration + */ + public function testBasicAuth() + { + $path = vfsStream::url('root'); + + $params = array(); + $params['logging'] = true; + $params['connectionParams']['auth'] = array('username', 'password', 'Basic'); + $params['logPath'] = "$path/elasticsearch.log"; + $params['logLevel'] = LogLevel::INFO; + + $params['hosts'] = array ($_SERVER['ES_TEST_HOST']); + + $client = new Elasticsearch\Client($params); + + try { + $client->ping(); + } catch (Exception $e) { + // Ok to fail, not actually trying to connect. Just want to see + // log for basic auth headers + } + + $log = file_get_contents('vfs://root/elasticsearch.log'); + $basicAuthSignature = 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='; + $this->assertContains($basicAuthSignature, $log); + } + + + /** + * @group integration + */ + public function testNoBasicAuth() + { + $path = vfsStream::url('root'); + + $params = array(); + $params['logging'] = true; + $params['logPath'] = "$path/elasticsearch.log"; + $params['logLevel'] = LogLevel::INFO; + + $params['hosts'] = array ($_SERVER['ES_TEST_HOST']); + + $client = new Elasticsearch\Client($params); + + try { + $client->ping(); + } catch (Exception $e) { + // Ok to fail, not actually trying to connect. Just want to see + // log + } + + $log = file_get_contents('vfs://root/elasticsearch.log'); + $basicAuthSignature = '"authorization"'; + $this->assertNotContains($basicAuthSignature, $log); + } + + /** + * @group integration + */ + public function testDisableLogging() + { + $path = vfsStream::url('root'); + + $params = array(); + $params['logging'] = false; + $params['hosts'] = array ($_SERVER['ES_TEST_HOST']); + $client = new Elasticsearch\Client($params); + + try { + $client->ping(); + } catch (Exception $e) { + // Ok to fail, not actually trying to connect. Just want to see + // log + } + + $logExists = file_exists('vfs://root/elasticsearch.log'); + $this->assertFalse($logExists); + } + + public function testHighTimeout() + { + $params = array(); + $params['connectionParams']['timeout'] = 5000; + $params['hosts'] = array ($_SERVER['ES_TEST_HOST']); + $client = new Elasticsearch\Client($params); + + try { + $client->ping(); + } catch (Exception $e) { + + } + + } + + public function testHTTPS() + { + // Hosts param must be an array. + $params = array('hosts' => array('https://localhost')); + $client = new Elasticsearch\Client($params); + + try { + $client->exists(array('index' => 't', 'type' => 't', 'id' => 1)); + } catch (\Exception $e) { + + } + + $last = $client->transport->getLastConnection()->getLastRequestInfo(); + $this->assertEquals('https://localhost:9200/t/t/1?', $last['request']['uri']); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/Selectors/RoundRobinSelectorTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/Selectors/RoundRobinSelectorTest.php new file mode 100644 index 00000000..bd8f9d60 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/Selectors/RoundRobinSelectorTest.php @@ -0,0 +1,86 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class RoundRobinSelectorTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Add Ten connections, select 15 to verify round robin + * + * @covers \Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector::select + * + * @return void + */ + public function testTenConnections() + { + $roundRobin = new Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector(); + + $mockConnections = array(); + foreach (range(0,10) as $index) { + $mockConnections[$index] = $this->getMockBuilder('\Elasticsearch\Connections\CurlMultiConnection') + ->disableOriginalConstructor() + ->getMock(); + } + + foreach (range(0,15) as $index) { + $retConnection = $roundRobin->select($mockConnections); + + $nextIndex = ($index % 10) + 1; + $this->assertEquals($mockConnections[$nextIndex], $retConnection); + } + + }//end testTenConnections() + + + /** + * Add Ten connections, select five, remove thre, test another 10 to check + * that the round-robining works after removing connections + * + * @covers \Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector::select + * + * @return void + */ + public function testAddTenConnectionsestFiveTRemoveThree() + { + $roundRobin = new Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector(); + + $mockConnections = array(); + foreach (range(0,10) as $index) { + $mockConnections[$index] = $this->getMockBuilder('\Elasticsearch\Connections\CurlMultiConnection') + ->disableOriginalConstructor() + ->getMock(); + } + + foreach (range(0,4) as $index) { + $retConnection = $roundRobin->select($mockConnections); + + $nextIndex = ($index % (count($mockConnections)-1)) + 1; + $this->assertEquals($mockConnections[$nextIndex], $retConnection); + } + + unset($mockConnections[8]); + unset($mockConnections[9]); + unset($mockConnections[10]); + + foreach (range(5,15) as $index) { + $retConnection = $roundRobin->select($mockConnections); + + $nextIndex = ($index % (count($mockConnections)-1)) + 1; + $this->assertEquals($mockConnections[$nextIndex], $retConnection); + } + + }//end testAddTenConnectionsestFiveTRemoveThree() + +}//end class \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/Selectors/StickyRoundRobinSelectorTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/Selectors/StickyRoundRobinSelectorTest.php new file mode 100644 index 00000000..474d95a0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/Selectors/StickyRoundRobinSelectorTest.php @@ -0,0 +1,77 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class StickyRoundRobinSelectorTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + + public function testTenConnections() + { + $roundRobin = new Elasticsearch\ConnectionPool\Selectors\StickyRoundRobinSelector(); + + $mockConnections = array(); + $mockConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->times(16)->andReturn(true)->getMock(); + + foreach (range(0,9) as $index) { + $mockConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection'); + } + + + foreach (range(0,15) as $index) { + $retConnection = $roundRobin->select($mockConnections); + + $this->assertEquals($mockConnections[0], $retConnection); + } + + } + + public function testTenConnectionsFirstDies() + { + $roundRobin = new Elasticsearch\ConnectionPool\Selectors\StickyRoundRobinSelector(); + + $mockConnections = array(); + $mockConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->once()->andReturn(false)->getMock(); + + $mockConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->times(15)->andReturn(true)->getMock(); + + foreach (range(0,8) as $index) { + $mockConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection'); + } + + + foreach (range(0,15) as $index) { + $retConnection = $roundRobin->select($mockConnections); + + $this->assertEquals($mockConnections[1], $retConnection); + } + + } + + + +}//end class \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/SniffingConnectionPoolIntegrationTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/SniffingConnectionPoolIntegrationTest.php new file mode 100644 index 00000000..d83377e1 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/SniffingConnectionPoolIntegrationTest.php @@ -0,0 +1,27 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class SniffingConnectionPoolIntegrationTest extends \PHPUnit_Framework_TestCase +{ + public function testSniff() { + $params['connectionPoolClass'] = '\Elasticsearch\ConnectionPool\SniffingConnectionPool'; + $params['connectionPoolParams']['sniffingInterval'] = -10; + $params['hosts'] = array ($_SERVER['ES_TEST_HOST']); + + $client = new \Elasticsearch\Client($params); + + $client->ping(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/SniffingConnectionPoolTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/SniffingConnectionPoolTest.php new file mode 100644 index 00000000..28877e83 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/SniffingConnectionPoolTest.php @@ -0,0 +1,443 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class SniffingConnectionPoolTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testAddOneHostThenGetConnection() + { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(true) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(true) + ->getMock(); + + $connections = array($mockConnection); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturn($connections[0]) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $connectionPoolParams = array('randomizeHosts' => false); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + + $this->assertEquals($mockConnection, $retConnection); + + } + + public function testAddOneHostAndTriggerSniff() + { + $clusterState['text'] = '{"ok":true,"cluster_name":"elasticsearch_zach","nodes":{"Bl2ihSr7TcuUHxhu1GA_YQ":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9300]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9200]"}}}'; + + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(true)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('getTransportSchema')->once()->andReturn('http')->getMock() + ->shouldReceive('sniff')->once()->andReturn($clusterState)->getMock(); + + $connections = array($mockConnection); + $mockNewConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(true)->getMock(); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select')->twice() + ->andReturn($mockNewConnection) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory') + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9200))->andReturn($mockNewConnection)->getMock(); + + $connectionPoolParams = array( + 'randomizeHosts' => false, + 'sniffingInterval' => -1 + ); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + + $this->assertEquals($mockNewConnection, $retConnection); + } + + public function testAddOneHostAndForceNext() + { + $clusterState['text'] = '{"ok":true,"cluster_name":"elasticsearch_zach","nodes":{"Bl2ihSr7TcuUHxhu1GA_YQ":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9300]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9200]"}}}'; + + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(true)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('getTransportSchema')->once()->andReturn('http')->getMock() + ->shouldReceive('sniff')->once()->andReturn($clusterState)->getMock(); + + $connections = array($mockConnection); + $mockNewConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(true)->getMock(); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select')->once()->andReturn($mockConnection)->getMock() + ->shouldReceive('select')->once()->andReturn($mockNewConnection)->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory') + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9200))->andReturn($mockNewConnection)->getMock(); + + $connectionPoolParams = array( + 'randomizeHosts' => false + ); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(true); + + $this->assertEquals($mockNewConnection, $retConnection); + } + + + public function testAddTenNodesThenGetConnection() + { + $connections = array(); + + foreach (range(1,10) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(true) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(true) + ->getMock(); + + $connections[] = $mockConnection; + } + + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturn($connections[0]) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $connectionPoolParams = array('randomizeHosts' => false); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + + $this->assertEquals($connections[0], $retConnection); + + } + + public function testAddTenNodesTimeoutAllButLast() + { + $connections = array(); + + foreach (range(1,9) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(false) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(false) + ->getMock(); + + $connections[] = $mockConnection; + } + + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(true) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(true) + ->getMock(); + + $connections[] = $mockConnection; + + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues($connections) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $connectionPoolParams = array('randomizeHosts' => false); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + + $this->assertEquals($connections[9], $retConnection); + + } + + + /** + * @expectedException Elasticsearch\Common\Exceptions\NoNodesAvailableException + */ + public function testAddTenNodesAllTimeout() + { + $connections = array(); + + foreach (range(1,10) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(false) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(false) + ->getMock(); + + $connections[] = $mockConnection; + } + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues($connections) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $connectionPoolParams = array('randomizeHosts' => false); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + + } + + public function testAddOneHostSniffTwo() + { + $clusterState['text'] = '{"ok":true,"cluster_name":"elasticsearch_zach","nodes":{"node1":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9300]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9200]"}, "node2":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9301]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9201]"}}}'; + + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(true)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('getTransportSchema')->twice()->andReturn('http')->getMock() + ->shouldReceive('sniff')->twice()->andReturn($clusterState)->getMock(); + + $connections = array($mockConnection); + + $newConnections = array(); + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(true)->getMock(); + + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(true)->getMock(); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues(array( //selects provided node first, then the new cluster list + $mockConnection, + $newConnections[0], + $newConnections[1] + )) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory') + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9200))->andReturn($newConnections[0])->getMock() + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9201))->andReturn($newConnections[1])->getMock(); + + $connectionPoolParams = array( + 'randomizeHosts' => false, + 'sniffingInterval' => -1 + ); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + $this->assertEquals($newConnections[0], $retConnection); + + $retConnection = $connectionPool->nextConnection(); + $this->assertEquals($newConnections[1], $retConnection); + } + + /** + * @expectedException Elasticsearch\Common\Exceptions\NoNodesAvailableException + */ + public function testAddSeed_SniffTwo_TimeoutTwo() + { + $clusterState['text'] = '{"ok":true,"cluster_name":"elasticsearch_zach","nodes":{"node1":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9300]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9200]"}, "node2":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9301]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9201]"}}}'; + + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(true)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('getTransportSchema')->once()->andReturn('http')->getMock() + ->shouldReceive('sniff')->once()->andReturn($clusterState)->getMock(); + + $connections = array($mockConnection); + + $newConnections = array(); + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(false)->getMock() + ->shouldReceive('ping')->andReturn(false)->getMock(); + + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(false)->getMock() + ->shouldReceive('ping')->andReturn(false)->getMock(); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues(array( //selects provided node first, then the new cluster list + $mockConnection, + $newConnections[0], + $newConnections[1] + )) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory') + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9200))->andReturn($newConnections[0])->getMock() + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9201))->andReturn($newConnections[1])->getMock(); + + $connectionPoolParams = array( + 'randomizeHosts' => false, + 'sniffingInterval' => -1 + ); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + $this->assertEquals($mockConnection, $retConnection); + + } + + + public function testTen_TimeoutNine_SniffTenth_AddTwoAlive() + { + $clusterState['text'] = '{"ok":true,"cluster_name":"elasticsearch_zach","nodes":{"node1":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9300]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9200]"}, "node2":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9301]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9201]"}}}'; + + $connections = array(); + + foreach (range(1,10) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(false)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('sniff')->andThrow('Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException')->getMock(); + + $connections[] = $mockConnection; + } + + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(true)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('sniff')->andReturn($clusterState)->getMock() + ->shouldReceive('getTransportSchema')->twice()->andReturn('http')->getMock(); + + $connections[] = $mockConnection; + + $newConnections = $connections; + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('ping')->andReturn(true)->getMock(); + + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('ping')->andReturn(true)->getMock(); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues($newConnections) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory') + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9200))->andReturn($newConnections[10])->getMock() + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9201))->andReturn($newConnections[11])->getMock(); + + $connectionPoolParams = array( + 'randomizeHosts' => false, + 'sniffingInterval' => -1 + ); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + $this->assertEquals($newConnections[11], $retConnection); + + $retConnection = $connectionPool->nextConnection(); + $this->assertEquals($newConnections[12], $retConnection); + + } + + /** + * @expectedException Elasticsearch\Common\Exceptions\NoNodesAvailableException + */ + public function testTen_TimeoutNine_SniffTenth_AddTwoDead_TimeoutEveryone() + { + $clusterState['text'] = '{"ok":true,"cluster_name":"elasticsearch_zach","nodes":{"node1":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9300]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9200]"}, "node2":{"name":"Vesta","transport_address":"inet[/192.168.1.119:9301]","hostname":"zach-ThinkPad-W530","version":"0.90.5","http_address":"inet[/192.168.1.119:9201]"}}}'; + + $connections = array(); + + foreach (range(1,10) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(false)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('sniff')->andThrow('Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException')->getMock(); + + $connections[] = $mockConnection; + } + + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->andReturn(true)->getMock() + ->shouldReceive('isAlive')->andReturn(true)->getMock() + ->shouldReceive('sniff')->andReturn($clusterState)->getMock() + ->shouldReceive('getTransportSchema')->once()->andReturn('http')->getMock() + ->shouldReceive('sniff')->andThrow('Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException')->getMock(); + + $connections[] = $mockConnection; + + $newConnections = $connections; + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(false)->getMock() + ->shouldReceive('ping')->andReturn(false)->getMock() + ->shouldReceive('sniff')->andThrow('Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException')->getMock(); + + $newConnections[] = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('isAlive')->andReturn(false)->getMock() + ->shouldReceive('ping')->andReturn(false)->getMock() + ->shouldReceive('sniff')->andThrow('Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException')->getMock(); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues($newConnections) + ->getMock(); + + $RRConnections = $newConnections; + //array_push($connections); + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory') + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9200))->andReturn($newConnections[10])->getMock() + ->shouldReceive('create')->with(array('host' => '192.168.1.119', 'port' => 9201))->andReturn($newConnections[11])->getMock(); + + $connectionPoolParams = array( + 'randomizeHosts' => false, + 'sniffingInterval' => -1 + ); + $connectionPool = new SniffingConnectionPool($connections, $selector, $connectionFactory, $connectionPoolParams); + + $retConnection = $connectionPool->nextConnection(); + $this->assertEquals($newConnections[11], $retConnection); + + $retConnection = $connectionPool->nextConnection(); + $this->assertEquals($newConnections[12], $retConnection); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/StaticConnectionPoolTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/StaticConnectionPoolTest.php new file mode 100644 index 00000000..7ba9a1b0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/ConnectionPool/StaticConnectionPoolTest.php @@ -0,0 +1,224 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class StaticConnectionPoolTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testAddOneHostThenGetConnection() + { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(true) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(true) + ->getMock() + ->shouldReceive('markDead')->once()->getMock(); + + $connections = array($mockConnection); + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturn($connections[0]) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $randomizeHosts = false; + $connectionPool = new \Elasticsearch\ConnectionPool\StaticConnectionPool($connections, $selector, $connectionFactory, $randomizeHosts); + + $retConnection = $connectionPool->nextConnection(); + + $this->assertEquals($mockConnection, $retConnection); + + } + + + public function testAddMultipleHostsThenGetFirst() + { + + $connections = array(); + + foreach (range(1,10) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(true) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(true) + ->getMock() + ->shouldReceive('markDead')->once()->getMock(); + + $connections[] = $mockConnection; + } + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturn($connections[0]) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $randomizeHosts = false; + $connectionPool = new \Elasticsearch\ConnectionPool\StaticConnectionPool($connections, $selector, $connectionFactory, $randomizeHosts); + + $retConnection = $connectionPool->nextConnection(); + + $this->assertEquals($connections[0], $retConnection); + } + + + /** + * @expectedException Elasticsearch\Common\Exceptions\NoNodesAvailableException + */ + public function testAllHostsFailPing() + { + + $connections = array(); + + foreach (range(1,10) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(false) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(false) + ->getMock() + ->shouldReceive('markDead')->once()->getMock() + ->shouldReceive('getPingFailures')->andReturn(0)->once()->getMock() + ->shouldReceive('getLastPing')->andReturn(time())->once()->getMock(); + + $connections[] = $mockConnection; + } + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues($connections) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $randomizeHosts = false; + $connectionPool = new \Elasticsearch\ConnectionPool\StaticConnectionPool($connections, $selector, $connectionFactory, $randomizeHosts); + + $connectionPool->nextConnection(); + + } + + + public function testAllExceptLastHostFailPingRevivesInSkip() + { + + $connections = array(); + + foreach (range(1,9) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(false) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(false) + ->getMock() + ->shouldReceive('markDead')->once()->getMock() + ->shouldReceive('getPingFailures')->andReturn(0)->once()->getMock() + ->shouldReceive('getLastPing')->andReturn(time())->once()->getMock(); + + $connections[] = $mockConnection; + } + + $goodConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->once() + ->andReturn(true) + ->getMock() + ->shouldReceive('isAlive')->once() + ->andReturn(false) + ->getMock() + ->shouldReceive('markDead')->once()->getMock() + ->shouldReceive('getPingFailures')->andReturn(0)->once()->getMock() + ->shouldReceive('getLastPing')->andReturn(time())->once()->getMock(); + + $connections[] = $goodConnection; + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues($connections) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $randomizeHosts = false; + $connectionPool = new \Elasticsearch\ConnectionPool\StaticConnectionPool($connections, $selector, $connectionFactory, $randomizeHosts); + + $ret = $connectionPool->nextConnection(); + $this->assertEquals($goodConnection, $ret); + + } + + public function testAllExceptLastHostFailPingRevivesPreSkip() + { + + $connections = array(); + + foreach (range(1,9) as $index) { + $mockConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping') + ->andReturn(false) + ->getMock() + ->shouldReceive('isAlive') + ->andReturn(false) + ->getMock() + ->shouldReceive('markDead')->once()->getMock() + ->shouldReceive('getPingFailures')->andReturn(0)->once()->getMock() + ->shouldReceive('getLastPing')->andReturn(time())->once()->getMock(); + + $connections[] = $mockConnection; + } + + $goodConnection = m::mock('\Elasticsearch\Connections\GuzzleConnection') + ->shouldReceive('ping')->once() + ->andReturn(true) + ->getMock() + ->shouldReceive('isAlive')->once() + ->andReturn(false) + ->getMock() + ->shouldReceive('markDead')->once()->getMock() + ->shouldReceive('getPingFailures')->andReturn(0)->once()->getMock() + ->shouldReceive('getLastPing')->andReturn(time()-10000)->once()->getMock(); + + $connections[] = $goodConnection; + + $selector = m::mock('\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector') + ->shouldReceive('select') + ->andReturnValues($connections) + ->getMock(); + + $connectionFactory = m::mock('\Elasticsearch\Connections\ConnectionFactory'); + + $randomizeHosts = false; + $connectionPool = new \Elasticsearch\ConnectionPool\StaticConnectionPool($connections, $selector, $connectionFactory, $randomizeHosts); + + $ret = $connectionPool->nextConnection(); + $this->assertEquals($goodConnection, $ret); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/AbstractConnectionTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/AbstractConnectionTest.php new file mode 100644 index 00000000..33b42422 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/AbstractConnectionTest.php @@ -0,0 +1,135 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class AbstractConnectionTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() + { + m::close(); + } + + public function testPing() + { + $logger = new Elasticsearch\Common\EmptyLogger(); + + $stub = $this->getMockForAbstractClass( + 'Elasticsearch\Connections\AbstractConnection', + array( + array('host' => 'localhost', 'port' => 9200), + array(), + $logger, + $logger + ) + ); + + $options = array('timeout' => 1); + $return = array('status' => 200); + + $stub->expects($this->once()) + ->method('performRequest') + ->with('HEAD', '', null, null, $options) + ->will($this->returnValue($return)); + + /** @var AbstractConnection $stub */ + $ret = $stub->ping(); + + $this->assertTrue($ret); + } + + public function testPingBadCode() + { + $logger = new Elasticsearch\Common\EmptyLogger(); + + $stub = $this->getMockForAbstractClass( + 'Elasticsearch\Connections\AbstractConnection', + array( + array('host' => 'localhost', 'port' => 9200), + array(), + $logger, + $logger + ) + ); + + $options = array('timeout' => 1); + $return = array('status' => 400); + + $stub->expects($this->once()) + ->method('performRequest') + ->with('HEAD', '', null, null, $options) + ->will($this->returnValue($return)); + + /** @var AbstractConnection $stub */ + $ret = $stub->ping(); + + $this->assertFalse($ret); + } + + + public function testPingTimeout() + { + $logger = new Elasticsearch\Common\EmptyLogger(); + $stub = $this->getMockForAbstractClass( + 'Elasticsearch\Connections\AbstractConnection', + array( + array('host' => 'localhost', 'port' => 9200), + array(), + $logger, + $logger + ) + ); + + $options = array('timeout' => 1); + $return = array('status' => 400); + + $stub->expects($this->once()) + ->method('performRequest') + ->with('HEAD', '', null, null, $options) + ->will($this->throwException(new Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException())); + + /** @var AbstractConnection $stub */ + $ret = $stub->ping(); + + $this->assertFalse($ret); + } + + public function testURLPrefix() + { + $logger = new Elasticsearch\Common\EmptyLogger(); + + $stub = $this->getMockForAbstractClass( + 'Elasticsearch\Connections\AbstractConnection', + array( + array('host' => 'localhost', 'port' => 9200, 'path' => '/prefix'), + array(), + $logger, + $logger + ) + ); + + /** @var AbstractConnection $stub */ + $this->assertEquals('http://localhost:9200/prefix', $stub->getHost()); + } + +} + diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/ConnectionFactoryTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/ConnectionFactoryTest.php new file mode 100644 index 00000000..d1943589 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/ConnectionFactoryTest.php @@ -0,0 +1,48 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class ConnectionFactoryTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testCreate() + { + $mockConnection = m::mock('\Elasticsearch\Connections\AbstractConnection'); + $mockFunction = function($hostDetails, $params, $log, $trace) use ($mockConnection) { + return $mockConnection; + }; + + // Eww... + $mockPimple = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockFunction)->getMock() + ->shouldReceive('offsetGet')->with('connectionParamsShared')->andReturn(array())->getMock() + ->shouldReceive('offsetGet')->with('logObject')->andReturn(array())->getMock() + ->shouldReceive('offsetGet')->with('traceObject')->andReturn(array())->getMock(); + + $hostDetails = array( + 'host' => 'localhost', + 'port' => 9200 + ); + + $factory = new ConnectionFactory($mockPimple); + $connection = $factory->create($hostDetails); + + $this->assertEquals($mockConnection, $connection); + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/CurlMultiConnectionTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/CurlMultiConnectionTest.php new file mode 100644 index 00000000..d0dc364e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/CurlMultiConnectionTest.php @@ -0,0 +1,125 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class CurlMultiConnectionTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() + { + m::close(); + } + + /** + * Test no multihandle + * + * @expectedException \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @expectedExceptionMessage curlMultiHandle must be set in connectionParams + * + * @covers \Elasticsearch\Connections\CurlMultiConnection::performRequest + * @return void + */ + public function testNoMultihandle() + { + $hostDetails = array('host' => 'localhost', 'port' => 9200); + $connectionParams = null; + + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + $connection = new Elasticsearch\Connections\CurlMultiConnection($hostDetails, $connectionParams, $log, $log); + + }//end testNoMultihandle() + + + /** + * Test bad host name + * + * @expectedException \Elasticsearch\Common\Exceptions\TransportException + * + * @covers \Elasticsearch\Connections\CurlMultiConnection::performRequest + * @return void + */ + public function testBadHost() + { + $hostDetails = array('host' => 'localhost5', 'port' => 9200); + $connectionParams['curlMultiHandle'] = curl_multi_init(); + + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + $connection = new Elasticsearch\Connections\CurlMultiConnection($hostDetails, $connectionParams, $log, $log); + $ret = $connection->performRequest('GET', '/'); + + }//end testBadHost() + + + /** + * Test bad port number + * + * @expectedException \Elasticsearch\Common\Exceptions\TransportException + * + * @covers \Elasticsearch\Connections\CurlMultiConnection::performRequest + * @return void + */ + public function testBadPort() + { + $hostDetails = array('host' => 'localhost', 'port' => 9800); + $connectionParams['curlMultiHandle'] = curl_multi_init(); + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $connection = new Elasticsearch\Connections\CurlMultiConnection($hostDetails, $connectionParams, $log, $log); + $ret = $connection->performRequest('GET', '/'); + + } + + public function testPingTimeout() + { + + $hostDetails = array('host' => 'localhost', 'port' => 9800); + + $opts = array(); + $connectionParams['curlMultiHandle'] = curl_multi_init(); + $that = $this; + + $argsValidator = function($args) use ($that) { + $that->assertEquals($args[155], 5000); + $that->assertEquals($args[156], 5000); + + return true; + }; + + $log = m::mock('Psr\Log\LoggerInterface')->shouldReceive('debug')->with("Curl Options:", \Mockery::on($argsValidator))->getMock(); + $trace = m::mock('Psr\Log\LoggerInterface'); + + $connection = new Elasticsearch\Connections\CurlMultiConnection($hostDetails, $connectionParams, $log, $trace); + try{ + $ret = $connection->performRequest('GET', '/', null, null, array('timeout' => 5000)); + } catch (\Exception $e) { + + } + + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/GuzzleConnectionIntegrationTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/GuzzleConnectionIntegrationTest.php new file mode 100644 index 00000000..29d7c128 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/GuzzleConnectionIntegrationTest.php @@ -0,0 +1,167 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GuzzleConnectionIntegrationTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() + { + m::close(); + } + + + /** + * @expectedException Elasticsearch\Common\Exceptions\Curl\CouldNotResolveHostException + */ + public function test5xxErrorBadHost() + { + $hostDetails = array('host' => 'localhost5', 'port' => 9200); + + $connectionParams['guzzleClient'] = new Client(); + + $log = m::mock('\Monolog\Logger')->shouldReceive('error')->once()->getMock(); + + $connection = new GuzzleConnection($hostDetails, $connectionParams, $log, $log); + $ret = $connection->performRequest('GET', '/'); + + } + + + /** + * @expectedException Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost + */ + public function test5xxErrorBadPort() + { + $hostDetails = array('host' => 'localhost', 'port' => 9800); + $connectionParams['guzzleClient'] = new Client(); + $log = m::mock('\Monolog\Logger')->shouldReceive('error')->once()->getMock(); + + $connection = new GuzzleConnection($hostDetails, $connectionParams, $log, $log); + $ret = $connection->performRequest('GET', '/'); + + } + + + /** + * @group ignore + */ + public function test4xxErrorNonexistantEndpoint() + { + $hostDetails = array('host' => 'localhost', 'port' => 9200); + $connectionParams['guzzleClient'] = new Client(); + $log = m::mock('\Monolog\Logger') + ->shouldReceive('debug') + ->times(6)->getMock() + ->shouldReceive('info') + ->times(4)->getMock(); + + $connection = new GuzzleConnection($hostDetails, $connectionParams, $log, $log); + $ret = $connection->performRequest('GET', '/abc'); + + $this->assertEquals(400, $ret['status']); + + } + + /** + * @group ignore + */ + public function testQueryParams() + { + $hostDetails = array('host' => 'localhost', 'port' => 9200); + $connectionParams['guzzleClient'] = new Client(); + $log = m::mock('\Monolog\Logger') + ->shouldReceive('debug') + ->times(3)->getMock() + ->shouldReceive('info') + ->times(2)->getMock(); + + $connection = new GuzzleConnection($hostDetails, $connectionParams, $log, $log); + $params['pretty'] = 'true'; + + $ret = $connection->performRequest('GET', '/', $params); + + $this->assertEquals(200, $ret['status']); + + $expectedURI = 'http://localhost:9200/?pretty=true'; + $this->assertEquals($expectedURI, $ret['info']['url']); + + } + + /** + * @group ignore + */ + public function testQueryURI() + { + $hostDetails = array('host' => 'localhost', 'port' => 9200); + $connectionParams['guzzleClient'] = new Client(); + $log = m::mock('\Monolog\Logger') + ->shouldReceive('debug') + ->times(3)->getMock() + ->shouldReceive('info') + ->times(2)->getMock(); + + $connection = new GuzzleConnection($hostDetails, $connectionParams, $log, $log); + + $ret = $connection->performRequest('GET', '/_cluster/nodes/'); + + $expectedURI = 'http://localhost:9200/_cluster/nodes/'; + $this->assertEquals($expectedURI, $ret['info']['url']); + + } + + /** + * @group ignore + */ + public function test4xxErrorInvalidIndexAndQueryBody() + { + $hostDetails = array('host' => 'localhost', 'port' => 9200); + $connectionParams['guzzleClient'] = new Client(); + $log = m::mock('\Monolog\Logger') + ->shouldReceive('debug') + ->times(6)->getMock() + ->shouldReceive('info') + ->times(4)->getMock(); + + $connection = new GuzzleConnection($hostDetails, $connectionParams, $log, $log); + + $body = '{"testsetting":"123"}'; + + /* + The index _doesnotexist is used with an underscore + because ES won't create it...invalid. + */ + + $ret = $connection->performRequest('POST', '/_doesnotexist', null, $body); + + $this->assertEquals(400, $ret['status']); + + $expectedURI = 'http://localhost:9200/_doesnotexist'; + $this->assertEquals($expectedURI, $ret['info']['url']); + + // Best we can do to make sure the post actually posted. + $this->assertEquals(strlen(($body)), $ret['info']['size_upload']); + + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/GuzzleConnectionTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/GuzzleConnectionTest.php new file mode 100644 index 00000000..4630b100 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Connections/GuzzleConnectionTest.php @@ -0,0 +1,45 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GuzzleConnectionTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() + { + m::close(); + } + + /** + * @expectedException \Elasticsearch\Common\Exceptions\InvalidArgumentException + */ + public function testNoGuzzleClient() + { + $hostDetails = array('host' => 'localhost', 'port' => 9200); + $connectionParams = null; + + $log = m::mock('\Monolog\Logger')->shouldReceive('critical')->once()->getMock(); + + $connection = new GuzzleConnection($hostDetails, $connectionParams, $log, $log); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/AbstractEndpointTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/AbstractEndpointTest.php new file mode 100644 index 00000000..882b30a7 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/AbstractEndpointTest.php @@ -0,0 +1,249 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class AbstractEndpointTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testPerformRequest() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once()->once() + ->with( + 'GET', + '/testIndex/', + array(), + null + ) + ->getMock(); + + $stub = $this->getMockForAbstractClass('\Elasticsearch\Endpoints\AbstractEndpoint', array($mockTransport)); + + $stub->expects($this->once()) + ->method('getURI') + ->will($this->returnValue('/testIndex/')); + + $stub->expects($this->once()) + ->method('getMethod') + ->will($this->returnValue('GET')); + + $stub->performRequest(); + + } + + public function testSetOneParam() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $stub = $this->getMockForAbstractClass('\Elasticsearch\Endpoints\AbstractEndpoint', array($mockTransport)); + + $paramWhiteList = array( + 'param1', + 'param2', + 'param3' + ); + + $stub->expects($this->once()) + ->method('getParamWhitelist') + ->will($this->returnValue($paramWhiteList)); + + + $params = array('param1'=>'value'); + $stub->setParams($params); + + } + + public function testSetMultipleParam() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $stub = $this->getMockForAbstractClass('\Elasticsearch\Endpoints\AbstractEndpoint', array($mockTransport)); + + $paramWhiteList = array( + 'param1', + 'param2', + 'param3' + ); + + $stub->expects($this->once()) + ->method('getParamWhitelist') + ->will($this->returnValue($paramWhiteList)); + + $params = array( + 'param1' => 'value', + 'param2' => 'value', + 'param3' => 'value' + ); + $stub->setParams($params); + + } + + + /** + * @expectedException UnexpectedValueException + */ + public function testSetInvalidParam() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $stub = $this->getMockForAbstractClass('\Elasticsearch\Endpoints\AbstractEndpoint', array($mockTransport)); + + $paramWhiteList = array( + 'param1', + 'param2', + 'param3' + ); + + $stub->expects($this->once()) + ->method('getParamWhitelist') + ->will($this->returnValue($paramWhiteList)); + + $params = array('param10' => 'value'); + $stub->setParams($params); + + } + + public function testSetSortParam() + { + $params = array( + 'sort' => array( + 'field' => 'value2', + 'field2' => array( + 'field3' => 'value3' + ) + ), + 'param2' => 'value', + 'param3' => 'value' + ); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once()->once() + ->with( + 'GET', + '/testIndex/', + $params, + null + ) + ->getMock(); + + + $stub = $this->getMockForAbstractClass('\Elasticsearch\Endpoints\AbstractEndpoint', array($mockTransport)); + + $paramWhiteList = array( + 'sort', + 'param2', + 'param3' + ); + + $stub->expects($this->once()) + ->method('getParamWhitelist') + ->will($this->returnValue($paramWhiteList)); + + $stub->expects($this->once()) + ->method('getURI') + ->will($this->returnValue('/testIndex/')); + + $stub->expects($this->once()) + ->method('getMethod') + ->will($this->returnValue('GET')); + + /** @var AbstractEndpoint $stub */ + $stub->setParams($params); + try { + $stub->performRequest(); + } catch (Exception $e) { + // Don't care about errors, just want to validate params + // in mock Transport + } + } + + public function testSetSortParamWithImplodeList() + { + $params = array( + 'sort' => array( + 'field' => 'value2', + 'field2' => array( + 'field3' => 'value3' + ) + ), + 'param2' => array( + 'implode1', + 'implode2' + ), + 'param3' => 'value' + ); + + $expected = array( + 'sort' => array( + 'field' => 'value2', + 'field2' => array( + 'field3' => 'value3' + ) + ), + 'param2' => 'implode1,implode2', + 'param3' => 'value' + ); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once()->once() + ->with( + 'GET', + '/testIndex/', + $expected, + null + ) + ->getMock(); + + + $stub = $this->getMockForAbstractClass('\Elasticsearch\Endpoints\AbstractEndpoint', array($mockTransport)); + + $paramWhiteList = array( + 'sort', + 'param2', + 'param3' + ); + + $stub->expects($this->once()) + ->method('getParamWhitelist') + ->will($this->returnValue($paramWhiteList)); + + $stub->expects($this->once()) + ->method('getURI') + ->will($this->returnValue('/testIndex/')); + + $stub->expects($this->once()) + ->method('getMethod') + ->will($this->returnValue('GET')); + + /** @var AbstractEndpoint $stub */ + $stub->setParams($params); + try { + $stub->performRequest(); + } catch (Exception $e) { + // Don't care about errors, just want to validate params + // in mock Transport + } + } + +} diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/BulkTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/BulkTest.php new file mode 100644 index 00000000..d586be44 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/BulkTest.php @@ -0,0 +1,137 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class BulkTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testSetBody() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once()->once() + ->with( + m::any(), + m::any(), + array(), + 'bulk data' + ) + ->getMock(); + + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Bulk($mockTransport, $mockSerializer); + $action->setBody('bulk data') + ->performRequest(); + + } + + + public function testGetURIWithNoIndexOrType() + { + + $uri = '/_all/_bulk'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Bulk($mockTransport, $mockSerializer); + $action->performRequest(); + + } + + public function testGetURIWithIndexButNoType() + { + $uri = '/testIndex/_bulk'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Bulk($mockTransport, $mockSerializer); + $action->setIndex('testIndex') + ->performRequest(); + + } + + public function testGetURIWithTypeButNoIndex() + { + + $uri = '/_all/testType/_bulk'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Bulk($mockTransport, $mockSerializer); + $action->setType('testType') + ->performRequest(); + + } + + public function testGetURIWithBothTypeAndIndex() + { + + $uri = '/testIndex/testType/_bulk'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Bulk($mockTransport, $mockSerializer); + $action->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/HealthTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/HealthTest.php new file mode 100644 index 00000000..0d1db2b6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/HealthTest.php @@ -0,0 +1,67 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class HealthTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testGetURIWithNoIndex() + { + + $uri = '/_cluster/health'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + $uri, + array(), + null + ) + ->getMock(); + + $action = new Health($mockTransport); + $action->performRequest(); + + } + + public function testGetURIWithIndex() + { + $uri = '/_cluster/health/testIndex'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + $uri, + array(), + null + ) + ->getMock(); + + $action = new Health($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/HotThreadsTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/HotThreadsTest.php new file mode 100644 index 00000000..4b906bd6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/HotThreadsTest.php @@ -0,0 +1,78 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class HotThreadsTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testValidSettingsWithNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once()->once() + ->with( + 'GET', + '/_cluster/nodes/abc/hotthreads', + array(), + null + ) + ->getMock(); + + $action = new HotThreads($mockTransport); + $action->setNodeID('abc') + ->performRequest(); + + } + + + /** + * @expectedException InvalidArgumentException + */ + public function testValidSettingsWithInvalidNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new HotThreads($mockTransport); + + $nodeID = new \stdClass(); + + $action->setNodeID($nodeID);; + + } + + public function testValidSettingsWithoutNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_cluster/nodes/hotthreads', + array(), + null + ) + ->getMock(); + + $action = new HotThreads($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/InfoTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/InfoTest.php new file mode 100644 index 00000000..f58d1550 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/InfoTest.php @@ -0,0 +1,79 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class InfoTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testValidSettingsWithNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once()->once() + ->with( + 'GET', + '/_nodes/abc', + array(), + null + ) + ->getMock(); + + $action = new Info($mockTransport); + $action->setNodeID('abc') + ->performRequest(); + + } + + + /** + * @expectedException InvalidArgumentException + */ + public function testValidSettingsWithInvalidNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Info($mockTransport); + + $nodeID = new \stdClass(); + + $action->setNodeID($nodeID) + ->performRequest(); + + } + + public function testValidSettingsWithoutNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_nodes', + array(), + null + ) + ->getMock(); + + $action = new Info($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/ShutdownTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/ShutdownTest.php new file mode 100644 index 00000000..25a24d40 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Nodes/ShutdownTest.php @@ -0,0 +1,79 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class ShutdownTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testValidSettingsWithNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once()->once() + ->with( + 'POST', + '/_cluster/nodes/abc/_shutdown', + array(), + null + ) + ->getMock(); + + $action = new Shutdown($mockTransport); + $action->setNodeID('abc') + ->performRequest(); + + } + + + /** + * @expectedException InvalidArgumentException + */ + public function testValidSettingsWithInvalidNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Shutdown($mockTransport); + + $nodeID = new \stdClass(); + + $action->setNodeID($nodeID) + ->performRequest(); + + } + + public function testValidSettingsWithoutNodeID() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/_shutdown', + array(), + null + ) + ->getMock(); + + $action = new Shutdown($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/RerouteTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/RerouteTest.php new file mode 100644 index 00000000..fad7048e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/RerouteTest.php @@ -0,0 +1,64 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class RerouteTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testSetBody() + { + $query['docs'] = '1'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + m::any(), + array(), + $query + ) + ->getMock(); + + $action = new Reroute($mockTransport); + $action->setBody($query) + ->performRequest(); + + } + + public function testValidReroute() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/_cluster/reroute', + array(), + null + ) + ->getMock(); + + $action = new Reroute($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Settings/GetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Settings/GetTest.php new file mode 100644 index 00000000..ecda82f2 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Settings/GetTest.php @@ -0,0 +1,43 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GetTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidGet() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_cluster/settings', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Settings/PutTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Settings/PutTest.php new file mode 100644 index 00000000..592bf5f6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/Settings/PutTest.php @@ -0,0 +1,84 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class PutTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testPutBody() + { + $query['docs'] = '1'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + m::any(), + array(), + $query + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($query) + ->performRequest(); + + } + + public function testValidPutWithBody() + { + $Puttings = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/_cluster/settings', + array(), + $Puttings + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($Puttings) + ->performRequest(); + + } + + public function testValidPutWithoutBody() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/_cluster/settings', + array(), + null + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/StateTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/StateTest.php new file mode 100644 index 00000000..e22c8c77 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Cluster/StateTest.php @@ -0,0 +1,44 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class StateTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testValidState() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_cluster/state', + array(), + null + ) + ->getMock(); + + $action = new State($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/CountTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/CountTest.php new file mode 100644 index 00000000..e78ae5f8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/CountTest.php @@ -0,0 +1,129 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class CountTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testGetURIWithNoIndexOrType() + { + + $uri = '/_count'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $action = new Count($mockTransport); + $action->performRequest(); + + } + + public function testGetURIWithIndexButNoType() + { + $uri = '/testIndex/_count'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $action = new Count($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + public function testGetURIWithTypeButNoIndex() + { + + $uri = '/_all/testType/_count'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $action = new Count($mockTransport); + $action->setType('testType') + ->performRequest(); + + } + + public function testGetURIWithBothTypeAndIndex() + { + + $uri = '/testIndex/testType/_count'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $action = new Count($mockTransport); + $action->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } + + public function testValidCount() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/_count', + array(), + null + ) + ->getMock(); + + $action = new Count($mockTransport); + $action->setIndex('testIndex') + ->setType('testType') + ->setID('testID') + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/DeleteTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/DeleteTest.php new file mode 100644 index 00000000..068ce8af --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/DeleteTest.php @@ -0,0 +1,99 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class DeleteTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testNoIndexTypeOrID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $delete = new Delete($mockTransport); + $delete->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $delete = new Delete($mockTransport); + $delete->setType('testType')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $delete = new Delete($mockTransport); + $delete->setIndex('testIndex')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $delete = new Delete($mockTransport); + $delete->setType('testType')->setIndex('testIndex')->performRequest(); + + } + + public function testValidDelete() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'DELETE', + '/testIndex/testType/testID', + array(), + null + ) + ->getMock(); + + $delete = new Delete($mockTransport); + $delete->setIndex('testIndex') + ->setType('testType') + ->setID('testID') + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/ExplainTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/ExplainTest.php new file mode 100644 index 00000000..7d4d2a12 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/ExplainTest.php @@ -0,0 +1,99 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class ExplainTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testNoIndexTypeOrID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Explain($mockTransport); + $action->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Explain($mockTransport); + $action->setType('testType')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Explain($mockTransport); + $action->setIndex('testIndex')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Explain($mockTransport); + $action->setType('testType')->setIndex('testIndex')->performRequest(); + + } + + public function testValidExplain() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/testID/_explain', + array(), + null + ) + ->getMock(); + + $action = new Explain($mockTransport); + $action->setIndex('testIndex') + ->setType('testType') + ->setID('testID') + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/GetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/GetTest.php new file mode 100644 index 00000000..98080aa4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/GetTest.php @@ -0,0 +1,149 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GetTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testNoIndexTypeOrID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Get($mockTransport); + $index->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Get($mockTransport); + $index->setType('testType')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Get($mockTransport); + $index->setIndex('testIndex')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Get($mockTransport); + $index->setIndex('testIndex')->setType('testType')->performRequest(); + + } + + public function testValidGet() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/abc', + array(), + null + ) + ->getMock(); + + + + $index = new Get($mockTransport); + $index->setIndex('testIndex') + ->setType('testType') + ->setID('abc') + ->performRequest(); + + } + + public function testValidIndexWithSourceOnly() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/abc/_source', + array(), + null + ) + ->getMock(); + + + + $index = new Get($mockTransport); + $index->setIndex('testIndex') + ->setType('testType') + ->setID('abc') + ->returnOnlySource() + ->performRequest(); + + } + + public function testValidIndexWithExistenceOnly() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'HEAD', + '/testIndex/testType/abc', + array(), + null + ) + ->getMock(); + + + + $index = new Get($mockTransport); + $index->setIndex('testIndex') + ->setType('testType') + ->setID('abc') + ->checkOnlyExistance() + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/IndexTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/IndexTest.php new file mode 100644 index 00000000..6af07dd6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/IndexTest.php @@ -0,0 +1,180 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class IndexTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testNoIndexTypeOrID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Index($mockTransport); + $index->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Index($mockTransport); + $index->setType('testType')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Index($mockTransport); + $index->setIndex('testIndex')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoDocumentBody() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Index($mockTransport); + $index->setIndex('testIndex')->setType('testType')->performRequest(); + + } + + public function testValidIndexNoID() + { + $doc = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/testType', + array(), + $doc + ) + ->getMock(); + + + + $index = new Index($mockTransport); + $index->setIndex('testIndex') + ->setType('testType') + ->setBody($doc) + ->performRequest(); + + } + + public function testValidIndexWithID() + { + $doc = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/testType/abc', + array(), + $doc + ) + ->getMock(); + + + + $index = new Index($mockTransport); + $index->setIndex('testIndex') + ->setType('testType') + ->setID('abc') + ->setBody($doc) + ->performRequest(); + + } + + public function testValidIndexNoIDWithCreateIfAbsent() + { + $doc = array('field' => 'value'); + $params = array('op_type' => 'create'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/testType', + $params, + $doc + ) + ->getMock(); + + + + $index = new Index($mockTransport); + $index->setIndex('testIndex') + ->setType('testType') + ->setBody($doc) + ->createIfAbsent() + ->performRequest(); + + } + + public function testValidIndexWithIDWithCreateIfAbsent() + { + $doc = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/testType/abc/_create', + array(), + $doc + ) + ->getMock(); + + + + $index = new Index($mockTransport); + $index->setIndex('testIndex') + ->setType('testType') + ->setID('abc') + ->setBody($doc) + ->createIfAbsent() + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/AliasesTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/AliasesTest.php new file mode 100644 index 00000000..cb3b5b32 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/AliasesTest.php @@ -0,0 +1,84 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class AliasesTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testSetArrayBody() + { + $body = array('field' => 'value'); + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/_aliases', + array(), + $body + ) + ->getMock(); + + $action = new Update($mockTransport); + $action->setBody($body)->performRequest(); + + } + + public function testValidAliasesWithoutIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_aliases', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->performRequest(); + + } + + public function testValidAliasesWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_aliases', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/DeleteTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/DeleteTest.php new file mode 100644 index 00000000..0439adef --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/DeleteTest.php @@ -0,0 +1,85 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class DeleteTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testNoIndexOrName() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Delete($mockTransport); + $action->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Delete($mockTransport); + $action->setName('testName')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoName() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Delete($mockTransport); + $action->setIndex('testIndex')->performRequest(); + + } + + public function testValidDelete() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'DELETE', + '/testIndex/_alias/testName', + array(), + null + ) + ->getMock(); + + $action = new Delete($mockTransport); + $action->setIndex('testIndex')->setName('testName') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/GetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/GetTest.php new file mode 100644 index 00000000..250b04b8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/GetTest.php @@ -0,0 +1,101 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class GetTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testNoIndexOrName() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_alias', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->performRequest(); + + } + + + public function testNoName() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_alias', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->performRequest(); + + } + + public function testValidGetWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_alias/testName', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->setName('testName') + ->performRequest(); + + } + + public function testValidGetWithoutIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_alias/testName', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setName('testName') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/PutTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/PutTest.php new file mode 100644 index 00000000..4f7f9d6f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Alias/PutTest.php @@ -0,0 +1,113 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class PutTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testSetArrayBody() + { + $body = array('field' => 'value'); + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/_alias/testName', + array(), + $body + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($body)->setIndex('testIndex')->setName('testName')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoBody() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + $action = new Put($mockTransport); + $action->performRequest(); + } + + + public function testNoIndex() + { + $body = array('field' => 'value'); + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/_alias/testName', + array(), + $body + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($body)->setName('testName')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoName() + { + $body = array('field' => 'value'); + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Put($mockTransport); + $action->setBody($body)->setIndex('testIndex') + ->performRequest(); + + } + + + public function testValidPutWithIndexBodyAndName() + { + $body = array('field' => 'value'); + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/_alias/testName', + array(), + $body + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($body)->setIndex('testIndex')->setName('testName') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/AnalyzeTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/AnalyzeTest.php new file mode 100644 index 00000000..c61d759e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/AnalyzeTest.php @@ -0,0 +1,89 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class AnalyzeTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testSetBody() + { + $body = 'abc'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + m::any(), + array(), + $body + ) + ->getMock(); + + $action = new Analyze($mockTransport); + $action->setBody($body) + ->performRequest(); + + } + + public function testGetURIWithNoIndex() + { + + $uri = '/_analyze'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + $uri, + array(), + m::any() + ) + ->getMock(); + + $action = new Analyze($mockTransport); + $action->performRequest(); + + } + + public function testGetURIWithIndex() + { + $uri = '/testIndex/_analyze'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + $uri, + array(), + m::any() + ) + ->getMock(); + + $action = new Analyze($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Cache/ClearTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Cache/ClearTest.php new file mode 100644 index 00000000..1b5b9b72 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Cache/ClearTest.php @@ -0,0 +1,65 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class ClearTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidSegmentsWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/_cache/clear', + array(), + null + ) + ->getMock(); + + $action = new Clear($mockTransport); + $action->performRequest(); + + } + + public function testValidSegmentsWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/_cache/clear', + array(), + null + ) + ->getMock(); + + $action = new Clear($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/CloseTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/CloseTest.php new file mode 100644 index 00000000..bbe55d07 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/CloseTest.php @@ -0,0 +1,62 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class CloseTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Close($mockTransport); + $action->performRequest(); + + } + + public function testValidClose() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/_close', + array(), + null + ) + ->getMock(); + + + + $action = new Close($mockTransport); + $action->setIndex('testIndex') + + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/CreateTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/CreateTest.php new file mode 100644 index 00000000..b093bcb8 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/CreateTest.php @@ -0,0 +1,118 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class CreateTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testSetBody() + { + $body = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport');; + + $action = new Create($mockTransport); + $action->setBody($body);; + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Create($mockTransport); + $action->performRequest(); + + } + + public function testValidCreateNoBody() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/', + array(), + null + ) + ->getMock(); + + $action = new Create($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + public function testValidCreateWithBodyNoMappings() + { + + $body = array('settings' => 'values'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/', + array(), + $body + ) + ->getMock(); + + $action = new Create($mockTransport); + $action->setIndex('testIndex') + ->setBody($body) + ->performRequest(); + + } + + public function testValidCreateWithBodyWithMappings() + { + + $body = array( + 'settings' => 'values', + 'mappings' => 'values' + ); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/', + array(), + $body + ) + ->getMock(); + + $action = new Create($mockTransport); + $action->setIndex('testIndex') + ->setBody($body) + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/DeleteTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/DeleteTest.php new file mode 100644 index 00000000..3566f9bf --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/DeleteTest.php @@ -0,0 +1,64 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class DeleteTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidDeleteWithNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'DELETE', + '/', + array(), + null + ) + ->getMock(); + + $action = new Delete($mockTransport); + $action->performRequest(); + + } + + public function testValidDeleteWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'DELETE', + '/testIndex', + array(), + null + ) + ->getMock(); + + $action = new Delete($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Exists/IndicesTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Exists/IndicesTest.php new file mode 100644 index 00000000..1ba85c51 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Exists/IndicesTest.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class IndicesTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Exists($mockTransport); + $index->performRequest(); + + } + + public function testValidIndicesExists() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'HEAD', + '/testIndex', + array(), + null + ) + ->getMock(); + + $action = new Exists($mockTransport); + $action->setIndex('testIndex')->performRequest(); + + } + + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Exists/TypesTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Exists/TypesTest.php new file mode 100644 index 00000000..18e1c600 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Exists/TypesTest.php @@ -0,0 +1,87 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class TypesTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndexNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Types($mockTransport); + $index->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Types($mockTransport); + $index->setType('testType')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Types($mockTransport); + $index->setIndex('testIndex')->performRequest(); + + } + + + public function testValidTypesExists() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'HEAD', + '/testIndex/testType', + array(), + null + ) + ->getMock(); + + $action = new Types($mockTransport); + $action->setIndex('testIndex')->setType('testType')->performRequest(); + + } + + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/FlushTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/FlushTest.php new file mode 100644 index 00000000..e6c71acb --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/FlushTest.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class FlushTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidFlushWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_flush', + array(), + null + ) + ->getMock(); + + $action = new Flush($mockTransport); + $action->performRequest(); + + } + + public function testValidFlushWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_flush', + array(), + null + ) + ->getMock(); + + $action = new Flush($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Gateway/SnapshotTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Gateway/SnapshotTest.php new file mode 100644 index 00000000..8952b5f0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Gateway/SnapshotTest.php @@ -0,0 +1,64 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class SnapshotTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidSnapshotWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/_gateway/snapshot', + array(), + null + ) + ->getMock(); + + $action = new Snapshot($mockTransport); + $action->performRequest(); + + } + + public function testValidSnapshotWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/_gateway/snapshot', + array(), + null + ) + ->getMock(); + + $action = new Snapshot($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/DeleteTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/DeleteTest.php new file mode 100644 index 00000000..bdce1f66 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/DeleteTest.php @@ -0,0 +1,86 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class DeleteTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndexOrType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Delete($mockTransport); + $index->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Delete($mockTransport); + $index->setType('testType')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Delete($mockTransport); + $index->setIndex('testIndex')->performRequest(); + + } + + public function testValidDeleteWith() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'DELETE', + '/testIndex/testType/_mapping', + array(), + null + ) + ->getMock(); + + $action = new Delete($mockTransport); + $action->setIndex('testIndex')->setType('testType') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/GetFieldTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/GetFieldTest.php new file mode 100644 index 00000000..0da22fc5 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/GetFieldTest.php @@ -0,0 +1,127 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GetFieldTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidGetWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_mapping/field/test', + array(), + null + ) + ->getMock(); + + $action = new GetField($mockTransport); + $action->setIndex('testIndex') + ->setField('test') + ->performRequest(); + + } + + public function testValidGetWithType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_all/testType/_mapping/field/test', + array(), + null + ) + ->getMock(); + + $action = new GetField($mockTransport); + $action->setType('testType') + ->setField('test') + ->performRequest(); + + } + + public function testValidGetWithNoIndexOrType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_all/_mapping/field/test', + array(), + null + ) + ->getMock(); + + $action = new GetField($mockTransport); + $action->setField('test') + ->performRequest(); + + } + + public function testValidGetWithIndexAndType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/_mapping/field/test', + array(), + null + ) + ->getMock(); + + $action = new GetField($mockTransport); + $action->setIndex('testIndex') + ->setType('testType') + ->setField('test') + ->performRequest(); + + } + + + /** + * @expectedException \Elasticsearch\Common\Exceptions\RuntimeException + */ + public function testNoField() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->never() + ->getMock(); + + $action = new GetField($mockTransport); + $action->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/GetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/GetTest.php new file mode 100644 index 00000000..66f33412 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/GetTest.php @@ -0,0 +1,104 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GetTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidGetWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_mapping', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + public function testValidGetWithType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_mapping/testType', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setType('testType') + ->performRequest(); + + } + + public function testValidGetWithNoIndexOrType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_mapping', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->performRequest(); + + } + + public function testValidGetWithIndexAndType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_mapping/testType', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->setType('testType') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/PutTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/PutTest.php new file mode 100644 index 00000000..ea76e746 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Mapping/PutTest.php @@ -0,0 +1,78 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class PutTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Put($mockTransport); + $index->setIndex('testIndex')->setBody(array())->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoBody() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Put($mockTransport); + $index->setIndex('testType')->setType('testType')->performRequest(); + + } + + + public function testValidPutWithIndexTypeAndBody() + { + + $body = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/testType/_mapping', + array(), + $body + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setIndex('testIndex')->setType('testType')->setBody($body) + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/OpenTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/OpenTest.php new file mode 100644 index 00000000..a60a3ec4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/OpenTest.php @@ -0,0 +1,62 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class OpenTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Open($mockTransport); + $action->performRequest(); + + } + + public function testValidOpen() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/_open', + array(), + null + ) + ->getMock(); + + + + $action = new Open($mockTransport); + $action->setIndex('testIndex') + + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/OptimizeTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/OptimizeTest.php new file mode 100644 index 00000000..1dc2bd9e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/OptimizeTest.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class OptimizeTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidOptimizeWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/_optimize', + array(), + null + ) + ->getMock(); + + $action = new Optimize($mockTransport); + $action->performRequest(); + + } + + public function testValidOptimizeWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/_optimize', + array(), + null + ) + ->getMock(); + + $action = new Optimize($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/RefreshTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/RefreshTest.php new file mode 100644 index 00000000..4bb36590 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/RefreshTest.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class RefreshTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidRefreshWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_refresh', + array(), + null + ) + ->getMock(); + + $action = new Refresh($mockTransport); + $action->performRequest(); + + } + + public function testValidRefreshWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_refresh', + array(), + null + ) + ->getMock(); + + $action = new Refresh($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/SegmentsTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/SegmentsTest.php new file mode 100644 index 00000000..6e78aae4 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/SegmentsTest.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class SegmentsTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidSegmentsWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_segments', + array(), + null + ) + ->getMock(); + + $action = new Segments($mockTransport); + $action->performRequest(); + + } + + public function testValidSegmentsWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_segments', + array(), + null + ) + ->getMock(); + + $action = new Segments($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Settings/GetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Settings/GetTest.php new file mode 100644 index 00000000..882bc46d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Settings/GetTest.php @@ -0,0 +1,64 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GetTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidSegmentsWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_settings', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->performRequest(); + + } + + public function testValidSegmentsWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_settings', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Settings/PutTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Settings/PutTest.php new file mode 100644 index 00000000..e9e0271a --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Settings/PutTest.php @@ -0,0 +1,86 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class PutTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testSetBody() + { + $query['docs'] = '1'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + m::any(), + array(), + $query + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($query) + ->performRequest(); + + } + + public function testValidSegmentsWithNoIndex() + { + $body['docs'] = '1'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/_settings', + array(), + array('docs' => 1) + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($body)->performRequest(); + + } + + public function testValidSegmentsWithIndex() + { + $body['docs'] = '1'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/_settings', + array(), + array('docs' => 1) + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setBody($body)->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/StatusTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/StatusTest.php new file mode 100644 index 00000000..865dd541 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/StatusTest.php @@ -0,0 +1,63 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class StatusTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidStatusWithNoIndex() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_status', + array(), + null + ) + ->getMock(); + + $action = new Status($mockTransport); + $action->performRequest(); + + } + + public function testValidStatusWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_status', + array(), + null + ) + ->getMock(); + + $action = new Status($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/DeleteTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/DeleteTest.php new file mode 100644 index 00000000..b01b550f --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/DeleteTest.php @@ -0,0 +1,60 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class DeleteTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Delete($mockTransport); + $action->performRequest(); + + } + + public function testValidDelete() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'DELETE', + '/_template/testName', + array(), + null + ) + ->getMock(); + + $action = new Delete($mockTransport); + $action->setIndex('testIndex')->setName('testName') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/GetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/GetTest.php new file mode 100644 index 00000000..69554834 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/GetTest.php @@ -0,0 +1,67 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GetTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testValidGetNoName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_template/', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + public function testValidGet() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_template/testName', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->setName('testName') + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/PutTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/PutTest.php new file mode 100644 index 00000000..22da1238 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Template/PutTest.php @@ -0,0 +1,88 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class PutTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoNameNoBody() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Put($mockTransport); + $action->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoBody() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Put($mockTransport); + $index->setName('testName')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $index = new Put($mockTransport); + $index->setBody(array())->performRequest(); + + } + + public function testValidPut() + { + $body = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/_template/testName', + array(), + $body + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setIndex('testIndex')->setName('testName')->setBody($body) + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Validate/QueryTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Validate/QueryTest.php new file mode 100644 index 00000000..4cbb6eda --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Validate/QueryTest.php @@ -0,0 +1,123 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class QueryTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + public function testValidQueryWithNoIndexNoType() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_all/_validate/query', + array(), + null + ) + ->getMock(); + + $action = new Query($mockTransport); + $action->performRequest(); + + } + + public function testValidQueryWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_validate/query', + array(), + null + ) + ->getMock(); + + $action = new Query($mockTransport); + $action->setIndex('testIndex') + ->performRequest(); + + } + + public function testValidQueryWithType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_all/testType/_validate/query', + array(), + null + ) + ->getMock(); + + $action = new Query($mockTransport); + $action->setType('testType') + ->performRequest(); + + } + + public function testValidQueryWithIndexAndType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/_validate/query', + array(), + null + ) + ->getMock(); + + $action = new Query($mockTransport); + $action->setIndex('testIndex')->setType('testType') + ->performRequest(); + + } + + public function testValidQueryWithBody() + { + + $body = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_all/_validate/query', + array(), + $body + ) + ->getMock(); + + $action = new Query($mockTransport); + $action->setBody($body) + ->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/DeleteTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/DeleteTest.php new file mode 100644 index 00000000..364a2878 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/DeleteTest.php @@ -0,0 +1,86 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class DeleteTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testDeleteNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Delete($mockTransport); + $action->performRequest(); + + } + + + /** + * @expectedException RuntimeException + */ + public function testDeleteWithOnlyIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Delete($mockTransport); + $action->setIndex('testIndex')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testDeleteWithOnlyName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Delete($mockTransport); + $action->setName('testName')->performRequest(); + + } + public function testDeleteWithIndexAndName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'DELETE', + '/testIndex/_warmer/testName', + array(), + null + ) + ->getMock(); + + $action = new Delete($mockTransport); + $action->setIndex('testIndex')->setName('testName')->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/GetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/GetTest.php new file mode 100644 index 00000000..a2c65529 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/GetTest.php @@ -0,0 +1,115 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class GetTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testGetNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/_warmer', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->performRequest(); + + } + + public function testGetWithIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_warmer', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->performRequest(); + + } + + + /** + * @expectedException RuntimeException + */ + public function testGetWithIndexAndType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->setType('testType')->performRequest(); + + } + + public function testGetWithIndexAndName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_warmer/testName', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->setName('testName')->performRequest(); + + } + + public function testGetWithIndexTypeAndName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/_warmer/testName', + array(), + null + ) + ->getMock(); + + $action = new Get($mockTransport); + $action->setIndex('testIndex')->setType('testType')->setName('testName')->performRequest(); + + } + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/PutTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/PutTest.php new file mode 100644 index 00000000..51db91b0 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/Indices/Warmer/PutTest.php @@ -0,0 +1,113 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class PutTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testPutNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/_warmer/testName', + array(), + null + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setName('testName')->setBody(array())->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testPutNoBody() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Put($mockTransport); + $action->setIndex('testIndex')->setName('testName')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testPutNoName() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Put($mockTransport); + $action->setIndex('testIndex')->setBody(array())->performRequest(); + + } + + + + public function testPutWithIndexNameAndBody() + { + $body = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/_warmer/testName', + array(), + $body + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setIndex('testIndex')->setName('testName')->setBody($body)->performRequest(); + + } + + public function testPutWithIndexTypeNameAndBody() + { + $body = array('field' => 'value'); + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'PUT', + '/testIndex/testType/_warmer/testName', + array(), + $body + ) + ->getMock(); + + $action = new Put($mockTransport); + $action->setIndex('testIndex')->setName('testName')->setBody($body)->setType('testType')->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/InfoTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/InfoTest.php new file mode 100644 index 00000000..eef24760 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/InfoTest.php @@ -0,0 +1,43 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class InfoTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + public function testValidInfo() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/', + array(), + null + ) + ->getMock(); + + $action = new Info($mockTransport); + $action->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MgetTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MgetTest.php new file mode 100644 index 00000000..619420e6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MgetTest.php @@ -0,0 +1,132 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class MgetTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testSetBody() + { + $body['docs'] = '1'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + m::any(), + array(), + $body + ) + ->getMock(); + + $action = new Mget($mockTransport); + $action->setBody($body) + ->performRequest(); + + } + + + public function testGetURIWithNoIndexOrType() + { + + $uri = '/_mget'; + $body['docs'] = '1'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $action = new Mget($mockTransport); + $action->setBody($body)->performRequest(); + + } + + public function testGetURIWithIndexButNoType() + { + $uri = '/testIndex/_mget'; + $body['docs'] = '1'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $action = new Mget($mockTransport); + $action->setBody($body)->setIndex('testIndex') + ->performRequest(); + + } + + public function testGetURIWithTypeButNoIndex() + { + + $uri = '/_all/testType/_mget'; + $body['docs'] = '1'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $action = new Mget($mockTransport); + $action->setBody($body)->setType('testType') + ->performRequest(); + + } + + public function testGetURIWithBothTypeAndIndex() + { + + $uri = '/testIndex/testType/_mget'; + $body['docs'] = '1'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $action = new Mget($mockTransport); + $action->setBody($body)->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MltTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MltTest.php new file mode 100644 index 00000000..9250c733 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MltTest.php @@ -0,0 +1,101 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class MltTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testNoIndexTypeOrID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Mlt($mockTransport); + $action->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Mlt($mockTransport); + $action->setType('testType')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Mlt($mockTransport); + $action->setIndex('testIndex')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Mlt($mockTransport); + $action->setType('testType')->setIndex('testIndex')->performRequest(); + + } + + public function testValidMlt() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/testID/_mlt', + array(), + null + ) + ->getMock(); + + $action = new Mlt($mockTransport); + $action->setIndex('testIndex') + ->setType('testType') + ->setID('testID') + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MsearchTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MsearchTest.php new file mode 100644 index 00000000..96a993ec --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/MsearchTest.php @@ -0,0 +1,188 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class MsearchTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testGetURIWithNoIndexTypeOrBody() + { + $mockTransport = m::mock('\Elasticsearch\Transport'); + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Msearch($mockTransport, $mockSerializer); + $action->performRequest(); + + } + + public function testGetURIWithNoIndexOrType() + { + + $uri = '/_msearch'; + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Msearch($mockTransport, $mockSerializer); + $action->setBody($body)->performRequest(); + + } + + public function testGetURIWithIndexButNoType() + { + $uri = '/testIndex/_msearch'; + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Msearch($mockTransport, $mockSerializer); + $action->setBody($body)->setIndex('testIndex') + ->performRequest(); + + } + + public function testGetURIWithTypeButNoIndex() + { + + $uri = '/_all/testType/_msearch'; + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Msearch($mockTransport, $mockSerializer); + $action->setBody($body)->setType('testType') + ->performRequest(); + + } + + public function testGetURIWithBothTypeAndIndex() + { + + $uri = '/testIndex/testType/_msearch'; + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Msearch($mockTransport, $mockSerializer); + $action->setBody($body)->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } + + + public function testValidMsearch() + { + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/_msearch', + array(), + $body + ) + ->getMock(); + + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer'); + + $action = new Msearch($mockTransport, $mockSerializer); + $action->setBody($body)->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } + + public function testSerializeArrayBody() + { + $uri = '/_msearch'; + $body = array(array('query'=>array('match_all' => array())),array('query'=>array('match_all' => array()))); + $serializedBody = json_encode($body[0])."\n".json_encode($body[1])."\n"; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $serializedBody + ) + ->getMock(); + + $mockSerializer = m::mock('\Elasticsearch\Serializers\ArrayToJSONSerializer') + ->shouldReceive('serialize') + ->once() + ->with($body[0]) + ->andReturn(json_encode($body[0])) + ->getMock() + ->shouldReceive('serialize') + ->once() + ->with($body[1]) + ->andReturn(json_encode($body[1])) + ->getMock(); + + $action = new Msearch($mockTransport, $mockSerializer); + $action->setBody($body)->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/PercolateTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/PercolateTest.php new file mode 100644 index 00000000..cdc0394b --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/PercolateTest.php @@ -0,0 +1,72 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class PercolateTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Percolate($mockTransport); + $action->setType('testType')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Percolate($mockTransport); + $action->setIndex('testIndex')->setID('testID')->performRequest(); + + } + + public function testValidPercolate() + { + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/testType/_percolate', + array(), + $body + ) + ->getMock(); + + $action = new Percolate($mockTransport); + $action->setBody($body)->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/ScrollTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/ScrollTest.php new file mode 100644 index 00000000..5473805c --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/ScrollTest.php @@ -0,0 +1,87 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://Elasticsearch.org + */ +class ScrollTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testSetStringBody() + { + $body = 'scrollid'; + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Scroll($mockTransport); + $action->setBody($body); + + + } + + + public function testWithBodyNoScrollID() + { + $body = 'scrollID'; + $uri = '/_search/scroll'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + $uri, + array(), + $body + ) + ->getMock(); + + + + $action = new Scroll($mockTransport); + $action->setBody($body) + ->performRequest(); + + } + + public function testWithBodyAndScrollID() + { + $body = 'scrollID'; + $uri = "/_search/scroll/$body"; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + $uri, + array(), + $body + ) + ->getMock(); + + + + $action = new Scroll($mockTransport); + $action->setBody($body)->setScrollID($body) + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/SearchTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/SearchTest.php new file mode 100644 index 00000000..0b4f4080 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/SearchTest.php @@ -0,0 +1,152 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class SearchTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() { + m::close(); + } + + public function testSetStringBody() + { + $body = 'testQuery'; + $uri = '/_search'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $search = new Search($mockTransport); + $search->setBody($body) + ->performRequest(); + + } + + public function testSetArrayQuery() + { + $query['query'] = 'testQuery'; + $uri = '/_search'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $query + ) + ->getMock(); + + $search = new Search($mockTransport); + $search->setBody($query) + ->performRequest(); + + } + + + public function testGetURIWithNoIndexOrType() + { + + $uri = '/_search'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $search = new Search($mockTransport); + $search->performRequest(); + + } + + public function testGetURIWithIndexButNoType() + { + $uri = '/testIndex/_search'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $search = new Search($mockTransport); + $search->setIndex('testIndex') + ->performRequest(); + + } + + public function testGetURIWithTypeButNoIndex() + { + + $uri = '/_all/testType/_search'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $search = new Search($mockTransport); + $search->setType('testType') + ->performRequest(); + + } + + public function testGetURIWithBothTypeAndIndex() + { + + $uri = '/testIndex/testType/_search'; + + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + m::any() + ) + ->getMock(); + + $search = new Search($mockTransport); + $search->setIndex('testIndex') + ->setType('testType') + ->performRequest(); + + } + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/SuggestTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/SuggestTest.php new file mode 100644 index 00000000..d2ee64e1 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/SuggestTest.php @@ -0,0 +1,79 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class SuggestTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testGetURIWithNoIndexOrBody() + { + $mockTransport = m::mock('\Elasticsearch\Transport');; + + $action = new Suggest($mockTransport); + $action->performRequest(); + + } + + public function testGetURIWithNoIndex() + { + + $uri = '/_suggest'; + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + m::any(), + $uri, + array(), + $body + ) + ->getMock(); + + $action = new Suggest($mockTransport); + $action->setBody($body)->performRequest(); + + } + + public function testValidSuggest() + { + $body = 'abc'; + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'GET', + '/testIndex/_suggest', + array(), + $body + ) + ->getMock(); + + $action = new Suggest($mockTransport); + $action->setBody($body)->setIndex('testIndex') + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/UpdateTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/UpdateTest.php new file mode 100644 index 00000000..462b116e --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Endpoints/UpdateTest.php @@ -0,0 +1,99 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class UpdateTest extends \PHPUnit_Framework_TestCase +{ + public function tearDown() { + m::close(); + } + + + /** + * @expectedException RuntimeException + */ + public function testNoIndexTypeOrID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Update($mockTransport); + $action->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoIndex() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Update($mockTransport); + $action->setType('testType')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoType() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Update($mockTransport); + $action->setIndex('testIndex')->setID('testID')->performRequest(); + + } + + /** + * @expectedException RuntimeException + */ + public function testNoID() + { + + $mockTransport = m::mock('\Elasticsearch\Transport'); + + $action = new Update($mockTransport); + $action->setType('testType')->setIndex('testIndex')->performRequest(); + + } + + public function testValidUpdate() + { + $mockTransport = m::mock('\Elasticsearch\Transport') + ->shouldReceive('performRequest')->once() + ->with( + 'POST', + '/testIndex/testType/testID/_update', + array(), + null + ) + ->getMock(); + + $action = new Update($mockTransport); + $action->setIndex('testIndex') + ->setType('testType') + ->setID('testID') + ->performRequest(); + + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Serializers/ArrayToJSONSerializerTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Serializers/ArrayToJSONSerializerTest.php new file mode 100644 index 00000000..02e5ddd5 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Serializers/ArrayToJSONSerializerTest.php @@ -0,0 +1,56 @@ + 'field'); + + $ret = $serializer->serialize($body); + + $body = json_encode($body); + $this->assertEquals($body, $ret); + } + + public function testSerializeString() + { + $serializer = new ArrayToJSONSerializer(); + $body = 'abc'; + + $ret = $serializer->serialize($body); + + $this->assertEquals($body, $ret); + } + + public function testDeserializeJSON() + { + $serializer = new ArrayToJSONSerializer(); + $body = '{"field":"value"}'; + + $ret = $serializer->deserialize($body, array()); + + $body = json_decode($body, true); + $this->assertEquals($body, $ret); + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Serializers/EverythingToJSONSerializerTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Serializers/EverythingToJSONSerializerTest.php new file mode 100644 index 00000000..31b0a2bf --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/Serializers/EverythingToJSONSerializerTest.php @@ -0,0 +1,57 @@ + 'field'); + + $ret = $serializer->serialize($body); + + $body = json_encode($body); + $this->assertEquals($body, $ret); + } + + public function testSerializeString() + { + $serializer = new EverythingToJSONSerializer(); + $body = 'abc'; + + $ret = $serializer->serialize($body); + + $body = '"abc"'; + $this->assertEquals($body, $ret); + } + + public function testDeserializeJSON() + { + $serializer = new EverythingToJSONSerializer(); + $body = '{"field":"value"}'; + + $ret = $serializer->deserialize($body, array()); + + $body = json_decode($body, true); + $this->assertEquals($body, $ret); + } +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/TransportTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/TransportTest.php new file mode 100644 index 00000000..8053d1d6 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/TransportTest.php @@ -0,0 +1,482 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class TransportTest extends \PHPUnit_Framework_TestCase +{ + + public function tearDown() + { + m::close(); + } + + + /** + * Test string constructors + * + * @expectedException \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @expectedExceptionMessage Hosts parameter must be an array + * + * @covers \Elasticsearch\Transport::__construct + * @return void + */ + public function testStringConstructor() + { + $hosts = 'arbitrary string'; + $params = 'arbitrary string'; + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + $transport = new Elasticsearch\Transport($hosts, $params, $log); + + }//end testStringConstructor() + + + public function testSniffOnStart() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->once()->getMock(); + + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface'); + + $mockConnection = m::mock('\Elasticsearch\Connections\ConnectionInterface'); + $mockConnectionFxn = function($host, $port = null) use ($mockConnection) { + return $mockConnection; + }; + + // Eww... + $params = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(true)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 0)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(1)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $params, $log); + } + + public function testSetRetries() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->once()->getMock(); + + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface'); + + $mockConnection = m::mock('\Elasticsearch\Connections\ConnectionInterface'); + $mockConnectionFxn = function($host, $port = null) use ($mockConnection) { + return $mockConnection; + }; + + // Eww... + $params = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(true)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(true)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(2)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $params, $log); + } + + public function testNoSniffOnStart() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->never()->getMock(); + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface'); + + $mockConnection = m::mock('\Elasticsearch\Connections\ConnectionInterface'); + $mockConnectionFxn = function($host, $port=null) use ($mockConnection) { + return $mockConnection; + }; + + // Eww... + $params = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(false)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 0)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(1)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $params, $log); + } + + public function testMixedHosts() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost'), array('host' => 'localhost', 'port' => 9200)); + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->never()->getMock(); + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface'); + + $mockConnection = m::mock('\Elasticsearch\Connections\ConnectionInterface'); + $mockConnectionFxn = function($host, $port=null) use ($mockConnection) { + return $mockConnection; + }; + + // Eww... + $params = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(false)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 1)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(2)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $params, $log); + } + + public function testPerformRequestNoBody() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + $method = 'GET'; + $uri = '/'; + $params = null; + $body = null; + $response = array( + 'text' => 'texty text', + 'status' => '200', + 'info' => array() + ); + + $mockConnection = m::mock('\Elasticsearch\Connections\AbstractConnection') + ->shouldReceive('performRequest')->once()->with($method, $uri, $params, $body)->andReturn($response)->getMock() + ->shouldReceive('markAlive')->once()->getMock(); + + $mockConnectionFxn = function($host, $port=null) use ($mockConnection) { + return $mockConnection; + }; + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->never()->getMock() + ->shouldReceive('nextConnection')->andReturn($mockConnection)->getMock(); + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface') + ->shouldReceive('deserialize')->with($response['text'], array())->andReturn('out')->getMock(); + + + + // Eww... + $pimple = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(false)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 0)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(1)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $pimple, $log); + $ret = $transport->performRequest($method, $uri, $params, $body); + + $expected = array( + 'status' => $response['status'], + 'data' => 'out', + 'info' => $response['info'] + ); + + $this->assertEquals($expected, $ret); + + } + + public function testPerformRequestWithBody() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + $method = 'GET'; + $uri = '/'; + $params = null; + $body = array('field' => 'value'); + $response = array( + 'text' => 'texty text', + 'status' => '200', + 'info' => array() + ); + $serializedBody = 'out_serialized'; + + + $mockConnection = m::mock('\Elasticsearch\Connections\AbstractConnection') + ->shouldReceive('performRequest')->once()->with($method, $uri, $params, $serializedBody)->andReturn($response)->getMock() + ->shouldReceive('markAlive')->once()->getMock(); + + $mockConnectionFxn = function($host, $port=null) use ($mockConnection) { + return $mockConnection; + }; + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->never()->getMock() + ->shouldReceive('nextConnection')->andReturn($mockConnection)->getMock(); + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface') + ->shouldReceive('serialize')->with($body)->andReturn($serializedBody)->getMock() + ->shouldReceive('deserialize')->with($response['text'], array())->andReturn('out_deserialize')->getMock(); + + + + // Eww... + $pimple = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(false)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 0)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(1)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $pimple, $log); + $ret = $transport->performRequest($method, $uri, $params, $body); + + $expected = array( + 'status' => $response['status'], + 'data' => 'out_deserialize', + 'info' => $response['info'] + ); + + $this->assertEquals($expected, $ret); + } + + public function testPerformRequestTimeout() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + $method = 'GET'; + $uri = '/'; + $params = null; + $body = null; + $response = array( + 'text' => 'texty text', + 'status' => '200', + 'info' => array() + ); + + $mockConnection = m::mock('\Elasticsearch\Connections\AbstractConnection') + ->shouldReceive('performRequest')->once()->with($method, $uri, $params, $body)->andThrow(new Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException())->getMock() + ->shouldReceive('performRequest')->once()->with($method, $uri, $params, $body)->andReturn($response)->getMock() + ->shouldReceive('markAlive')->once()->getMock(); + + $mockConnectionFxn = function($host, $port=null) use ($mockConnection) { + return $mockConnection; + }; + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->once()->getMock() + ->shouldReceive('nextConnection')->twice()->andReturn($mockConnection)->getMock(); + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface') + ->shouldReceive('deserialize')->with($response['text'], array())->andReturn('out')->getMock(); + + + + // Eww... + $pimple = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(false)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 0)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(1)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $pimple, $log); + $ret = $transport->performRequest($method, $uri, $params, $body); + + $expected = array( + 'status' => $response['status'], + 'data' => 'out', + 'info' => $response['info'] + ); + + $this->assertEquals($expected, $ret); + } + + + /** + * @expectedException \Elasticsearch\Common\Exceptions\NoNodesAvailableException + */ + public function testPerformRequestNoNodesAvailable() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + $method = 'GET'; + $uri = '/'; + $params = null; + $body = null; + $response = array( + 'text' => 'texty text', + 'status' => '200', + 'info' => array() + ); + + $mockConnection = m::mock('\Elasticsearch\Connections\AbstractConnection'); + + $mockConnectionFxn = function($host, $port=null) use ($mockConnection) { + return $mockConnection; + }; + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('nextConnection')->once()->andThrow(new Elasticsearch\Common\Exceptions\NoNodesAvailableException())->getMock(); + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface'); + + // Eww... + $pimple = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(false)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 0)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(1)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $pimple, $log); + $transport->performRequest($method, $uri, $params, $body); + + + } + + public function testPerformRequestTransportException() + { + $log = $this->getMockBuilder('\Monolog\Logger') + ->disableOriginalConstructor() + ->getMock(); + + $hosts = array(array('host' => 'localhost')); + $method = 'GET'; + $uri = '/'; + $params = null; + $body = null; + $response = array( + 'text' => 'texty text', + 'status' => '200', + 'info' => array() + ); + + $mockConnection = m::mock('\Elasticsearch\Connections\AbstractConnection') + ->shouldReceive('performRequest')->once()->with($method, $uri, $params, $body)->andThrow(new Elasticsearch\Common\Exceptions\TransportException())->getMock() + ->shouldReceive('performRequest')->once()->with($method, $uri, $params, $body)->andReturn($response)->getMock() + ->shouldReceive('markDead')->once()->getMock() + ->shouldReceive('markAlive')->once()->getMock(); + + $mockConnectionFxn = function($host, $port=null) use ($mockConnection) { + return $mockConnection; + }; + + $mockConnectionPool = m::mock('\Elasticsearch\ConnectionPool\StaticConnectionPool') + ->shouldReceive('scheduleCheck')->once()->getMock() + ->shouldReceive('nextConnection')->twice()->andReturn($mockConnection)->getMock(); + $mockConnectionPoolFxn = function($connections) use ($mockConnectionPool) { + return $mockConnectionPool; + }; + + $mockSerializer = m::mock('\Elasticsearch\Serializers\SerializerInterface') + ->shouldReceive('deserialize')->with($response['text'], array())->andReturn('out')->getMock(); + + + + // Eww... + $pimple = m::mock('Pimple') + ->shouldReceive('offsetGet')->with('connectionPool')->andReturn($mockConnectionPoolFxn)->getMock() + ->shouldReceive('offsetGet')->with('serializer')->andReturn($mockSerializer)->getMock() + ->shouldReceive('offsetGet')->with('connection')->andReturn($mockConnectionFxn)->getMock() + ->shouldReceive('offsetGet')->with('sniffOnStart')->andReturn(false)->getMock() + ->shouldReceive('offsetExists')->with('retries')->andReturn(false)->getMock() + ->shouldReceive('offsetSet')->with('retries', 0)->getMock() + ->shouldReceive('offsetGet')->with('retries')->andReturn(1)->getMock(); + + $transport = new Elasticsearch\Transport($hosts, $pimple, $log); + $ret = $transport->performRequest($method, $uri, $params, $body); + + $expected = array( + 'status' => $response['status'], + 'data' => 'out', + 'info' => $response['info'] + ); + + $this->assertEquals($expected, $ret); + + } + + + +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/YamlRunnerTest.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/YamlRunnerTest.php new file mode 100644 index 00000000..2c8fc136 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/Elasticsearch/Tests/YamlRunnerTest.php @@ -0,0 +1,652 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ +class YamlRunnerTest extends \PHPUnit_Framework_TestCase +{ + /** @var Parser */ + private $yaml; + + /** @var Elasticsearch\client */ + private $client; + + /** @var string */ + static $esVersion; + + + /** + * @return mixed + */ + public static function getHostEnvVar() + { + if (isset($_SERVER['ES_TEST_HOST']) === true) { + echo "Test Host: ".$_SERVER['ES_TEST_HOST']."\n"; + return $_SERVER['ES_TEST_HOST']; + } else { + echo 'Environment variable for elasticsearch test cluster (ES_TEST_HOST) not defined. Exiting yaml test'; + exit; + } + } + + + public static function setUpBeforeClass() + { + $host = YamlRunnerTest::getHostEnvVar(); + $ch = curl_init($host); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + + $response = curl_exec($ch); + curl_close($ch); + + $response = json_decode($response, true); + YamlRunnerTest::$esVersion = $response['version']['number']; + echo "ES Version: ".YamlRunnerTest::$esVersion."\n"; + } + + public function setUp() + { + $this->yaml = new Parser(); + $uri = parse_url($host = YamlRunnerTest::getHostEnvVar()); + + $params['hosts'] = array($uri['host'].':'.$uri['port']); + $params['connectionParams']['timeout'] = 10000; + $params['logging'] = true; + $params['logLevel'] = \Psr\Log\LogLevel::DEBUG; + $this->client = new Elasticsearch\Client($params); + + } + + private function clearCluster() + { + echo "\n>>>CLEARING<<<\n"; + $host = YamlRunnerTest::getHostEnvVar(); + $ch = curl_init($host."/*"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + + $response = curl_exec($ch); + curl_close($ch); + + $ch = curl_init($host."/_template/*"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + + $response = curl_exec($ch); + curl_close($ch); + + $this->waitForYellow(); + } + + private function assertTruthy($value) + { + echo "\n |assertTruthy: ".json_encode($value)."\n"; + ob_flush(); + if (isset($value) === false || $value === 0 || $value === false || $value === null || $value === '') { + $this->fail("Value is not truthy: ".print_r($value, true)); + } + } + + private function assertFalsey($value) + { + echo "\n |assertFalsey: ".json_encode($value)."\n"; + ob_flush(); + if (!(isset($value) === false || $value === 0 || $value === false || $value === null || $value === '')) { + $this->fail("Value is not falsey: ".print_r($value, true)); + } + } + + private function assertRegex($pattern, $actual) { + $pattern = trim($pattern); + + // PHP doesn't like unescaped forward slashes + $pattern = substr($pattern, 1, strlen($pattern)-2); + $pattern = str_replace('/', '\/', $pattern); + $pattern = "/$pattern/mx"; + echo "\n |> actual: $actual\n"; + echo "\n |> pattern: $pattern\n"; + ob_flush(); + $result = preg_match($pattern, $actual, $matches); + $this->assertEquals(1, $result); + + } + + private function waitForYellow() + { + $host = YamlRunnerTest::getHostEnvVar(); + $ch = curl_init("$host/_cluster/health?wait_for_status=yellow&timeout=50s"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + + $response = json_decode(curl_exec($ch), true); + + $counter = 0; + while ($response['status'] === 'red') { + sleep(0.5); + $response = json_decode(curl_exec($ch), true); + ++$counter; + + if ($counter > 10) { + echo "Aborting test due to failure in clearing cluster.\n"; + print_r($response); + exit; + } + } + curl_close($ch); + } + + + public static function provider() + { + $path = dirname(__FILE__).'/../../../util/elasticsearch/rest-api-spec/test/'; + + $files = array(); + $objects = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + RecursiveIteratorIterator::SELF_FIRST + ); + + foreach($objects as $object) { + + /** @var FilesystemIterator $object */ + if ($object->isFile() === true && $object->getFilename() !== 'README.asciidoc' && $object->getFilename() !== 'TODO.txt') { + $path = $object->getPathInfo()->getRealPath()."/".$object->getBasename(); + $files[] = array($path); + } + } + + YamlRunnerTest::recursiveSort($files); + return $files; + + } + + private static function recursiveSort(&$array) { + foreach ($array as &$value) { + if (is_array($value)) YamlRunnerTest::recursiveSort($value); + } + return sort($array); + } + + + /** + * @dataProvider provider + * @group yaml + */ + public function testYaml() + { + //* @runInSeparateProcess + + $files = func_get_args(); + + foreach ($files as $testFile) { + echo "$testFile\n"; + ob_flush(); + + if ($this->skipTest($testFile) === true) { + $this->markTestSkipped('Skipped due to skip-list'); + } + + $fileData = file_get_contents($testFile); + $documents = array_filter(explode("---", $fileData)); + + $yamlDocs = array(); + $setup = null; + foreach ($documents as $document) { + try { + $tDoc = array(); + $tDoc['document'] = $this->checkForTimestamp($testFile, $document); + $tDoc['document'] = $this->checkForEmptyProperty($testFile, $tDoc['document']); + $tDoc['values'] = $this->yaml->parse($tDoc['document'], false, false, true); + + if (key($tDoc['values']) === 'setup') { + $setup = $tDoc['values']; + } else { + $yamlDocs[] = $tDoc; + } + + } catch (ParseException $e) { + printf("Unable to parse the YAML string: %s", $e->getMessage()); + } + } + + foreach ($yamlDocs as $doc) { + $ts = date('c'); + echo " ".key($doc['values'])." [$ts]\n"; + ob_flush(); + + $this->clearCluster(); + + if ($setup !== null) { + try { + $this->executeTestCase($setup, $testFile); + } catch (SetupSkipException $e) { + break; //exit this test since we skipped in the setup + } + + } + $this->executeTestCase($doc['values'], $testFile); + + } + + + } + + + } + + private function replaceWithStash($values, $stash) + { + if (count($stash) === 0) { + return $values; + } + + if (is_array($values) === true) { + array_walk_recursive($values, function(&$item, $key) use ($stash) { + if (is_string($item) === true || is_numeric($item) === true) { + if (array_key_exists($item, $stash) == true) { + $item = $stash[$item]; + } + } + + }); + } elseif (is_string($values) || is_numeric($values)) { + if (array_key_exists($values, $stash) == true) { + $values = $stash[$values]; + } + } + + + return $values; + } + + private function executeTestCase($test, $testFile) + { + $stash = array(); + $response = array(); + reset($test); + $key = key($test); + + foreach ($test[$key] as $operators) { + + + foreach ($operators as $operator => $settings) { + echo " > $operator: "; + ob_flush(); + if ($operator === 'do') { + if (key($settings) === 'catch') { + + $catch = $this->getValue($settings, 'catch'); + $expectedError = str_replace("/", "", $catch); + next($settings); + + echo "(catch: $expectedError) "; + ob_flush(); + } else { + $expectedError = null; + } + + $method = key($settings); + $hash = $this->getValue($settings, $method); + + echo "\n |$method\n"; + ob_flush(); + + + $hash = $this->replaceWithStash($hash, $stash); + + + try { + echo " |".json_encode($hash)."\n"; + $response = $this->callMethod($method, $hash); + echo " |".json_encode($response)."\n"; + ob_flush(); + + //$this->waitForYellow(); + + if (isset($expectedError) === true) { + $this->fail("Expected Exception not thrown: $expectedError"); + } + } catch (Missing404Exception $exception){ + if ($expectedError === 'missing') { + $this->assertTrue(true); + } else { + $this->fail($exception->getMessage()); + } + $response = array(); + + + } catch (Conflict409Exception $exception) { + if ($expectedError === 'conflict') { + $this->assertTrue(true); + } else { + $this->fail($exception->getMessage()); + } + $response = array(); + + } catch (Forbidden403Exception $exception) { + if ($expectedError === 'forbidden') { + $this->assertTrue(true); + } else { + $this->fail($exception->getMessage()); + } + $response = array(); + + } catch (BadRequest400Exception $exception){ + if ($expectedError === 'request') { + $this->assertTrue(true); + } elseif (isset($expectedError) === true && preg_match("/$expectedError/", $exception->getMessage()) === 1) { + $this->assertTrue(true); + } else { + $this->fail($exception->getMessage()); + } + $response = array(); + + } catch (ServerErrorResponseException $exception){ + if ($expectedError === 'request') { + $this->assertTrue(true); + } elseif (isset($expectedError) === true && preg_match("/$expectedError/", $exception->getMessage()) === 1) { + $this->assertTrue(true); + } else { + $this->fail($exception->getMessage()); + } + $response = array(); + + } catch (Elasticsearch\Common\Exceptions\RuntimeException $exception){ + if ($expectedError === 'param') { + $this->assertTrue(true); + } elseif (isset($expectedError) === true && preg_match("/$expectedError/", $exception->getMessage()) === 1) { + $this->assertTrue(true); + } else { + $this->fail($exception->getMessage()); + } + $response = array(); + + } catch (\Exception $exception) { + if ($expectedError === null) { + $this->fail($exception->getMessage()); + } elseif (preg_match("/$expectedError/", $exception->getMessage()) === 1) { + $this->assertTrue(true); + } else { + $this->fail($exception->getMessage()); + } + $response = array(); + + } + + } elseif($operator === 'match') { + + $expected = $this->getValue($settings, key($settings)); + if (key($settings) === '') { + $actual = $response; + } else if (key($settings) === '$body') { + $actual = $response; + } else { + $actual = $this->getNestedVar($response, key($settings)); + + } + + $expected = $this->replaceWithStash($expected, $stash); + $actual = $this->replaceWithStash($actual, $stash); + if ($actual != $expected) { + //Holy janky batman + if (is_array($actual) && count($actual) == 0) { + $actual = (object) $actual; + } else { + $actual = json_decode(json_encode($actual)); + } + + $expected = json_decode(json_encode($expected)); + } + + if ($this->checkForRegex($expected) === true) { + $this->assertRegex($expected, $actual); + } else { + $this->assertEquals($expected, $actual); + } + + //$this->assertSame() + + echo "\n"; + + } elseif ($operator === "is_true") { + if (empty($settings) === true) { + $response = $this->replaceWithStash($response, $stash); + $this->assertTruthy($response); + + } else { + $actual = $this->getNestedVar($response, $settings); + $actual = $this->replaceWithStash($actual, $stash); + $this->assertTruthy($actual); + } + + echo "\n"; + + } elseif ($operator === "is_false") { + if (empty($settings) === true) { + $response = $this->replaceWithStash($response, $stash); + $this->assertFalsey($response); + } else { + $actual = $this->getNestedVar($response, $settings); + $actual = $this->replaceWithStash($actual, $stash); + $this->assertFalsey($actual); + } + + echo "\n"; + + } elseif ($operator === 'set') { + $stashKey = $this->getValue($settings, key($settings)); + $stash["$$stashKey"] = $this->getNestedVar($response, key($settings)); + + echo "\n"; + + } elseif ($operator === "length") { + $expectedCount = $this->getValue($settings, key($settings)); + $this->assertCount($expectedCount, $this->getNestedVar($response, key($settings))); + echo "\n"; + + } elseif ($operator === "lt") { + $expectedCount = $this->getValue($settings, key($settings)); + $this->assertLessThan($expectedCount, $this->getNestedVar($response, key($settings))); + echo "\n"; + + } elseif ($operator === "gt") { + $expectedCount = $this->getValue($settings, key($settings)); + $this->assertGreaterThan($expectedCount, $this->getNestedVar($response, key($settings))); + echo "\n"; + } elseif ($operator === "skip") { + if (isset($settings['version']) === true) { + $version = $settings['version']; + $version = str_replace(" ", "", $version); + $version = explode("-", $version); + if (version_compare(YamlRunnerTest::$esVersion, $version[0]) >= 0 + && version_compare($version[1], YamlRunnerTest::$esVersion) >= 0) { + echo "Skipping: ".$settings['reason']."\n"; + + if ($key == 'setup') { + throw new SetupSkipException(); + } + return; + } + } else if (isset($settings['features']) === true) { + $feature = $settings['features']; + $whitelist = array(); + + if (array_search($feature, $whitelist) === false) { + echo "Unsupported optional feature: $feature\n"; + return; + } + } + + } + ob_flush(); + } + } + } + + private function callMethod($method, $hash) + { + $ret = array(); + + $methodParts = explode(".", $method); + + if (count($methodParts) > 1) { + $methodParts[1] = $this->snakeToCamel($methodParts[1]); + $ret = $this->client->$methodParts[0]()->$methodParts[1]($hash); + } else { + $method = $this->snakeToCamel($method); + $ret = $this->client->$method($hash); + } + + + + return $ret; + } + + private function getValue($a, $key) { + if (is_array($a)) { + return $a[$key]; + } elseif(is_object($a)) { + return $a->$key; + } else { + die('non-array, non-object in getValue()'); + } + } + + private function snakeToCamel($val) { + return str_replace(' ', '', lcfirst(ucwords(str_replace('_', ' ', $val)))); + } + + private function getNestedVar(&$context, $name) { + $pieces = preg_split('/(?getTimestampRegex(), $document, $matches); + if ($isMatch) { + $newTime = new \DateTime($matches[0].'GMT'); + $document = preg_replace($this->getTimestampRegex(), $newTime->format('U') * 1000, $document); + } + + return $document; + + } + + private function checkForEmptyProperty($file, $document) { + $pattern = "/{.*?('').*?:.*?{/"; + + $document = preg_replace($pattern, '{ $body: {', $document); + + return $document; + } + + private function checkForRegex($value) { + if (is_string($value) !== true) { + return false; + } + + $value = trim($value); + if (substr($value, 0, 1) === '/' && substr($value, strlen($value) - 1, 1) === '/') { + return true; + } else { + return false; + } + } + + private function getTimestampRegex() + { + return <<[0-9][0-9][0-9][0-9]) + -(?P[0-9][0-9]?) + -(?P[0-9][0-9]?) + (?:(?:[Tt]|[ \t]+) + (?P[0-9][0-9]?) + :(?P[0-9][0-9]) + :(?P[0-9][0-9]) + (?:\.(?P[0-9]*))? + (?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?) + (?::(?P[0-9][0-9]))?))?)? + ~x +EOF; + } + + private function skipTest($path) + { + $skipList = array( + 'indices.delete_mapping/all_path_options.yaml', + 'indices.exists_type/10_basic.yaml', + 'indices.get_mapping/10_basic.yaml', + 'indices.create/10_basic.yaml', + 'indices.get_alias/10_basic.yaml' + ); + + foreach ($skipList as $skip) { + if (strpos($path, $skip) !== false) { + return true; + } + } + + return false; + } + +} + +class SetupSkipException extends \Exception +{ +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/tests/bootstrap.php b/src/lib/vendor/elasticsearch/elasticsearch/tests/bootstrap.php new file mode 100644 index 00000000..0c16b1bc --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/tests/bootstrap.php @@ -0,0 +1,21 @@ +workingCopy(dirname(__DIR__) . '/util/elasticsearch'); + + + +echo "Update elasticsearch submodule\n"; +$git->fetchAll(array('verbose' => true)); + + +$hash = $_SERVER['TEST_BUILD_REF']; +echo "Checkout yaml tests (hash: $hash)\n"; +$git->checkout($hash, array('force' => true, 'quiet' => true)); diff --git a/src/lib/vendor/elasticsearch/elasticsearch/util/SpecParser.php b/src/lib/vendor/elasticsearch/elasticsearch/util/SpecParser.php new file mode 100644 index 00000000..16f06f0d --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/util/SpecParser.php @@ -0,0 +1,199 @@ +loadTemplate('endpoint.twig'); + +$counter = 0; + +if ($handle = opendir('../vendor/elasticsearch/elasticsearch_src/rest-api-spec/api/')) { + while (false !== ($entry = readdir($handle))) { + if ($entry != "." && $entry != "..") { + generateTemplate($entry, $template); + } + + } + closedir($handle); +} + + +function processURLPaths($data) +{ + $final = array(); + + $containsType = false; + $containsIndex = false; + foreach ($data['url']['paths'] as $path) { + $params = array(); + preg_match_all('/{(.*?)}/', $path, $params); + $params = $params[1]; + $count = count($params); + $parsedPath = str_replace('}','',$path); + $parsedPath = str_replace('{','$',$parsedPath); + + if (array_search('index', $params) !== false) { + $containsIndex = true; + } + + if (array_search('type', $params) !== false) { + $containsType = true; + } + + $duplicate = false; + foreach ($final as $existing) { + if ($existing['params'] === $params) { + $duplicate = true; + } + } + + if ($duplicate !== true) { + $final[] = array( + 'path' => $path, + 'parsedPath' => $parsedPath, + 'params' => $params, + 'count' => $count + ); + } + } + + /* + foreach ($final as &$existing) { + if ($containsIndex === true && array_search('index', $existing['params']) === false && array_search('type', $existing['params']) !== false) { + $existing['parsedPath'] = '/_all'.$existing['parsedPath']; + } + } + */ + + usort($final, function($a, $b) { + if ($a['count'] == $b['count']) { + return 0; + } + return ($a['count'] > $b['count']) ? -1 : 1; + }); + + return $final; +} + +function getDefaultPath($path) { + if ($path['count'] === 0) { + return $path['path']; + } else { + $final = str_replace('}','',$path['path']); + $final = str_replace('{','$',$final); + return $final; + } +} + +function forbid($key, $value) +{ + $forbid = array( + 'GET' => array( + '/_nodes/hotthreads', + '/_nodes/{node_id}/hotthreads', + '/_nodes/{metric}' + ), + 'HEAD' => array(), + 'PUT' => array( + '/{index}/{type}/_mapping' + ), + 'POST' => array( + '/_all/{type}/_bulk', + '/_all/{type}/_mget' + ), + 'DELETE' => array( + '/{index}/{type}', + '/{index}/{type}/_mapping' + ), + 'QS' => array( + 'operation_threading', + 'field_data' + ) + ); + + if (isset($forbid['key']) && $forbid['key'] === $value) { + return true; + } else { + return false; + } +} + +function generateTemplate($path, $template) +{ + $ignoreList = array( + 'index.json', 'bulk.json' + ); + + if (array_search($path, $ignoreList) !== false) { + return; + } + + $path = '../vendor/elasticsearch/elasticsearch_src/rest-api-spec/api/'.$path; + $json = file_get_contents($path); + $data = json_decode($json, true); + + reset($data); + $namespace = key($data); + $data = $data[$namespace]; + $namespace = explode(".", $namespace); + + $underscoreNamespace = array( + 'get', + 'put', + 'post', + 'delete', + 'exists', + 'update', + 'create' + ); + + $exceptions = array( + 'delete_by_query' + ); + + if (strpos($namespace[count($namespace)-1], '_')) { + $temp = explode('_',$namespace[count($namespace)-1]); + + if (array_search($temp[0], $underscoreNamespace) !== false && array_search($namespace[count($namespace)-1], $exceptions) === false) { + $namespace[count($namespace)-1] = $temp[1]; + $namespace[] = $temp[0]; + } else { + $namespace[count($namespace)-1] = str_replace('_', '', $namespace[count($namespace)-1]); + } + + } + + + + $data['url']['processed'] = processURLPaths($data); + $data['url']['default'] = getDefaultPath($data['url']['processed'][count($data['url']['processed'])-1]); + + $renderVars = array( + 'json' => $json, + 'data' => $data, + 'namespace' => $namespace, + 'className' => ucfirst($namespace[count($namespace)-1]), + ); + + $ret = $template->render($renderVars); + + $dir = './output/'.implode('/', array_map("ucfirst", array_splice($namespace,0,count($namespace)-1))); + + if (substr($dir,-1) !== '/') { + $dir .= '/'; + } + if (!file_exists($dir)) { + echo 'making dir: '.$dir."\n\n"; + $oldumask = umask(0); + mkdir($dir, 0777, true); + umask($oldumask); + } + + echo $dir."\n\n"; + $path = $dir.$renderVars['className'].'.php'; + echo $path."\n\n";; + + file_put_contents($path, $ret); + echo $ret; +} \ No newline at end of file diff --git a/src/lib/vendor/elasticsearch/elasticsearch/util/templates/endpoint.twig b/src/lib/vendor/elasticsearch/elasticsearch/util/templates/endpoint.twig new file mode 100644 index 00000000..e26d2973 --- /dev/null +++ b/src/lib/vendor/elasticsearch/elasticsearch/util/templates/endpoint.twig @@ -0,0 +1,159 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 + * @link http://elasticsearch.org + */ + +class {{ className|title }} extends AbstractEndpoint +{ +{% for part, info in data.url.parts %} +{% if part != 'index' and part != 'type' and part != 'id' %} + // {{info.description }} + private ${{part}}; + + +{% endif %} +{% endfor %} +{% if data.body is not null %} + /** + * @param array $body + * + * @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException + * @return $this + */ + public function setBody($body) + { + if (isset($body) !== true) { + return $this; + } + + if (is_array($body) !== true) { + throw new Exceptions\InvalidArgumentException( + 'Body must be an array' + ); + } + $this->body = $body; + return $this; + } + + + +{% endif %} +{% for part, info in data.url.parts %} +{% if part != 'index' and part != 'type' and part != 'id' %} + /** + * @param ${{part}} + * + * @return $this + */ + public function set{{part|title}}(${{part}}) + { + if (isset(${{part}}) !== true) { + return $this; + } + + $this->{{part}} = ${{part}}; + return $this; + } + + +{% endif %} +{% endfor %} +{% set exception = '' %} + /** +{% for part, info in data.url.parts %} +{% if info.required is not null %} +{% set exception = ' * @throws \\Elasticsearch\\Common\\Exceptions\\BadMethodCallException +' %} +{% endif %} +{% endfor %}{% autoescape false %}{{ exception }}{% endautoescape %} + * @return string + */ + protected function getURI() + { +{% for part, info in data.url.parts %} +{% if info.required == true %} + if (isset($this->{{ part }}) !== true) { + throw new Exceptions\RuntimeException( + '{{ part }} is required for {{ className }}' + ); + } +{% endif %} +{% endfor %} +{% for part, info in data.url.parts %} + ${{ part }} = $this->{{ part }}; +{% endfor %} + $uri = "{{ data.url.default }}"; +{% set loopCounter = 0 %} +{% for part, info in data.url.processed %} +{% if info.count > 0 %} +{% set counter = 0 %} + {% if loopCounter != 0 %}else{% set loopCounter = 1 %}{% endif %}if ({% for param in info.params %}{% if counter == 0 %}isset(${{ param }}) === true{% else %} && isset(${{ param }}) === true{% endif %}{% set counter = counter + 1 %}{% endfor %}) { + $uri = "{{ info.parsedPath }}"; + } +{% endif %} +{% endfor %} + + return $uri; + } + + + /** + * @return string[] + */ + protected function getParamWhitelist() + { + return array( +{% for param, options in data.url.params %} + '{{ param }}', +{% endfor %} + ); + } + + +{% if data.body.required == true %} + /** + * @return array + * @throws \Elasticsearch\Common\Exceptions\RuntimeException + */ + protected function getBody() + { + if (isset($this->body) !== true) { + throw new Exceptions\RuntimeException('Body is required for Put'); + } + return $this->body; + } + + +{% endif %} + /** + * @return string + */ + protected function getMethod() + { +{% if data.methods|length > 1 %} + //TODO Fix Me! + return '{{ data.methods|join(',') }}'; +{% else %} + return '{{ data.methods[0] }}'; +{% endif %} + } +} \ No newline at end of file diff --git a/src/lib/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php b/src/lib/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php new file mode 100644 index 00000000..d1e842b1 --- /dev/null +++ b/src/lib/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php @@ -0,0 +1,49 @@ +eventDispatcher = $eventDispatcher; + + return $this; + } + + public function getEventDispatcher() + { + if (!$this->eventDispatcher) { + $this->eventDispatcher = new EventDispatcher(); + } + + return $this->eventDispatcher; + } + + public function dispatch($eventName, array $context = array()) + { + return $this->getEventDispatcher()->dispatch($eventName, new Event($context)); + } + + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->getEventDispatcher()->addSubscriber($subscriber); + + return $this; + } +} diff --git a/src/lib/vendor/guzzle/common/Guzzle/Common/Collection.php b/src/lib/vendor/guzzle/common/Guzzle/Common/Collection.php new file mode 100644 index 00000000..5cb1535d --- /dev/null +++ b/src/lib/vendor/guzzle/common/Guzzle/Common/Collection.php @@ -0,0 +1,403 @@ +data = $data; + } + + /** + * Create a new collection from an array, validate the keys, and add default values where missing + * + * @param array $config Configuration values to apply. + * @param array $defaults Default parameters + * @param array $required Required parameter names + * + * @return self + * @throws InvalidArgumentException if a parameter is missing + */ + public static function fromConfig(array $config = array(), array $defaults = array(), array $required = array()) + { + $data = $config + $defaults; + + if ($missing = array_diff($required, array_keys($data))) { + throw new InvalidArgumentException('Config is missing the following keys: ' . implode(', ', $missing)); + } + + return new self($data); + } + + public function count() + { + return count($this->data); + } + + public function getIterator() + { + return new \ArrayIterator($this->data); + } + + public function toArray() + { + return $this->data; + } + + /** + * Removes all key value pairs + * + * @return Collection + */ + public function clear() + { + $this->data = array(); + + return $this; + } + + /** + * Get all or a subset of matching key value pairs + * + * @param array $keys Pass an array of keys to retrieve only a subset of key value pairs + * + * @return array Returns an array of all matching key value pairs + */ + public function getAll(array $keys = null) + { + return $keys ? array_intersect_key($this->data, array_flip($keys)) : $this->data; + } + + /** + * Get a specific key value. + * + * @param string $key Key to retrieve. + * + * @return mixed|null Value of the key or NULL + */ + public function get($key) + { + return isset($this->data[$key]) ? $this->data[$key] : null; + } + + /** + * Set a key value pair + * + * @param string $key Key to set + * @param mixed $value Value to set + * + * @return Collection Returns a reference to the object + */ + public function set($key, $value) + { + $this->data[$key] = $value; + + return $this; + } + + /** + * Add a value to a key. If a key of the same name has already been added, the key value will be converted into an + * array and the new value will be pushed to the end of the array. + * + * @param string $key Key to add + * @param mixed $value Value to add to the key + * + * @return Collection Returns a reference to the object. + */ + public function add($key, $value) + { + if (!array_key_exists($key, $this->data)) { + $this->data[$key] = $value; + } elseif (is_array($this->data[$key])) { + $this->data[$key][] = $value; + } else { + $this->data[$key] = array($this->data[$key], $value); + } + + return $this; + } + + /** + * Remove a specific key value pair + * + * @param string $key A key to remove + * + * @return Collection + */ + public function remove($key) + { + unset($this->data[$key]); + + return $this; + } + + /** + * Get all keys in the collection + * + * @return array + */ + public function getKeys() + { + return array_keys($this->data); + } + + /** + * Returns whether or not the specified key is present. + * + * @param string $key The key for which to check the existence. + * + * @return bool + */ + public function hasKey($key) + { + return array_key_exists($key, $this->data); + } + + /** + * Case insensitive search the keys in the collection + * + * @param string $key Key to search for + * + * @return bool|string Returns false if not found, otherwise returns the key + */ + public function keySearch($key) + { + foreach (array_keys($this->data) as $k) { + if (!strcasecmp($k, $key)) { + return $k; + } + } + + return false; + } + + /** + * Checks if any keys contains a certain value + * + * @param string $value Value to search for + * + * @return mixed Returns the key if the value was found FALSE if the value was not found. + */ + public function hasValue($value) + { + return array_search($value, $this->data); + } + + /** + * Replace the data of the object with the value of an array + * + * @param array $data Associative array of data + * + * @return Collection Returns a reference to the object + */ + public function replace(array $data) + { + $this->data = $data; + + return $this; + } + + /** + * Add and merge in a Collection or array of key value pair data. + * + * @param Collection|array $data Associative array of key value pair data + * + * @return Collection Returns a reference to the object. + */ + public function merge($data) + { + foreach ($data as $key => $value) { + $this->add($key, $value); + } + + return $this; + } + + /** + * Over write key value pairs in this collection with all of the data from an array or collection. + * + * @param array|\Traversable $data Values to override over this config + * + * @return self + */ + public function overwriteWith($data) + { + if (is_array($data)) { + $this->data = $data + $this->data; + } elseif ($data instanceof Collection) { + $this->data = $data->toArray() + $this->data; + } else { + foreach ($data as $key => $value) { + $this->data[$key] = $value; + } + } + + return $this; + } + + /** + * Returns a Collection containing all the elements of the collection after applying the callback function to each + * one. The Closure should accept three parameters: (string) $key, (string) $value, (array) $context and return a + * modified value + * + * @param \Closure $closure Closure to apply + * @param array $context Context to pass to the closure + * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection + * + * @return Collection + */ + public function map(\Closure $closure, array $context = array(), $static = true) + { + $collection = $static ? new static() : new self(); + foreach ($this as $key => $value) { + $collection->add($key, $closure($key, $value, $context)); + } + + return $collection; + } + + /** + * Iterates over each key value pair in the collection passing them to the Closure. If the Closure function returns + * true, the current value from input is returned into the result Collection. The Closure must accept three + * parameters: (string) $key, (string) $value and return Boolean TRUE or FALSE for each value. + * + * @param \Closure $closure Closure evaluation function + * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection + * + * @return Collection + */ + public function filter(\Closure $closure, $static = true) + { + $collection = ($static) ? new static() : new self(); + foreach ($this->data as $key => $value) { + if ($closure($key, $value)) { + $collection->add($key, $value); + } + } + + return $collection; + } + + public function offsetExists($offset) + { + return isset($this->data[$offset]); + } + + public function offsetGet($offset) + { + return isset($this->data[$offset]) ? $this->data[$offset] : null; + } + + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } + + /** + * Set a value into a nested array key. Keys will be created as needed to set the value. + * + * @param string $path Path to set + * @param mixed $value Value to set at the key + * + * @return self + * @throws RuntimeException when trying to setPath using a nested path that travels through a scalar value + */ + public function setPath($path, $value) + { + $current =& $this->data; + $queue = explode('/', $path); + while (null !== ($key = array_shift($queue))) { + if (!is_array($current)) { + throw new RuntimeException("Trying to setPath {$path}, but {$key} is set and is not an array"); + } elseif (!$queue) { + $current[$key] = $value; + } elseif (isset($current[$key])) { + $current =& $current[$key]; + } else { + $current[$key] = array(); + $current =& $current[$key]; + } + } + + return $this; + } + + /** + * Gets a value from the collection using an array path (e.g. foo/baz/bar would retrieve bar from two nested arrays) + * Allows for wildcard searches which recursively combine matches up to the level at which the wildcard occurs. This + * can be useful for accepting any key of a sub-array and combining matching keys from each diverging path. + * + * @param string $path Path to traverse and retrieve a value from + * @param string $separator Character used to add depth to the search + * @param mixed $data Optional data to descend into (used when wildcards are encountered) + * + * @return mixed|null + */ + public function getPath($path, $separator = '/', $data = null) + { + if ($data === null) { + $data =& $this->data; + } + + $path = is_array($path) ? $path : explode($separator, $path); + while (null !== ($part = array_shift($path))) { + if (!is_array($data)) { + return null; + } elseif (isset($data[$part])) { + $data =& $data[$part]; + } elseif ($part != '*') { + return null; + } else { + // Perform a wildcard search by diverging and merging paths + $result = array(); + foreach ($data as $value) { + if (!$path) { + $result = array_merge_recursive($result, (array) $value); + } elseif (null !== ($test = $this->getPath($path, $separator, $value))) { + $result = array_merge_recursive($result, (array) $test); + } + } + return $result; + } + } + + return $data; + } + + /** + * Inject configuration settings into an input string + * + * @param string $input Input to inject + * + * @return string + * @deprecated + */ + public function inject($input) + { + Version::warn(__METHOD__ . ' is deprecated'); + $replace = array(); + foreach ($this->data as $key => $val) { + $replace['{' . $key . '}'] = $val; + } + + return strtr($input, $replace); + } +} diff --git a/src/lib/vendor/guzzle/common/Guzzle/Common/Event.php b/src/lib/vendor/guzzle/common/Guzzle/Common/Event.php new file mode 100644 index 00000000..fad76a9b --- /dev/null +++ b/src/lib/vendor/guzzle/common/Guzzle/Common/Event.php @@ -0,0 +1,52 @@ +context = $context; + } + + public function getIterator() + { + return new \ArrayIterator($this->context); + } + + public function offsetGet($offset) + { + return isset($this->context[$offset]) ? $this->context[$offset] : null; + } + + public function offsetSet($offset, $value) + { + $this->context[$offset] = $value; + } + + public function offsetExists($offset) + { + return isset($this->context[$offset]); + } + + public function offsetUnset($offset) + { + unset($this->context[$offset]); + } + + public function toArray() + { + return $this->context; + } +} diff --git a/src/lib/vendor/guzzle/common/Guzzle/Common/Exception/BadMethodCallException.php b/src/lib/vendor/guzzle/common/Guzzle/Common/Exception/BadMethodCallException.php new file mode 100644 index 00000000..08d1c725 --- /dev/null +++ b/src/lib/vendor/guzzle/common/Guzzle/Common/Exception/BadMethodCallException.php @@ -0,0 +1,5 @@ +shortMessage = $message; + } + + /** + * Set all of the exceptions + * + * @param array $exceptions Array of exceptions + * + * @return self + */ + public function setExceptions(array $exceptions) + { + $this->exceptions = array(); + foreach ($exceptions as $exception) { + $this->add($exception); + } + + return $this; + } + + /** + * Add exceptions to the collection + * + * @param ExceptionCollection|\Exception $e Exception to add + * + * @return ExceptionCollection; + */ + public function add($e) + { + $this->exceptions[] = $e; + if ($this->message) { + $this->message .= "\n"; + } + + $this->message .= $this->getExceptionMessage($e, 0); + + return $this; + } + + /** + * Get the total number of request exceptions + * + * @return int + */ + public function count() + { + return count($this->exceptions); + } + + /** + * Allows array-like iteration over the request exceptions + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new \ArrayIterator($this->exceptions); + } + + /** + * Get the first exception in the collection + * + * @return \Exception + */ + public function getFirst() + { + return $this->exceptions ? $this->exceptions[0] : null; + } + + private function getExceptionMessage(\Exception $e, $depth = 0) + { + static $sp = ' '; + $prefix = $depth ? str_repeat($sp, $depth) : ''; + $message = "{$prefix}(" . get_class($e) . ') ' . $e->getFile() . ' line ' . $e->getLine() . "\n"; + + if ($e instanceof self) { + if ($e->shortMessage) { + $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->shortMessage) . "\n"; + } + foreach ($e as $ee) { + $message .= "\n" . $this->getExceptionMessage($ee, $depth + 1); + } + } else { + $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->getMessage()) . "\n"; + $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->getTraceAsString()) . "\n"; + } + + return str_replace(getcwd(), '.', $message); + } +} diff --git a/src/lib/vendor/guzzle/common/Guzzle/Common/Exception/GuzzleException.php b/src/lib/vendor/guzzle/common/Guzzle/Common/Exception/GuzzleException.php new file mode 100644 index 00000000..458e6f2e --- /dev/null +++ b/src/lib/vendor/guzzle/common/Guzzle/Common/Exception/GuzzleException.php @@ -0,0 +1,8 @@ +=5.3.2", + "symfony/event-dispatcher": ">=2.1" + }, + "autoload": { + "psr-0": { "Guzzle\\Common": "" } + }, + "target-dir": "Guzzle/Common", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php b/src/lib/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php new file mode 100644 index 00000000..5005a887 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php @@ -0,0 +1,221 @@ +body = $body; + } + + public function __toString() + { + return (string) $this->body; + } + + /** + * Allow decorators to implement custom methods + * + * @param string $method Missing method name + * @param array $args Method arguments + * + * @return mixed + */ + public function __call($method, array $args) + { + return call_user_func_array(array($this->body, $method), $args); + } + + public function close() + { + return $this->body->close(); + } + + public function setRewindFunction($callable) + { + $this->body->setRewindFunction($callable); + + return $this; + } + + public function rewind() + { + return $this->body->rewind(); + } + + public function compress($filter = 'zlib.deflate') + { + return $this->body->compress($filter); + } + + public function uncompress($filter = 'zlib.inflate') + { + return $this->body->uncompress($filter); + } + + public function getContentLength() + { + return $this->getSize(); + } + + public function getContentType() + { + return $this->body->getContentType(); + } + + public function getContentMd5($rawOutput = false, $base64Encode = false) + { + $hash = Stream::getHash($this, 'md5', $rawOutput); + + return $hash && $base64Encode ? base64_encode($hash) : $hash; + } + + public function getContentEncoding() + { + return $this->body->getContentEncoding(); + } + + public function getMetaData($key = null) + { + return $this->body->getMetaData($key); + } + + public function getStream() + { + return $this->body->getStream(); + } + + public function setStream($stream, $size = 0) + { + $this->body->setStream($stream, $size); + + return $this; + } + + public function detachStream() + { + $this->body->detachStream(); + + return $this; + } + + public function getWrapper() + { + return $this->body->getWrapper(); + } + + public function getWrapperData() + { + return $this->body->getWrapperData(); + } + + public function getStreamType() + { + return $this->body->getStreamType(); + } + + public function getUri() + { + return $this->body->getUri(); + } + + public function getSize() + { + return $this->body->getSize(); + } + + public function isReadable() + { + return $this->body->isReadable(); + } + + public function isRepeatable() + { + return $this->isSeekable() && $this->isReadable(); + } + + public function isWritable() + { + return $this->body->isWritable(); + } + + public function isConsumed() + { + return $this->body->isConsumed(); + } + + /** + * Alias of isConsumed() + * {@inheritdoc} + */ + public function feof() + { + return $this->isConsumed(); + } + + public function isLocal() + { + return $this->body->isLocal(); + } + + public function isSeekable() + { + return $this->body->isSeekable(); + } + + public function setSize($size) + { + $this->body->setSize($size); + + return $this; + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->body->seek($offset, $whence); + } + + public function read($length) + { + return $this->body->read($length); + } + + public function write($string) + { + return $this->body->write($string); + } + + public function readLine($maxLength = null) + { + return $this->body->readLine($maxLength); + } + + public function ftell() + { + return $this->body->ftell(); + } + + public function getCustomData($key) + { + return $this->body->getCustomData($key); + } + + public function setCustomData($key, $value) + { + $this->body->setCustomData($key, $value); + + return $this; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php b/src/lib/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php new file mode 100644 index 00000000..c65c1365 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php @@ -0,0 +1,229 @@ +remoteStream = $body; + $this->body = new EntityBody(fopen('php://temp', 'r+')); + } + + /** + * Will give the contents of the buffer followed by the exhausted remote stream. + * + * Warning: Loads the entire stream into memory + * + * @return string + */ + public function __toString() + { + $pos = $this->ftell(); + $this->rewind(); + + $str = ''; + while (!$this->isConsumed()) { + $str .= $this->read(16384); + } + + $this->seek($pos); + + return $str; + } + + public function getSize() + { + return max($this->body->getSize(), $this->remoteStream->getSize()); + } + + /** + * {@inheritdoc} + * @throws RuntimeException When seeking with SEEK_END or when seeking past the total size of the buffer stream + */ + public function seek($offset, $whence = SEEK_SET) + { + if ($whence == SEEK_SET) { + $byte = $offset; + } elseif ($whence == SEEK_CUR) { + $byte = $offset + $this->ftell(); + } else { + throw new RuntimeException(__CLASS__ . ' supports only SEEK_SET and SEEK_CUR seek operations'); + } + + // You cannot skip ahead past where you've read from the remote stream + if ($byte > $this->body->getSize()) { + throw new RuntimeException( + "Cannot seek to byte {$byte} when the buffered stream only contains {$this->body->getSize()} bytes" + ); + } + + return $this->body->seek($byte); + } + + public function rewind() + { + return $this->seek(0); + } + + /** + * Does not support custom rewind functions + * + * @throws RuntimeException + */ + public function setRewindFunction($callable) + { + throw new RuntimeException(__CLASS__ . ' does not support custom stream rewind functions'); + } + + public function read($length) + { + // Perform a regular read on any previously read data from the buffer + $data = $this->body->read($length); + $remaining = $length - strlen($data); + + // More data was requested so read from the remote stream + if ($remaining) { + // If data was written to the buffer in a position that would have been filled from the remote stream, + // then we must skip bytes on the remote stream to emulate overwriting bytes from that position. This + // mimics the behavior of other PHP stream wrappers. + $remoteData = $this->remoteStream->read($remaining + $this->skipReadBytes); + + if ($this->skipReadBytes) { + $len = strlen($remoteData); + $remoteData = substr($remoteData, $this->skipReadBytes); + $this->skipReadBytes = max(0, $this->skipReadBytes - $len); + } + + $data .= $remoteData; + $this->body->write($remoteData); + } + + return $data; + } + + public function write($string) + { + // When appending to the end of the currently read stream, you'll want to skip bytes from being read from + // the remote stream to emulate other stream wrappers. Basically replacing bytes of data of a fixed length. + $overflow = (strlen($string) + $this->ftell()) - $this->remoteStream->ftell(); + if ($overflow > 0) { + $this->skipReadBytes += $overflow; + } + + return $this->body->write($string); + } + + /** + * {@inheritdoc} + * @link http://php.net/manual/en/function.fgets.php + */ + public function readLine($maxLength = null) + { + $buffer = ''; + $size = 0; + while (!$this->isConsumed()) { + $byte = $this->read(1); + $buffer .= $byte; + // Break when a new line is found or the max length - 1 is reached + if ($byte == PHP_EOL || ++$size == $maxLength - 1) { + break; + } + } + + return $buffer; + } + + public function isConsumed() + { + return $this->body->isConsumed() && $this->remoteStream->isConsumed(); + } + + /** + * Close both the remote stream and buffer stream + */ + public function close() + { + return $this->remoteStream->close() && $this->body->close(); + } + + public function setStream($stream, $size = 0) + { + $this->remoteStream->setStream($stream, $size); + } + + public function getContentType() + { + return $this->remoteStream->getContentType(); + } + + public function getContentEncoding() + { + return $this->remoteStream->getContentEncoding(); + } + + public function getMetaData($key = null) + { + return $this->remoteStream->getMetaData($key); + } + + public function getStream() + { + return $this->remoteStream->getStream(); + } + + public function getWrapper() + { + return $this->remoteStream->getWrapper(); + } + + public function getWrapperData() + { + return $this->remoteStream->getWrapperData(); + } + + public function getStreamType() + { + return $this->remoteStream->getStreamType(); + } + + public function getUri() + { + return $this->remoteStream->getUri(); + } + + /** + * Always retrieve custom data from the remote stream + * {@inheritdoc} + */ + public function getCustomData($key) + { + return $this->remoteStream->getCustomData($key); + } + + /** + * Always set custom data on the remote stream + * {@inheritdoc} + */ + public function setCustomData($key, $value) + { + $this->remoteStream->setCustomData($key, $value); + + return $this; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Client.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Client.php new file mode 100644 index 00000000..3d7298dc --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Client.php @@ -0,0 +1,524 @@ +setConfig($config ?: new Collection()); + $this->initSsl(); + $this->setBaseUrl($baseUrl); + $this->defaultHeaders = new Collection(); + $this->setRequestFactory(RequestFactory::getInstance()); + $this->userAgent = $this->getDefaultUserAgent(); + if (!$this->config[self::DISABLE_REDIRECTS]) { + $this->addSubscriber(new RedirectPlugin()); + } + } + + final public function setConfig($config) + { + if ($config instanceof Collection) { + $this->config = $config; + } elseif (is_array($config)) { + $this->config = new Collection($config); + } else { + throw new InvalidArgumentException('Config must be an array or Collection'); + } + + return $this; + } + + final public function getConfig($key = false) + { + return $key ? $this->config[$key] : $this->config; + } + + /** + * Set a default request option on the client that will be used as a default for each request + * + * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) + * @param mixed $value Value to set + * + * @return $this + */ + public function setDefaultOption($keyOrPath, $value) + { + $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; + $this->config->setPath($keyOrPath, $value); + + return $this; + } + + /** + * Retrieve a default request option from the client + * + * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) + * + * @return mixed|null + */ + public function getDefaultOption($keyOrPath) + { + $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; + + return $this->config->getPath($keyOrPath); + } + + final public function setSslVerification($certificateAuthority = true, $verifyPeer = true, $verifyHost = 2) + { + $opts = $this->config[self::CURL_OPTIONS] ?: array(); + + if ($certificateAuthority === true) { + // use bundled CA bundle, set secure defaults + $opts[CURLOPT_CAINFO] = __DIR__ . '/Resources/cacert.pem'; + $opts[CURLOPT_SSL_VERIFYPEER] = true; + $opts[CURLOPT_SSL_VERIFYHOST] = 2; + } elseif ($certificateAuthority === false) { + unset($opts[CURLOPT_CAINFO]); + $opts[CURLOPT_SSL_VERIFYPEER] = false; + $opts[CURLOPT_SSL_VERIFYHOST] = 0; + } elseif ($verifyPeer !== true && $verifyPeer !== false && $verifyPeer !== 1 && $verifyPeer !== 0) { + throw new InvalidArgumentException('verifyPeer must be 1, 0 or boolean'); + } elseif ($verifyHost !== 0 && $verifyHost !== 1 && $verifyHost !== 2) { + throw new InvalidArgumentException('verifyHost must be 0, 1 or 2'); + } else { + $opts[CURLOPT_SSL_VERIFYPEER] = $verifyPeer; + $opts[CURLOPT_SSL_VERIFYHOST] = $verifyHost; + if (is_file($certificateAuthority)) { + unset($opts[CURLOPT_CAPATH]); + $opts[CURLOPT_CAINFO] = $certificateAuthority; + } elseif (is_dir($certificateAuthority)) { + unset($opts[CURLOPT_CAINFO]); + $opts[CURLOPT_CAPATH] = $certificateAuthority; + } else { + throw new RuntimeException( + 'Invalid option passed to ' . self::SSL_CERT_AUTHORITY . ': ' . $certificateAuthority + ); + } + } + + $this->config->set(self::CURL_OPTIONS, $opts); + + return $this; + } + + public function createRequest($method = 'GET', $uri = null, $headers = null, $body = null, array $options = array()) + { + if (!$uri) { + $url = $this->getBaseUrl(); + } else { + if (!is_array($uri)) { + $templateVars = null; + } else { + list($uri, $templateVars) = $uri; + } + if (strpos($uri, '://')) { + // Use absolute URLs as-is + $url = $this->expandTemplate($uri, $templateVars); + } else { + $url = Url::factory($this->getBaseUrl())->combine($this->expandTemplate($uri, $templateVars)); + } + } + + // If default headers are provided, then merge them under any explicitly provided headers for the request + if (count($this->defaultHeaders)) { + if (!$headers) { + $headers = $this->defaultHeaders->toArray(); + } elseif (is_array($headers)) { + $headers += $this->defaultHeaders->toArray(); + } elseif ($headers instanceof Collection) { + $headers = $headers->toArray() + $this->defaultHeaders->toArray(); + } + } + + return $this->prepareRequest($this->requestFactory->create($method, (string) $url, $headers, $body), $options); + } + + public function getBaseUrl($expand = true) + { + return $expand ? $this->expandTemplate($this->baseUrl) : $this->baseUrl; + } + + public function setBaseUrl($url) + { + $this->baseUrl = $url; + + return $this; + } + + public function setUserAgent($userAgent, $includeDefault = false) + { + if ($includeDefault) { + $userAgent .= ' ' . $this->getDefaultUserAgent(); + } + $this->userAgent = $userAgent; + + return $this; + } + + /** + * Get the default User-Agent string to use with Guzzle + * + * @return string + */ + public function getDefaultUserAgent() + { + return 'Guzzle/' . Version::VERSION + . ' curl/' . CurlVersion::getInstance()->get('version') + . ' PHP/' . PHP_VERSION; + } + + public function get($uri = null, $headers = null, $options = array()) + { + // BC compat: $options can be a string, resource, etc to specify where the response body is downloaded + return is_array($options) + ? $this->createRequest('GET', $uri, $headers, null, $options) + : $this->createRequest('GET', $uri, $headers, $options); + } + + public function head($uri = null, $headers = null, array $options = array()) + { + return $this->createRequest('HEAD', $uri, $headers, null, $options); + } + + public function delete($uri = null, $headers = null, $body = null, array $options = array()) + { + return $this->createRequest('DELETE', $uri, $headers, $body, $options); + } + + public function put($uri = null, $headers = null, $body = null, array $options = array()) + { + return $this->createRequest('PUT', $uri, $headers, $body, $options); + } + + public function patch($uri = null, $headers = null, $body = null, array $options = array()) + { + return $this->createRequest('PATCH', $uri, $headers, $body, $options); + } + + public function post($uri = null, $headers = null, $postBody = null, array $options = array()) + { + return $this->createRequest('POST', $uri, $headers, $postBody, $options); + } + + public function options($uri = null, array $options = array()) + { + return $this->createRequest('OPTIONS', $uri, $options); + } + + public function send($requests) + { + if (!($requests instanceof RequestInterface)) { + return $this->sendMultiple($requests); + } + + try { + /** @var $requests RequestInterface */ + $this->getCurlMulti()->add($requests)->send(); + return $requests->getResponse(); + } catch (ExceptionCollection $e) { + throw $e->getFirst(); + } + } + + /** + * Set a curl multi object to be used internally by the client for transferring requests. + * + * @param CurlMultiInterface $curlMulti Multi object + * + * @return self + */ + public function setCurlMulti(CurlMultiInterface $curlMulti) + { + $this->curlMulti = $curlMulti; + + return $this; + } + + /** + * @return CurlMultiInterface|CurlMultiProxy + */ + public function getCurlMulti() + { + if (!$this->curlMulti) { + $this->curlMulti = new CurlMultiProxy( + self::MAX_HANDLES, + $this->getConfig('select_timeout') ?: self::DEFAULT_SELECT_TIMEOUT + ); + } + + return $this->curlMulti; + } + + public function setRequestFactory(RequestFactoryInterface $factory) + { + $this->requestFactory = $factory; + + return $this; + } + + /** + * Set the URI template expander to use with the client + * + * @param UriTemplateInterface $uriTemplate URI template expander + * + * @return self + */ + public function setUriTemplate(UriTemplateInterface $uriTemplate) + { + $this->uriTemplate = $uriTemplate; + + return $this; + } + + /** + * Expand a URI template while merging client config settings into the template variables + * + * @param string $template Template to expand + * @param array $variables Variables to inject + * + * @return string + */ + protected function expandTemplate($template, array $variables = null) + { + $expansionVars = $this->getConfig()->toArray(); + if ($variables) { + $expansionVars = $variables + $expansionVars; + } + + return $this->getUriTemplate()->expand($template, $expansionVars); + } + + /** + * Get the URI template expander used by the client + * + * @return UriTemplateInterface + */ + protected function getUriTemplate() + { + if (!$this->uriTemplate) { + $this->uriTemplate = ParserRegistry::getInstance()->getParser('uri_template'); + } + + return $this->uriTemplate; + } + + /** + * Send multiple requests in parallel + * + * @param array $requests Array of RequestInterface objects + * + * @return array Returns an array of Response objects + */ + protected function sendMultiple(array $requests) + { + $curlMulti = $this->getCurlMulti(); + foreach ($requests as $request) { + $curlMulti->add($request); + } + $curlMulti->send(); + + /** @var $request RequestInterface */ + $result = array(); + foreach ($requests as $request) { + $result[] = $request->getResponse(); + } + + return $result; + } + + /** + * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request. + * + * @param RequestInterface $request Request to prepare for the client + * @param array $options Options to apply to the request + * + * @return RequestInterface + */ + protected function prepareRequest(RequestInterface $request, array $options = array()) + { + $request->setClient($this)->setEventDispatcher(clone $this->getEventDispatcher()); + + if ($curl = $this->config[self::CURL_OPTIONS]) { + $request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($curl)); + } + + if ($params = $this->config[self::REQUEST_PARAMS]) { + Version::warn('request.params is deprecated. Use request.options to add default request options.'); + $request->getParams()->overwriteWith($params); + } + + if ($this->userAgent && !$request->hasHeader('User-Agent')) { + $request->setHeader('User-Agent', $this->userAgent); + } + + if ($defaults = $this->config[self::REQUEST_OPTIONS]) { + $this->requestFactory->applyOptions($request, $defaults, RequestFactoryInterface::OPTIONS_AS_DEFAULTS); + } + + if ($options) { + $this->requestFactory->applyOptions($request, $options); + } + + $this->dispatch('client.create_request', array('client' => $this, 'request' => $request)); + + return $request; + } + + /** + * Initializes SSL settings + */ + protected function initSsl() + { + $authority = $this->config[self::SSL_CERT_AUTHORITY]; + + if ($authority === 'system') { + return; + } + + if ($authority === null) { + $authority = true; + } + + if ($authority === true && substr(__FILE__, 0, 7) == 'phar://') { + $authority = self::extractPharCacert(__DIR__ . '/Resources/cacert.pem'); + } + + $this->setSslVerification($authority); + } + + /** + * @deprecated + */ + public function getDefaultHeaders() + { + Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to retrieve default request options'); + return $this->defaultHeaders; + } + + /** + * @deprecated + */ + public function setDefaultHeaders($headers) + { + Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to specify default request options'); + if ($headers instanceof Collection) { + $this->defaultHeaders = $headers; + } elseif (is_array($headers)) { + $this->defaultHeaders = new Collection($headers); + } else { + throw new InvalidArgumentException('Headers must be an array or Collection'); + } + + return $this; + } + + /** + * @deprecated + */ + public function preparePharCacert($md5Check = true) + { + return sys_get_temp_dir() . '/guzzle-cacert.pem'; + } + + /** + * Copies the phar cacert from a phar into the temp directory. + * + * @param string $pharCacertPath Path to the phar cacert. For example: + * 'phar://aws.phar/Guzzle/Http/Resources/cacert.pem' + * + * @return string Returns the path to the extracted cacert file. + * @throws \RuntimeException Throws if the phar cacert cannot be found or + * the file cannot be copied to the temp dir. + */ + public static function extractPharCacert($pharCacertPath) + { + // Copy the cacert.pem file from the phar if it is not in the temp + // folder. + $certFile = sys_get_temp_dir() . '/guzzle-cacert.pem'; + + if (!file_exists($pharCacertPath)) { + throw new \RuntimeException("Could not find $pharCacertPath"); + } + + if (!file_exists($certFile) || + filesize($certFile) != filesize($pharCacertPath) + ) { + if (!copy($pharCacertPath, $certFile)) { + throw new \RuntimeException( + "Could not copy {$pharCacertPath} to {$certFile}: " + . var_export(error_get_last(), true) + ); + } + } + + return $certFile; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/ClientInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/ClientInterface.php new file mode 100644 index 00000000..10e4de2a --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/ClientInterface.php @@ -0,0 +1,223 @@ +getCurlOptions(); + $mediator = new RequestMediator($request, $requestCurlOptions->get('emit_io')); + $tempContentLength = null; + $method = $request->getMethod(); + $bodyAsString = $requestCurlOptions->get(self::BODY_AS_STRING); + + // Prepare url + $url = (string)$request->getUrl(); + if(($pos = strpos($url, '#')) !== false ){ + // strip fragment from url + $url = substr($url, 0, $pos); + } + + // Array of default cURL options. + $curlOptions = array( + CURLOPT_URL => $url, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_RETURNTRANSFER => false, + CURLOPT_HEADER => false, + CURLOPT_PORT => $request->getPort(), + CURLOPT_HTTPHEADER => array(), + CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'), + CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), + CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' + ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, + // Verifies the authenticity of the peer's certificate + CURLOPT_SSL_VERIFYPEER => 1, + // Certificate must indicate that the server is the server to which you meant to connect + CURLOPT_SSL_VERIFYHOST => 2 + ); + + if (defined('CURLOPT_PROTOCOLS')) { + // Allow only HTTP and HTTPS protocols + $curlOptions[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + // Add CURLOPT_ENCODING if Accept-Encoding header is provided + if ($acceptEncodingHeader = $request->getHeader('Accept-Encoding')) { + $curlOptions[CURLOPT_ENCODING] = (string) $acceptEncodingHeader; + // Let cURL set the Accept-Encoding header, prevents duplicate values + $request->removeHeader('Accept-Encoding'); + } + + // Enable curl debug information if the 'debug' param was set + if ($requestCurlOptions->get('debug')) { + $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+'); + // @codeCoverageIgnoreStart + if (false === $curlOptions[CURLOPT_STDERR]) { + throw new RuntimeException('Unable to create a stream for CURLOPT_STDERR'); + } + // @codeCoverageIgnoreEnd + $curlOptions[CURLOPT_VERBOSE] = true; + } + + // Specify settings according to the HTTP method + if ($method == 'GET') { + $curlOptions[CURLOPT_HTTPGET] = true; + } elseif ($method == 'HEAD') { + $curlOptions[CURLOPT_NOBODY] = true; + // HEAD requests do not use a write function + unset($curlOptions[CURLOPT_WRITEFUNCTION]); + } elseif (!($request instanceof EntityEnclosingRequest)) { + $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; + } else { + + $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; + + // Handle sending raw bodies in a request + if ($request->getBody()) { + // You can send the body as a string using curl's CURLOPT_POSTFIELDS + if ($bodyAsString) { + $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody(); + // Allow curl to add the Content-Length for us to account for the times when + // POST redirects are followed by GET requests + if ($tempContentLength = $request->getHeader('Content-Length')) { + $tempContentLength = (int) (string) $tempContentLength; + } + // Remove the curl generated Content-Type header if none was set manually + if (!$request->hasHeader('Content-Type')) { + $curlOptions[CURLOPT_HTTPHEADER][] = 'Content-Type:'; + } + } else { + $curlOptions[CURLOPT_UPLOAD] = true; + // Let cURL handle setting the Content-Length header + if ($tempContentLength = $request->getHeader('Content-Length')) { + $tempContentLength = (int) (string) $tempContentLength; + $curlOptions[CURLOPT_INFILESIZE] = $tempContentLength; + } + // Add a callback for curl to read data to send with the request only if a body was specified + $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody'); + // Attempt to seek to the start of the stream + $request->getBody()->seek(0); + } + + } else { + + // Special handling for POST specific fields and files + $postFields = false; + if (count($request->getPostFiles())) { + $postFields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); + foreach ($request->getPostFiles() as $key => $data) { + $prefixKeys = count($data) > 1; + foreach ($data as $index => $file) { + // Allow multiple files in the same key + $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; + $postFields[$fieldKey] = $file->getCurlValue(); + } + } + } elseif (count($request->getPostFields())) { + $postFields = (string) $request->getPostFields()->useUrlEncoding(true); + } + + if ($postFields !== false) { + if ($method == 'POST') { + unset($curlOptions[CURLOPT_CUSTOMREQUEST]); + $curlOptions[CURLOPT_POST] = true; + } + $curlOptions[CURLOPT_POSTFIELDS] = $postFields; + $request->removeHeader('Content-Length'); + } + } + + // If the Expect header is not present, prevent curl from adding it + if (!$request->hasHeader('Expect')) { + $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:'; + } + } + + // If a Content-Length header was specified but we want to allow curl to set one for us + if (null !== $tempContentLength) { + $request->removeHeader('Content-Length'); + } + + // Set custom cURL options + foreach ($requestCurlOptions->toArray() as $key => $value) { + if (is_numeric($key)) { + $curlOptions[$key] = $value; + } + } + + // Do not set an Accept header by default + if (!isset($curlOptions[CURLOPT_ENCODING])) { + $curlOptions[CURLOPT_HTTPHEADER][] = 'Accept:'; + } + + // Add any custom headers to the request. Empty headers will cause curl to not send the header at all. + foreach ($request->getHeaderLines() as $line) { + $curlOptions[CURLOPT_HTTPHEADER][] = $line; + } + + // Add the content-length header back if it was temporarily removed + if ($tempContentLength) { + $request->setHeader('Content-Length', $tempContentLength); + } + + // Apply the options to a new cURL handle. + $handle = curl_init(); + + // Enable the progress function if the 'progress' param was set + if ($requestCurlOptions->get('progress')) { + // Wrap the function in a function that provides the curl handle to the mediator's progress function + // Using this rather than injecting the handle into the mediator prevents a circular reference + $curlOptions[CURLOPT_PROGRESSFUNCTION] = function () use ($mediator, $handle) { + $args = func_get_args(); + $args[] = $handle; + + // PHP 5.5 pushed the handle onto the start of the args + if (is_resource($args[0])) { + array_shift($args); + } + + call_user_func_array(array($mediator, 'progress'), $args); + }; + $curlOptions[CURLOPT_NOPROGRESS] = false; + } + + curl_setopt_array($handle, $curlOptions); + + return new static($handle, $curlOptions); + } + + /** + * Construct a new CurlHandle object that wraps a cURL handle + * + * @param resource $handle Configured cURL handle resource + * @param Collection|array $options Curl options to use with the handle + * + * @throws InvalidArgumentException + */ + public function __construct($handle, $options) + { + if (!is_resource($handle)) { + throw new InvalidArgumentException('Invalid handle provided'); + } + if (is_array($options)) { + $this->options = new Collection($options); + } elseif ($options instanceof Collection) { + $this->options = $options; + } else { + throw new InvalidArgumentException('Expected array or Collection'); + } + $this->handle = $handle; + } + + /** + * Destructor + */ + public function __destruct() + { + $this->close(); + } + + /** + * Close the curl handle + */ + public function close() + { + if (is_resource($this->handle)) { + curl_close($this->handle); + } + $this->handle = null; + } + + /** + * Check if the handle is available and still OK + * + * @return bool + */ + public function isAvailable() + { + return is_resource($this->handle); + } + + /** + * Get the last error that occurred on the cURL handle + * + * @return string + */ + public function getError() + { + return $this->isAvailable() ? curl_error($this->handle) : ''; + } + + /** + * Get the last error number that occurred on the cURL handle + * + * @return int + */ + public function getErrorNo() + { + if ($this->errorNo) { + return $this->errorNo; + } + + return $this->isAvailable() ? curl_errno($this->handle) : CURLE_OK; + } + + /** + * Set the curl error number + * + * @param int $error Error number to set + * + * @return CurlHandle + */ + public function setErrorNo($error) + { + $this->errorNo = $error; + + return $this; + } + + /** + * Get cURL curl_getinfo data + * + * @param int $option Option to retrieve. Pass null to retrieve all data as an array. + * + * @return array|mixed + */ + public function getInfo($option = null) + { + if (!is_resource($this->handle)) { + return null; + } + + if (null !== $option) { + return curl_getinfo($this->handle, $option) ?: null; + } + + return curl_getinfo($this->handle) ?: array(); + } + + /** + * Get the stderr output + * + * @param bool $asResource Set to TRUE to get an fopen resource + * + * @return string|resource|null + */ + public function getStderr($asResource = false) + { + $stderr = $this->getOptions()->get(CURLOPT_STDERR); + if (!$stderr) { + return null; + } + + if ($asResource) { + return $stderr; + } + + fseek($stderr, 0); + $e = stream_get_contents($stderr); + fseek($stderr, 0, SEEK_END); + + return $e; + } + + /** + * Get the URL that this handle is connecting to + * + * @return Url + */ + public function getUrl() + { + return Url::factory($this->options->get(CURLOPT_URL)); + } + + /** + * Get the wrapped curl handle + * + * @return resource|null Returns the cURL handle or null if it was closed + */ + public function getHandle() + { + return $this->isAvailable() ? $this->handle : null; + } + + /** + * Get the cURL setopt options of the handle. Changing values in the return object will have no effect on the curl + * handle after it is created. + * + * @return Collection + */ + public function getOptions() + { + return $this->options; + } + + /** + * Update a request based on the log messages of the CurlHandle + * + * @param RequestInterface $request Request to update + */ + public function updateRequestFromTransfer(RequestInterface $request) + { + if (!$request->getResponse()) { + return; + } + + // Update the transfer stats of the response + $request->getResponse()->setInfo($this->getInfo()); + + if (!$log = $this->getStderr(true)) { + return; + } + + // Parse the cURL stderr output for outgoing requests + $headers = ''; + fseek($log, 0); + while (($line = fgets($log)) !== false) { + if ($line && $line[0] == '>') { + $headers = substr(trim($line), 2) . "\r\n"; + while (($line = fgets($log)) !== false) { + if ($line[0] == '*' || $line[0] == '<') { + break; + } else { + $headers .= trim($line) . "\r\n"; + } + } + } + } + + // Add request headers to the request exactly as they were sent + if ($headers) { + $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($headers); + if (!empty($parsed['headers'])) { + $request->setHeaders(array()); + foreach ($parsed['headers'] as $name => $value) { + $request->setHeader($name, $value); + } + } + if (!empty($parsed['version'])) { + $request->setProtocolVersion($parsed['version']); + } + } + } + + /** + * Parse the config and replace curl.* configurators into the constant based values so it can be used elsewhere + * + * @param array|Collection $config The configuration we want to parse + * + * @return array + */ + public static function parseCurlConfig($config) + { + $curlOptions = array(); + foreach ($config as $key => $value) { + if (is_string($key) && defined($key)) { + // Convert constants represented as string to constant int values + $key = constant($key); + } + if (is_string($value) && defined($value)) { + $value = constant($value); + } + $curlOptions[$key] = $value; + } + + return $curlOptions; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php new file mode 100644 index 00000000..9e4e6372 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php @@ -0,0 +1,423 @@ + array('CURLM_BAD_HANDLE', 'The passed-in handle is not a valid CURLM handle.'), + CURLM_BAD_EASY_HANDLE => array('CURLM_BAD_EASY_HANDLE', "An easy handle was not good/valid. It could mean that it isn't an easy handle at all, or possibly that the handle already is in used by this or another multi handle."), + CURLM_OUT_OF_MEMORY => array('CURLM_OUT_OF_MEMORY', 'You are doomed.'), + CURLM_INTERNAL_ERROR => array('CURLM_INTERNAL_ERROR', 'This can only be returned if libcurl bugs. Please report it to us!') + ); + + /** @var float */ + protected $selectTimeout; + + public function __construct($selectTimeout = 1.0) + { + $this->selectTimeout = $selectTimeout; + $this->multiHandle = curl_multi_init(); + // @codeCoverageIgnoreStart + if ($this->multiHandle === false) { + throw new CurlException('Unable to create multi handle'); + } + // @codeCoverageIgnoreEnd + $this->reset(); + } + + public function __destruct() + { + if (is_resource($this->multiHandle)) { + curl_multi_close($this->multiHandle); + } + } + + public function add(RequestInterface $request) + { + $this->requests[] = $request; + // If requests are currently transferring and this is async, then the + // request must be prepared now as the send() method is not called. + $this->beforeSend($request); + $this->dispatch(self::ADD_REQUEST, array('request' => $request)); + + return $this; + } + + public function all() + { + return $this->requests; + } + + public function remove(RequestInterface $request) + { + $this->removeHandle($request); + if (($index = array_search($request, $this->requests, true)) !== false) { + $request = $this->requests[$index]; + unset($this->requests[$index]); + $this->requests = array_values($this->requests); + $this->dispatch(self::REMOVE_REQUEST, array('request' => $request)); + return true; + } + + return false; + } + + public function reset($hard = false) + { + // Remove each request + if ($this->requests) { + foreach ($this->requests as $request) { + $this->remove($request); + } + } + + $this->handles = new \SplObjectStorage(); + $this->requests = $this->resourceHash = $this->exceptions = $this->successful = array(); + } + + public function send() + { + $this->perform(); + $exceptions = $this->exceptions; + $successful = $this->successful; + $this->reset(); + + if ($exceptions) { + $this->throwMultiException($exceptions, $successful); + } + } + + public function count() + { + return count($this->requests); + } + + /** + * Build and throw a MultiTransferException + * + * @param array $exceptions Exceptions encountered + * @param array $successful Successful requests + * @throws MultiTransferException + */ + protected function throwMultiException(array $exceptions, array $successful) + { + $multiException = new MultiTransferException('Errors during multi transfer'); + + while ($e = array_shift($exceptions)) { + $multiException->addFailedRequestWithException($e['request'], $e['exception']); + } + + // Add successful requests + foreach ($successful as $request) { + if (!$multiException->containsRequest($request)) { + $multiException->addSuccessfulRequest($request); + } + } + + throw $multiException; + } + + /** + * Prepare for sending + * + * @param RequestInterface $request Request to prepare + * @throws \Exception on error preparing the request + */ + protected function beforeSend(RequestInterface $request) + { + try { + $state = $request->setState(RequestInterface::STATE_TRANSFER); + if ($state == RequestInterface::STATE_TRANSFER) { + $this->addHandle($request); + } else { + // Requests might decide they don't need to be sent just before + // transfer (e.g. CachePlugin) + $this->remove($request); + if ($state == RequestInterface::STATE_COMPLETE) { + $this->successful[] = $request; + } + } + } catch (\Exception $e) { + // Queue the exception to be thrown when sent + $this->removeErroredRequest($request, $e); + } + } + + private function addHandle(RequestInterface $request) + { + $handle = $this->createCurlHandle($request)->getHandle(); + $this->checkCurlResult( + curl_multi_add_handle($this->multiHandle, $handle) + ); + } + + /** + * Create a curl handle for a request + * + * @param RequestInterface $request Request + * + * @return CurlHandle + */ + protected function createCurlHandle(RequestInterface $request) + { + $wrapper = CurlHandle::factory($request); + $this->handles[$request] = $wrapper; + $this->resourceHash[(int) $wrapper->getHandle()] = $request; + + return $wrapper; + } + + /** + * Get the data from the multi handle + */ + protected function perform() + { + $event = new Event(array('curl_multi' => $this)); + + while ($this->requests) { + // Notify each request as polling + $blocking = $total = 0; + foreach ($this->requests as $request) { + ++$total; + $event['request'] = $request; + $request->getEventDispatcher()->dispatch(self::POLLING_REQUEST, $event); + // The blocking variable just has to be non-falsey to block the loop + if ($request->getParams()->hasKey(self::BLOCKING)) { + ++$blocking; + } + } + if ($blocking == $total) { + // Sleep to prevent eating CPU because no requests are actually pending a select call + usleep(500); + } else { + $this->executeHandles(); + } + } + } + + /** + * Execute and select curl handles + */ + private function executeHandles() + { + // The first curl_multi_select often times out no matter what, but is usually required for fast transfers + $selectTimeout = 0.001; + $active = false; + do { + while (($mrc = curl_multi_exec($this->multiHandle, $active)) == CURLM_CALL_MULTI_PERFORM); + $this->checkCurlResult($mrc); + $this->processMessages(); + if ($active && curl_multi_select($this->multiHandle, $selectTimeout) === -1) { + // Perform a usleep if a select returns -1: https://bugs.php.net/bug.php?id=61141 + usleep(150); + } + $selectTimeout = $this->selectTimeout; + } while ($active); + } + + /** + * Process any received curl multi messages + */ + private function processMessages() + { + while ($done = curl_multi_info_read($this->multiHandle)) { + $request = $this->resourceHash[(int) $done['handle']]; + try { + $this->processResponse($request, $this->handles[$request], $done); + $this->successful[] = $request; + } catch (\Exception $e) { + $this->removeErroredRequest($request, $e); + } + } + } + + /** + * Remove a request that encountered an exception + * + * @param RequestInterface $request Request to remove + * @param \Exception $e Exception encountered + */ + protected function removeErroredRequest(RequestInterface $request, \Exception $e = null) + { + $this->exceptions[] = array('request' => $request, 'exception' => $e); + $this->remove($request); + $this->dispatch(self::MULTI_EXCEPTION, array('exception' => $e, 'all_exceptions' => $this->exceptions)); + } + + /** + * Check for errors and fix headers of a request based on a curl response + * + * @param RequestInterface $request Request to process + * @param CurlHandle $handle Curl handle object + * @param array $curl Array returned from curl_multi_info_read + * + * @throws CurlException on Curl error + */ + protected function processResponse(RequestInterface $request, CurlHandle $handle, array $curl) + { + // Set the transfer stats on the response + $handle->updateRequestFromTransfer($request); + // Check if a cURL exception occurred, and if so, notify things + $curlException = $this->isCurlException($request, $handle, $curl); + + // Always remove completed curl handles. They can be added back again + // via events if needed (e.g. ExponentialBackoffPlugin) + $this->removeHandle($request); + + if (!$curlException) { + if ($this->validateResponseWasSet($request)) { + $state = $request->setState( + RequestInterface::STATE_COMPLETE, + array('handle' => $handle) + ); + // Only remove the request if it wasn't resent as a result of + // the state change + if ($state != RequestInterface::STATE_TRANSFER) { + $this->remove($request); + } + } + return; + } + + // Set the state of the request to an error + $state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $curlException)); + // Allow things to ignore the error if possible + if ($state != RequestInterface::STATE_TRANSFER) { + $this->remove($request); + } + + // The error was not handled, so fail + if ($state == RequestInterface::STATE_ERROR) { + /** @var CurlException $curlException */ + throw $curlException; + } + } + + /** + * Remove a curl handle from the curl multi object + * + * @param RequestInterface $request Request that owns the handle + */ + protected function removeHandle(RequestInterface $request) + { + if (isset($this->handles[$request])) { + $handle = $this->handles[$request]; + curl_multi_remove_handle($this->multiHandle, $handle->getHandle()); + unset($this->handles[$request]); + unset($this->resourceHash[(int) $handle->getHandle()]); + $handle->close(); + } + } + + /** + * Check if a cURL transfer resulted in what should be an exception + * + * @param RequestInterface $request Request to check + * @param CurlHandle $handle Curl handle object + * @param array $curl Array returned from curl_multi_info_read + * + * @return CurlException|bool + */ + private function isCurlException(RequestInterface $request, CurlHandle $handle, array $curl) + { + if (CURLM_OK == $curl['result'] || CURLM_CALL_MULTI_PERFORM == $curl['result']) { + return false; + } + + $handle->setErrorNo($curl['result']); + $e = new CurlException(sprintf('[curl] %s: %s [url] %s', + $handle->getErrorNo(), $handle->getError(), $handle->getUrl())); + $e->setCurlHandle($handle) + ->setRequest($request) + ->setCurlInfo($handle->getInfo()) + ->setError($handle->getError(), $handle->getErrorNo()); + + return $e; + } + + /** + * Throw an exception for a cURL multi response if needed + * + * @param int $code Curl response code + * @throws CurlException + */ + private function checkCurlResult($code) + { + if ($code != CURLM_OK && $code != CURLM_CALL_MULTI_PERFORM) { + throw new CurlException(isset($this->multiErrors[$code]) + ? "cURL error: {$code} ({$this->multiErrors[$code][0]}): cURL message: {$this->multiErrors[$code][1]}" + : 'Unexpected cURL error: ' . $code + ); + } + } + + /** + * @link https://github.com/guzzle/guzzle/issues/710 + */ + private function validateResponseWasSet(RequestInterface $request) + { + if ($request->getResponse()) { + return true; + } + + $body = $request instanceof EntityEnclosingRequestInterface + ? $request->getBody() + : null; + + if (!$body) { + $rex = new RequestException( + 'No response was received for a request with no body. This' + . ' could mean that you are saturating your network.' + ); + $rex->setRequest($request); + $this->removeErroredRequest($request, $rex); + } elseif (!$body->isSeekable() || !$body->seek(0)) { + // Nothing we can do with this. Sorry! + $rex = new RequestException( + 'The connection was unexpectedly closed. The request would' + . ' have been retried, but attempting to rewind the' + . ' request body failed.' + ); + $rex->setRequest($request); + $this->removeErroredRequest($request, $rex); + } else { + $this->remove($request); + // Add the request back to the batch to retry automatically. + $this->requests[] = $request; + $this->addHandle($request); + } + + return false; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php new file mode 100644 index 00000000..0ead7573 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php @@ -0,0 +1,58 @@ +maxHandles = $maxHandles; + $this->selectTimeout = $selectTimeout; + // You can get some weird "Too many open files" errors when sending a large amount of requests in parallel. + // These two statements autoload classes before a system runs out of file descriptors so that you can get back + // valuable error messages if you run out. + class_exists('Guzzle\Http\Message\Response'); + class_exists('Guzzle\Http\Exception\CurlException'); + } + + public function add(RequestInterface $request) + { + $this->queued[] = $request; + + return $this; + } + + public function all() + { + $requests = $this->queued; + foreach ($this->handles as $handle) { + $requests = array_merge($requests, $handle->all()); + } + + return $requests; + } + + public function remove(RequestInterface $request) + { + foreach ($this->queued as $i => $r) { + if ($request === $r) { + unset($this->queued[$i]); + return true; + } + } + + foreach ($this->handles as $handle) { + if ($handle->remove($request)) { + return true; + } + } + + return false; + } + + public function reset($hard = false) + { + $this->queued = array(); + $this->groups = array(); + foreach ($this->handles as $handle) { + $handle->reset(); + } + if ($hard) { + $this->handles = array(); + } + + return $this; + } + + public function send() + { + if ($this->queued) { + $group = $this->getAvailableHandle(); + // Add this handle to a list of handles than is claimed + $this->groups[] = $group; + while ($request = array_shift($this->queued)) { + $group->add($request); + } + try { + $group->send(); + array_pop($this->groups); + $this->cleanupHandles(); + } catch (\Exception $e) { + // Remove the group and cleanup if an exception was encountered and no more requests in group + if (!$group->count()) { + array_pop($this->groups); + $this->cleanupHandles(); + } + throw $e; + } + } + } + + public function count() + { + return count($this->all()); + } + + /** + * Get an existing available CurlMulti handle or create a new one + * + * @return CurlMulti + */ + protected function getAvailableHandle() + { + // Grab a handle that is not claimed + foreach ($this->handles as $h) { + if (!in_array($h, $this->groups, true)) { + return $h; + } + } + + // All are claimed, so create one + $handle = new CurlMulti($this->selectTimeout); + $handle->setEventDispatcher($this->getEventDispatcher()); + $this->handles[] = $handle; + + return $handle; + } + + /** + * Trims down unused CurlMulti handles to limit the number of open connections + */ + protected function cleanupHandles() + { + if ($diff = max(0, count($this->handles) - $this->maxHandles)) { + for ($i = count($this->handles) - 1; $i > 0 && $diff > 0; $i--) { + if (!count($this->handles[$i])) { + unset($this->handles[$i]); + $diff--; + } + } + $this->handles = array_values($this->handles); + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php new file mode 100644 index 00000000..c3f99dd2 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php @@ -0,0 +1,66 @@ +version) { + $this->version = curl_version(); + } + + return $this->version; + } + + /** + * Get a specific type of curl information + * + * @param string $type Version information to retrieve. This value is one of: + * - version_number: cURL 24 bit version number + * - version: cURL version number, as a string + * - ssl_version_number: OpenSSL 24 bit version number + * - ssl_version: OpenSSL version number, as a string + * - libz_version: zlib version number, as a string + * - host: Information about the host where cURL was built + * - features: A bitmask of the CURL_VERSION_XXX constants + * - protocols: An array of protocols names supported by cURL + * + * @return string|float|bool if the $type is found, and false if not found + */ + public function get($type) + { + $version = $this->getAll(); + + return isset($version[$type]) ? $version[$type] : false; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php new file mode 100644 index 00000000..5d1a0cd8 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php @@ -0,0 +1,147 @@ +request = $request; + $this->emitIo = $emitIo; + } + + /** + * Receive a response header from curl + * + * @param resource $curl Curl handle + * @param string $header Received header + * + * @return int + */ + public function receiveResponseHeader($curl, $header) + { + static $normalize = array("\r", "\n"); + $length = strlen($header); + $header = str_replace($normalize, '', $header); + + if (strpos($header, 'HTTP/') === 0) { + + $startLine = explode(' ', $header, 3); + $code = $startLine[1]; + $status = isset($startLine[2]) ? $startLine[2] : ''; + + // Only download the body of the response to the specified response + // body when a successful response is received. + if ($code >= 200 && $code < 300) { + $body = $this->request->getResponseBody(); + } else { + $body = EntityBody::factory(); + } + + $response = new Response($code, null, $body); + $response->setStatus($code, $status); + $this->request->startResponse($response); + + $this->request->dispatch('request.receive.status_line', array( + 'request' => $this, + 'line' => $header, + 'status_code' => $code, + 'reason_phrase' => $status + )); + + } elseif ($pos = strpos($header, ':')) { + $this->request->getResponse()->addHeader( + trim(substr($header, 0, $pos)), + trim(substr($header, $pos + 1)) + ); + } + + return $length; + } + + /** + * Received a progress notification + * + * @param int $downloadSize Total download size + * @param int $downloaded Amount of bytes downloaded + * @param int $uploadSize Total upload size + * @param int $uploaded Amount of bytes uploaded + * @param resource $handle CurlHandle object + */ + public function progress($downloadSize, $downloaded, $uploadSize, $uploaded, $handle = null) + { + $this->request->dispatch('curl.callback.progress', array( + 'request' => $this->request, + 'handle' => $handle, + 'download_size' => $downloadSize, + 'downloaded' => $downloaded, + 'upload_size' => $uploadSize, + 'uploaded' => $uploaded + )); + } + + /** + * Write data to the response body of a request + * + * @param resource $curl Curl handle + * @param string $write Data that was received + * + * @return int + */ + public function writeResponseBody($curl, $write) + { + if ($this->emitIo) { + $this->request->dispatch('curl.callback.write', array( + 'request' => $this->request, + 'write' => $write + )); + } + + if ($response = $this->request->getResponse()) { + return $response->getBody()->write($write); + } else { + // Unexpected data received before response headers - abort transfer + return 0; + } + } + + /** + * Read data from the request body and send it to curl + * + * @param resource $ch Curl handle + * @param resource $fd File descriptor + * @param int $length Amount of data to read + * + * @return string + */ + public function readRequestBody($ch, $fd, $length) + { + if (!($body = $this->request->getBody())) { + return ''; + } + + $read = (string) $body->read($length); + if ($this->emitIo) { + $this->request->dispatch('curl.callback.read', array('request' => $this->request, 'read' => $read)); + } + + return $read; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/EntityBody.php b/src/lib/vendor/guzzle/http/Guzzle/Http/EntityBody.php new file mode 100644 index 00000000..b60d170f --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/EntityBody.php @@ -0,0 +1,201 @@ +rewindFunction = $callable; + + return $this; + } + + public function rewind() + { + return $this->rewindFunction ? call_user_func($this->rewindFunction, $this) : parent::rewind(); + } + + /** + * Create a new EntityBody from a string + * + * @param string $string String of data + * + * @return EntityBody + */ + public static function fromString($string) + { + $stream = fopen('php://temp', 'r+'); + if ($string !== '') { + fwrite($stream, $string); + rewind($stream); + } + + return new static($stream); + } + + public function compress($filter = 'zlib.deflate') + { + $result = $this->handleCompression($filter); + $this->contentEncoding = $result ? $filter : false; + + return $result; + } + + public function uncompress($filter = 'zlib.inflate') + { + $offsetStart = 0; + + // When inflating gzipped data, the first 10 bytes must be stripped + // if a gzip header is present + if ($filter == 'zlib.inflate') { + // @codeCoverageIgnoreStart + if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { + return false; + } + // @codeCoverageIgnoreEnd + if (stream_get_contents($this->stream, 3, 0) === "\x1f\x8b\x08") { + $offsetStart = 10; + } + } + + $this->contentEncoding = false; + + return $this->handleCompression($filter, $offsetStart); + } + + public function getContentLength() + { + return $this->getSize(); + } + + public function getContentType() + { + return $this->getUri() ? Mimetypes::getInstance()->fromFilename($this->getUri()) : null; + } + + public function getContentMd5($rawOutput = false, $base64Encode = false) + { + if ($hash = self::getHash($this, 'md5', $rawOutput)) { + return $hash && $base64Encode ? base64_encode($hash) : $hash; + } else { + return false; + } + } + + /** + * Calculate the MD5 hash of an entity body + * + * @param EntityBodyInterface $body Entity body to calculate the hash for + * @param bool $rawOutput Whether or not to use raw output + * @param bool $base64Encode Whether or not to base64 encode raw output (only if raw output is true) + * + * @return bool|string Returns an MD5 string on success or FALSE on failure + * @deprecated This will be deprecated soon + * @codeCoverageIgnore + */ + public static function calculateMd5(EntityBodyInterface $body, $rawOutput = false, $base64Encode = false) + { + Version::warn(__CLASS__ . ' is deprecated. Use getContentMd5()'); + return $body->getContentMd5($rawOutput, $base64Encode); + } + + public function setStreamFilterContentEncoding($streamFilterContentEncoding) + { + $this->contentEncoding = $streamFilterContentEncoding; + + return $this; + } + + public function getContentEncoding() + { + return strtr($this->contentEncoding, array( + 'zlib.deflate' => 'gzip', + 'bzip2.compress' => 'compress' + )) ?: false; + } + + protected function handleCompression($filter, $offsetStart = 0) + { + // @codeCoverageIgnoreStart + if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { + return false; + } + // @codeCoverageIgnoreEnd + + $handle = fopen('php://temp', 'r+'); + $filter = @stream_filter_append($handle, $filter, STREAM_FILTER_WRITE); + if (!$filter) { + return false; + } + + // Seek to the offset start if possible + $this->seek($offsetStart); + while ($data = fread($this->stream, 8096)) { + fwrite($handle, $data); + } + + fclose($this->stream); + $this->stream = $handle; + stream_filter_remove($filter); + $stat = fstat($this->stream); + $this->size = $stat['size']; + $this->rebuildCache(); + $this->seek(0); + + // Remove any existing rewind function as the underlying stream has been replaced + $this->rewindFunction = null; + + return true; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php new file mode 100644 index 00000000..e640f578 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php @@ -0,0 +1,73 @@ +isClientError()) { + $label = 'Client error response'; + $class = __NAMESPACE__ . '\\ClientErrorResponseException'; + } elseif ($response->isServerError()) { + $label = 'Server error response'; + $class = __NAMESPACE__ . '\\ServerErrorResponseException'; + } else { + $label = 'Unsuccessful response'; + $class = __CLASS__; + } + + $message = $label . PHP_EOL . implode(PHP_EOL, array( + '[status code] ' . $response->getStatusCode(), + '[reason phrase] ' . $response->getReasonPhrase(), + '[url] ' . $request->getUrl(), + )); + + $e = new $class($message); + $e->setResponse($response); + $e->setRequest($request); + + return $e; + } + + /** + * Set the response that caused the exception + * + * @param Response $response Response to set + */ + public function setResponse(Response $response) + { + $this->response = $response; + } + + /** + * Get the response that caused the exception + * + * @return Response + */ + public function getResponse() + { + return $this->response; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/ClientErrorResponseException.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/ClientErrorResponseException.php new file mode 100644 index 00000000..04d7ddc0 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/ClientErrorResponseException.php @@ -0,0 +1,8 @@ +curlError = $error; + $this->curlErrorNo = $number; + + return $this; + } + + /** + * Set the associated curl handle + * + * @param CurlHandle $handle Curl handle + * + * @return self + */ + public function setCurlHandle(CurlHandle $handle) + { + $this->handle = $handle; + + return $this; + } + + /** + * Get the associated cURL handle + * + * @return CurlHandle|null + */ + public function getCurlHandle() + { + return $this->handle; + } + + /** + * Get the associated cURL error message + * + * @return string|null + */ + public function getError() + { + return $this->curlError; + } + + /** + * Get the associated cURL error number + * + * @return int|null + */ + public function getErrorNo() + { + return $this->curlErrorNo; + } + + /** + * Returns curl information about the transfer + * + * @return array + */ + public function getCurlInfo() + { + return $this->curlInfo; + } + + /** + * Set curl transfer information + * + * @param array $info Array of curl transfer information + * + * @return self + * @link http://php.net/manual/en/function.curl-getinfo.php + */ + public function setCurlInfo(array $info) + { + $this->curlInfo = $info; + + return $this; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/HttpException.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/HttpException.php new file mode 100644 index 00000000..ee87295d --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/HttpException.php @@ -0,0 +1,10 @@ +successfulRequests, $this->failedRequests); + } + + /** + * Add to the array of successful requests + * + * @param RequestInterface $request Successful request + * + * @return self + */ + public function addSuccessfulRequest(RequestInterface $request) + { + $this->successfulRequests[] = $request; + + return $this; + } + + /** + * Add to the array of failed requests + * + * @param RequestInterface $request Failed request + * + * @return self + */ + public function addFailedRequest(RequestInterface $request) + { + $this->failedRequests[] = $request; + + return $this; + } + + /** + * Add to the array of failed requests and associate with exceptions + * + * @param RequestInterface $request Failed request + * @param \Exception $exception Exception to add and associate with + * + * @return self + */ + public function addFailedRequestWithException(RequestInterface $request, \Exception $exception) + { + $this->add($exception) + ->addFailedRequest($request) + ->exceptionForRequest[spl_object_hash($request)] = $exception; + + return $this; + } + + /** + * Get the Exception that caused the given $request to fail + * + * @param RequestInterface $request Failed command + * + * @return \Exception|null + */ + public function getExceptionForFailedRequest(RequestInterface $request) + { + $oid = spl_object_hash($request); + + return isset($this->exceptionForRequest[$oid]) ? $this->exceptionForRequest[$oid] : null; + } + + /** + * Set all of the successful requests + * + * @param array Array of requests + * + * @return self + */ + public function setSuccessfulRequests(array $requests) + { + $this->successfulRequests = $requests; + + return $this; + } + + /** + * Set all of the failed requests + * + * @param array Array of requests + * + * @return self + */ + public function setFailedRequests(array $requests) + { + $this->failedRequests = $requests; + + return $this; + } + + /** + * Get an array of successful requests sent in the multi transfer + * + * @return array + */ + public function getSuccessfulRequests() + { + return $this->successfulRequests; + } + + /** + * Get an array of failed requests sent in the multi transfer + * + * @return array + */ + public function getFailedRequests() + { + return $this->failedRequests; + } + + /** + * Check if the exception object contains a request + * + * @param RequestInterface $request Request to check + * + * @return bool + */ + public function containsRequest(RequestInterface $request) + { + return in_array($request, $this->failedRequests, true) || in_array($request, $this->successfulRequests, true); + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php new file mode 100644 index 00000000..274df2cb --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php @@ -0,0 +1,39 @@ +request = $request; + + return $this; + } + + /** + * Get the request that caused the exception + * + * @return RequestInterface + */ + public function getRequest() + { + return $this->request; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/ServerErrorResponseException.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/ServerErrorResponseException.php new file mode 100644 index 00000000..f0f7cfe4 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Exception/ServerErrorResponseException.php @@ -0,0 +1,8 @@ +eventDispatcher = $eventDispatcher; + + return $this; + } + + public function getEventDispatcher() + { + if (!$this->eventDispatcher) { + $this->eventDispatcher = new EventDispatcher(); + } + + return $this->eventDispatcher; + } + + public function dispatch($eventName, array $context = array()) + { + return $this->getEventDispatcher()->dispatch($eventName, new Event($context)); + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->getEventDispatcher()->addSubscriber($subscriber); + + return $this; + } + + public function read($length) + { + $event = array( + 'body' => $this, + 'length' => $length, + 'read' => $this->body->read($length) + ); + $this->dispatch('body.read', $event); + + return $event['read']; + } + + public function write($string) + { + $event = array( + 'body' => $this, + 'write' => $string, + 'result' => $this->body->write($string) + ); + $this->dispatch('body.write', $event); + + return $event['result']; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php new file mode 100644 index 00000000..0d066ffc --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php @@ -0,0 +1,220 @@ +params = new Collection(); + $this->headerFactory = new HeaderFactory(); + $this->headers = new HeaderCollection(); + } + + /** + * Set the header factory to use to create headers + * + * @param HeaderFactoryInterface $factory + * + * @return self + */ + public function setHeaderFactory(HeaderFactoryInterface $factory) + { + $this->headerFactory = $factory; + + return $this; + } + + public function getParams() + { + return $this->params; + } + + public function addHeader($header, $value) + { + if (isset($this->headers[$header])) { + $this->headers[$header]->add($value); + } elseif ($value instanceof HeaderInterface) { + $this->headers[$header] = $value; + } else { + $this->headers[$header] = $this->headerFactory->createHeader($header, $value); + } + + return $this; + } + + public function addHeaders(array $headers) + { + foreach ($headers as $key => $value) { + $this->addHeader($key, $value); + } + + return $this; + } + + public function getHeader($header) + { + return $this->headers[$header]; + } + + public function getHeaders() + { + return $this->headers; + } + + public function getHeaderLines() + { + $headers = array(); + foreach ($this->headers as $value) { + $headers[] = $value->getName() . ': ' . $value; + } + + return $headers; + } + + public function setHeader($header, $value) + { + unset($this->headers[$header]); + $this->addHeader($header, $value); + + return $this; + } + + public function setHeaders(array $headers) + { + $this->headers->clear(); + foreach ($headers as $key => $value) { + $this->addHeader($key, $value); + } + + return $this; + } + + public function hasHeader($header) + { + return isset($this->headers[$header]); + } + + public function removeHeader($header) + { + unset($this->headers[$header]); + + return $this; + } + + /** + * @deprecated Use $message->getHeader()->parseParams() + * @codeCoverageIgnore + */ + public function getTokenizedHeader($header, $token = ';') + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader()->parseParams()'); + if ($this->hasHeader($header)) { + $data = new Collection(); + foreach ($this->getHeader($header)->parseParams() as $values) { + foreach ($values as $key => $value) { + if ($value === '') { + $data->set($data->count(), $key); + } else { + $data->add($key, $value); + } + } + } + return $data; + } + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function setTokenizedHeader($header, $data, $token = ';') + { + Version::warn(__METHOD__ . ' is deprecated.'); + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getCacheControlDirective($directive) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->getDirective()'); + if (!($header = $this->getHeader('Cache-Control'))) { + return null; + } + + return $header->getDirective($directive); + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function hasCacheControlDirective($directive) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->hasDirective()'); + if ($header = $this->getHeader('Cache-Control')) { + return $header->hasDirective($directive); + } else { + return false; + } + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function addCacheControlDirective($directive, $value = true) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->addDirective()'); + if (!($header = $this->getHeader('Cache-Control'))) { + $this->addHeader('Cache-Control', ''); + $header = $this->getHeader('Cache-Control'); + } + + $header->addDirective($directive, $value); + + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function removeCacheControlDirective($directive) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->removeDirective()'); + if ($header = $this->getHeader('Cache-Control')) { + $header->removeDirective($directive); + } + + return $this; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php new file mode 100644 index 00000000..212850a2 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php @@ -0,0 +1,247 @@ +postFields = new QueryString(); + parent::__construct($method, $url, $headers); + } + + /** + * @return string + */ + public function __toString() + { + // Only attempt to include the POST data if it's only fields + if (count($this->postFields) && empty($this->postFiles)) { + return parent::__toString() . (string) $this->postFields; + } + + return parent::__toString() . $this->body; + } + + public function setState($state, array $context = array()) + { + parent::setState($state, $context); + if ($state == self::STATE_TRANSFER && !$this->body && !count($this->postFields) && !count($this->postFiles)) { + $this->setHeader('Content-Length', 0)->removeHeader('Transfer-Encoding'); + } + + return $this->state; + } + + public function setBody($body, $contentType = null) + { + $this->body = EntityBody::factory($body); + + // Auto detect the Content-Type from the path of the request if possible + if ($contentType === null && !$this->hasHeader('Content-Type')) { + $contentType = $this->body->getContentType(); + } + + if ($contentType) { + $this->setHeader('Content-Type', $contentType); + } + + // Always add the Expect 100-Continue header if the body cannot be rewound. This helps with redirects. + if (!$this->body->isSeekable() && $this->expectCutoff !== false) { + $this->setHeader('Expect', '100-Continue'); + } + + // Set the Content-Length header if it can be determined + $size = $this->body->getContentLength(); + if ($size !== null && $size !== false) { + $this->setHeader('Content-Length', $size); + if ($size > $this->expectCutoff) { + $this->setHeader('Expect', '100-Continue'); + } + } elseif (!$this->hasHeader('Content-Length')) { + if ('1.1' == $this->protocolVersion) { + $this->setHeader('Transfer-Encoding', 'chunked'); + } else { + throw new RequestException( + 'Cannot determine Content-Length and cannot use chunked Transfer-Encoding when using HTTP/1.0' + ); + } + } + + return $this; + } + + public function getBody() + { + return $this->body; + } + + /** + * Set the size that the entity body of the request must exceed before adding the Expect: 100-Continue header. + * + * @param int|bool $size Cutoff in bytes. Set to false to never send the expect header (even with non-seekable data) + * + * @return self + */ + public function setExpectHeaderCutoff($size) + { + $this->expectCutoff = $size; + if ($size === false || !$this->body) { + $this->removeHeader('Expect'); + } elseif ($this->body && $this->body->getSize() && $this->body->getSize() > $size) { + $this->setHeader('Expect', '100-Continue'); + } + + return $this; + } + + public function configureRedirects($strict = false, $maxRedirects = 5) + { + $this->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, $strict); + if ($maxRedirects == 0) { + $this->getParams()->set(RedirectPlugin::DISABLE, true); + } else { + $this->getParams()->set(RedirectPlugin::MAX_REDIRECTS, $maxRedirects); + } + + return $this; + } + + public function getPostField($field) + { + return $this->postFields->get($field); + } + + public function getPostFields() + { + return $this->postFields; + } + + public function setPostField($key, $value) + { + $this->postFields->set($key, $value); + $this->processPostFields(); + + return $this; + } + + public function addPostFields($fields) + { + $this->postFields->merge($fields); + $this->processPostFields(); + + return $this; + } + + public function removePostField($field) + { + $this->postFields->remove($field); + $this->processPostFields(); + + return $this; + } + + public function getPostFiles() + { + return $this->postFiles; + } + + public function getPostFile($fieldName) + { + return isset($this->postFiles[$fieldName]) ? $this->postFiles[$fieldName] : null; + } + + public function removePostFile($fieldName) + { + unset($this->postFiles[$fieldName]); + $this->processPostFields(); + + return $this; + } + + public function addPostFile($field, $filename = null, $contentType = null, $postname = null) + { + $data = null; + + if ($field instanceof PostFileInterface) { + $data = $field; + } elseif (is_array($filename)) { + // Allow multiple values to be set in a single key + foreach ($filename as $file) { + $this->addPostFile($field, $file, $contentType); + } + return $this; + } elseif (!is_string($filename)) { + throw new RequestException('The path to a file must be a string'); + } elseif (!empty($filename)) { + // Adding an empty file will cause cURL to error out + $data = new PostFile($field, $filename, $contentType, $postname); + } + + if ($data) { + if (!isset($this->postFiles[$data->getFieldName()])) { + $this->postFiles[$data->getFieldName()] = array($data); + } else { + $this->postFiles[$data->getFieldName()][] = $data; + } + $this->processPostFields(); + } + + return $this; + } + + public function addPostFiles(array $files) + { + foreach ($files as $key => $file) { + if ($file instanceof PostFileInterface) { + $this->addPostFile($file, null, null, false); + } elseif (is_string($file)) { + // Convert non-associative array keys into 'file' + if (is_numeric($key)) { + $key = 'file'; + } + $this->addPostFile($key, $file, null, false); + } else { + throw new RequestException('File must be a string or instance of PostFileInterface'); + } + } + + return $this; + } + + /** + * Determine what type of request should be sent based on post fields + */ + protected function processPostFields() + { + if (!$this->postFiles) { + $this->removeHeader('Expect')->setHeader('Content-Type', self::URL_ENCODED); + } else { + $this->setHeader('Content-Type', self::MULTIPART); + if ($this->expectCutoff !== false) { + $this->setHeader('Expect', '100-Continue'); + } + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php new file mode 100644 index 00000000..49ad4595 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php @@ -0,0 +1,137 @@ + filenames where filename can be a string or PostFileInterface + * + * @return self + */ + public function addPostFiles(array $files); + + /** + * Configure how redirects are handled for the request + * + * @param bool $strict Set to true to follow strict RFC compliance when redirecting POST requests. Most + * browsers with follow a 301-302 redirect for a POST request with a GET request. This is + * the default behavior of Guzzle. Enable strict redirects to redirect these responses + * with a POST rather than a GET request. + * @param int $maxRedirects Specify the maximum number of allowed redirects. Set to 0 to disable redirects. + * + * @return self + */ + public function configureRedirects($strict = false, $maxRedirects = 5); +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header.php new file mode 100644 index 00000000..50597b2a --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header.php @@ -0,0 +1,182 @@ +header = trim($header); + $this->glue = $glue; + + foreach ((array) $values as $value) { + foreach ((array) $value as $v) { + $this->values[] = $v; + } + } + } + + public function __toString() + { + return implode($this->glue . ' ', $this->toArray()); + } + + public function add($value) + { + $this->values[] = $value; + + return $this; + } + + public function getName() + { + return $this->header; + } + + public function setName($name) + { + $this->header = $name; + + return $this; + } + + public function setGlue($glue) + { + $this->glue = $glue; + + return $this; + } + + public function getGlue() + { + return $this->glue; + } + + /** + * Normalize the header to be a single header with an array of values. + * + * If any values of the header contains the glue string value (e.g. ","), then the value will be exploded into + * multiple entries in the header. + * + * @return self + */ + public function normalize() + { + $values = $this->toArray(); + + for ($i = 0, $total = count($values); $i < $total; $i++) { + if (strpos($values[$i], $this->glue) !== false) { + // Explode on glue when the glue is not inside of a comma + foreach (preg_split('/' . preg_quote($this->glue) . '(?=([^"]*"[^"]*")*[^"]*$)/', $values[$i]) as $v) { + $values[] = trim($v); + } + unset($values[$i]); + } + } + + $this->values = array_values($values); + + return $this; + } + + public function hasValue($searchValue) + { + return in_array($searchValue, $this->toArray()); + } + + public function removeValue($searchValue) + { + $this->values = array_values(array_filter($this->values, function ($value) use ($searchValue) { + return $value != $searchValue; + })); + + return $this; + } + + public function toArray() + { + return $this->values; + } + + public function count() + { + return count($this->toArray()); + } + + public function getIterator() + { + return new \ArrayIterator($this->toArray()); + } + + public function parseParams() + { + $params = $matches = array(); + $callback = array($this, 'trimHeader'); + + // Normalize the header into a single array and iterate over all values + foreach ($this->normalize()->toArray() as $val) { + $part = array(); + foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { + if (!preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { + continue; + } + $pieces = array_map($callback, $matches[0]); + $part[$pieces[0]] = isset($pieces[1]) ? $pieces[1] : ''; + } + if ($part) { + $params[] = $part; + } + } + + return $params; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function hasExactHeader($header) + { + Version::warn(__METHOD__ . ' is deprecated'); + return $this->header == $header; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function raw() + { + Version::warn(__METHOD__ . ' is deprecated. Use toArray()'); + return $this->toArray(); + } + + /** + * Trim a header by removing excess spaces and wrapping quotes + * + * @param $str + * + * @return string + */ + protected function trimHeader($str) + { + static $trimmed = "\"' \n\t"; + + return trim($str, $trimmed); + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php new file mode 100644 index 00000000..77789e51 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php @@ -0,0 +1,121 @@ +directives = null; + } + + public function removeValue($searchValue) + { + parent::removeValue($searchValue); + $this->directives = null; + } + + /** + * Check if a specific cache control directive exists + * + * @param string $param Directive to retrieve + * + * @return bool + */ + public function hasDirective($param) + { + $directives = $this->getDirectives(); + + return isset($directives[$param]); + } + + /** + * Get a specific cache control directive + * + * @param string $param Directive to retrieve + * + * @return string|bool|null + */ + public function getDirective($param) + { + $directives = $this->getDirectives(); + + return isset($directives[$param]) ? $directives[$param] : null; + } + + /** + * Add a cache control directive + * + * @param string $param Directive to add + * @param string $value Value to set + * + * @return self + */ + public function addDirective($param, $value) + { + $directives = $this->getDirectives(); + $directives[$param] = $value; + $this->updateFromDirectives($directives); + + return $this; + } + + /** + * Remove a cache control directive by name + * + * @param string $param Directive to remove + * + * @return self + */ + public function removeDirective($param) + { + $directives = $this->getDirectives(); + unset($directives[$param]); + $this->updateFromDirectives($directives); + + return $this; + } + + /** + * Get an associative array of cache control directives + * + * @return array + */ + public function getDirectives() + { + if ($this->directives === null) { + $this->directives = array(); + foreach ($this->parseParams() as $collection) { + foreach ($collection as $key => $value) { + $this->directives[$key] = $value === '' ? true : $value; + } + } + } + + return $this->directives; + } + + /** + * Updates the header value based on the parsed directives + * + * @param array $directives Array of cache control directives + */ + protected function updateFromDirectives(array $directives) + { + $this->directives = $directives; + $this->values = array(); + + foreach ($directives as $key => $value) { + $this->values[] = $value === true ? $key : "{$key}={$value}"; + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php new file mode 100644 index 00000000..8c7f6aef --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php @@ -0,0 +1,108 @@ +headers = $headers; + } + + public function __clone() + { + foreach ($this->headers as &$header) { + $header = clone $header; + } + } + + /** + * Clears the header collection + */ + public function clear() + { + $this->headers = array(); + } + + /** + * Set a header on the collection + * + * @param HeaderInterface $header Header to add + * + * @return self + */ + public function add(HeaderInterface $header) + { + $this->headers[strtolower($header->getName())] = $header; + + return $this; + } + + /** + * Get an array of header objects + * + * @return array + */ + public function getAll() + { + return $this->headers; + } + + /** + * Alias of offsetGet + */ + public function get($key) + { + return $this->offsetGet($key); + } + + public function count() + { + return count($this->headers); + } + + public function offsetExists($offset) + { + return isset($this->headers[strtolower($offset)]); + } + + public function offsetGet($offset) + { + $l = strtolower($offset); + + return isset($this->headers[$l]) ? $this->headers[$l] : null; + } + + public function offsetSet($offset, $value) + { + $this->add($value); + } + + public function offsetUnset($offset) + { + unset($this->headers[strtolower($offset)]); + } + + public function getIterator() + { + return new \ArrayIterator($this->headers); + } + + public function toArray() + { + $result = array(); + foreach ($this->headers as $header) { + $result[$header->getName()] = $header->toArray(); + } + + return $result; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php new file mode 100644 index 00000000..0273be52 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php @@ -0,0 +1,26 @@ + 'Guzzle\Http\Message\Header\CacheControl', + 'link' => 'Guzzle\Http\Message\Header\Link', + ); + + public function createHeader($header, $value = null) + { + $lowercase = strtolower($header); + + return isset($this->mapping[$lowercase]) + ? new $this->mapping[$lowercase]($header, $value) + : new Header($header, $value); + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php new file mode 100644 index 00000000..9457cf64 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php @@ -0,0 +1,19 @@ +", "rel=\"{$rel}\""); + + foreach ($params as $k => $v) { + $values[] = "{$k}=\"{$v}\""; + } + + return $this->add(implode('; ', $values)); + } + + /** + * Check if a specific link exists for a given rel attribute + * + * @param string $rel rel value + * + * @return bool + */ + public function hasLink($rel) + { + return $this->getLink($rel) !== null; + } + + /** + * Get a specific link for a given rel attribute + * + * @param string $rel Rel value + * + * @return array|null + */ + public function getLink($rel) + { + foreach ($this->getLinks() as $link) { + if (isset($link['rel']) && $link['rel'] == $rel) { + return $link; + } + } + + return null; + } + + /** + * Get an associative array of links + * + * For example: + * Link: ; rel=front; type="image/jpeg", ; rel=back; type="image/jpeg" + * + * + * var_export($response->getLinks()); + * array( + * array( + * 'url' => 'http:/.../front.jpeg', + * 'rel' => 'back', + * 'type' => 'image/jpeg', + * ) + * ) + * + * + * @return array + */ + public function getLinks() + { + $links = $this->parseParams(); + + foreach ($links as &$link) { + $key = key($link); + unset($link[$key]); + $link['url'] = trim($key, '<> '); + } + + return $links; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php new file mode 100644 index 00000000..62bcd439 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php @@ -0,0 +1,102 @@ +fieldName = $fieldName; + $this->setFilename($filename); + $this->postname = $postname ? $postname : basename($filename); + $this->contentType = $contentType ?: $this->guessContentType(); + } + + public function setFieldName($name) + { + $this->fieldName = $name; + + return $this; + } + + public function getFieldName() + { + return $this->fieldName; + } + + public function setFilename($filename) + { + // Remove leading @ symbol + if (strpos($filename, '@') === 0) { + $filename = substr($filename, 1); + } + + if (!is_readable($filename)) { + throw new InvalidArgumentException("Unable to open {$filename} for reading"); + } + + $this->filename = $filename; + + return $this; + } + + public function setPostname($postname) + { + $this->postname = $postname; + + return $this; + } + + public function getFilename() + { + return $this->filename; + } + + public function getPostname() + { + return $this->postname; + } + + public function setContentType($type) + { + $this->contentType = $type; + + return $this; + } + + public function getContentType() + { + return $this->contentType; + } + + public function getCurlValue() + { + // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax + // See: https://wiki.php.net/rfc/curl-file-upload + if (function_exists('curl_file_create')) { + return curl_file_create($this->filename, $this->contentType, $this->postname); + } + + // Use the old style if using an older version of PHP + $value = "@{$this->filename};filename=" . $this->postname; + if ($this->contentType) { + $value .= ';type=' . $this->contentType; + } + + return $value; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getCurlString() + { + Version::warn(__METHOD__ . ' is deprecated. Use getCurlValue()'); + return $this->getCurlValue(); + } + + /** + * Determine the Content-Type of the file + */ + protected function guessContentType() + { + return Mimetypes::getInstance()->fromFilename($this->filename) ?: 'application/octet-stream'; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php new file mode 100644 index 00000000..7f0779d1 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php @@ -0,0 +1,83 @@ +method = strtoupper($method); + $this->curlOptions = new Collection(); + $this->setUrl($url); + + if ($headers) { + // Special handling for multi-value headers + foreach ($headers as $key => $value) { + // Deal with collisions with Host and Authorization + if ($key == 'host' || $key == 'Host') { + $this->setHeader($key, $value); + } elseif ($value instanceof HeaderInterface) { + $this->addHeader($key, $value); + } else { + foreach ((array) $value as $v) { + $this->addHeader($key, $v); + } + } + } + } + + $this->setState(self::STATE_NEW); + } + + public function __clone() + { + if ($this->eventDispatcher) { + $this->eventDispatcher = clone $this->eventDispatcher; + } + $this->curlOptions = clone $this->curlOptions; + $this->params = clone $this->params; + $this->url = clone $this->url; + $this->response = $this->responseBody = null; + $this->headers = clone $this->headers; + + $this->setState(RequestInterface::STATE_NEW); + $this->dispatch('request.clone', array('request' => $this)); + } + + /** + * Get the HTTP request as a string + * + * @return string + */ + public function __toString() + { + return $this->getRawHeaders() . "\r\n\r\n"; + } + + /** + * Default method that will throw exceptions if an unsuccessful response is received. + * + * @param Event $event Received + * @throws BadResponseException if the response is not successful + */ + public static function onRequestError(Event $event) + { + $e = BadResponseException::factory($event['request'], $event['response']); + $event['request']->setState(self::STATE_ERROR, array('exception' => $e) + $event->toArray()); + throw $e; + } + + public function setClient(ClientInterface $client) + { + $this->client = $client; + + return $this; + } + + public function getClient() + { + return $this->client; + } + + public function getRawHeaders() + { + $protocolVersion = $this->protocolVersion ?: '1.1'; + + return trim($this->method . ' ' . $this->getResource()) . ' ' + . strtoupper(str_replace('https', 'http', $this->url->getScheme())) + . '/' . $protocolVersion . "\r\n" . implode("\r\n", $this->getHeaderLines()); + } + + public function setUrl($url) + { + if ($url instanceof Url) { + $this->url = $url; + } else { + $this->url = Url::factory($url); + } + + // Update the port and host header + $this->setPort($this->url->getPort()); + + if ($this->url->getUsername() || $this->url->getPassword()) { + $this->setAuth($this->url->getUsername(), $this->url->getPassword()); + // Remove the auth info from the URL + $this->url->setUsername(null); + $this->url->setPassword(null); + } + + return $this; + } + + public function send() + { + if (!$this->client) { + throw new RuntimeException('A client must be set on the request'); + } + + return $this->client->send($this); + } + + public function getResponse() + { + return $this->response; + } + + public function getQuery($asString = false) + { + return $asString + ? (string) $this->url->getQuery() + : $this->url->getQuery(); + } + + public function getMethod() + { + return $this->method; + } + + public function getScheme() + { + return $this->url->getScheme(); + } + + public function setScheme($scheme) + { + $this->url->setScheme($scheme); + + return $this; + } + + public function getHost() + { + return $this->url->getHost(); + } + + public function setHost($host) + { + $this->url->setHost($host); + $this->setPort($this->url->getPort()); + + return $this; + } + + public function getProtocolVersion() + { + return $this->protocolVersion; + } + + public function setProtocolVersion($protocol) + { + $this->protocolVersion = $protocol; + + return $this; + } + + public function getPath() + { + return '/' . ltrim($this->url->getPath(), '/'); + } + + public function setPath($path) + { + $this->url->setPath($path); + + return $this; + } + + public function getPort() + { + return $this->url->getPort(); + } + + public function setPort($port) + { + $this->url->setPort($port); + + // Include the port in the Host header if it is not the default port for the scheme of the URL + $scheme = $this->url->getScheme(); + if ($port && (($scheme == 'http' && $port != 80) || ($scheme == 'https' && $port != 443))) { + $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost() . ':' . $port); + } else { + $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost()); + } + + return $this; + } + + public function getUsername() + { + return $this->username; + } + + public function getPassword() + { + return $this->password; + } + + public function setAuth($user, $password = '', $scheme = CURLAUTH_BASIC) + { + static $authMap = array( + 'basic' => CURLAUTH_BASIC, + 'digest' => CURLAUTH_DIGEST, + 'ntlm' => CURLAUTH_NTLM, + 'any' => CURLAUTH_ANY + ); + + // If we got false or null, disable authentication + if (!$user) { + $this->password = $this->username = null; + $this->removeHeader('Authorization'); + $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); + return $this; + } + + if (!is_numeric($scheme)) { + $scheme = strtolower($scheme); + if (!isset($authMap[$scheme])) { + throw new InvalidArgumentException($scheme . ' is not a valid authentication type'); + } + $scheme = $authMap[$scheme]; + } + + $this->username = $user; + $this->password = $password; + + // Bypass CURL when using basic auth to promote connection reuse + if ($scheme == CURLAUTH_BASIC) { + $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); + $this->setHeader('Authorization', 'Basic ' . base64_encode($this->username . ':' . $this->password)); + } else { + $this->getCurlOptions() + ->set(CURLOPT_HTTPAUTH, $scheme) + ->set(CURLOPT_USERPWD, $this->username . ':' . $this->password); + } + + return $this; + } + + public function getResource() + { + $resource = $this->getPath(); + if ($query = (string) $this->url->getQuery()) { + $resource .= '?' . $query; + } + + return $resource; + } + + public function getUrl($asObject = false) + { + return $asObject ? clone $this->url : (string) $this->url; + } + + public function getState() + { + return $this->state; + } + + public function setState($state, array $context = array()) + { + $oldState = $this->state; + $this->state = $state; + + switch ($state) { + case self::STATE_NEW: + $this->response = null; + break; + case self::STATE_TRANSFER: + if ($oldState !== $state) { + // Fix Content-Length and Transfer-Encoding collisions + if ($this->hasHeader('Transfer-Encoding') && $this->hasHeader('Content-Length')) { + $this->removeHeader('Transfer-Encoding'); + } + $this->dispatch('request.before_send', array('request' => $this)); + } + break; + case self::STATE_COMPLETE: + if ($oldState !== $state) { + $this->processResponse($context); + $this->responseBody = null; + } + break; + case self::STATE_ERROR: + if (isset($context['exception'])) { + $this->dispatch('request.exception', array( + 'request' => $this, + 'response' => isset($context['response']) ? $context['response'] : $this->response, + 'exception' => isset($context['exception']) ? $context['exception'] : null + )); + } + } + + return $this->state; + } + + public function getCurlOptions() + { + return $this->curlOptions; + } + + public function startResponse(Response $response) + { + $this->state = self::STATE_TRANSFER; + $response->setEffectiveUrl((string) $this->getUrl()); + $this->response = $response; + + return $this; + } + + public function setResponse(Response $response, $queued = false) + { + $response->setEffectiveUrl((string) $this->url); + + if ($queued) { + $ed = $this->getEventDispatcher(); + $ed->addListener('request.before_send', $f = function ($e) use ($response, &$f, $ed) { + $e['request']->setResponse($response); + $ed->removeListener('request.before_send', $f); + }, -9999); + } else { + $this->response = $response; + // If a specific response body is specified, then use it instead of the response's body + if ($this->responseBody && !$this->responseBody->getCustomData('default') && !$response->isRedirect()) { + $this->getResponseBody()->write((string) $this->response->getBody()); + } else { + $this->responseBody = $this->response->getBody(); + } + $this->setState(self::STATE_COMPLETE); + } + + return $this; + } + + public function setResponseBody($body) + { + // Attempt to open a file for writing if a string was passed + if (is_string($body)) { + // @codeCoverageIgnoreStart + if (!($body = fopen($body, 'w+'))) { + throw new InvalidArgumentException('Could not open ' . $body . ' for writing'); + } + // @codeCoverageIgnoreEnd + } + + $this->responseBody = EntityBody::factory($body); + + return $this; + } + + public function getResponseBody() + { + if ($this->responseBody === null) { + $this->responseBody = EntityBody::factory()->setCustomData('default', true); + } + + return $this->responseBody; + } + + /** + * Determine if the response body is repeatable (readable + seekable) + * + * @return bool + * @deprecated Use getResponseBody()->isSeekable() + * @codeCoverageIgnore + */ + public function isResponseBodyRepeatable() + { + Version::warn(__METHOD__ . ' is deprecated. Use $request->getResponseBody()->isRepeatable()'); + return !$this->responseBody ? true : $this->responseBody->isRepeatable(); + } + + public function getCookies() + { + if ($cookie = $this->getHeader('Cookie')) { + $data = ParserRegistry::getInstance()->getParser('cookie')->parseCookie($cookie); + return $data['cookies']; + } + + return array(); + } + + public function getCookie($name) + { + $cookies = $this->getCookies(); + + return isset($cookies[$name]) ? $cookies[$name] : null; + } + + public function addCookie($name, $value) + { + if (!$this->hasHeader('Cookie')) { + $this->setHeader('Cookie', "{$name}={$value}"); + } else { + $this->getHeader('Cookie')->add("{$name}={$value}"); + } + + // Always use semicolons to separate multiple cookie headers + $this->getHeader('Cookie')->setGlue(';'); + + return $this; + } + + public function removeCookie($name) + { + if ($cookie = $this->getHeader('Cookie')) { + foreach ($cookie as $cookieValue) { + if (strpos($cookieValue, $name . '=') === 0) { + $cookie->removeValue($cookieValue); + } + } + } + + return $this; + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + $this->eventDispatcher->addListener('request.error', array(__CLASS__, 'onRequestError'), -255); + + return $this; + } + + public function getEventDispatcher() + { + if (!$this->eventDispatcher) { + $this->setEventDispatcher(new EventDispatcher()); + } + + return $this->eventDispatcher; + } + + public function dispatch($eventName, array $context = array()) + { + $context['request'] = $this; + + return $this->getEventDispatcher()->dispatch($eventName, new Event($context)); + } + + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->getEventDispatcher()->addSubscriber($subscriber); + + return $this; + } + + /** + * Get an array containing the request and response for event notifications + * + * @return array + */ + protected function getEventArray() + { + return array( + 'request' => $this, + 'response' => $this->response + ); + } + + /** + * Process a received response + * + * @param array $context Contextual information + * @throws RequestException|BadResponseException on unsuccessful responses + */ + protected function processResponse(array $context = array()) + { + if (!$this->response) { + // If no response, then processResponse shouldn't have been called + $e = new RequestException('Error completing request'); + $e->setRequest($this); + throw $e; + } + + $this->state = self::STATE_COMPLETE; + + // A request was sent, but we don't know if we'll send more or if the final response will be successful + $this->dispatch('request.sent', $this->getEventArray() + $context); + + // Some response processors will remove the response or reset the state (example: ExponentialBackoffPlugin) + if ($this->state == RequestInterface::STATE_COMPLETE) { + + // The request completed, so the HTTP transaction is complete + $this->dispatch('request.complete', $this->getEventArray()); + + // If the response is bad, allow listeners to modify it or throw exceptions. You can change the response by + // modifying the Event object in your listeners or calling setResponse() on the request + if ($this->response->isError()) { + $event = new Event($this->getEventArray()); + $this->getEventDispatcher()->dispatch('request.error', $event); + // Allow events of request.error to quietly change the response + if ($event['response'] !== $this->response) { + $this->response = $event['response']; + } + } + + // If a successful response was received, dispatch an event + if ($this->response->isSuccessful()) { + $this->dispatch('request.success', $this->getEventArray()); + } + } + } + + /** + * @deprecated Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy + * @codeCoverageIgnore + */ + public function canCache() + { + Version::warn(__METHOD__ . ' is deprecated. Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy.'); + if (class_exists('Guzzle\Plugin\Cache\DefaultCanCacheStrategy')) { + $canCache = new \Guzzle\Plugin\Cache\DefaultCanCacheStrategy(); + return $canCache->canCacheRequest($this); + } else { + return false; + } + } + + /** + * @deprecated Use the history plugin (not emitting a warning as this is built-into the RedirectPlugin for now) + * @codeCoverageIgnore + */ + public function setIsRedirect($isRedirect) + { + $this->isRedirect = $isRedirect; + + return $this; + } + + /** + * @deprecated Use the history plugin + * @codeCoverageIgnore + */ + public function isRedirect() + { + Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin to track this.'); + return $this->isRedirect; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php new file mode 100644 index 00000000..ba00a767 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php @@ -0,0 +1,359 @@ +methods = array_flip(get_class_methods(__CLASS__)); + } + + public function fromMessage($message) + { + $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($message); + + if (!$parsed) { + return false; + } + + $request = $this->fromParts($parsed['method'], $parsed['request_url'], + $parsed['headers'], $parsed['body'], $parsed['protocol'], + $parsed['version']); + + // EntityEnclosingRequest adds an "Expect: 100-Continue" header when using a raw request body for PUT or POST + // requests. This factory method should accurately reflect the message, so here we are removing the Expect + // header if one was not supplied in the message. + if (!isset($parsed['headers']['Expect']) && !isset($parsed['headers']['expect'])) { + $request->removeHeader('Expect'); + } + + return $request; + } + + public function fromParts( + $method, + array $urlParts, + $headers = null, + $body = null, + $protocol = 'HTTP', + $protocolVersion = '1.1' + ) { + return $this->create($method, Url::buildUrl($urlParts), $headers, $body) + ->setProtocolVersion($protocolVersion); + } + + public function create($method, $url, $headers = null, $body = null, array $options = array()) + { + $method = strtoupper($method); + + if ($method == 'GET' || $method == 'HEAD' || $method == 'TRACE') { + // Handle non-entity-enclosing request methods + $request = new $this->requestClass($method, $url, $headers); + if ($body) { + // The body is where the response body will be stored + $type = gettype($body); + if ($type == 'string' || $type == 'resource' || $type == 'object') { + $request->setResponseBody($body); + } + } + } else { + // Create an entity enclosing request by default + $request = new $this->entityEnclosingRequestClass($method, $url, $headers); + if ($body || $body === '0') { + // Add POST fields and files to an entity enclosing request if an array is used + if (is_array($body) || $body instanceof Collection) { + // Normalize PHP style cURL uploads with a leading '@' symbol + foreach ($body as $key => $value) { + if (is_string($value) && substr($value, 0, 1) == '@') { + $request->addPostFile($key, $value); + unset($body[$key]); + } + } + // Add the fields if they are still present and not all files + $request->addPostFields($body); + } else { + // Add a raw entity body body to the request + $request->setBody($body, (string) $request->getHeader('Content-Type')); + if ((string) $request->getHeader('Transfer-Encoding') == 'chunked') { + $request->removeHeader('Content-Length'); + } + } + } + } + + if ($options) { + $this->applyOptions($request, $options); + } + + return $request; + } + + /** + * Clone a request while changing the method. Emulates the behavior of + * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method. + * + * @param RequestInterface $request Request to clone + * @param string $method Method to set + * + * @return RequestInterface + */ + public function cloneRequestWithMethod(RequestInterface $request, $method) + { + // Create the request with the same client if possible + if ($request->getClient()) { + $cloned = $request->getClient()->createRequest($method, $request->getUrl(), $request->getHeaders()); + } else { + $cloned = $this->create($method, $request->getUrl(), $request->getHeaders()); + } + + $cloned->getCurlOptions()->replace($request->getCurlOptions()->toArray()); + $cloned->setEventDispatcher(clone $request->getEventDispatcher()); + // Ensure that that the Content-Length header is not copied if changing to GET or HEAD + if (!($cloned instanceof EntityEnclosingRequestInterface)) { + $cloned->removeHeader('Content-Length'); + } elseif ($request instanceof EntityEnclosingRequestInterface) { + $cloned->setBody($request->getBody()); + } + $cloned->getParams()->replace($request->getParams()->toArray()); + $cloned->dispatch('request.clone', array('request' => $cloned)); + + return $cloned; + } + + public function applyOptions(RequestInterface $request, array $options = array(), $flags = self::OPTIONS_NONE) + { + // Iterate over each key value pair and attempt to apply a config using function visitors + foreach ($options as $key => $value) { + $method = "visit_{$key}"; + if (isset($this->methods[$method])) { + $this->{$method}($request, $value, $flags); + } + } + } + + protected function visit_headers(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('headers value must be an array'); + } + + if ($flags & self::OPTIONS_AS_DEFAULTS) { + // Merge headers in but do not overwrite existing values + foreach ($value as $key => $header) { + if (!$request->hasHeader($key)) { + $request->setHeader($key, $header); + } + } + } else { + $request->addHeaders($value); + } + } + + protected function visit_body(RequestInterface $request, $value, $flags) + { + if ($request instanceof EntityEnclosingRequestInterface) { + $request->setBody($value); + } else { + throw new InvalidArgumentException('Attempting to set a body on a non-entity-enclosing request'); + } + } + + protected function visit_allow_redirects(RequestInterface $request, $value, $flags) + { + if ($value === false) { + $request->getParams()->set(RedirectPlugin::DISABLE, true); + } + } + + protected function visit_auth(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('auth value must be an array'); + } + + $request->setAuth($value[0], isset($value[1]) ? $value[1] : null, isset($value[2]) ? $value[2] : 'basic'); + } + + protected function visit_query(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('query value must be an array'); + } + + if ($flags & self::OPTIONS_AS_DEFAULTS) { + // Merge query string values in but do not overwrite existing values + $query = $request->getQuery(); + $query->overwriteWith(array_diff_key($value, $query->toArray())); + } else { + $request->getQuery()->overwriteWith($value); + } + } + + protected function visit_cookies(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('cookies value must be an array'); + } + + foreach ($value as $name => $v) { + $request->addCookie($name, $v); + } + } + + protected function visit_events(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('events value must be an array'); + } + + foreach ($value as $name => $method) { + if (is_array($method)) { + $request->getEventDispatcher()->addListener($name, $method[0], $method[1]); + } else { + $request->getEventDispatcher()->addListener($name, $method); + } + } + } + + protected function visit_plugins(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('plugins value must be an array'); + } + + foreach ($value as $plugin) { + $request->addSubscriber($plugin); + } + } + + protected function visit_exceptions(RequestInterface $request, $value, $flags) + { + if ($value === false || $value === 0) { + $dispatcher = $request->getEventDispatcher(); + foreach ($dispatcher->getListeners('request.error') as $listener) { + if (is_array($listener) && $listener[0] == 'Guzzle\Http\Message\Request' && $listener[1] = 'onRequestError') { + $dispatcher->removeListener('request.error', $listener); + break; + } + } + } + } + + protected function visit_save_to(RequestInterface $request, $value, $flags) + { + $request->setResponseBody($value); + } + + protected function visit_params(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('params value must be an array'); + } + + $request->getParams()->overwriteWith($value); + } + + protected function visit_timeout(RequestInterface $request, $value, $flags) + { + if (defined('CURLOPT_TIMEOUT_MS')) { + $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, $value * 1000); + } else { + $request->getCurlOptions()->set(CURLOPT_TIMEOUT, $value); + } + } + + protected function visit_connect_timeout(RequestInterface $request, $value, $flags) + { + if (defined('CURLOPT_CONNECTTIMEOUT_MS')) { + $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, $value * 1000); + } else { + $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT, $value); + } + } + + protected function visit_debug(RequestInterface $request, $value, $flags) + { + if ($value) { + $request->getCurlOptions()->set(CURLOPT_VERBOSE, true); + } + } + + protected function visit_verify(RequestInterface $request, $value, $flags) + { + $curl = $request->getCurlOptions(); + if ($value === true || is_string($value)) { + $curl[CURLOPT_SSL_VERIFYHOST] = 2; + $curl[CURLOPT_SSL_VERIFYPEER] = true; + if ($value !== true) { + $curl[CURLOPT_CAINFO] = $value; + } + } elseif ($value === false) { + unset($curl[CURLOPT_CAINFO]); + $curl[CURLOPT_SSL_VERIFYHOST] = 0; + $curl[CURLOPT_SSL_VERIFYPEER] = false; + } + } + + protected function visit_proxy(RequestInterface $request, $value, $flags) + { + $request->getCurlOptions()->set(CURLOPT_PROXY, $value, $flags); + } + + protected function visit_cert(RequestInterface $request, $value, $flags) + { + if (is_array($value)) { + $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value[0]); + $request->getCurlOptions()->set(CURLOPT_SSLCERTPASSWD, $value[1]); + } else { + $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value); + } + } + + protected function visit_ssl_key(RequestInterface $request, $value, $flags) + { + if (is_array($value)) { + $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value[0]); + $request->getCurlOptions()->set(CURLOPT_SSLKEYPASSWD, $value[1]); + } else { + $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value); + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php new file mode 100644 index 00000000..6088f10e --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php @@ -0,0 +1,105 @@ + 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 208 => 'Already Reported', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'Reserved for WebDAV advanced collections expired proposal', + 426 => 'Upgrade required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates (Experimental)', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 510 => 'Not Extended', + 511 => 'Network Authentication Required', + ); + + /** @var EntityBodyInterface The response body */ + protected $body; + + /** @var string The reason phrase of the response (human readable code) */ + protected $reasonPhrase; + + /** @var string The status code of the response */ + protected $statusCode; + + /** @var array Information about the request */ + protected $info = array(); + + /** @var string The effective URL that returned this response */ + protected $effectiveUrl; + + /** @var array Cacheable response codes (see RFC 2616:13.4) */ + protected static $cacheResponseCodes = array(200, 203, 206, 300, 301, 410); + + /** + * Create a new Response based on a raw response message + * + * @param string $message Response message + * + * @return self|bool Returns false on error + */ + public static function fromMessage($message) + { + $data = ParserRegistry::getInstance()->getParser('message')->parseResponse($message); + if (!$data) { + return false; + } + + $response = new static($data['code'], $data['headers'], $data['body']); + $response->setProtocol($data['protocol'], $data['version']) + ->setStatus($data['code'], $data['reason_phrase']); + + // Set the appropriate Content-Length if the one set is inaccurate (e.g. setting to X) + $contentLength = (string) $response->getHeader('Content-Length'); + $actualLength = strlen($data['body']); + if (strlen($data['body']) > 0 && $contentLength != $actualLength) { + $response->setHeader('Content-Length', $actualLength); + } + + return $response; + } + + /** + * Construct the response + * + * @param string $statusCode The response status code (e.g. 200, 404, etc) + * @param ToArrayInterface|array $headers The response headers + * @param string|resource|EntityBodyInterface $body The body of the response + * + * @throws BadResponseException if an invalid response code is given + */ + public function __construct($statusCode, $headers = null, $body = null) + { + parent::__construct(); + $this->setStatus($statusCode); + $this->body = EntityBody::factory($body !== null ? $body : ''); + + if ($headers) { + if (is_array($headers)) { + $this->setHeaders($headers); + } elseif ($headers instanceof ToArrayInterface) { + $this->setHeaders($headers->toArray()); + } else { + throw new BadResponseException('Invalid headers argument received'); + } + } + } + + /** + * @return string + */ + public function __toString() + { + return $this->getMessage(); + } + + public function serialize() + { + return json_encode(array( + 'status' => $this->statusCode, + 'body' => (string) $this->body, + 'headers' => $this->headers->toArray() + )); + } + + public function unserialize($serialize) + { + $data = json_decode($serialize, true); + $this->__construct($data['status'], $data['headers'], $data['body']); + } + + /** + * Get the response entity body + * + * @param bool $asString Set to TRUE to return a string of the body rather than a full body object + * + * @return EntityBodyInterface|string + */ + public function getBody($asString = false) + { + return $asString ? (string) $this->body : $this->body; + } + + /** + * Set the response entity body + * + * @param EntityBodyInterface|string $body Body to set + * + * @return self + */ + public function setBody($body) + { + $this->body = EntityBody::factory($body); + + return $this; + } + + /** + * Set the protocol and protocol version of the response + * + * @param string $protocol Response protocol + * @param string $version Protocol version + * + * @return self + */ + public function setProtocol($protocol, $version) + { + $this->protocol = $protocol; + $this->protocolVersion = $version; + + return $this; + } + + /** + * Get the protocol used for the response (e.g. HTTP) + * + * @return string + */ + public function getProtocol() + { + return $this->protocol; + } + + /** + * Get the HTTP protocol version + * + * @return string + */ + public function getProtocolVersion() + { + return $this->protocolVersion; + } + + /** + * Get a cURL transfer information + * + * @param string $key A single statistic to check + * + * @return array|string|null Returns all stats if no key is set, a single stat if a key is set, or null if a key + * is set and not found + * @link http://www.php.net/manual/en/function.curl-getinfo.php + */ + public function getInfo($key = null) + { + if ($key === null) { + return $this->info; + } elseif (array_key_exists($key, $this->info)) { + return $this->info[$key]; + } else { + return null; + } + } + + /** + * Set the transfer information + * + * @param array $info Array of cURL transfer stats + * + * @return self + */ + public function setInfo(array $info) + { + $this->info = $info; + + return $this; + } + + /** + * Set the response status + * + * @param int $statusCode Response status code to set + * @param string $reasonPhrase Response reason phrase + * + * @return self + * @throws BadResponseException when an invalid response code is received + */ + public function setStatus($statusCode, $reasonPhrase = '') + { + $this->statusCode = (int) $statusCode; + + if (!$reasonPhrase && isset(self::$statusTexts[$this->statusCode])) { + $this->reasonPhrase = self::$statusTexts[$this->statusCode]; + } else { + $this->reasonPhrase = $reasonPhrase; + } + + return $this; + } + + /** + * Get the response status code + * + * @return integer + */ + public function getStatusCode() + { + return $this->statusCode; + } + + /** + * Get the entire response as a string + * + * @return string + */ + public function getMessage() + { + $message = $this->getRawHeaders(); + + // Only include the body in the message if the size is < 2MB + $size = $this->body->getSize(); + if ($size < 2097152) { + $message .= (string) $this->body; + } + + return $message; + } + + /** + * Get the the raw message headers as a string + * + * @return string + */ + public function getRawHeaders() + { + $headers = 'HTTP/1.1 ' . $this->statusCode . ' ' . $this->reasonPhrase . "\r\n"; + $lines = $this->getHeaderLines(); + if (!empty($lines)) { + $headers .= implode("\r\n", $lines) . "\r\n"; + } + + return $headers . "\r\n"; + } + + /** + * Get the response reason phrase- a human readable version of the numeric + * status code + * + * @return string + */ + public function getReasonPhrase() + { + return $this->reasonPhrase; + } + + /** + * Get the Accept-Ranges HTTP header + * + * @return string Returns what partial content range types this server supports. + */ + public function getAcceptRanges() + { + return (string) $this->getHeader('Accept-Ranges'); + } + + /** + * Calculate the age of the response + * + * @return integer + */ + public function calculateAge() + { + $age = $this->getHeader('Age'); + + if ($age === null && $this->getDate()) { + $age = time() - strtotime($this->getDate()); + } + + return $age === null ? null : (int) (string) $age; + } + + /** + * Get the Age HTTP header + * + * @return integer|null Returns the age the object has been in a proxy cache in seconds. + */ + public function getAge() + { + return (string) $this->getHeader('Age'); + } + + /** + * Get the Allow HTTP header + * + * @return string|null Returns valid actions for a specified resource. To be used for a 405 Method not allowed. + */ + public function getAllow() + { + return (string) $this->getHeader('Allow'); + } + + /** + * Check if an HTTP method is allowed by checking the Allow response header + * + * @param string $method Method to check + * + * @return bool + */ + public function isMethodAllowed($method) + { + $allow = $this->getHeader('Allow'); + if ($allow) { + foreach (explode(',', $allow) as $allowable) { + if (!strcasecmp(trim($allowable), $method)) { + return true; + } + } + } + + return false; + } + + /** + * Get the Cache-Control HTTP header + * + * @return string + */ + public function getCacheControl() + { + return (string) $this->getHeader('Cache-Control'); + } + + /** + * Get the Connection HTTP header + * + * @return string + */ + public function getConnection() + { + return (string) $this->getHeader('Connection'); + } + + /** + * Get the Content-Encoding HTTP header + * + * @return string|null + */ + public function getContentEncoding() + { + return (string) $this->getHeader('Content-Encoding'); + } + + /** + * Get the Content-Language HTTP header + * + * @return string|null Returns the language the content is in. + */ + public function getContentLanguage() + { + return (string) $this->getHeader('Content-Language'); + } + + /** + * Get the Content-Length HTTP header + * + * @return integer Returns the length of the response body in bytes + */ + public function getContentLength() + { + return (int) (string) $this->getHeader('Content-Length'); + } + + /** + * Get the Content-Location HTTP header + * + * @return string|null Returns an alternate location for the returned data (e.g /index.htm) + */ + public function getContentLocation() + { + return (string) $this->getHeader('Content-Location'); + } + + /** + * Get the Content-Disposition HTTP header + * + * @return string|null Returns the Content-Disposition header + */ + public function getContentDisposition() + { + return (string) $this->getHeader('Content-Disposition'); + } + + /** + * Get the Content-MD5 HTTP header + * + * @return string|null Returns a Base64-encoded binary MD5 sum of the content of the response. + */ + public function getContentMd5() + { + return (string) $this->getHeader('Content-MD5'); + } + + /** + * Get the Content-Range HTTP header + * + * @return string Returns where in a full body message this partial message belongs (e.g. bytes 21010-47021/47022). + */ + public function getContentRange() + { + return (string) $this->getHeader('Content-Range'); + } + + /** + * Get the Content-Type HTTP header + * + * @return string Returns the mime type of this content. + */ + public function getContentType() + { + return (string) $this->getHeader('Content-Type'); + } + + /** + * Checks if the Content-Type is of a certain type. This is useful if the + * Content-Type header contains charset information and you need to know if + * the Content-Type matches a particular type. + * + * @param string $type Content type to check against + * + * @return bool + */ + public function isContentType($type) + { + return stripos($this->getHeader('Content-Type'), $type) !== false; + } + + /** + * Get the Date HTTP header + * + * @return string|null Returns the date and time that the message was sent. + */ + public function getDate() + { + return (string) $this->getHeader('Date'); + } + + /** + * Get the ETag HTTP header + * + * @return string|null Returns an identifier for a specific version of a resource, often a Message digest. + */ + public function getEtag() + { + return (string) $this->getHeader('ETag'); + } + + /** + * Get the Expires HTTP header + * + * @return string|null Returns the date/time after which the response is considered stale. + */ + public function getExpires() + { + return (string) $this->getHeader('Expires'); + } + + /** + * Get the Last-Modified HTTP header + * + * @return string|null Returns the last modified date for the requested object, in RFC 2822 format + * (e.g. Tue, 15 Nov 1994 12:45:26 GMT) + */ + public function getLastModified() + { + return (string) $this->getHeader('Last-Modified'); + } + + /** + * Get the Location HTTP header + * + * @return string|null Used in redirection, or when a new resource has been created. + */ + public function getLocation() + { + return (string) $this->getHeader('Location'); + } + + /** + * Get the Pragma HTTP header + * + * @return Header|null Returns the implementation-specific headers that may have various effects anywhere along + * the request-response chain. + */ + public function getPragma() + { + return (string) $this->getHeader('Pragma'); + } + + /** + * Get the Proxy-Authenticate HTTP header + * + * @return string|null Authentication to access the proxy (e.g. Basic) + */ + public function getProxyAuthenticate() + { + return (string) $this->getHeader('Proxy-Authenticate'); + } + + /** + * Get the Retry-After HTTP header + * + * @return int|null If an entity is temporarily unavailable, this instructs the client to try again after a + * specified period of time. + */ + public function getRetryAfter() + { + return (string) $this->getHeader('Retry-After'); + } + + /** + * Get the Server HTTP header + * + * @return string|null A name for the server + */ + public function getServer() + { + return (string) $this->getHeader('Server'); + } + + /** + * Get the Set-Cookie HTTP header + * + * @return string|null An HTTP cookie. + */ + public function getSetCookie() + { + return (string) $this->getHeader('Set-Cookie'); + } + + /** + * Get the Trailer HTTP header + * + * @return string|null The Trailer general field value indicates that the given set of header fields is present in + * the trailer of a message encoded with chunked transfer-coding. + */ + public function getTrailer() + { + return (string) $this->getHeader('Trailer'); + } + + /** + * Get the Transfer-Encoding HTTP header + * + * @return string|null The form of encoding used to safely transfer the entity to the user + */ + public function getTransferEncoding() + { + return (string) $this->getHeader('Transfer-Encoding'); + } + + /** + * Get the Vary HTTP header + * + * @return string|null Tells downstream proxies how to match future request headers to decide whether the cached + * response can be used rather than requesting a fresh one from the origin server. + */ + public function getVary() + { + return (string) $this->getHeader('Vary'); + } + + /** + * Get the Via HTTP header + * + * @return string|null Informs the client of proxies through which the response was sent. + */ + public function getVia() + { + return (string) $this->getHeader('Via'); + } + + /** + * Get the Warning HTTP header + * + * @return string|null A general warning about possible problems with the entity body + */ + public function getWarning() + { + return (string) $this->getHeader('Warning'); + } + + /** + * Get the WWW-Authenticate HTTP header + * + * @return string|null Indicates the authentication scheme that should be used to access the requested entity + */ + public function getWwwAuthenticate() + { + return (string) $this->getHeader('WWW-Authenticate'); + } + + /** + * Checks if HTTP Status code is a Client Error (4xx) + * + * @return bool + */ + public function isClientError() + { + return $this->statusCode >= 400 && $this->statusCode < 500; + } + + /** + * Checks if HTTP Status code is Server OR Client Error (4xx or 5xx) + * + * @return boolean + */ + public function isError() + { + return $this->isClientError() || $this->isServerError(); + } + + /** + * Checks if HTTP Status code is Information (1xx) + * + * @return bool + */ + public function isInformational() + { + return $this->statusCode < 200; + } + + /** + * Checks if HTTP Status code is a Redirect (3xx) + * + * @return bool + */ + public function isRedirect() + { + return $this->statusCode >= 300 && $this->statusCode < 400; + } + + /** + * Checks if HTTP Status code is Server Error (5xx) + * + * @return bool + */ + public function isServerError() + { + return $this->statusCode >= 500 && $this->statusCode < 600; + } + + /** + * Checks if HTTP Status code is Successful (2xx | 304) + * + * @return bool + */ + public function isSuccessful() + { + return ($this->statusCode >= 200 && $this->statusCode < 300) || $this->statusCode == 304; + } + + /** + * Check if the response can be cached based on the response headers + * + * @return bool Returns TRUE if the response can be cached or false if not + */ + public function canCache() + { + // Check if the response is cacheable based on the code + if (!in_array((int) $this->getStatusCode(), self::$cacheResponseCodes)) { + return false; + } + + // Make sure a valid body was returned and can be cached + if ((!$this->getBody()->isReadable() || !$this->getBody()->isSeekable()) + && ($this->getContentLength() > 0 || $this->getTransferEncoding() == 'chunked')) { + return false; + } + + // Never cache no-store resources (this is a private cache, so private + // can be cached) + if ($this->getHeader('Cache-Control') && $this->getHeader('Cache-Control')->hasDirective('no-store')) { + return false; + } + + return $this->isFresh() || $this->getFreshness() === null || $this->canValidate(); + } + + /** + * Gets the number of seconds from the current time in which this response is still considered fresh + * + * @return int|null Returns the number of seconds + */ + public function getMaxAge() + { + if ($header = $this->getHeader('Cache-Control')) { + // s-max-age, then max-age, then Expires + if ($age = $header->getDirective('s-maxage')) { + return $age; + } + if ($age = $header->getDirective('max-age')) { + return $age; + } + } + + if ($this->getHeader('Expires')) { + return strtotime($this->getExpires()) - time(); + } + + return null; + } + + /** + * Check if the response is considered fresh. + * + * A response is considered fresh when its age is less than or equal to the freshness lifetime (maximum age) of the + * response. + * + * @return bool|null + */ + public function isFresh() + { + $fresh = $this->getFreshness(); + + return $fresh === null ? null : $fresh >= 0; + } + + /** + * Check if the response can be validated against the origin server using a conditional GET request. + * + * @return bool + */ + public function canValidate() + { + return $this->getEtag() || $this->getLastModified(); + } + + /** + * Get the freshness of the response by returning the difference of the maximum lifetime of the response and the + * age of the response (max-age - age). + * + * Freshness values less than 0 mean that the response is no longer fresh and is ABS(freshness) seconds expired. + * Freshness values of greater than zero is the number of seconds until the response is no longer fresh. A NULL + * result means that no freshness information is available. + * + * @return int + */ + public function getFreshness() + { + $maxAge = $this->getMaxAge(); + $age = $this->calculateAge(); + + return $maxAge && $age ? ($maxAge - $age) : null; + } + + /** + * Parse the JSON response body and return an array + * + * @return array|string|int|bool|float + * @throws RuntimeException if the response body is not in JSON format + */ + public function json() + { + $data = json_decode((string) $this->body, true); + if (JSON_ERROR_NONE !== json_last_error()) { + throw new RuntimeException('Unable to parse response body into JSON: ' . json_last_error()); + } + + return $data === null ? array() : $data; + } + + /** + * Parse the XML response body and return a \SimpleXMLElement. + * + * In order to prevent XXE attacks, this method disables loading external + * entities. If you rely on external entities, then you must parse the + * XML response manually by accessing the response body directly. + * + * @return \SimpleXMLElement + * @throws RuntimeException if the response body is not in XML format + * @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html + */ + public function xml() + { + $errorMessage = null; + $internalErrors = libxml_use_internal_errors(true); + $disableEntities = libxml_disable_entity_loader(true); + libxml_clear_errors(); + + try { + $xml = new \SimpleXMLElement((string) $this->body ?: '', LIBXML_NONET); + if ($error = libxml_get_last_error()) { + $errorMessage = $error->message; + } + } catch (\Exception $e) { + $errorMessage = $e->getMessage(); + } + + libxml_clear_errors(); + libxml_use_internal_errors($internalErrors); + libxml_disable_entity_loader($disableEntities); + + if ($errorMessage) { + throw new RuntimeException('Unable to parse response body into XML: ' . $errorMessage); + } + + return $xml; + } + + /** + * Get the redirect count of this response + * + * @return int + */ + public function getRedirectCount() + { + return (int) $this->params->get(RedirectPlugin::REDIRECT_COUNT); + } + + /** + * Set the effective URL that resulted in this response (e.g. the last redirect URL) + * + * @param string $url The effective URL + * + * @return self + */ + public function setEffectiveUrl($url) + { + $this->effectiveUrl = $url; + + return $this; + } + + /** + * Get the effective URL that resulted in this response (e.g. the last redirect URL) + * + * @return string + */ + public function getEffectiveUrl() + { + return $this->effectiveUrl; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getPreviousResponse() + { + Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin.'); + return null; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function setRequest($request) + { + Version::warn(__METHOD__ . ' is deprecated'); + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getRequest() + { + Version::warn(__METHOD__ . ' is deprecated'); + return null; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Mimetypes.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Mimetypes.php new file mode 100644 index 00000000..d71586a0 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Mimetypes.php @@ -0,0 +1,962 @@ + 'text/vnd.in3d.3dml', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-aac', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/pkix-attr-cert', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'application' => 'application/x-ms-application', + 'apr' => 'application/vnd.lotus-approach', + 'asa' => 'text/plain', + 'asax' => 'application/octet-stream', + 'asc' => 'application/pgp-signature', + 'ascx' => 'text/plain', + 'asf' => 'video/x-ms-asf', + 'ashx' => 'text/plain', + 'asm' => 'text/x-asm', + 'asmx' => 'text/plain', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asp' => 'text/plain', + 'aspx' => 'text/plain', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'aw' => 'application/applixware', + 'axd' => 'text/plain', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azw' => 'application/vnd.amazon.ebook', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'bmi' => 'application/vnd.bmi', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'btif' => 'image/prs.btif', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cab' => 'application/vnd.ms-cab-compressed', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cc' => 'text/x-c', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfc' => 'application/x-coldfusion', + 'cfm' => 'application/x-coldfusion', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/java-vm', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'cryptonote' => 'application/vnd.rig.cryptonote', + 'cs' => 'text/plain', + 'csh' => 'application/x-csh', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/x-msdownload', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.document.macroenabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es3' => 'application/vnd.eszigno3+xml', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'exe' => 'application/x-msdownload', + 'exi' => 'application/exi', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/x-f4v', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gdl' => 'model/vnd.gdl', + 'geo' => 'application/vnd.dynageo', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gph' => 'application/vnd.flographit', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxt' => 'application/vnd.geonext', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hdf' => 'application/x-hdf', + 'hh' => 'text/x-c', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'hta' => 'application/octet-stream', + 'htc' => 'text/html', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ini' => 'text/plain', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/octet-stream', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'java' => 'text/x-java-source', + 'jisp' => 'application/vnd.jisp', + 'jlt' => 'application/vnd.hp-jlyt', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'js' => 'text/javascript', + 'json' => 'application/json', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'lha' => 'application/octet-stream', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/octet-stream', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm21' => 'application/mp21', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpegurl', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/mp4', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/mp4', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp21' => 'application/mp21', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msty' => 'application/vnd.muvee.style', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nsf' => 'application/vnd.lotus-notes', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'oprc' => 'application/vnd.palm', + 'org' => 'application/vnd.lotus-organizer', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'application/x-font-otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p10' => 'application/pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp-encrypted', + 'php' => 'text/x-php', + 'phps' => 'application/x-httpd-phps', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-mobipocket-ebook', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'image/vnd.adobe.photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rb' => 'text/plain', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'resx' => 'text/xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rnc' => 'application/relax-ng-compact-syntax', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'rtx' => 'text/richtext', + 's' => 'text/x-asm', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shf' => 'application/shf+xml', + 'sig' => 'application/pgp-signature', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'src' => 'application/x-wais-source', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'application/vnd.ms-pki.stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sub' => 'image/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tmo' => 'application/vnd.tmobile-livetv', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'application/x-font-ttf', + 'ttf' => 'application/x-font-ttf', + 'ttl' => 'text/turtle', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvx' => 'application/vnd.dece.unspecified', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'weba' => 'audio/webm', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'application/x-msmetafile', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-ms-wmz', + 'woff' => 'application/x-font-woff', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'application/vnd.hzn-3d-crossword', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/patch-ops-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xml' => 'application/xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'yaml' => 'text/yaml', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'yml' => 'text/yaml', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml' + ); + + /** + * Get a singleton instance of the class + * + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Get a mimetype value from a file extension + * + * @param string $extension File extension + * + * @return string|null + * + */ + public function fromExtension($extension) + { + $extension = strtolower($extension); + + return isset($this->mimetypes[$extension]) ? $this->mimetypes[$extension] : null; + } + + /** + * Get a mimetype from a filename + * + * @param string $filename Filename to generate a mimetype from + * + * @return string|null + */ + public function fromFilename($filename) + { + return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION)); + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php new file mode 100644 index 00000000..4b4e49d0 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php @@ -0,0 +1,20 @@ +isUrlEncoding()) { + return array($query->encodeValue($key) => implode(',', array_map(array($query, 'encodeValue'), $value))); + } else { + return array($key => implode(',', $value)); + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php new file mode 100644 index 00000000..1bf1730e --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php @@ -0,0 +1,22 @@ +isUrlEncoding()) { + return array($query->encodeValue($key) => array_map(array($query, 'encodeValue'), $value)); + } else { + return array($key => $value); + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php new file mode 100644 index 00000000..133ea2bd --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php @@ -0,0 +1,27 @@ + $v) { + $k = "{$key}[{$k}]"; + if (is_array($v)) { + $ret = array_merge($ret, self::aggregate($k, $v, $query)); + } else { + $ret[$query->encodeValue($k)] = $query->encodeValue($v); + } + } + + return $ret; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php new file mode 100644 index 00000000..72bee620 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php @@ -0,0 +1,22 @@ +add($key, $value); + $foundDuplicates = true; + } elseif ($paramIsPhpStyleArray) { + $q[$key] = array($value); + } else { + $q[$key] = $value; + } + } else { + // Uses false by default to represent keys with no trailing "=" sign. + $q->add($key, false); + } + } + + // Use the duplicate aggregator if duplicates were found and not using PHP style arrays + if ($foundDuplicates && !$foundPhpStyle) { + $q->setAggregator(new DuplicateAggregator()); + } + + return $q; + } + + /** + * Convert the query string parameters to a query string string + * + * @return string + * @throws RuntimeException + */ + public function __toString() + { + if (!$this->data) { + return ''; + } + + $queryList = array(); + foreach ($this->prepareData($this->data) as $name => $value) { + $queryList[] = $this->convertKvp($name, $value); + } + + return implode($this->fieldSeparator, $queryList); + } + + /** + * Get the query string field separator + * + * @return string + */ + public function getFieldSeparator() + { + return $this->fieldSeparator; + } + + /** + * Get the query string value separator + * + * @return string + */ + public function getValueSeparator() + { + return $this->valueSeparator; + } + + /** + * Returns the type of URL encoding used by the query string + * + * One of: false, "RFC 3986", or "application/x-www-form-urlencoded" + * + * @return bool|string + */ + public function getUrlEncoding() + { + return $this->urlEncode; + } + + /** + * Returns true or false if using URL encoding + * + * @return bool + */ + public function isUrlEncoding() + { + return $this->urlEncode !== false; + } + + /** + * Provide a function for combining multi-valued query string parameters into a single or multiple fields + * + * @param null|QueryAggregatorInterface $aggregator Pass in a QueryAggregatorInterface object to handle converting + * deeply nested query string variables into a flattened array. + * Pass null to use the default PHP style aggregator. For legacy + * reasons, this function accepts a callable that must accepts a + * $key, $value, and query object. + * @return self + * @see \Guzzle\Http\QueryString::aggregateUsingComma() + */ + public function setAggregator(QueryAggregatorInterface $aggregator = null) + { + // Use the default aggregator if none was set + if (!$aggregator) { + if (!self::$defaultAggregator) { + self::$defaultAggregator = new PhpAggregator(); + } + $aggregator = self::$defaultAggregator; + } + + $this->aggregator = $aggregator; + + return $this; + } + + /** + * Set whether or not field names and values should be rawurlencoded + * + * @param bool|string $encode Set to TRUE to use RFC 3986 encoding (rawurlencode), false to disable encoding, or + * form_urlencoding to use application/x-www-form-urlencoded encoding (urlencode) + * @return self + */ + public function useUrlEncoding($encode) + { + $this->urlEncode = ($encode === true) ? self::RFC_3986 : $encode; + + return $this; + } + + /** + * Set the query string separator + * + * @param string $separator The query string separator that will separate fields + * + * @return self + */ + public function setFieldSeparator($separator) + { + $this->fieldSeparator = $separator; + + return $this; + } + + /** + * Set the query string value separator + * + * @param string $separator The query string separator that will separate values from fields + * + * @return self + */ + public function setValueSeparator($separator) + { + $this->valueSeparator = $separator; + + return $this; + } + + /** + * Returns an array of url encoded field names and values + * + * @return array + */ + public function urlEncode() + { + return $this->prepareData($this->data); + } + + /** + * URL encodes a value based on the url encoding type of the query string object + * + * @param string $value Value to encode + * + * @return string + */ + public function encodeValue($value) + { + if ($this->urlEncode == self::RFC_3986) { + return rawurlencode($value); + } elseif ($this->urlEncode == self::FORM_URLENCODED) { + return urlencode($value); + } else { + return (string) $value; + } + } + + /** + * Url encode parameter data and convert nested query strings into a flattened hash. + * + * @param array $data The data to encode + * + * @return array Returns an array of encoded values and keys + */ + protected function prepareData(array $data) + { + // If no aggregator is present then set the default + if (!$this->aggregator) { + $this->setAggregator(null); + } + + $temp = array(); + foreach ($data as $key => $value) { + if ($value === false || $value === null) { + // False and null will not include the "=". Use an empty string to include the "=". + $temp[$this->encodeValue($key)] = $value; + } elseif (is_array($value)) { + $temp = array_merge($temp, $this->aggregator->aggregate($key, $value, $this)); + } else { + $temp[$this->encodeValue($key)] = $this->encodeValue($value); + } + } + + return $temp; + } + + /** + * Converts a key value pair that can contain strings, nulls, false, or arrays + * into a single string. + * + * @param string $name Name of the field + * @param mixed $value Value of the field + * @return string + */ + private function convertKvp($name, $value) + { + if ($value === self::BLANK || $value === null || $value === false) { + return $name; + } elseif (!is_array($value)) { + return $name . $this->valueSeparator . $value; + } + + $result = ''; + foreach ($value as $v) { + $result .= $this->convertKvp($name, $v) . $this->fieldSeparator; + } + + return rtrim($result, $this->fieldSeparator); + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php b/src/lib/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php new file mode 100644 index 00000000..a34893a6 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php @@ -0,0 +1,106 @@ +setLimit($limit)->setOffset($offset); + } + + /** + * Returns only a subset of the decorated entity body when cast as a string + * {@inheritdoc} + */ + public function __toString() + { + return substr((string) $this->body, $this->offset, $this->limit) ?: ''; + } + + public function isConsumed() + { + return $this->body->isConsumed() || + ($this->body->ftell() >= $this->offset + $this->limit); + } + + /** + * Returns the Content-Length of the limited subset of data + * {@inheritdoc} + */ + public function getContentLength() + { + $length = $this->body->getContentLength(); + + return $length === false + ? $this->limit + : min($this->limit, min($length, $this->offset + $this->limit) - $this->offset); + } + + /** + * Allow for a bounded seek on the read limited entity body + * {@inheritdoc} + */ + public function seek($offset, $whence = SEEK_SET) + { + return $whence === SEEK_SET + ? $this->body->seek(max($this->offset, min($this->offset + $this->limit, $offset))) + : false; + } + + /** + * Set the offset to start limiting from + * + * @param int $offset Offset to seek to and begin byte limiting from + * + * @return self + */ + public function setOffset($offset) + { + $this->body->seek($offset); + $this->offset = $offset; + + return $this; + } + + /** + * Set the limit of bytes that the decorator allows to be read from the stream + * + * @param int $limit Total number of bytes to allow to be read from the stream + * + * @return self + */ + public function setLimit($limit) + { + $this->limit = $limit; + + return $this; + } + + public function read($length) + { + // Check if the current position is less than the total allowed bytes + original offset + $remaining = ($this->offset + $this->limit) - $this->body->ftell(); + if ($remaining > 0) { + // Only return the amount of requested data, ensuring that the byte limit is not exceeded + return $this->body->read(min($remaining, $length)); + } else { + return false; + } + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php b/src/lib/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php new file mode 100644 index 00000000..1a824b8b --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php @@ -0,0 +1,250 @@ + array('onRequestSent', 100), + 'request.clone' => 'cleanupRequest', + 'request.before_send' => 'cleanupRequest' + ); + } + + /** + * Clean up the parameters of a request when it is cloned + * + * @param Event $event Event emitted + */ + public function cleanupRequest(Event $event) + { + $params = $event['request']->getParams(); + unset($params[self::REDIRECT_COUNT]); + unset($params[self::PARENT_REQUEST]); + } + + /** + * Called when a request receives a redirect response + * + * @param Event $event Event emitted + */ + public function onRequestSent(Event $event) + { + $response = $event['response']; + $request = $event['request']; + + // Only act on redirect requests with Location headers + if (!$response || $request->getParams()->get(self::DISABLE)) { + return; + } + + // Trace the original request based on parameter history + $original = $this->getOriginalRequest($request); + + // Terminating condition to set the effective response on the original request + if (!$response->isRedirect() || !$response->hasHeader('Location')) { + if ($request !== $original) { + // This is a terminating redirect response, so set it on the original request + $response->getParams()->set(self::REDIRECT_COUNT, $original->getParams()->get(self::REDIRECT_COUNT)); + $original->setResponse($response); + $response->setEffectiveUrl($request->getUrl()); + } + return; + } + + $this->sendRedirectRequest($original, $request, $response); + } + + /** + * Get the original request that initiated a series of redirects + * + * @param RequestInterface $request Request to get the original request from + * + * @return RequestInterface + */ + protected function getOriginalRequest(RequestInterface $request) + { + $original = $request; + // The number of redirects is held on the original request, so determine which request that is + while ($parent = $original->getParams()->get(self::PARENT_REQUEST)) { + $original = $parent; + } + + return $original; + } + + /** + * Create a redirect request for a specific request object + * + * Takes into account strict RFC compliant redirection (e.g. redirect POST with POST) vs doing what most clients do + * (e.g. redirect POST with GET). + * + * @param RequestInterface $request Request being redirected + * @param RequestInterface $original Original request + * @param int $statusCode Status code of the redirect + * @param string $location Location header of the redirect + * + * @return RequestInterface Returns a new redirect request + * @throws CouldNotRewindStreamException If the body needs to be rewound but cannot + */ + protected function createRedirectRequest( + RequestInterface $request, + $statusCode, + $location, + RequestInterface $original + ) { + $redirectRequest = null; + $strict = $original->getParams()->get(self::STRICT_REDIRECTS); + + // Switch method to GET for 303 redirects. 301 and 302 redirects also switch to GET unless we are forcing RFC + // compliance to emulate what most browsers do. NOTE: IE only switches methods on 301/302 when coming from a POST. + if ($request instanceof EntityEnclosingRequestInterface && ($statusCode == 303 || (!$strict && $statusCode <= 302))) { + $redirectRequest = RequestFactory::getInstance()->cloneRequestWithMethod($request, 'GET'); + } else { + $redirectRequest = clone $request; + } + + $redirectRequest->setIsRedirect(true); + // Always use the same response body when redirecting + $redirectRequest->setResponseBody($request->getResponseBody()); + + $location = Url::factory($location); + // If the location is not absolute, then combine it with the original URL + if (!$location->isAbsolute()) { + $originalUrl = $redirectRequest->getUrl(true); + // Remove query string parameters and just take what is present on the redirect Location header + $originalUrl->getQuery()->clear(); + $location = $originalUrl->combine((string) $location, true); + } + + $redirectRequest->setUrl($location); + + // Add the parent request to the request before it sends (make sure it's before the onRequestClone event too) + $redirectRequest->getEventDispatcher()->addListener( + 'request.before_send', + $func = function ($e) use (&$func, $request, $redirectRequest) { + $redirectRequest->getEventDispatcher()->removeListener('request.before_send', $func); + $e['request']->getParams()->set(RedirectPlugin::PARENT_REQUEST, $request); + } + ); + + // Rewind the entity body of the request if needed + if ($redirectRequest instanceof EntityEnclosingRequestInterface && $redirectRequest->getBody()) { + $body = $redirectRequest->getBody(); + // Only rewind the body if some of it has been read already, and throw an exception if the rewind fails + if ($body->ftell() && !$body->rewind()) { + throw new CouldNotRewindStreamException( + 'Unable to rewind the non-seekable entity body of the request after redirecting. cURL probably ' + . 'sent part of body before the redirect occurred. Try adding acustom rewind function using on the ' + . 'entity body of the request using setRewindFunction().' + ); + } + } + + return $redirectRequest; + } + + /** + * Prepare the request for redirection and enforce the maximum number of allowed redirects per client + * + * @param RequestInterface $original Original request + * @param RequestInterface $request Request to prepare and validate + * @param Response $response The current response + * + * @return RequestInterface + */ + protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response) + { + $params = $original->getParams(); + // This is a new redirect, so increment the redirect counter + $current = $params[self::REDIRECT_COUNT] + 1; + $params[self::REDIRECT_COUNT] = $current; + // Use a provided maximum value or default to a max redirect count of 5 + $max = isset($params[self::MAX_REDIRECTS]) ? $params[self::MAX_REDIRECTS] : $this->defaultMaxRedirects; + + // Throw an exception if the redirect count is exceeded + if ($current > $max) { + $this->throwTooManyRedirectsException($original, $max); + return false; + } else { + // Create a redirect request based on the redirect rules set on the request + return $this->createRedirectRequest( + $request, + $response->getStatusCode(), + trim($response->getLocation()), + $original + ); + } + } + + /** + * Send a redirect request and handle any errors + * + * @param RequestInterface $original The originating request + * @param RequestInterface $request The current request being redirected + * @param Response $response The response of the current request + * + * @throws BadResponseException|\Exception + */ + protected function sendRedirectRequest(RequestInterface $original, RequestInterface $request, Response $response) + { + // Validate and create a redirect request based on the original request and current response + if ($redirectRequest = $this->prepareRedirection($original, $request, $response)) { + try { + $redirectRequest->send(); + } catch (BadResponseException $e) { + $e->getResponse(); + if (!$e->getResponse()) { + throw $e; + } + } + } + } + + /** + * Throw a too many redirects exception for a request + * + * @param RequestInterface $original Request + * @param int $max Max allowed redirects + * + * @throws TooManyRedirectsException when too many redirects have been issued + */ + protected function throwTooManyRedirectsException(RequestInterface $original, $max) + { + $original->getEventDispatcher()->addListener( + 'request.complete', + $func = function ($e) use (&$func, $original, $max) { + $original->getEventDispatcher()->removeListener('request.complete', $func); + $str = "{$max} redirects were issued for this request:\n" . $e['request']->getRawHeaders(); + throw new TooManyRedirectsException($str); + } + ); + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem b/src/lib/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem new file mode 100644 index 00000000..9794dfb7 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem @@ -0,0 +1,3866 @@ +## +## ca-bundle.crt -- Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Tue Apr 22 08:29:31 2014 +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## http://mxr.mozilla.org/mozilla-release/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## + + +GTE CyberTrust Global Root +========================== +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG +A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz +MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL +Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 +IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u +sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql +HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID +AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW +M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF +NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +Thawte Server CA +================ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE +AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j +b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV +BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u +c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG +A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl +/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 +1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J +GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ +GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +Thawte Premium Server CA +======================== +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE +AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl +ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU +VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 +aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ +cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh +Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ +qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm +SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf +8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t +UCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +Equifax Secure CA +================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR +fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW +8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE +CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS +spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 +zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB +BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 +70+sB3c4 +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA +TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah +WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf +Tqj/ZA1k +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO +FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 +lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT +1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD +Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 +-----END CERTIFICATE----- + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +ValiCert Class 1 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy +MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi +GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm +DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG +lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX +icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP +Orf1LXLI +-----END CERTIFICATE----- + +ValiCert Class 2 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC +CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf +ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ +SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV +UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 +W9ViH0Pd +-----END CERTIFICATE----- + +RSA Root Certificate 1 +====================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td +3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H +BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs +3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF +V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r +on+jjBXu +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS +tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM +8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW +Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX +Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd +RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG +UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +Entrust.net Secure Server CA +============================ +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg +cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl +ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG +A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi +eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p +dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ +aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 +gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw +ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l +dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw +NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow +HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN +Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 +n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Equifax Secure Global eBusiness CA +================================== +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp +bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds +b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV +PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN +qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn +hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs +MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN +I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY +NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 1 +============================= +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB +LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE +ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz +IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ +1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a +IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk +MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW +Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF +AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 +lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ +KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +AddTrust Low-Value Services Root +================================ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU +cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO +ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 +54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr +oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 +Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui +GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w +HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw +HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt +ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr +mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj +ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +AddTrust Public Services Root +============================= +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU +cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ +BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l +dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu +nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i +d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG +Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw +HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G +A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G +A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 +JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 +Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H +EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +AddTrust Qualified Certificates Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU +cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx +CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx +64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 +KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o +L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR +wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU +MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE +BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y +azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze +RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB +iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +RSA Security 2048 v3 +==================== +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK +ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy +MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb +BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 +Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb +WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH +KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP ++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E +FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY +v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj +0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj +VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 +nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Global CA 2 +==================== +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw +MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ +NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k +LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA +Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b +HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH +K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 +srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh +ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL +OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC +x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF +H4z1Ir+rzoPz4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +America Online Root Certification Authority 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG +v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z +DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh +sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP +8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z +o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf +GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF +VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft +3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- + +America Online Root Certification Authority 2 +============================================= +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en +fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 +f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO +qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN +RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 +gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn +6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid +FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 +Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj +B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY +T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p ++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg +JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy +zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO +ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh +1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf +GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff +Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP +cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Certum Root CA +============== +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK +ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla +Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u +by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x +wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL +kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ +89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K +Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P +NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ +GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg +GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ +0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS +qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +Comodo Secure Services root +=========================== +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw +MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi +BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP +9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc +rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC +oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V +p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E +FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj +YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm +aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL +DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw +pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H +RR3B7Hzs/Sk= +-----END CERTIFICATE----- + +Comodo Trusted Services root +============================ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw +MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h +bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw +IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 +3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y +/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 +juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS +ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud +DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp +ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl +cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA +BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l +R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O +9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA +============================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE +ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w +HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh +bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt +vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P +jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca +C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth +vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 +22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV +HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v +dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN +BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR +EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw +MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- + +TDC Internet Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE +ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx +NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu +ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j +xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL +znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc +5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 +otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI +AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM +VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM +MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe +UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G +CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m +gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb +O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU +Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- + +UTN DATACorp SGC Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ +BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa +MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w +HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy +dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys +raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo +wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA +9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv +33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud +DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 +BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD +LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 +I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx +EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP +DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx +NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp +cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn +MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU +xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH +NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW +DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV +d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud +EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v +cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P +AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh +bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD +VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi +fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD +L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN +UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n +ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 +erfutGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +================================== +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx +NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt +YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg +MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw +ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J +1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O +by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl +6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c +8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ +BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j +aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B +Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj +aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y +ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA +PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y +gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ +PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 +IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes +t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +NetLock Notary (Class A) Root +============================= +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI +EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j +ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX +DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH +EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD +VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz +cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM +D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ +z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC +/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 +tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 +4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG +A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC +Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv +bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn +LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 +ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz +IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh +IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu +b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg +Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp +bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 +ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP +ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB +CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr +KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM +8CgHrTwXZoi1/baI +-----END CERTIFICATE----- + +NetLock Business (Class B) Root +=============================== +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg +VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD +VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv +bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg +VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S +o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr +1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ +RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh +dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 +ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv +c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg +YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz +Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA +bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl +IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 +YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj +cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM +43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR +stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +NetLock Express (Class C) Root +============================== +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ +BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j +ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z +W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 +euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw +DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN +RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn +YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB +IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i +aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 +ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y +emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k +IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ +UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg +YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 +xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW +gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj +YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH +AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw +Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg +U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 +LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh +cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT +dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC +AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh +3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm +vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk +fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 +fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ +EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl +1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ +lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro +g14= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +Swisscom Root CA 1 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 +MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM +MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF +NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe +AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC +b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn +7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN +cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp +WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 +haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY +MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 +MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn +jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ +MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H +VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl +vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl +OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 +1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq +nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy +x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW +NY6E0F/6MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +DST ACES CA X6 +============== +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT +MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha +MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE +CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI +DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa +pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow +GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy +MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu +Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy +dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU +CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 +5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t +Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs +vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 +oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 1 +============================================== +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP +MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 +acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx +MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg +U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB +TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC +aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX +yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i +Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ +8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 +W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 +sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE +q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY +nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2 +============================================== +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN +MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr +dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe +LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI +x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g +QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr +5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB +AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt +Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ +hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P +9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 +UrbnBEI= +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +WellsSecure Public Root Certificate Authority +============================================= +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM +F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw +NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl +bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD +VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 +iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 +i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 +bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB +K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB +AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu +cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm +lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB +i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww +GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI +K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 +bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj +qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es +E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ +tylv2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +IGC/A +===== +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD +VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE +Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy +MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI +EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT +STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 +TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW +So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy +HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd +frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ +tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB +egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC +iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK +q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q +MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI +lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF +0mBWWg== +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +================================= +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE +BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl +Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO +/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX +WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z +ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 +bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK +9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm +iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG +Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW +mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW +T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE +BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL +EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 +MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz +dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT +GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG +d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N +oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc +QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ +PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb +MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG +IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD +VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 +LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A +dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA +4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg +AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA +egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 +Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO +PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv +c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h +cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw +IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT +WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV +MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp +Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal +HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT +nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE +aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK +yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB +S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. +====================================== +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT +AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg +LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w +HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ +U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh +IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN +yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU +2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 +4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP +2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm +8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf +HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa +Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK +5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b +czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g +ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF +BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug +cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf +AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX +EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v +/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 +MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 +3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk +eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f +/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h +RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU +Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 2 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw +MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw +IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 +xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ +Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u +SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G +dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ +KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj +TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP +JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk +vQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 3 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw +MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W +yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo +6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ +uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk +2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE +O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 +yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 +IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal +092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc +5A== +-----END CERTIFICATE----- + +TC TrustCenter Universal CA I +============================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN +MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg +VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw +JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC +qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv +xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw +ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O +gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j +BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG +1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy +vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 +ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a +7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +ComSign Secured CA +================== +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE +AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w +NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD +QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs +49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH +7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB +kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 +9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw +AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t +U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA +j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC +AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a +BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp +FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP +51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 +============================================================================================================================= +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH +DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q +aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry +b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV +BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg +S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 +MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl +IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF +n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl +IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft +dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl +cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO +Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 +xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR +6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd +BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 +N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT +y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh +LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M +dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +Buypass Class 2 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 +MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M +cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 +0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 +0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R +uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV +1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt +7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 +fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w +wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +Buypass Class 3 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 +MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx +ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 +n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia +AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c +1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 +pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA +EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 +htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj +el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- + +EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 +========================================================================== +-----BEGIN CERTIFICATE----- +MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg +QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe +Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt +IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by +X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b +gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr +eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ +TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy +Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn +uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI +qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm +ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 +Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW +Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t +FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm +zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k +XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT +bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU +RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK +1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt +2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ +Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 +AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +CNNIC ROOT +========== +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE +ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw +OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD +o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz +VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT +VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or +czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK +y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC +wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S +lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 +Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM +O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 +BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 +G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m +mxE= +-----END CERTIFICATE----- + +ApplicationCA - Japanese Government +=================================== +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT +SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw +MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl +cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 +fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN +wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE +jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu +nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU +WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV +BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD +vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs +o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g +/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD +io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW +dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +============================================ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ +5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn +vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj +CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil +e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR +OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI +CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 +48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi +trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 +qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB +AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC +ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA +A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz ++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj +f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN +kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk +CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF +URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb +CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h +oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV +IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm +66+KAQ== +-----END CERTIFICATE----- + +CA Disig +======== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK +QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw +MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz +bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm +GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD +Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo +hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt +ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w +gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P +AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz +aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff +ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa +BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t +WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 +mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K +ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA +4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- + +Juur-SK +======= +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA +c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw +DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG +SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy +aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf +TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC ++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw +UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa +Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF +MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD +HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh +AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA +cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr +AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw +cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G +A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo +ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL +abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 +IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh +Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 +yyqcjg== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +ACEDICOM Root +============= +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD +T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 +MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG +A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk +WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD +YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew +MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb +m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk +HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT +xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 +3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 +2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq +TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz +4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU +9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv +bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg +aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP +eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk +zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 +ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI +KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq +nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE +I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp +MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o +tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky +CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX +bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ +D/xwzoiQ +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi +=================================================== +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz +ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 +MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 +cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u +aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY +8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y +jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI +JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk +9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG +SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d +F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq +D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 +Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq +fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +Certinomis - Autorité Racine +============================= +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg +LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG +A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw +JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa +wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly +Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw +2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N +jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q +c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC +lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb +xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g +530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna +4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x +WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva +R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 +nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B +CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv +JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE +qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b +WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE +wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ +vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +Root CA Generalitat Valenciana +============================== +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE +ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 +IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 +WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE +CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 +F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B +ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ +D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte +JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB +AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n +dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB +ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl +AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA +YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy +AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt +AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA +YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu +AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA +OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 +dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV +BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S +b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh +TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz +Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 +NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH +iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt ++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +A-Trust-nQual-03 +================ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE +Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R +dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw +RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 +ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 +c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA +zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n +yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE +SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 +iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V +cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV +eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 +ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr +sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd +JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 +ahq97BvIxYSazQ== +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Trustis FPS Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 +IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ +RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk +H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa +cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt +o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA +AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd +BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c +GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC +yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P +8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV +l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl +iB6XzCGcKQENZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ +Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 +dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu +c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv +bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 +aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 +fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm +N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN +Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T +tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX +e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA +2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs +HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib +D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= +-----END CERTIFICATE----- + +StartCom Certification Authority G2 +=================================== +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE +ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O +o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG +4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi +Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul +Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs +O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H +vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L +nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS +FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa +z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ +KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk +J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ +JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG +/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc +nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld +blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc +l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm +7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm +obp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2007 +================================================= +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X +DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl +a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN +BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp +bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N +YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv +KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya +KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT +rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC +AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s +Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO +Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb +BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK +poRq0Tl9 +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +PSCProcert +========== +-----BEGIN CERTIFICATE----- +MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk +ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ +MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz +dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl +cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw +IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw +MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w +DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD +ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp +Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC +wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA +3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh +RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO +EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 +0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH +0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU +td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw +Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp +r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ +AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz +Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId +xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp +ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH +EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h +Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k +ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG +9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG +MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG +LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 +ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy +YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v +Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o +dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq +T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN +g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q +uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 +n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn +FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo +5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq +3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 +poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y +eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km +-----END CERTIFICATE----- + +China Internet Network Information Center EV Certificates Root +============================================================== +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D +aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg +Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG +A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM +PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl +cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y +jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV +98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H +klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 +KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC +7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD +glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 +0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM +7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 +5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= +-----END CERTIFICATE----- + +Swisscom Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 +MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM +LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo +ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ +wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH +Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a +SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS +NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab +mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY +Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 +qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O +BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu +MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO +v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ +82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz +o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs +a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx +OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW +mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o ++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC +rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX +5OfNeOI5wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- + +Swisscom Root EV CA 2 +===================== +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE +BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl +cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN +MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT +HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg +Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz +o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy +Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti +GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li +qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH +Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG +alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa +m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox +bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi +xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED +MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB +bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL +j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU +wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 +XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH +59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ +23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq +J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA +HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi +uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW +l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- + +CA Disig Root R1 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy +3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 +u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 +m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk +CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa +YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 +vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL +LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX +ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is +XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ +04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B +LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM +CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb +VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 +YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS +ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix +lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N +UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ +a7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +=============================== +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w +DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls +ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw +NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx +QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl +cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD +DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd +hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K +CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g +ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ +BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 +E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz +rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq +jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 +dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK +kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO +XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 +VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo +a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc +dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV +KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT +Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 +8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G +C7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/StaticClient.php b/src/lib/vendor/guzzle/http/Guzzle/Http/StaticClient.php new file mode 100644 index 00000000..dbd4c184 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/StaticClient.php @@ -0,0 +1,157 @@ +createRequest($method, $url, null, null, $options); + + if (isset($options['stream'])) { + if ($options['stream'] instanceof StreamRequestFactoryInterface) { + return $options['stream']->fromRequest($request); + } elseif ($options['stream'] == true) { + $streamFactory = new PhpStreamRequestFactory(); + return $streamFactory->fromRequest($request); + } + } + + return $request->send(); + } + + /** + * Send a GET request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function get($url, $options = array()) + { + return self::request('GET', $url, $options); + } + + /** + * Send a HEAD request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function head($url, $options = array()) + { + return self::request('HEAD', $url, $options); + } + + /** + * Send a DELETE request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function delete($url, $options = array()) + { + return self::request('DELETE', $url, $options); + } + + /** + * Send a POST request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function post($url, $options = array()) + { + return self::request('POST', $url, $options); + } + + /** + * Send a PUT request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function put($url, $options = array()) + { + return self::request('PUT', $url, $options); + } + + /** + * Send a PATCH request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function patch($url, $options = array()) + { + return self::request('PATCH', $url, $options); + } + + /** + * Send an OPTIONS request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function options($url, $options = array()) + { + return self::request('OPTIONS', $url, $options); + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/Url.php b/src/lib/vendor/guzzle/http/Guzzle/Http/Url.php new file mode 100644 index 00000000..6a4e7724 --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/Url.php @@ -0,0 +1,554 @@ + null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + 'user' => null, 'pass' => null, 'fragment' => null); + + if (false === ($parts = parse_url($url))) { + throw new InvalidArgumentException('Was unable to parse malformed url: ' . $url); + } + + $parts += $defaults; + + // Convert the query string into a QueryString object + if ($parts['query'] || 0 !== strlen($parts['query'])) { + $parts['query'] = QueryString::fromString($parts['query']); + } + + return new static($parts['scheme'], $parts['host'], $parts['user'], + $parts['pass'], $parts['port'], $parts['path'], $parts['query'], + $parts['fragment']); + } + + /** + * Build a URL from parse_url parts. The generated URL will be a relative URL if a scheme or host are not provided. + * + * @param array $parts Array of parse_url parts + * + * @return string + */ + public static function buildUrl(array $parts) + { + $url = $scheme = ''; + + if (isset($parts['scheme'])) { + $scheme = $parts['scheme']; + $url .= $scheme . ':'; + } + + if (isset($parts['host'])) { + $url .= '//'; + if (isset($parts['user'])) { + $url .= $parts['user']; + if (isset($parts['pass'])) { + $url .= ':' . $parts['pass']; + } + $url .= '@'; + } + + $url .= $parts['host']; + + // Only include the port if it is not the default port of the scheme + if (isset($parts['port']) + && !(($scheme == 'http' && $parts['port'] == 80) || ($scheme == 'https' && $parts['port'] == 443)) + ) { + $url .= ':' . $parts['port']; + } + } + + // Add the path component if present + if (isset($parts['path']) && 0 !== strlen($parts['path'])) { + // Always ensure that the path begins with '/' if set and something is before the path + if ($url && $parts['path'][0] != '/' && substr($url, -1) != '/') { + $url .= '/'; + } + $url .= $parts['path']; + } + + // Add the query string if present + if (isset($parts['query'])) { + $url .= '?' . $parts['query']; + } + + // Ensure that # is only added to the url if fragment contains anything. + if (isset($parts['fragment'])) { + $url .= '#' . $parts['fragment']; + } + + return $url; + } + + /** + * Create a new URL from URL parts + * + * @param string $scheme Scheme of the URL + * @param string $host Host of the URL + * @param string $username Username of the URL + * @param string $password Password of the URL + * @param int $port Port of the URL + * @param string $path Path of the URL + * @param QueryString|array|string $query Query string of the URL + * @param string $fragment Fragment of the URL + */ + public function __construct($scheme, $host, $username = null, $password = null, $port = null, $path = null, QueryString $query = null, $fragment = null) + { + $this->scheme = $scheme; + $this->host = $host; + $this->port = $port; + $this->username = $username; + $this->password = $password; + $this->fragment = $fragment; + if (!$query) { + $this->query = new QueryString(); + } else { + $this->setQuery($query); + } + $this->setPath($path); + } + + /** + * Clone the URL + */ + public function __clone() + { + $this->query = clone $this->query; + } + + /** + * Returns the URL as a URL string + * + * @return string + */ + public function __toString() + { + return self::buildUrl($this->getParts()); + } + + /** + * Get the parts of the URL as an array + * + * @return array + */ + public function getParts() + { + $query = (string) $this->query; + + return array( + 'scheme' => $this->scheme, + 'user' => $this->username, + 'pass' => $this->password, + 'host' => $this->host, + 'port' => $this->port, + 'path' => $this->getPath(), + 'query' => $query !== '' ? $query : null, + 'fragment' => $this->fragment, + ); + } + + /** + * Set the host of the request. + * + * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com) + * + * @return Url + */ + public function setHost($host) + { + if (strpos($host, ':') === false) { + $this->host = $host; + } else { + list($host, $port) = explode(':', $host); + $this->host = $host; + $this->setPort($port); + } + + return $this; + } + + /** + * Get the host part of the URL + * + * @return string + */ + public function getHost() + { + return $this->host; + } + + /** + * Set the scheme part of the URL (http, https, ftp, etc) + * + * @param string $scheme Scheme to set + * + * @return Url + */ + public function setScheme($scheme) + { + if ($this->scheme == 'http' && $this->port == 80) { + $this->port = null; + } elseif ($this->scheme == 'https' && $this->port == 443) { + $this->port = null; + } + + $this->scheme = $scheme; + + return $this; + } + + /** + * Get the scheme part of the URL + * + * @return string + */ + public function getScheme() + { + return $this->scheme; + } + + /** + * Set the port part of the URL + * + * @param int $port Port to set + * + * @return Url + */ + public function setPort($port) + { + $this->port = $port; + + return $this; + } + + /** + * Get the port part of the URl. Will return the default port for a given scheme if no port has been set. + * + * @return int|null + */ + public function getPort() + { + if ($this->port) { + return $this->port; + } elseif ($this->scheme == 'http') { + return 80; + } elseif ($this->scheme == 'https') { + return 443; + } + + return null; + } + + /** + * Set the path part of the URL + * + * @param array|string $path Path string or array of path segments + * + * @return Url + */ + public function setPath($path) + { + static $pathReplace = array(' ' => '%20', '?' => '%3F'); + if (is_array($path)) { + $path = '/' . implode('/', $path); + } + + $this->path = strtr($path, $pathReplace); + + return $this; + } + + /** + * Normalize the URL so that double slashes and relative paths are removed + * + * @return Url + */ + public function normalizePath() + { + if (!$this->path || $this->path == '/' || $this->path == '*') { + return $this; + } + + $results = array(); + $segments = $this->getPathSegments(); + foreach ($segments as $segment) { + if ($segment == '..') { + array_pop($results); + } elseif ($segment != '.' && $segment != '') { + $results[] = $segment; + } + } + + // Combine the normalized parts and add the leading slash if needed + $this->path = ($this->path[0] == '/' ? '/' : '') . implode('/', $results); + + // Add the trailing slash if necessary + if ($this->path != '/' && end($segments) == '') { + $this->path .= '/'; + } + + return $this; + } + + /** + * Add a relative path to the currently set path. + * + * @param string $relativePath Relative path to add + * + * @return Url + */ + public function addPath($relativePath) + { + if ($relativePath != '/' && is_string($relativePath) && strlen($relativePath) > 0) { + // Add a leading slash if needed + if ($relativePath[0] != '/') { + $relativePath = '/' . $relativePath; + } + $this->setPath(str_replace('//', '/', $this->path . $relativePath)); + } + + return $this; + } + + /** + * Get the path part of the URL + * + * @return string + */ + public function getPath() + { + return $this->path; + } + + /** + * Get the path segments of the URL as an array + * + * @return array + */ + public function getPathSegments() + { + return array_slice(explode('/', $this->getPath()), 1); + } + + /** + * Set the password part of the URL + * + * @param string $password Password to set + * + * @return Url + */ + public function setPassword($password) + { + $this->password = $password; + + return $this; + } + + /** + * Get the password part of the URL + * + * @return null|string + */ + public function getPassword() + { + return $this->password; + } + + /** + * Set the username part of the URL + * + * @param string $username Username to set + * + * @return Url + */ + public function setUsername($username) + { + $this->username = $username; + + return $this; + } + + /** + * Get the username part of the URl + * + * @return null|string + */ + public function getUsername() + { + return $this->username; + } + + /** + * Get the query part of the URL as a QueryString object + * + * @return QueryString + */ + public function getQuery() + { + return $this->query; + } + + /** + * Set the query part of the URL + * + * @param QueryString|string|array $query Query to set + * + * @return Url + */ + public function setQuery($query) + { + if (is_string($query)) { + $output = null; + parse_str($query, $output); + $this->query = new QueryString($output); + } elseif (is_array($query)) { + $this->query = new QueryString($query); + } elseif ($query instanceof QueryString) { + $this->query = $query; + } + + return $this; + } + + /** + * Get the fragment part of the URL + * + * @return null|string + */ + public function getFragment() + { + return $this->fragment; + } + + /** + * Set the fragment part of the URL + * + * @param string $fragment Fragment to set + * + * @return Url + */ + public function setFragment($fragment) + { + $this->fragment = $fragment; + + return $this; + } + + /** + * Check if this is an absolute URL + * + * @return bool + */ + public function isAbsolute() + { + return $this->scheme && $this->host; + } + + /** + * Combine the URL with another URL. Follows the rules specific in RFC 3986 section 5.4. + * + * @param string $url Relative URL to combine with + * @param bool $strictRfc3986 Set to true to use strict RFC 3986 compliance when merging paths. When first + * released, Guzzle used an incorrect algorithm for combining relative URL paths. In + * order to not break users, we introduced this flag to allow the merging of URLs based + * on strict RFC 3986 section 5.4.1. This means that "http://a.com/foo/baz" merged with + * "bar" would become "http://a.com/foo/bar". When this value is set to false, it would + * become "http://a.com/foo/baz/bar". + * @return Url + * @throws InvalidArgumentException + * @link http://tools.ietf.org/html/rfc3986#section-5.4 + */ + public function combine($url, $strictRfc3986 = false) + { + $url = self::factory($url); + + // Use the more absolute URL as the base URL + if (!$this->isAbsolute() && $url->isAbsolute()) { + $url = $url->combine($this); + } + + // Passing a URL with a scheme overrides everything + if ($buffer = $url->getScheme()) { + $this->scheme = $buffer; + $this->host = $url->getHost(); + $this->port = $url->getPort(); + $this->username = $url->getUsername(); + $this->password = $url->getPassword(); + $this->path = $url->getPath(); + $this->query = $url->getQuery(); + $this->fragment = $url->getFragment(); + return $this; + } + + // Setting a host overrides the entire rest of the URL + if ($buffer = $url->getHost()) { + $this->host = $buffer; + $this->port = $url->getPort(); + $this->username = $url->getUsername(); + $this->password = $url->getPassword(); + $this->path = $url->getPath(); + $this->query = $url->getQuery(); + $this->fragment = $url->getFragment(); + return $this; + } + + $path = $url->getPath(); + $query = $url->getQuery(); + + if (!$path) { + if (count($query)) { + $this->addQuery($query, $strictRfc3986); + } + } else { + if ($path[0] == '/') { + $this->path = $path; + } elseif ($strictRfc3986) { + $this->path .= '/../' . $path; + } else { + $this->path .= '/' . $path; + } + $this->normalizePath(); + $this->addQuery($query, $strictRfc3986); + } + + $this->fragment = $url->getFragment(); + + return $this; + } + + private function addQuery(QueryString $new, $strictRfc386) + { + if (!$strictRfc386) { + $new->merge($this->query); + } + + $this->query = $new; + } +} diff --git a/src/lib/vendor/guzzle/http/Guzzle/Http/composer.json b/src/lib/vendor/guzzle/http/Guzzle/Http/composer.json new file mode 100644 index 00000000..9384a5bf --- /dev/null +++ b/src/lib/vendor/guzzle/http/Guzzle/Http/composer.json @@ -0,0 +1,32 @@ +{ + "name": "guzzle/http", + "description": "HTTP libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": ["http client", "http", "client", "Guzzle", "curl"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/common": "self.version", + "guzzle/parser": "self.version", + "guzzle/stream": "self.version" + }, + "suggest": { + "ext-curl": "*" + }, + "autoload": { + "psr-0": { "Guzzle\\Http": "" } + }, + "target-dir": "Guzzle/Http", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php new file mode 100644 index 00000000..4349eeb3 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php @@ -0,0 +1,131 @@ + 'Domain', + 'path' => 'Path', + 'max_age' => 'Max-Age', + 'expires' => 'Expires', + 'version' => 'Version', + 'secure' => 'Secure', + 'port' => 'Port', + 'discard' => 'Discard', + 'comment' => 'Comment', + 'comment_url' => 'Comment-Url', + 'http_only' => 'HttpOnly' + ); + + public function parseCookie($cookie, $host = null, $path = null, $decode = false) + { + // Explode the cookie string using a series of semicolons + $pieces = array_filter(array_map('trim', explode(';', $cookie))); + + // The name of the cookie (first kvp) must include an equal sign. + if (empty($pieces) || !strpos($pieces[0], '=')) { + return false; + } + + // Create the default return array + $data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array( + 'cookies' => array(), + 'data' => array(), + 'path' => null, + 'http_only' => false, + 'discard' => false, + 'domain' => $host + )); + $foundNonCookies = 0; + + // Add the cookie pieces into the parsed data array + foreach ($pieces as $part) { + + $cookieParts = explode('=', $part, 2); + $key = trim($cookieParts[0]); + + if (count($cookieParts) == 1) { + // Can be a single value (e.g. secure, httpOnly) + $value = true; + } else { + // Be sure to strip wrapping quotes + $value = trim($cookieParts[1], " \n\r\t\0\x0B\""); + if ($decode) { + $value = urldecode($value); + } + } + + // Only check for non-cookies when cookies have been found + if (!empty($data['cookies'])) { + foreach (self::$cookieParts as $mapValue => $search) { + if (!strcasecmp($search, $key)) { + $data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value; + $foundNonCookies++; + continue 2; + } + } + } + + // If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a + // cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data. + $data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value; + } + + // Calculate the expires date + if (!$data['expires'] && $data['max_age']) { + $data['expires'] = time() + (int) $data['max_age']; + } + + // Check path attribute according RFC6265 http://tools.ietf.org/search/rfc6265#section-5.2.4 + // "If the attribute-value is empty or if the first character of the + // attribute-value is not %x2F ("/"): + // Let cookie-path be the default-path. + // Otherwise: + // Let cookie-path be the attribute-value." + if (!$data['path'] || substr($data['path'], 0, 1) !== '/') { + $data['path'] = $this->getDefaultPath($path); + } + + return $data; + } + + /** + * Get default cookie path according to RFC 6265 + * http://tools.ietf.org/search/rfc6265#section-5.1.4 Paths and Path-Match + * + * @param string $path Request uri-path + * + * @return string + */ + protected function getDefaultPath($path) { + // "The user agent MUST use an algorithm equivalent to the following algorithm + // to compute the default-path of a cookie:" + + // "2. If the uri-path is empty or if the first character of the uri-path is not + // a %x2F ("/") character, output %x2F ("/") and skip the remaining steps. + if (empty($path) || substr($path, 0, 1) !== '/') { + return '/'; + } + + // "3. If the uri-path contains no more than one %x2F ("/") character, output + // %x2F ("/") and skip the remaining step." + if ($path === "/") { + return $path; + } + + $rightSlashPos = strrpos($path, '/'); + if ($rightSlashPos === 0) { + return "/"; + } + + // "4. Output the characters of the uri-path from the first character up to, + // but not including, the right-most %x2F ("/")." + return substr($path, 0, $rightSlashPos); + + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php new file mode 100644 index 00000000..d21ffe21 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php @@ -0,0 +1,33 @@ + $requestUrl, + 'scheme' => 'http' + ); + + // Check for the Host header + if (isset($parts['headers']['Host'])) { + $urlParts['host'] = $parts['headers']['Host']; + } elseif (isset($parts['headers']['host'])) { + $urlParts['host'] = $parts['headers']['host']; + } else { + $urlParts['host'] = null; + } + + if (false === strpos($urlParts['host'], ':')) { + $urlParts['port'] = ''; + } else { + $hostParts = explode(':', $urlParts['host']); + $urlParts['host'] = trim($hostParts[0]); + $urlParts['port'] = (int) trim($hostParts[1]); + if ($urlParts['port'] == 443) { + $urlParts['scheme'] = 'https'; + } + } + + // Check if a query is present + $path = $urlParts['path']; + $qpos = strpos($path, '?'); + if ($qpos) { + $urlParts['query'] = substr($path, $qpos + 1); + $urlParts['path'] = substr($path, 0, $qpos); + } else { + $urlParts['query'] = ''; + } + + return $urlParts; + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php new file mode 100644 index 00000000..10474006 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php @@ -0,0 +1,110 @@ +parseMessage($message); + + // Parse the protocol and protocol version + if (isset($parts['start_line'][2])) { + $startParts = explode('/', $parts['start_line'][2]); + $protocol = strtoupper($startParts[0]); + $version = isset($startParts[1]) ? $startParts[1] : '1.1'; + } else { + $protocol = 'HTTP'; + $version = '1.1'; + } + + $parsed = array( + 'method' => strtoupper($parts['start_line'][0]), + 'protocol' => $protocol, + 'version' => $version, + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ); + + $parsed['request_url'] = $this->getUrlPartsFromMessage($parts['start_line'][1], $parsed); + + return $parsed; + } + + public function parseResponse($message) + { + if (!$message) { + return false; + } + + $parts = $this->parseMessage($message); + list($protocol, $version) = explode('/', trim($parts['start_line'][0])); + + return array( + 'protocol' => $protocol, + 'version' => $version, + 'code' => $parts['start_line'][1], + 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '', + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ); + } + + /** + * Parse a message into parts + * + * @param string $message Message to parse + * + * @return array + */ + protected function parseMessage($message) + { + $startLine = null; + $headers = array(); + $body = ''; + + // Iterate over each line in the message, accounting for line endings + $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); + for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { + + $line = $lines[$i]; + + // If two line breaks were encountered, then this is the end of body + if (empty($line)) { + if ($i < $totalLines - 1) { + $body = implode('', array_slice($lines, $i + 2)); + } + break; + } + + // Parse message headers + if (!$startLine) { + $startLine = explode(' ', $line, 3); + } elseif (strpos($line, ':')) { + $parts = explode(':', $line, 2); + $key = trim($parts[0]); + $value = isset($parts[1]) ? trim($parts[1]) : ''; + if (!isset($headers[$key])) { + $headers[$key] = $value; + } elseif (!is_array($headers[$key])) { + $headers[$key] = array($headers[$key], $value); + } else { + $headers[$key][] = $value; + } + } + } + + return array( + 'start_line' => $startLine, + 'headers' => $headers, + 'body' => $body + ); + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php new file mode 100644 index 00000000..cc448088 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php @@ -0,0 +1,27 @@ + $parts->requestMethod, + 'protocol' => 'HTTP', + 'version' => number_format($parts->httpVersion, 1), + 'headers' => $parts->headers, + 'body' => $parts->body + ); + + $parsed['request_url'] = $this->getUrlPartsFromMessage($parts->requestUrl, $parsed); + + return $parsed; + } + + public function parseResponse($message) + { + if (!$message) { + return false; + } + + $parts = http_parse_message($message); + + return array( + 'protocol' => 'HTTP', + 'version' => number_format($parts->httpVersion, 1), + 'code' => $parts->responseCode, + 'reason_phrase' => $parts->responseStatus, + 'headers' => $parts->headers, + 'body' => $parts->body + ); + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php new file mode 100644 index 00000000..f8386831 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php @@ -0,0 +1,75 @@ + 'Guzzle\\Parser\\Message\\MessageParser', + 'cookie' => 'Guzzle\\Parser\\Cookie\\CookieParser', + 'url' => 'Guzzle\\Parser\\Url\\UrlParser', + 'uri_template' => 'Guzzle\\Parser\\UriTemplate\\UriTemplate', + ); + + /** + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new static; + } + + return self::$instance; + } + + public function __construct() + { + // Use the PECL URI template parser if available + if (extension_loaded('uri_template')) { + $this->mapping['uri_template'] = 'Guzzle\\Parser\\UriTemplate\\PeclUriTemplate'; + } + } + + /** + * Get a parser by name from an instance + * + * @param string $name Name of the parser to retrieve + * + * @return mixed|null + */ + public function getParser($name) + { + if (!isset($this->instances[$name])) { + if (!isset($this->mapping[$name])) { + return null; + } + $class = $this->mapping[$name]; + $this->instances[$name] = new $class(); + } + + return $this->instances[$name]; + } + + /** + * Register a custom parser by name with the register + * + * @param string $name Name or handle of the parser to register + * @param mixed $parser Instantiated parser to register + */ + public function registerParser($name, $parser) + { + $this->instances[$name] = $parser; + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php new file mode 100644 index 00000000..b0764e83 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php @@ -0,0 +1,26 @@ + true, '#' => true, '.' => true, '/' => true, ';' => true, '?' => true, '&' => true + ); + + /** @var array Delimiters */ + private static $delims = array( + ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' + ); + + /** @var array Percent encoded delimiters */ + private static $delimsPct = array( + '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', + '%3B', '%3D' + ); + + public function expand($template, array $variables) + { + if ($this->regex == self::DEFAULT_PATTERN && false === strpos($template, '{')) { + return $template; + } + + $this->template = $template; + $this->variables = $variables; + + return preg_replace_callback($this->regex, array($this, 'expandMatch'), $this->template); + } + + /** + * Set the regex patten used to expand URI templates + * + * @param string $regexPattern + */ + public function setRegex($regexPattern) + { + $this->regex = $regexPattern; + } + + /** + * Parse an expression into parts + * + * @param string $expression Expression to parse + * + * @return array Returns an associative array of parts + */ + private function parseExpression($expression) + { + // Check for URI operators + $operator = ''; + + if (isset(self::$operatorHash[$expression[0]])) { + $operator = $expression[0]; + $expression = substr($expression, 1); + } + + $values = explode(',', $expression); + foreach ($values as &$value) { + $value = trim($value); + $varspec = array(); + $substrPos = strpos($value, ':'); + if ($substrPos) { + $varspec['value'] = substr($value, 0, $substrPos); + $varspec['modifier'] = ':'; + $varspec['position'] = (int) substr($value, $substrPos + 1); + } elseif (substr($value, -1) == '*') { + $varspec['modifier'] = '*'; + $varspec['value'] = substr($value, 0, -1); + } else { + $varspec['value'] = (string) $value; + $varspec['modifier'] = ''; + } + $value = $varspec; + } + + return array( + 'operator' => $operator, + 'values' => $values + ); + } + + /** + * Process an expansion + * + * @param array $matches Matches met in the preg_replace_callback + * + * @return string Returns the replacement string + */ + private function expandMatch(array $matches) + { + static $rfc1738to3986 = array( + '+' => '%20', + '%7e' => '~' + ); + + $parsed = self::parseExpression($matches[1]); + $replacements = array(); + + $prefix = $parsed['operator']; + $joiner = $parsed['operator']; + $useQueryString = false; + if ($parsed['operator'] == '?') { + $joiner = '&'; + $useQueryString = true; + } elseif ($parsed['operator'] == '&') { + $useQueryString = true; + } elseif ($parsed['operator'] == '#') { + $joiner = ','; + } elseif ($parsed['operator'] == ';') { + $useQueryString = true; + } elseif ($parsed['operator'] == '' || $parsed['operator'] == '+') { + $joiner = ','; + $prefix = ''; + } + + foreach ($parsed['values'] as $value) { + + if (!array_key_exists($value['value'], $this->variables) || $this->variables[$value['value']] === null) { + continue; + } + + $variable = $this->variables[$value['value']]; + $actuallyUseQueryString = $useQueryString; + $expanded = ''; + + if (is_array($variable)) { + + $isAssoc = $this->isAssoc($variable); + $kvp = array(); + foreach ($variable as $key => $var) { + + if ($isAssoc) { + $key = rawurlencode($key); + $isNestedArray = is_array($var); + } else { + $isNestedArray = false; + } + + if (!$isNestedArray) { + $var = rawurlencode($var); + if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + $var = $this->decodeReserved($var); + } + } + + if ($value['modifier'] == '*') { + if ($isAssoc) { + if ($isNestedArray) { + // Nested arrays must allow for deeply nested structures + $var = strtr(http_build_query(array($key => $var)), $rfc1738to3986); + } else { + $var = $key . '=' . $var; + } + } elseif ($key > 0 && $actuallyUseQueryString) { + $var = $value['value'] . '=' . $var; + } + } + + $kvp[$key] = $var; + } + + if (empty($variable)) { + $actuallyUseQueryString = false; + } elseif ($value['modifier'] == '*') { + $expanded = implode($joiner, $kvp); + if ($isAssoc) { + // Don't prepend the value name when using the explode modifier with an associative array + $actuallyUseQueryString = false; + } + } else { + if ($isAssoc) { + // When an associative array is encountered and the explode modifier is not set, then the + // result must be a comma separated list of keys followed by their respective values. + foreach ($kvp as $k => &$v) { + $v = $k . ',' . $v; + } + } + $expanded = implode(',', $kvp); + } + + } else { + if ($value['modifier'] == ':') { + $variable = substr($variable, 0, $value['position']); + } + $expanded = rawurlencode($variable); + if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + $expanded = $this->decodeReserved($expanded); + } + } + + if ($actuallyUseQueryString) { + if (!$expanded && $joiner != '&') { + $expanded = $value['value']; + } else { + $expanded = $value['value'] . '=' . $expanded; + } + } + + $replacements[] = $expanded; + } + + $ret = implode($joiner, $replacements); + if ($ret && $prefix) { + return $prefix . $ret; + } + + return $ret; + } + + /** + * Determines if an array is associative + * + * @param array $array Array to check + * + * @return bool + */ + private function isAssoc(array $array) + { + return (bool) count(array_filter(array_keys($array), 'is_string')); + } + + /** + * Removes percent encoding on reserved characters (used with + and # modifiers) + * + * @param string $string String to fix + * + * @return string + */ + private function decodeReserved($string) + { + return str_replace(self::$delimsPct, self::$delims, $string); + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplateInterface.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplateInterface.php new file mode 100644 index 00000000..c81d5154 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplateInterface.php @@ -0,0 +1,21 @@ +utf8 = $utf8; + } + + public function parseUrl($url) + { + Version::warn(__CLASS__ . ' is deprecated. Just use parse_url()'); + + static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + 'user' => null, 'pass' => null, 'fragment' => null); + + $parts = parse_url($url); + + // Need to handle query parsing specially for UTF-8 requirements + if ($this->utf8 && isset($parts['query'])) { + $queryPos = strpos($url, '?'); + if (isset($parts['fragment'])) { + $parts['query'] = substr($url, $queryPos + 1, strpos($url, '#') - $queryPos - 1); + } else { + $parts['query'] = substr($url, $queryPos + 1); + } + } + + return $parts + $defaults; + } +} diff --git a/src/lib/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php new file mode 100644 index 00000000..89ac4b30 --- /dev/null +++ b/src/lib/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php @@ -0,0 +1,19 @@ +=5.3.2" + }, + "autoload": { + "psr-0": { "Guzzle\\Parser": "" } + }, + "target-dir": "Guzzle/Parser", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/src/lib/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php b/src/lib/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php new file mode 100644 index 00000000..9949e456 --- /dev/null +++ b/src/lib/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php @@ -0,0 +1,276 @@ +contextOptions = stream_context_get_options($context); + $this->context = $context; + } elseif (is_array($context) || !$context) { + $this->contextOptions = $context; + $this->createContext($params); + } elseif ($context) { + throw new InvalidArgumentException('$context must be an array or resource'); + } + + // Dispatch the before send event + $request->dispatch('request.before_send', array( + 'request' => $request, + 'context' => $this->context, + 'context_options' => $this->contextOptions + )); + + $this->setUrl($request); + $this->addDefaultContextOptions($request); + $this->addSslOptions($request); + $this->addBodyOptions($request); + $this->addProxyOptions($request); + + // Create the file handle but silence errors + return $this->createStream($params) + ->setCustomData('request', $request) + ->setCustomData('response_headers', $this->getLastResponseHeaders()); + } + + /** + * Set an option on the context and the internal options array + * + * @param string $wrapper Stream wrapper name of http + * @param string $name Context name + * @param mixed $value Context value + * @param bool $overwrite Set to true to overwrite an existing value + */ + protected function setContextValue($wrapper, $name, $value, $overwrite = false) + { + if (!isset($this->contextOptions[$wrapper])) { + $this->contextOptions[$wrapper] = array($name => $value); + } elseif (!$overwrite && isset($this->contextOptions[$wrapper][$name])) { + return; + } + $this->contextOptions[$wrapper][$name] = $value; + stream_context_set_option($this->context, $wrapper, $name, $value); + } + + /** + * Create a stream context + * + * @param array $params Parameter array + */ + protected function createContext(array $params) + { + $options = $this->contextOptions; + $this->context = $this->createResource(function () use ($params, $options) { + return stream_context_create($options, $params); + }); + } + + /** + * Get the last response headers received by the HTTP request + * + * @return array + */ + public function getLastResponseHeaders() + { + return $this->lastResponseHeaders; + } + + /** + * Adds the default context options to the stream context options + * + * @param RequestInterface $request Request + */ + protected function addDefaultContextOptions(RequestInterface $request) + { + $this->setContextValue('http', 'method', $request->getMethod()); + $headers = $request->getHeaderLines(); + + // "Connection: close" is required to get streams to work in HTTP 1.1 + if (!$request->hasHeader('Connection')) { + $headers[] = 'Connection: close'; + } + + $this->setContextValue('http', 'header', $headers); + $this->setContextValue('http', 'protocol_version', $request->getProtocolVersion()); + $this->setContextValue('http', 'ignore_errors', true); + } + + /** + * Set the URL to use with the factory + * + * @param RequestInterface $request Request that owns the URL + */ + protected function setUrl(RequestInterface $request) + { + $this->url = $request->getUrl(true); + + // Check for basic Auth username + if ($request->getUsername()) { + $this->url->setUsername($request->getUsername()); + } + + // Check for basic Auth password + if ($request->getPassword()) { + $this->url->setPassword($request->getPassword()); + } + } + + /** + * Add SSL options to the stream context + * + * @param RequestInterface $request Request + */ + protected function addSslOptions(RequestInterface $request) + { + if ($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)) { + $this->setContextValue('ssl', 'verify_peer', true, true); + if ($cafile = $request->getCurlOptions()->get(CURLOPT_CAINFO)) { + $this->setContextValue('ssl', 'cafile', $cafile, true); + } + } else { + $this->setContextValue('ssl', 'verify_peer', false, true); + } + } + + /** + * Add body (content) specific options to the context options + * + * @param RequestInterface $request + */ + protected function addBodyOptions(RequestInterface $request) + { + // Add the content for the request if needed + if (!($request instanceof EntityEnclosingRequestInterface)) { + return; + } + + if (count($request->getPostFields())) { + $this->setContextValue('http', 'content', (string) $request->getPostFields(), true); + } elseif ($request->getBody()) { + $this->setContextValue('http', 'content', (string) $request->getBody(), true); + } + + // Always ensure a content-length header is sent + if (isset($this->contextOptions['http']['content'])) { + $headers = isset($this->contextOptions['http']['header']) ? $this->contextOptions['http']['header'] : array(); + $headers[] = 'Content-Length: ' . strlen($this->contextOptions['http']['content']); + $this->setContextValue('http', 'header', $headers, true); + } + } + + /** + * Add proxy parameters to the context if needed + * + * @param RequestInterface $request Request + */ + protected function addProxyOptions(RequestInterface $request) + { + if ($proxy = $request->getCurlOptions()->get(CURLOPT_PROXY)) { + $this->setContextValue('http', 'proxy', $proxy); + } + } + + /** + * Create the stream for the request with the context options + * + * @param array $params Parameters of the stream + * + * @return StreamInterface + */ + protected function createStream(array $params) + { + $http_response_header = null; + $url = $this->url; + $context = $this->context; + $fp = $this->createResource(function () use ($context, $url, &$http_response_header) { + return fopen((string) $url, 'r', false, $context); + }); + + // Determine the class to instantiate + $className = isset($params['stream_class']) ? $params['stream_class'] : __NAMESPACE__ . '\\Stream'; + + /** @var $stream StreamInterface */ + $stream = new $className($fp); + + // Track the response headers of the request + if (isset($http_response_header)) { + $this->lastResponseHeaders = $http_response_header; + $this->processResponseHeaders($stream); + } + + return $stream; + } + + /** + * Process response headers + * + * @param StreamInterface $stream + */ + protected function processResponseHeaders(StreamInterface $stream) + { + // Set the size on the stream if it was returned in the response + foreach ($this->lastResponseHeaders as $header) { + if ((stripos($header, 'Content-Length:')) === 0) { + $stream->setSize(trim(substr($header, 15))); + } + } + } + + /** + * Create a resource and check to ensure it was created successfully + * + * @param callable $callback Closure to invoke that must return a valid resource + * + * @return resource + * @throws RuntimeException on error + */ + protected function createResource($callback) + { + // Turn off error reporting while we try to initiate the request + $level = error_reporting(0); + $resource = call_user_func($callback); + error_reporting($level); + + // If the resource could not be created, then grab the last error and throw an exception + if (false === $resource) { + $message = 'Error creating resource. '; + foreach (error_get_last() as $key => $value) { + $message .= "[{$key}] {$value} "; + } + throw new RuntimeException(trim($message)); + } + + return $resource; + } +} diff --git a/src/lib/vendor/guzzle/stream/Guzzle/Stream/Stream.php b/src/lib/vendor/guzzle/stream/Guzzle/Stream/Stream.php new file mode 100644 index 00000000..12bed268 --- /dev/null +++ b/src/lib/vendor/guzzle/stream/Guzzle/Stream/Stream.php @@ -0,0 +1,289 @@ + array( + 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, + 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, + 'rt' => true, 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a+' => true + ), + 'write' => array( + 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, 'c+' => true, + 'wb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, + 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true + ) + ); + + /** + * @param resource $stream Stream resource to wrap + * @param int $size Size of the stream in bytes. Only pass if the size cannot be obtained from the stream. + * + * @throws InvalidArgumentException if the stream is not a stream resource + */ + public function __construct($stream, $size = null) + { + $this->setStream($stream, $size); + } + + /** + * Closes the stream when the helper is destructed + */ + public function __destruct() + { + $this->close(); + } + + public function __toString() + { + if (!$this->isReadable() || (!$this->isSeekable() && $this->isConsumed())) { + return ''; + } + + $originalPos = $this->ftell(); + $body = stream_get_contents($this->stream, -1, 0); + $this->seek($originalPos); + + return $body; + } + + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->cache[self::IS_READABLE] = false; + $this->cache[self::IS_WRITABLE] = false; + } + + /** + * Calculate a hash of a Stream + * + * @param StreamInterface $stream Stream to calculate the hash for + * @param string $algo Hash algorithm (e.g. md5, crc32, etc) + * @param bool $rawOutput Whether or not to use raw output + * + * @return bool|string Returns false on failure or a hash string on success + */ + public static function getHash(StreamInterface $stream, $algo, $rawOutput = false) + { + $pos = $stream->ftell(); + if (!$stream->seek(0)) { + return false; + } + + $ctx = hash_init($algo); + while (!$stream->feof()) { + hash_update($ctx, $stream->read(8192)); + } + + $out = hash_final($ctx, (bool) $rawOutput); + $stream->seek($pos); + + return $out; + } + + public function getMetaData($key = null) + { + $meta = stream_get_meta_data($this->stream); + + return !$key ? $meta : (array_key_exists($key, $meta) ? $meta[$key] : null); + } + + public function getStream() + { + return $this->stream; + } + + public function setStream($stream, $size = null) + { + if (!is_resource($stream)) { + throw new InvalidArgumentException('Stream must be a resource'); + } + + $this->size = $size; + $this->stream = $stream; + $this->rebuildCache(); + + return $this; + } + + public function detachStream() + { + $this->stream = null; + + return $this; + } + + public function getWrapper() + { + return $this->cache[self::WRAPPER_TYPE]; + } + + public function getWrapperData() + { + return $this->getMetaData('wrapper_data') ?: array(); + } + + public function getStreamType() + { + return $this->cache[self::STREAM_TYPE]; + } + + public function getUri() + { + return $this->cache['uri']; + } + + public function getSize() + { + if ($this->size !== null) { + return $this->size; + } + + // If the stream is a file based stream and local, then use fstat + clearstatcache(true, $this->cache['uri']); + $stats = fstat($this->stream); + if (isset($stats['size'])) { + $this->size = $stats['size']; + return $this->size; + } elseif ($this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]) { + // Only get the size based on the content if the the stream is readable and seekable + $pos = $this->ftell(); + $this->size = strlen((string) $this); + $this->seek($pos); + return $this->size; + } + + return false; + } + + public function isReadable() + { + return $this->cache[self::IS_READABLE]; + } + + public function isRepeatable() + { + return $this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]; + } + + public function isWritable() + { + return $this->cache[self::IS_WRITABLE]; + } + + public function isConsumed() + { + return feof($this->stream); + } + + public function feof() + { + return $this->isConsumed(); + } + + public function isLocal() + { + return $this->cache[self::IS_LOCAL]; + } + + public function isSeekable() + { + return $this->cache[self::SEEKABLE]; + } + + public function setSize($size) + { + $this->size = $size; + + return $this; + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false; + } + + public function read($length) + { + return fread($this->stream, $length); + } + + public function write($string) + { + // We can't know the size after writing anything + $this->size = null; + + return fwrite($this->stream, $string); + } + + public function ftell() + { + return ftell($this->stream); + } + + public function rewind() + { + return $this->seek(0); + } + + public function readLine($maxLength = null) + { + if (!$this->cache[self::IS_READABLE]) { + return false; + } else { + return $maxLength ? fgets($this->getStream(), $maxLength) : fgets($this->getStream()); + } + } + + public function setCustomData($key, $value) + { + $this->customData[$key] = $value; + + return $this; + } + + public function getCustomData($key) + { + return isset($this->customData[$key]) ? $this->customData[$key] : null; + } + + /** + * Reprocess stream metadata + */ + protected function rebuildCache() + { + $this->cache = stream_get_meta_data($this->stream); + $this->cache[self::IS_LOCAL] = stream_is_local($this->stream); + $this->cache[self::IS_READABLE] = isset(self::$readWriteHash['read'][$this->cache['mode']]); + $this->cache[self::IS_WRITABLE] = isset(self::$readWriteHash['write'][$this->cache['mode']]); + } +} diff --git a/src/lib/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php b/src/lib/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php new file mode 100644 index 00000000..6d7dc376 --- /dev/null +++ b/src/lib/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php @@ -0,0 +1,218 @@ +=5.3.2", + "guzzle/common": "self.version" + }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, + "autoload": { + "psr-0": { "Guzzle\\Stream": "" } + }, + "target-dir": "Guzzle/Stream", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/src/lib/vendor/monolog/monolog/CHANGELOG.mdown b/src/lib/vendor/monolog/monolog/CHANGELOG.mdown new file mode 100644 index 00000000..06134f7f --- /dev/null +++ b/src/lib/vendor/monolog/monolog/CHANGELOG.mdown @@ -0,0 +1,170 @@ +### 1.10.0 (2014-06-04) + + * Added Logger::getHandlers() and Logger::getProcessors() methods + * Added $passthruLevel argument to FingersCrossedHandler to let it always pass some records through even if the trigger level is not reached + * Added support for extra data in NewRelicHandler + * Added $expandNewlines flag to the ErrorLogHandler to create multiple log entries when a message has multiple lines + +### 1.9.1 (2014-04-24) + + * Fixed regression in RotatingFileHandler file permissions + * Fixed initialization of the BufferHandler to make sure it gets flushed after receiving records + * Fixed ChromePHPHandler and FirePHPHandler's activation strategies to be more conservative + +### 1.9.0 (2014-04-20) + + * Added LogEntriesHandler to send logs to a LogEntries account + * Added $filePermissions to tweak file mode on StreamHandler and RotatingFileHandler + * Added $useFormatting flag to MemoryProcessor to make it send raw data in bytes + * Added support for table formatting in FirePHPHandler via the table context key + * Added a TagProcessor to add tags to records, and support for tags in RavenHandler + * Added $appendNewline flag to the JsonFormatter to enable using it when logging to files + * Added sound support to the PushoverHandler + * Fixed multi-threading support in StreamHandler + * Fixed empty headers issue when ChromePHPHandler received no records + * Fixed default format of the ErrorLogHandler + +### 1.8.0 (2014-03-23) + + * Break: the LineFormatter now strips newlines by default because this was a bug, set $allowInlineLineBreaks to true if you need them + * Added BrowserConsoleHandler to send logs to any browser's console via console.log() injection in the output + * Added FilterHandler to filter records and only allow those of a given list of levels through to the wrapped handler + * Added FlowdockHandler to send logs to a Flowdock account + * Added RollbarHandler to send logs to a Rollbar account + * Added HtmlFormatter to send prettier log emails with colors for each log level + * Added GitProcessor to add the current branch/commit to extra record data + * Added a Monolog\Registry class to allow easier global access to pre-configured loggers + * Added support for the new official graylog2/gelf-php lib for GelfHandler, upgrade if you can by replacing the mlehner/gelf-php requirement + * Added support for HHVM + * Added support for Loggly batch uploads + * Added support for tweaking the content type and encoding in NativeMailerHandler + * Added $skipClassesPartials to tweak the ignored classes in the IntrospectionProcessor + * Fixed batch request support in GelfHandler + +### 1.7.0 (2013-11-14) + + * Added ElasticSearchHandler to send logs to an Elastic Search server + * Added DynamoDbHandler and ScalarFormatter to send logs to Amazon's Dynamo DB + * Added SyslogUdpHandler to send logs to a remote syslogd server + * Added LogglyHandler to send logs to a Loggly account + * Added $level to IntrospectionProcessor so it only adds backtraces when needed + * Added $version to LogstashFormatter to allow using the new v1 Logstash format + * Added $appName to NewRelicHandler + * Added configuration of Pushover notification retries/expiry + * Added $maxColumnWidth to NativeMailerHandler to change the 70 chars default + * Added chainability to most setters for all handlers + * Fixed RavenHandler batch processing so it takes the message from the record with highest priority + * Fixed HipChatHandler batch processing so it sends all messages at once + * Fixed issues with eAccelerator + * Fixed and improved many small things + +### 1.6.0 (2013-07-29) + + * Added HipChatHandler to send logs to a HipChat chat room + * Added ErrorLogHandler to send logs to PHP's error_log function + * Added NewRelicHandler to send logs to NewRelic's service + * Added Monolog\ErrorHandler helper class to register a Logger as exception/error/fatal handler + * Added ChannelLevelActivationStrategy for the FingersCrossedHandler to customize levels by channel + * Added stack traces output when normalizing exceptions (json output & co) + * Added Monolog\Logger::API constant (currently 1) + * Added support for ChromePHP's v4.0 extension + * Added support for message priorities in PushoverHandler, see $highPriorityLevel and $emergencyLevel + * Added support for sending messages to multiple users at once with the PushoverHandler + * Fixed RavenHandler's support for batch sending of messages (when behind a Buffer or FingersCrossedHandler) + * Fixed normalization of Traversables with very large data sets, only the first 1000 items are shown now + * Fixed issue in RotatingFileHandler when an open_basedir restriction is active + * Fixed minor issues in RavenHandler and bumped the API to Raven 0.5.0 + * Fixed SyslogHandler issue when many were used concurrently with different facilities + +### 1.5.0 (2013-04-23) + + * Added ProcessIdProcessor to inject the PID in log records + * Added UidProcessor to inject a unique identifier to all log records of one request/run + * Added support for previous exceptions in the LineFormatter exception serialization + * Added Monolog\Logger::getLevels() to get all available levels + * Fixed ChromePHPHandler so it avoids sending headers larger than Chrome can handle + +### 1.4.1 (2013-04-01) + + * Fixed exception formatting in the LineFormatter to be more minimalistic + * Fixed RavenHandler's handling of context/extra data, requires Raven client >0.1.0 + * Fixed log rotation in RotatingFileHandler to work with long running scripts spanning multiple days + * Fixed WebProcessor array access so it checks for data presence + * Fixed Buffer, Group and FingersCrossed handlers to make use of their processors + +### 1.4.0 (2013-02-13) + + * Added RedisHandler to log to Redis via the Predis library or the phpredis extension + * Added ZendMonitorHandler to log to the Zend Server monitor + * Added the possibility to pass arrays of handlers and processors directly in the Logger constructor + * Added `$useSSL` option to the PushoverHandler which is enabled by default + * Fixed ChromePHPHandler and FirePHPHandler issue when multiple instances are used simultaneously + * Fixed header injection capability in the NativeMailHandler + +### 1.3.1 (2013-01-11) + + * Fixed LogstashFormatter to be usable with stream handlers + * Fixed GelfMessageFormatter levels on Windows + +### 1.3.0 (2013-01-08) + + * Added PSR-3 compliance, the `Monolog\Logger` class is now an instance of `Psr\Log\LoggerInterface` + * Added PsrLogMessageProcessor that you can selectively enable for full PSR-3 compliance + * Added LogstashFormatter (combine with SocketHandler or StreamHandler to send logs to Logstash) + * Added PushoverHandler to send mobile notifications + * Added CouchDBHandler and DoctrineCouchDBHandler + * Added RavenHandler to send data to Sentry servers + * Added support for the new MongoClient class in MongoDBHandler + * Added microsecond precision to log records' timestamps + * Added `$flushOnOverflow` param to BufferHandler to flush by batches instead of losing + the oldest entries + * Fixed normalization of objects with cyclic references + +### 1.2.1 (2012-08-29) + + * Added new $logopts arg to SyslogHandler to provide custom openlog options + * Fixed fatal error in SyslogHandler + +### 1.2.0 (2012-08-18) + + * Added AmqpHandler (for use with AMQP servers) + * Added CubeHandler + * Added NativeMailerHandler::addHeader() to send custom headers in mails + * Added the possibility to specify more than one recipient in NativeMailerHandler + * Added the possibility to specify float timeouts in SocketHandler + * Added NOTICE and EMERGENCY levels to conform with RFC 5424 + * Fixed the log records to use the php default timezone instead of UTC + * Fixed BufferHandler not being flushed properly on PHP fatal errors + * Fixed normalization of exotic resource types + * Fixed the default format of the SyslogHandler to avoid duplicating datetimes in syslog + +### 1.1.0 (2012-04-23) + + * Added Monolog\Logger::isHandling() to check if a handler will + handle the given log level + * Added ChromePHPHandler + * Added MongoDBHandler + * Added GelfHandler (for use with Graylog2 servers) + * Added SocketHandler (for use with syslog-ng for example) + * Added NormalizerFormatter + * Added the possibility to change the activation strategy of the FingersCrossedHandler + * Added possibility to show microseconds in logs + * Added `server` and `referer` to WebProcessor output + +### 1.0.2 (2011-10-24) + + * Fixed bug in IE with large response headers and FirePHPHandler + +### 1.0.1 (2011-08-25) + + * Added MemoryPeakUsageProcessor and MemoryUsageProcessor + * Added Monolog\Logger::getName() to get a logger's channel name + +### 1.0.0 (2011-07-06) + + * Added IntrospectionProcessor to get info from where the logger was called + * Fixed WebProcessor in CLI + +### 1.0.0-RC1 (2011-07-01) + + * Initial release diff --git a/src/lib/vendor/monolog/monolog/LICENSE b/src/lib/vendor/monolog/monolog/LICENSE new file mode 100644 index 00000000..35727045 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011-2014 Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/lib/vendor/monolog/monolog/README.mdown b/src/lib/vendor/monolog/monolog/README.mdown new file mode 100644 index 00000000..fd28a473 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/README.mdown @@ -0,0 +1,267 @@ +Monolog - Logging for PHP 5.3+ [![Build Status](https://secure.travis-ci.org/Seldaek/monolog.png)](http://travis-ci.org/Seldaek/monolog) +============================== + +[![Total Downloads](https://poser.pugx.org/monolog/monolog/downloads.png)](https://packagist.org/packages/monolog/monolog) +[![Latest Stable Version](https://poser.pugx.org/monolog/monolog/v/stable.png)](https://packagist.org/packages/monolog/monolog) + + +Monolog sends your logs to files, sockets, inboxes, databases and various +web services. See the complete list of handlers below. Special handlers +allow you to build advanced logging strategies. + +This library implements the [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +interface that you can type-hint against in your own libraries to keep +a maximum of interoperability. You can also use it in your applications to +make sure you can always use another compatible logger at a later time. + +Usage +----- + +```php +pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING)); + +// add records to the log +$log->addWarning('Foo'); +$log->addError('Bar'); +``` + +Core Concepts +------------- + +Every `Logger` instance has a channel (name) and a stack of handlers. Whenever +you add a record to the logger, it traverses the handler stack. Each handler +decides whether it handled fully the record, and if so, the propagation of the +record ends there. + +This allows for flexible logging setups, for example having a `StreamHandler` at +the bottom of the stack that will log anything to disk, and on top of that add +a `MailHandler` that will send emails only when an error message is logged. +Handlers also have a `$bubble` property which defines whether they block the +record or not if they handled it. In this example, setting the `MailHandler`'s +`$bubble` argument to false means that records handled by the `MailHandler` will +not propagate to the `StreamHandler` anymore. + +You can create many `Logger`s, each defining a channel (e.g.: db, request, +router, ..) and each of them combining various handlers, which can be shared +or not. The channel is reflected in the logs and allows you to easily see or +filter records. + +Each Handler also has a Formatter, a default one with settings that make sense +will be created if you don't set one. The formatters normalize and format +incoming records so that they can be used by the handlers to output useful +information. + +Custom severity levels are not available. Only the eight +[RFC 5424](http://tools.ietf.org/html/rfc5424) levels (debug, info, notice, +warning, error, critical, alert, emergency) are present for basic filtering +purposes, but for sorting and other use cases that would require +flexibility, you should add Processors to the Logger that can add extra +information (tags, user ip, ..) to the records before they are handled. + +Log Levels +---------- + +Monolog supports the logging levels described by [RFC 5424](http://tools.ietf.org/html/rfc5424). + +- **DEBUG** (100): Detailed debug information. + +- **INFO** (200): Interesting events. Examples: User logs in, SQL logs. + +- **NOTICE** (250): Normal but significant events. + +- **WARNING** (300): Exceptional occurrences that are not errors. Examples: + Use of deprecated APIs, poor use of an API, undesirable things that are not + necessarily wrong. + +- **ERROR** (400): Runtime errors that do not require immediate action but + should typically be logged and monitored. + +- **CRITICAL** (500): Critical conditions. Example: Application component + unavailable, unexpected exception. + +- **ALERT** (550): Action must be taken immediately. Example: Entire website + down, database unavailable, etc. This should trigger the SMS alerts and wake + you up. + +- **EMERGENCY** (600): Emergency: system is unusable. + +Docs +==== + +**See the `doc` directory for more detailed documentation. +The following is only a list of all parts that come with Monolog.** + +Handlers +-------- + +### Log to files and syslog + +- _StreamHandler_: Logs records into any PHP stream, use this for log files. +- _RotatingFileHandler_: Logs records to a file and creates one logfile per day. + It will also delete files older than `$maxFiles`. You should use + [logrotate](http://linuxcommand.org/man_pages/logrotate8.html) for high profile + setups though, this is just meant as a quick and dirty solution. +- _SyslogHandler_: Logs records to the syslog. +- _ErrorLogHandler_: Logs records to PHP's + [`error_log()`](http://docs.php.net/manual/en/function.error-log.php) function. + +### Send alerts and emails + +- _NativeMailerHandler_: Sends emails using PHP's + [`mail()`](http://php.net/manual/en/function.mail.php) function. +- _SwiftMailerHandler_: Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance. +- _PushoverHandler_: Sends mobile notifications via the [Pushover](https://www.pushover.net/) API. +- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API. +- _FlowdockHandler_: Logs records to a [Flowdock](https://www.flowdock.com/) account. + +### Log specific servers and networked logging + +- _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this + for UNIX and TCP sockets. See an [example](https://github.com/Seldaek/monolog/blob/master/doc/sockets.md). +- _AmqpHandler_: Logs records to an [amqp](http://www.amqp.org/) compatible + server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+). +- _GelfHandler_: Logs records to a [Graylog2](http://www.graylog2.org) server. +- _CubeHandler_: Logs records to a [Cube](http://square.github.com/cube/) server. +- _RavenHandler_: Logs records to a [Sentry](http://getsentry.com/) server using + [raven](https://packagist.org/packages/raven/raven). +- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server. +- _NewRelicHandler_: Logs records to a [NewRelic](http://newrelic.com/) application. +- _LogglyHandler_: Logs records to a [Loggly](http://www.loggly.com/) account. +- _RollbarHandler_: Logs records to a [Rollbar](https://rollbar.com/) account. +- _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server. +- _LogEntriesHandler_: Logs records to a [LogEntries](http://logentries.com/) account. + +### Logging in development + +- _FirePHPHandler_: Handler for [FirePHP](http://www.firephp.org/), providing + inline `console` messages within [FireBug](http://getfirebug.com/). +- _ChromePHPHandler_: Handler for [ChromePHP](http://www.chromephp.com/), providing + inline `console` messages within Chrome. +- _BrowserConsoleHandler_: Handler to send logs to browser's Javascript `console` with + no browser extension required. Most browsers supporting `console` API are supported. + +### Log to databases + +- _RedisHandler_: Logs records to a [redis](http://redis.io) server. +- _MongoDBHandler_: Handler to write records in MongoDB via a + [Mongo](http://pecl.php.net/package/mongo) extension connection. +- _CouchDBHandler_: Logs records to a CouchDB server. +- _DoctrineCouchDBHandler_: Logs records to a CouchDB server via the Doctrine CouchDB ODM. +- _ElasticSearchHandler_: Logs records to an Elastic Search server. +- _DynamoDbHandler_: Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php). + +### Wrappers / Special Handlers + +- _FingersCrossedHandler_: A very interesting wrapper. It takes a logger as + parameter and will accumulate log records of all levels until a record + exceeds the defined severity level. At which point it delivers all records, + including those of lower severity, to the handler it wraps. This means that + until an error actually happens you will not see anything in your logs, but + when it happens you will have the full information, including debug and info + records. This provides you with all the information you need, but only when + you need it. +- _NullHandler_: Any record it can handle will be thrown away. This can be used + to put on top of an existing handler stack to disable it temporarily. +- _BufferHandler_: This handler will buffer all the log records it receives + until `close()` is called at which point it will call `handleBatch()` on the + handler it wraps with all the log messages at once. This is very useful to + send an email with all records at once for example instead of having one mail + for every log record. +- _GroupHandler_: This handler groups other handlers. Every record received is + sent to all the handlers it is configured with. +- _FilterHandler_: This handler only lets records of the given levels through + to the wrapped handler. +- _TestHandler_: Used for testing, it records everything that is sent to it and + has accessors to read out the information. + +Formatters +---------- + +- _LineFormatter_: Formats a log record into a one-line string. +- _HtmlFormatter_: Used to format log records into a human readable html table, mainly suitable for emails. +- _NormalizerFormatter_: Normalizes objects/resources down to strings so a record can easily be serialized/encoded. +- _ScalarFormatter_: Used to format log records into an associative array of scalar values. +- _JsonFormatter_: Encodes a log record into json. +- _WildfireFormatter_: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler. +- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler. +- _GelfMessageFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler. +- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/1.1.5/). +- _ElasticaFormatter_: Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler. +- _LogglyFormatter_: Used to format log records into Loggly messages, only useful for the LogglyHandler. +- _FlowdockFormatter_: Used to format log records into Flowdock messages, only useful for the FlowdockHandler. + +Processors +---------- + +- _IntrospectionProcessor_: Adds the line/file/class/method from which the log call originated. +- _WebProcessor_: Adds the current request URI, request method and client IP to a log record. +- _MemoryUsageProcessor_: Adds the current memory usage to a log record. +- _MemoryPeakUsageProcessor_: Adds the peak memory usage to a log record. +- _ProcessIdProcessor_: Adds the process id to a log record. +- _UidProcessor_: Adds a unique identifier to a log record. +- _GitProcessor_: Adds the current git branch and commit to a log record. +- _TagProcessor_: Adds an array of predefined tags to a log record. + +Utilities +--------- + +- _Registry_: The `Monolog\Registry` class lets you configure global loggers that you + can then statically access from anywhere. It is not really a best practice but can + help in some older codebases or for ease of use. +- _ErrorHandler_: The `Monolog\ErrorHandler` class allows you to easily register + a Logger instance as an exception handler, error handler or fatal error handler. +- _ErrorLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain log + level is reached. +- _ChannelLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain + log level is reached, depending on which channel received the log record. + +About +===== + +Requirements +------------ + +- Monolog works with PHP 5.3 or above, and is also tested to work with HHVM. + +Submitting bugs and feature requests +------------------------------------ + +Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/monolog/issues) + +Frameworks Integration +---------------------- + +- Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) + can be used very easily with Monolog since it implements the interface. +- [Symfony2](http://symfony.com) comes out of the box with Monolog. +- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog. +- [Laravel 4](http://laravel.com/) comes out of the box with Monolog. +- [PPI](http://www.ppi.io/) comes out of the box with Monolog. +- [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin. +- [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer. +- [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog. +- [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) comes out of the box with Monolog. + +Author +------ + +Jordi Boggiano - -
+See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project. + +License +------- + +Monolog is licensed under the MIT License - see the `LICENSE` file for details + +Acknowledgements +---------------- + +This library is heavily inspired by Python's [Logbook](http://packages.python.org/Logbook/) +library, although most concepts have been adjusted to fit to the PHP world. diff --git a/src/lib/vendor/monolog/monolog/composer.json b/src/lib/vendor/monolog/monolog/composer.json new file mode 100644 index 00000000..c94c302c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/composer.json @@ -0,0 +1,45 @@ +{ + "name": "monolog/monolog", + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "keywords": ["log", "logging", "psr-3"], + "homepage": "http://github.com/Seldaek/monolog", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.0", + "graylog2/gelf-php": "~1.0", + "raven/raven": "~0.5", + "ruflin/elastica": "0.90.*", + "doctrine/couchdb": "~1.0@dev", + "aws/aws-sdk-php": "~2.4, >2.4.8" + }, + "suggest": { + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "rollbar/rollbar": "Allow sending log messages to Rollbar" + }, + "autoload": { + "psr-4": {"Monolog\\": "src/Monolog"} + }, + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + } +} diff --git a/src/lib/vendor/monolog/monolog/doc/extending.md b/src/lib/vendor/monolog/monolog/doc/extending.md new file mode 100644 index 00000000..bb39ddcf --- /dev/null +++ b/src/lib/vendor/monolog/monolog/doc/extending.md @@ -0,0 +1,76 @@ +Extending Monolog +================= + +Monolog is fully extensible, allowing you to adapt your logger to your needs. + +Writing your own handler +------------------------ + +Monolog provides many built-in handlers. But if the one you need does not +exist, you can write it and use it in your logger. The only requirement is +to implement `Monolog\Handler\HandlerInterface`. + +Let's write a PDOHandler to log records to a database. We will extend the +abstract class provided by Monolog to keep things DRY. + +```php +pdo = $pdo; + parent::__construct($level, $bubble); + } + + protected function write(array $record) + { + if (!$this->initialized) { + $this->initialize(); + } + + $this->statement->execute(array( + 'channel' => $record['channel'], + 'level' => $record['level'], + 'message' => $record['formatted'], + 'time' => $record['datetime']->format('U'), + )); + } + + private function initialize() + { + $this->pdo->exec( + 'CREATE TABLE IF NOT EXISTS monolog ' + .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)' + ); + $this->statement = $this->pdo->prepare( + 'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)' + ); + + $this->initialized = true; + } +} +``` + +You can now use this handler in your logger: + +```php +pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite'))); + +// You can now use your logger +$logger->addInfo('My logger is now ready'); +``` + +The `Monolog\Handler\AbstractProcessingHandler` class provides most of the +logic needed for the handler, including the use of processors and the formatting +of the record (which is why we use ``$record['formatted']`` instead of ``$record['message']``). diff --git a/src/lib/vendor/monolog/monolog/doc/sockets.md b/src/lib/vendor/monolog/monolog/doc/sockets.md new file mode 100644 index 00000000..fad30a9f --- /dev/null +++ b/src/lib/vendor/monolog/monolog/doc/sockets.md @@ -0,0 +1,37 @@ +Sockets Handler +=============== + +This handler allows you to write your logs to sockets using [fsockopen](http://php.net/fsockopen) +or [pfsockopen](http://php.net/pfsockopen). + +Persistent sockets are mainly useful in web environments where you gain some performance not closing/opening +the connections between requests. + +Basic Example +------------- + +```php +setPersistent(true); + +// Now add the handler +$logger->pushHandler($handler, Logger::DEBUG); + +// You can now use your logger +$logger->addInfo('My logger is now ready'); + +``` + +In this example, using syslog-ng, you should see the log on the log server: + + cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] [] + diff --git a/src/lib/vendor/monolog/monolog/doc/usage.md b/src/lib/vendor/monolog/monolog/doc/usage.md new file mode 100644 index 00000000..846bd51a --- /dev/null +++ b/src/lib/vendor/monolog/monolog/doc/usage.md @@ -0,0 +1,162 @@ +Using Monolog +============= + +Installation +------------ + +Monolog is available on Packagist ([monolog/monolog](http://packagist.org/packages/monolog/monolog)) +and as such installable via [Composer](http://getcomposer.org/). + +```bash +php composer.phar require monolog/monolog '~1.7' +``` + +If you do not use Composer, you can grab the code from GitHub, and use any +PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader)) +to load Monolog classes. + +Configuring a logger +-------------------- + +Here is a basic setup to log to a file and to firephp on the DEBUG level: + +```php +pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG)); +$logger->pushHandler(new FirePHPHandler()); + +// You can now use your logger +$logger->addInfo('My logger is now ready'); +``` + +Let's explain it. The first step is to create the logger instance which will +be used in your code. The argument is a channel name, which is useful when +you use several loggers (see below for more details about it). + +The logger itself does not know how to handle a record. It delegates it to +some handlers. The code above registers two handlers in the stack to allow +handling records in two different ways. + +Note that the FirePHPHandler is called first as it is added on top of the +stack. This allows you to temporarily add a logger with bubbling disabled if +you want to override other configured loggers. + +Adding extra data in the records +-------------------------------- + +Monolog provides two different ways to add extra informations along the simple +textual message. + +### Using the logging context + +The first way is the context, allowing to pass an array of data along the +record: + +```php +addInfo('Adding a new user', array('username' => 'Seldaek')); +``` + +Simple handlers (like the StreamHandler for instance) will simply format +the array to a string but richer handlers can take advantage of the context +(FirePHP is able to display arrays in pretty way for instance). + +### Using processors + +The second way is to add extra data for all records by using a processor. +Processors can be any callable. They will get the record as parameter and +must return it after having eventually changed the `extra` part of it. Let's +write a processor adding some dummy data in the record: + +```php +pushProcessor(function ($record) { + $record['extra']['dummy'] = 'Hello world!'; + + return $record; +}); +``` + +Monolog provides some built-in processors that can be used in your project. +Look at the [README file](https://github.com/Seldaek/monolog/blob/master/README.mdown) for the list. + +> Tip: processors can also be registered on a specific handler instead of + the logger to apply only for this handler. + +Leveraging channels +------------------- + +Channels are a great way to identify to which part of the application a record +is related. This is useful in big applications (and is leveraged by +MonologBundle in Symfony2). + +Picture two loggers sharing a handler that writes to a single log file. +Channels would allow you to identify the logger that issued every record. +You can easily grep through the log files filtering this or that channel. + +```php +pushHandler($stream); +$logger->pushHandler($firephp); + +// Create a logger for the security-related stuff with a different channel +$securityLogger = new Logger('security'); +$securityLogger->pushHandler($stream); +$securityLogger->pushHandler($firephp); +``` + +Customizing log format +---------------------- + +In Monolog it's easy to customize the format of the logs written into files, +sockets, mails, databases and other handlers. Most of the handlers use the + +```php +$record['formatted'] +``` + +value to be automatically put into the log device. This value depends on the +formatter settings. You can choose between predefined formatter classes or +write your own (e.g. a multiline text file for human-readable output). + +To configure a predefined formatter class, just set it as the handler's field: + +```php +// the default date format is "Y-m-d H:i:s" +$dateFormat = "Y n j, g:i a"; +// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n" +$output = "%datetime% > %level_name% > %message% %context% %extra%\n"; +// finally, create a formatter +$formatter = new LineFormatter($output, $dateFormat); + +// Create a handler +$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG); +$stream->setFormatter($formatter); +// bind it to a logger object +$securityLogger = new Logger('security'); +$securityLogger->pushHandler($stream); +``` + +You may also reuse the same formatter between multiple handlers and share those +handlers between multiple loggers. diff --git a/src/lib/vendor/monolog/monolog/phpunit.xml.dist b/src/lib/vendor/monolog/monolog/phpunit.xml.dist new file mode 100644 index 00000000..17545707 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/phpunit.xml.dist @@ -0,0 +1,15 @@ + + + + + + tests/Monolog/ + + + + + + src/Monolog/ + + + diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/ErrorHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/ErrorHandler.php new file mode 100644 index 00000000..f9cca004 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/ErrorHandler.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; + +/** + * Monolog error handler + * + * A facility to enable logging of runtime errors, exceptions and fatal errors. + * + * Quick setup: ErrorHandler::register($logger); + * + * @author Jordi Boggiano + */ +class ErrorHandler +{ + private $logger; + + private $previousExceptionHandler; + private $uncaughtExceptionLevel; + + private $previousErrorHandler; + private $errorLevelMap; + + private $fatalLevel; + private $reservedMemory; + private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); + + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * Registers a new ErrorHandler for a given Logger + * + * By default it will handle errors, exceptions and fatal errors + * + * @param LoggerInterface $logger + * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling + * @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling + * @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling + * @return ErrorHandler + */ + public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null) + { + $handler = new static($logger); + if ($errorLevelMap !== false) { + $handler->registerErrorHandler($errorLevelMap); + } + if ($exceptionLevel !== false) { + $handler->registerExceptionHandler($exceptionLevel); + } + if ($fatalLevel !== false) { + $handler->registerFatalHandler($fatalLevel); + } + + return $handler; + } + + public function registerExceptionHandler($level = null, $callPrevious = true) + { + $prev = set_exception_handler(array($this, 'handleException')); + $this->uncaughtExceptionLevel = $level; + if ($callPrevious && $prev) { + $this->previousExceptionHandler = $prev; + } + } + + public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1) + { + $prev = set_error_handler(array($this, 'handleError'), $errorTypes); + $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap); + if ($callPrevious) { + $this->previousErrorHandler = $prev ?: true; + } + } + + public function registerFatalHandler($level = null, $reservedMemorySize = 20) + { + register_shutdown_function(array($this, 'handleFatalError')); + + $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize); + $this->fatalLevel = $level; + } + + protected function defaultErrorLevelMap() + { + return array( + E_ERROR => LogLevel::CRITICAL, + E_WARNING => LogLevel::WARNING, + E_PARSE => LogLevel::ALERT, + E_NOTICE => LogLevel::NOTICE, + E_CORE_ERROR => LogLevel::CRITICAL, + E_CORE_WARNING => LogLevel::WARNING, + E_COMPILE_ERROR => LogLevel::ALERT, + E_COMPILE_WARNING => LogLevel::WARNING, + E_USER_ERROR => LogLevel::ERROR, + E_USER_WARNING => LogLevel::WARNING, + E_USER_NOTICE => LogLevel::NOTICE, + E_STRICT => LogLevel::NOTICE, + E_RECOVERABLE_ERROR => LogLevel::ERROR, + E_DEPRECATED => LogLevel::NOTICE, + E_USER_DEPRECATED => LogLevel::NOTICE, + ); + } + + /** + * @private + */ + public function handleException(\Exception $e) + { + $this->logger->log( + $this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel, + sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()), + array('exception' => $e) + ); + + if ($this->previousExceptionHandler) { + call_user_func($this->previousExceptionHandler, $e); + } + } + + /** + * @private + */ + public function handleError($code, $message, $file = '', $line = 0, $context = array()) + { + if (!(error_reporting() & $code)) { + return; + } + + $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL; + $this->logger->log($level, self::codeToString($code).': '.$message, array('file' => $file, 'line' => $line)); + + if ($this->previousErrorHandler === true) { + return false; + } elseif ($this->previousErrorHandler) { + return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context); + } + } + + /** + * @private + */ + public function handleFatalError() + { + $this->reservedMemory = null; + + $lastError = error_get_last(); + if ($lastError && in_array($lastError['type'], self::$fatalErrors)) { + $this->logger->log( + $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel, + 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], + array('file' => $lastError['file'], 'line' => $lastError['line']) + ); + } + } + + private static function codeToString($code) + { + switch ($code) { + case E_ERROR: + return 'E_ERROR'; + case E_WARNING: + return 'E_WARNING'; + case E_PARSE: + return 'E_PARSE'; + case E_NOTICE: + return 'E_NOTICE'; + case E_CORE_ERROR: + return 'E_CORE_ERROR'; + case E_CORE_WARNING: + return 'E_CORE_WARNING'; + case E_COMPILE_ERROR: + return 'E_COMPILE_ERROR'; + case E_COMPILE_WARNING: + return 'E_COMPILE_WARNING'; + case E_USER_ERROR: + return 'E_USER_ERROR'; + case E_USER_WARNING: + return 'E_USER_WARNING'; + case E_USER_NOTICE: + return 'E_USER_NOTICE'; + case E_STRICT: + return 'E_STRICT'; + case E_RECOVERABLE_ERROR: + return 'E_RECOVERABLE_ERROR'; + case E_DEPRECATED: + return 'E_DEPRECATED'; + case E_USER_DEPRECATED: + return 'E_USER_DEPRECATED'; + } + + return 'Unknown PHP error'; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php new file mode 100644 index 00000000..56d3e278 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +/** + * Formats a log message according to the ChromePHP array format + * + * @author Christophe Coevoet + */ +class ChromePHPFormatter implements FormatterInterface +{ + /** + * Translates Monolog log levels to Wildfire levels. + */ + private $logLevels = array( + Logger::DEBUG => 'log', + Logger::INFO => 'info', + Logger::NOTICE => 'info', + Logger::WARNING => 'warn', + Logger::ERROR => 'error', + Logger::CRITICAL => 'error', + Logger::ALERT => 'error', + Logger::EMERGENCY => 'error', + ); + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + // Retrieve the line and file if set and remove them from the formatted extra + $backtrace = 'unknown'; + if (isset($record['extra']['file']) && isset($record['extra']['line'])) { + $backtrace = $record['extra']['file'].' : '.$record['extra']['line']; + unset($record['extra']['file']); + unset($record['extra']['line']); + } + + $message = array('message' => $record['message']); + if ($record['context']) { + $message['context'] = $record['context']; + } + if ($record['extra']) { + $message['extra'] = $record['extra']; + } + if (count($message) === 1) { + $message = reset($message); + } + + return array( + $record['channel'], + $message, + $backtrace, + $this->logLevels[$record['level']], + ); + } + + public function formatBatch(array $records) + { + $formatted = array(); + + foreach ($records as $record) { + $formatted[] = $this->format($record); + } + + return $formatted; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php new file mode 100644 index 00000000..b0b0cf06 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Elastica\Document; + +/** + * Format a log message into an Elastica Document + * + * @author Jelle Vink + */ +class ElasticaFormatter extends NormalizerFormatter +{ + /** + * @var string Elastic search index name + */ + protected $index; + + /** + * @var string Elastic search document type + */ + protected $type; + + /** + * @param string $index Elastic Search index name + * @param string $type Elastic Search document type + */ + public function __construct($index, $type) + { + parent::__construct(\DateTime::ISO8601); + $this->index = $index; + $this->type = $type; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $record = parent::format($record); + + return $this->getDocument($record); + } + + /** + * Getter index + * @return string + */ + public function getIndex() + { + return $this->index; + } + + /** + * Getter type + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Convert a log message into an Elastica Document + * + * @param array $record Log message + * @return Document + */ + protected function getDocument($record) + { + $document = new Document(); + $document->setData($record); + $document->setType($this->type); + $document->setIndex($this->index); + + return $document; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php new file mode 100644 index 00000000..af63d011 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * formats the record to be used in the FlowdockHandler + * + * @author Dominik Liebler + */ +class FlowdockFormatter implements FormatterInterface +{ + /** + * @var string + */ + private $source; + + /** + * @var string + */ + private $sourceEmail; + + /** + * @param string $source + * @param string $sourceEmail + */ + public function __construct($source, $sourceEmail) + { + $this->source = $source; + $this->sourceEmail = $sourceEmail; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $tags = array( + '#logs', + '#' . strtolower($record['level_name']), + '#' . $record['channel'], + ); + + foreach ($record['extra'] as $value) { + $tags[] = '#' . $value; + } + + $subject = sprintf( + 'in %s: %s - %s', + $this->source, + $record['level_name'], + $this->getShortMessage($record['message']) + ); + + $record['flowdock'] = array( + 'source' => $this->source, + 'from_address' => $this->sourceEmail, + 'subject' => $subject, + 'content' => $record['message'], + 'tags' => $tags, + 'project' => $this->source, + ); + + return $record; + } + + /** + * {@inheritdoc} + */ + public function formatBatch(array $records) + { + $formatted = array(); + + foreach ($records as $record) { + $formatted[] = $this->format($record); + } + + return $formatted; + } + + /** + * @param string $message + * + * @return string + */ + public function getShortMessage($message) + { + $maxLength = 45; + + if (strlen($message) > $maxLength) { + $message = substr($message, 0, $maxLength - 4) . ' ...'; + } + + return $message; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php new file mode 100644 index 00000000..b5de7511 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Interface for formatters + * + * @author Jordi Boggiano + */ +interface FormatterInterface +{ + /** + * Formats a log record. + * + * @param array $record A record to format + * @return mixed The formatted record + */ + public function format(array $record); + + /** + * Formats a set of log records. + * + * @param array $records A set of records to format + * @return mixed The formatted set of records + */ + public function formatBatch(array $records); +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php new file mode 100644 index 00000000..6ebfaa7f --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; +use Gelf\Message; + +/** + * Serializes a log message to GELF + * @see http://www.graylog2.org/about/gelf + * + * @author Matt Lehner + */ +class GelfMessageFormatter extends NormalizerFormatter +{ + /** + * @var string the name of the system for the Gelf log message + */ + protected $systemName; + + /** + * @var string a prefix for 'extra' fields from the Monolog record (optional) + */ + protected $extraPrefix; + + /** + * @var string a prefix for 'context' fields from the Monolog record (optional) + */ + protected $contextPrefix; + + /** + * Translates Monolog log levels to Graylog2 log priorities. + */ + private $logLevels = array( + Logger::DEBUG => 7, + Logger::INFO => 6, + Logger::NOTICE => 5, + Logger::WARNING => 4, + Logger::ERROR => 3, + Logger::CRITICAL => 2, + Logger::ALERT => 1, + Logger::EMERGENCY => 0, + ); + + public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_') + { + parent::__construct('U.u'); + + $this->systemName = $systemName ?: gethostname(); + + $this->extraPrefix = $extraPrefix; + $this->contextPrefix = $contextPrefix; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $record = parent::format($record); + $message = new Message(); + $message + ->setTimestamp($record['datetime']) + ->setShortMessage((string) $record['message']) + ->setFacility($record['channel']) + ->setHost($this->systemName) + ->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null) + ->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null) + ->setLevel($this->logLevels[$record['level']]); + + // Do not duplicate these values in the additional fields + unset($record['extra']['line']); + unset($record['extra']['file']); + + foreach ($record['extra'] as $key => $val) { + $message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : $this->toJson($val)); + } + + foreach ($record['context'] as $key => $val) { + $message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val)); + } + + if (null === $message->getFile() && isset($record['context']['exception'])) { + if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) { + $message->setFile($matches[1]); + $message->setLine($matches[2]); + } + } + + return $message; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php new file mode 100644 index 00000000..f07c8715 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +/** + * Formats incoming records into an HTML table + * + * This is especially useful for html email logging + * + * @author Tiago Brito + */ +class HtmlFormatter extends NormalizerFormatter +{ + /** + * Translates Monolog log levels to html color priorities. + */ + private $logLevels = array( + Logger::DEBUG => '#cccccc', + Logger::INFO => '#468847', + Logger::NOTICE => '#3a87ad', + Logger::WARNING => '#c09853', + Logger::ERROR => '#f0ad4e', + Logger::CRITICAL => '#FF7708', + Logger::ALERT => '#C12A19', + Logger::EMERGENCY => '#000000', + ); + + /** + * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + */ + public function __construct($dateFormat = null) + { + parent::__construct($dateFormat); + } + + /** + * Creates an HTML table row + * + * @param string $th Row header content + * @param string $td Row standard cell content + * @return string + */ + private function addRow($th, $td = ' ') + { + $th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8'); + $td = '
'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'
'; + + return "\n$th:\n".$td."\n"; + } + + /** + * Create a HTML h1 tag + * + * @param string $title Text to be in the h1 + * @param integer $level Error level + * @return string + */ + private function addTitle($title, $level) + { + $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8'); + + return '

'.$title.'

'; + } + /** + * Formats a log record. + * + * @param array $record A record to format + * @return mixed The formatted record + */ + public function format(array $record) + { + $output = $this->addTitle($record['level_name'], $record['level']); + $output .= ''; + + $output .= $this->addRow('Message', (string) $record['message']); + $output .= $this->addRow('Time', $record['datetime']->format('Y-m-d\TH:i:s.uO')); + $output .= $this->addRow('Channel', $record['channel']); + if ($record['context']) { + $output .= $this->addRow('Context', $this->convertToString($record['context'])); + } + if ($record['extra']) { + $output .= $this->addRow('Extra', $this->convertToString($record['extra'])); + } + + return $output.'
'; + } + + /** + * Formats a set of log records. + * + * @param array $records A set of records to format + * @return mixed The formatted set of records + */ + public function formatBatch(array $records) + { + $message = ''; + foreach ($records as $record) { + $message .= $this->format($record); + } + + return $message; + } + + protected function convertToString($data) + { + if (null === $data || is_scalar($data)) { + return (string) $data; + } + + $data = $this->normalize($data); + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return str_replace('\\/', '/', json_encode($data)); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php new file mode 100644 index 00000000..ac6f58c0 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Encodes whatever record data is passed to it as json + * + * This can be useful to log to databases or remote APIs + * + * @author Jordi Boggiano + */ +class JsonFormatter implements FormatterInterface +{ + protected $batchMode; + protected $appendNewline; + + const BATCH_MODE_JSON = 1; + const BATCH_MODE_NEWLINES = 2; + + /** + * @param int $batchMode + */ + public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true) + { + $this->batchMode = $batchMode; + $this->appendNewline = $appendNewline; + } + + /** + * The batch mode option configures the formatting style for + * multiple records. By default, multiple records will be + * formatted as a JSON-encoded array. However, for + * compatibility with some API endpoints, alternive styles + * are available. + * + * @return int + */ + public function getBatchMode() + { + return $this->batchMode; + } + + /** + * True if newlines are appended to every formatted record + * + * @return bool + */ + public function isAppendingNewlines() + { + return $this->appendNewline; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + return json_encode($record) . ($this->appendNewline ? "\n" : ''); + } + + /** + * {@inheritdoc} + */ + public function formatBatch(array $records) + { + switch ($this->batchMode) { + case static::BATCH_MODE_NEWLINES: + return $this->formatBatchNewlines($records); + + case static::BATCH_MODE_JSON: + default: + return $this->formatBatchJson($records); + } + } + + /** + * Return a JSON-encoded array of records. + * + * @param array $records + * @return string + */ + protected function formatBatchJson(array $records) + { + return json_encode($records); + } + + /** + * Use new lines to separate records instead of a + * JSON-encoded array. + * + * @param array $records + * @return string + */ + protected function formatBatchNewlines(array $records) + { + $instance = $this; + + $oldNewline = $this->appendNewline; + $this->appendNewline = false; + array_walk($records, function (&$value, $key) use ($instance) { + $value = $instance->format($value); + }); + $this->appendNewline = $oldNewline; + + return implode("\n", $records); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php new file mode 100644 index 00000000..9ef0a645 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Exception; + +/** + * Formats incoming records into a one-line string + * + * This is especially useful for logging to files + * + * @author Jordi Boggiano + * @author Christophe Coevoet + */ +class LineFormatter extends NormalizerFormatter +{ + const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; + + protected $format; + protected $allowInlineLineBreaks; + + /** + * @param string $format The format of the message + * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries + */ + public function __construct($format = null, $dateFormat = null, $allowInlineLineBreaks = false) + { + $this->format = $format ?: static::SIMPLE_FORMAT; + $this->allowInlineLineBreaks = $allowInlineLineBreaks; + parent::__construct($dateFormat); + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $vars = parent::format($record); + + $output = $this->format; + foreach ($vars['extra'] as $var => $val) { + if (false !== strpos($output, '%extra.'.$var.'%')) { + $output = str_replace('%extra.'.$var.'%', $this->replaceNewlines($this->convertToString($val)), $output); + unset($vars['extra'][$var]); + } + } + foreach ($vars as $var => $val) { + if (false !== strpos($output, '%'.$var.'%')) { + $output = str_replace('%'.$var.'%', $this->replaceNewlines($this->convertToString($val)), $output); + } + } + + return $output; + } + + public function formatBatch(array $records) + { + $message = ''; + foreach ($records as $record) { + $message .= $this->format($record); + } + + return $message; + } + + protected function normalizeException(Exception $e) + { + $previousText = ''; + if ($previous = $e->getPrevious()) { + do { + $previousText .= ', '.get_class($previous).': '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); + } while ($previous = $previous->getPrevious()); + } + + return '[object] ('.get_class($e).': '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')'; + } + + protected function convertToString($data) + { + if (null === $data || is_bool($data)) { + return var_export($data, true); + } + + if (is_scalar($data)) { + return (string) $data; + } + + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return $this->toJson($data, true); + } + + return str_replace('\\/', '/', @json_encode($data)); + } + + protected function replaceNewlines($str) + { + if ($this->allowInlineLineBreaks) { + return $str; + } + + return preg_replace('{[\r\n]+}', ' ', $str); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php new file mode 100644 index 00000000..5ef0d9fa --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Encodes message information into JSON in a format compatible with Loggly. + * + * @author Adam Pancutt + */ +class LogglyFormatter extends JsonFormatter +{ + /** + * Overrides the default batch mode to new lines for compatibility with the + * Loggly bulk API. + * + * @param integer $batchMode + */ + public function __construct($batchMode = self::BATCH_MODE_NEWLINES, $appendNewline = false) + { + parent::__construct($batchMode, $appendNewline); + } + + /** + * Appends the 'timestamp' parameter for indexing by Loggly. + * + * @see https://www.loggly.com/docs/automated-parsing/#json + * @see \Monolog\Formatter\JsonFormatter::format() + */ + public function format(array $record) + { + if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTime)) { + $record["timestamp"] = $record["datetime"]->format("c"); + // TODO 2.0 unset the 'datetime' parameter, retained for BC + } + + return parent::format($record); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php new file mode 100644 index 00000000..7a7b3b3c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Serializes a log message to Logstash Event Format + * + * @see http://logstash.net/ + * @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb + * + * @author Tim Mower + */ +class LogstashFormatter extends NormalizerFormatter +{ + const V0 = 0; + const V1 = 1; + + /** + * @var string the name of the system for the Logstash log message, used to fill the @source field + */ + protected $systemName; + + /** + * @var string an application name for the Logstash log message, used to fill the @type field + */ + protected $applicationName; + + /** + * @var string a prefix for 'extra' fields from the Monolog record (optional) + */ + protected $extraPrefix; + + /** + * @var string a prefix for 'context' fields from the Monolog record (optional) + */ + protected $contextPrefix; + + /** + * @var integer logstash format version to use + */ + protected $version; + + /** + * @param string $applicationName the application that sends the data, used as the "type" field of logstash + * @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine + * @param string $extraPrefix prefix for extra keys inside logstash "fields" + * @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_ + */ + public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0) + { + // logstash requires a ISO 8601 format date with optional millisecond precision. + parent::__construct('Y-m-d\TH:i:s.uP'); + + $this->systemName = $systemName ?: gethostname(); + $this->applicationName = $applicationName; + $this->extraPrefix = $extraPrefix; + $this->contextPrefix = $contextPrefix; + $this->version = $version; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $record = parent::format($record); + + if ($this->version === self::V1) { + $message = $this->formatV1($record); + } else { + $message = $this->formatV0($record); + } + + return $this->toJson($message) . "\n"; + } + + protected function formatV0(array $record) + { + if (empty($record['datetime'])) { + $record['datetime'] = gmdate('c'); + } + $message = array( + '@timestamp' => $record['datetime'], + '@source' => $this->systemName, + '@fields' => array() + ); + if (isset($record['message'])) { + $message['@message'] = $record['message']; + } + if (isset($record['channel'])) { + $message['@tags'] = array($record['channel']); + $message['@fields']['channel'] = $record['channel']; + } + if (isset($record['level'])) { + $message['@fields']['level'] = $record['level']; + } + if ($this->applicationName) { + $message['@type'] = $this->applicationName; + } + if (isset($record['extra']['server'])) { + $message['@source_host'] = $record['extra']['server']; + } + if (isset($record['extra']['url'])) { + $message['@source_path'] = $record['extra']['url']; + } + if (!empty($record['extra'])) { + foreach ($record['extra'] as $key => $val) { + $message['@fields'][$this->extraPrefix . $key] = $val; + } + } + if (!empty($record['context'])) { + foreach ($record['context'] as $key => $val) { + $message['@fields'][$this->contextPrefix . $key] = $val; + } + } + + return $message; + } + + protected function formatV1(array $record) + { + if (empty($record['datetime'])) { + $record['datetime'] = gmdate('c'); + } + $message = array( + '@timestamp' => $record['datetime'], + '@version' => 1, + 'host' => $this->systemName, + ); + if (isset($record['message'])) { + $message['message'] = $record['message']; + } + if (isset($record['channel'])) { + $message['type'] = $record['channel']; + $message['channel'] = $record['channel']; + } + if (isset($record['level_name'])) { + $message['level'] = $record['level_name']; + } + if ($this->applicationName) { + $message['type'] = $this->applicationName; + } + if (!empty($record['extra'])) { + foreach ($record['extra'] as $key => $val) { + $message[$this->extraPrefix . $key] = $val; + } + } + if (!empty($record['context'])) { + foreach ($record['context'] as $key => $val) { + $message[$this->contextPrefix . $key] = $val; + } + } + + return $message; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php new file mode 100644 index 00000000..dfa3cb91 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Exception; + +/** + * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets + * + * @author Jordi Boggiano + */ +class NormalizerFormatter implements FormatterInterface +{ + const SIMPLE_DATE = "Y-m-d H:i:s"; + + protected $dateFormat; + + /** + * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + */ + public function __construct($dateFormat = null) + { + $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + return $this->normalize($record); + } + + /** + * {@inheritdoc} + */ + public function formatBatch(array $records) + { + foreach ($records as $key => $record) { + $records[$key] = $this->format($record); + } + + return $records; + } + + protected function normalize($data) + { + if (null === $data || is_scalar($data)) { + return $data; + } + + if (is_array($data) || $data instanceof \Traversable) { + $normalized = array(); + + $count = 1; + foreach ($data as $key => $value) { + if ($count++ >= 1000) { + $normalized['...'] = 'Over 1000 items, aborting normalization'; + break; + } + $normalized[$key] = $this->normalize($value); + } + + return $normalized; + } + + if ($data instanceof \DateTime) { + return $data->format($this->dateFormat); + } + + if (is_object($data)) { + if ($data instanceof Exception) { + return $this->normalizeException($data); + } + + return sprintf("[object] (%s: %s)", get_class($data), $this->toJson($data, true)); + } + + if (is_resource($data)) { + return '[resource]'; + } + + return '[unknown('.gettype($data).')]'; + } + + protected function normalizeException(Exception $e) + { + $data = array( + 'class' => get_class($e), + 'message' => $e->getMessage(), + 'file' => $e->getFile().':'.$e->getLine(), + ); + + $trace = $e->getTrace(); + foreach ($trace as $frame) { + if (isset($frame['file'])) { + $data['trace'][] = $frame['file'].':'.$frame['line']; + } else { + $data['trace'][] = json_encode($frame); + } + } + + if ($previous = $e->getPrevious()) { + $data['previous'] = $this->normalizeException($previous); + } + + return $data; + } + + protected function toJson($data, $ignoreErrors = false) + { + // suppress json_encode errors since it's twitchy with some inputs + if ($ignoreErrors) { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return @json_encode($data); + } + + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return json_encode($data); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php new file mode 100644 index 00000000..5d345d53 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Formats data into an associative array of scalar values. + * Objects and arrays will be JSON encoded. + * + * @author Andrew Lawson + */ +class ScalarFormatter extends NormalizerFormatter +{ + /** + * {@inheritdoc} + */ + public function format(array $record) + { + foreach ($record as $key => $value) { + $record[$key] = $this->normalizeValue($value); + } + + return $record; + } + + /** + * @param mixed $value + * @return mixed + */ + protected function normalizeValue($value) + { + $normalized = $this->normalize($value); + + if (is_array($normalized) || is_object($normalized)) { + return $this->toJson($normalized, true); + } + + return $normalized; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php new file mode 100644 index 00000000..654710a8 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +/** + * Serializes a log message according to Wildfire's header requirements + * + * @author Eric Clemmons (@ericclemmons) + * @author Christophe Coevoet + * @author Kirill chEbba Chebunin + */ +class WildfireFormatter extends NormalizerFormatter +{ + const TABLE = 'table'; + + /** + * Translates Monolog log levels to Wildfire levels. + */ + private $logLevels = array( + Logger::DEBUG => 'LOG', + Logger::INFO => 'INFO', + Logger::NOTICE => 'INFO', + Logger::WARNING => 'WARN', + Logger::ERROR => 'ERROR', + Logger::CRITICAL => 'ERROR', + Logger::ALERT => 'ERROR', + Logger::EMERGENCY => 'ERROR', + ); + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + // Retrieve the line and file if set and remove them from the formatted extra + $file = $line = ''; + if (isset($record['extra']['file'])) { + $file = $record['extra']['file']; + unset($record['extra']['file']); + } + if (isset($record['extra']['line'])) { + $line = $record['extra']['line']; + unset($record['extra']['line']); + } + + $record = $this->normalize($record); + $message = array('message' => $record['message']); + $handleError = false; + if ($record['context']) { + $message['context'] = $record['context']; + $handleError = true; + } + if ($record['extra']) { + $message['extra'] = $record['extra']; + $handleError = true; + } + if (count($message) === 1) { + $message = reset($message); + } + + if (isset($record['context'][self::TABLE])) { + $type = 'TABLE'; + $label = $record['channel'] .': '. $record['message']; + $message = $record['context'][self::TABLE]; + } else { + $type = $this->logLevels[$record['level']]; + $label = $record['channel']; + } + + // Create JSON object describing the appearance of the message in the console + $json = $this->toJson(array( + array( + 'Type' => $type, + 'File' => $file, + 'Line' => $line, + 'Label' => $label, + ), + $message, + ), $handleError); + + // The message itself is a serialization of the above JSON object + it's length + return sprintf( + '%s|%s|', + strlen($json), + $json + ); + } + + public function formatBatch(array $records) + { + throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); + } + + protected function normalize($data) + { + if (is_object($data) && !$data instanceof \DateTime) { + return $data; + } + + return parent::normalize($data); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php new file mode 100644 index 00000000..3bb21b71 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php @@ -0,0 +1,184 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; + +/** + * Base Handler class providing the Handler structure + * + * @author Jordi Boggiano + */ +abstract class AbstractHandler implements HandlerInterface +{ + protected $level = Logger::DEBUG; + protected $bubble = true; + + /** + * @var FormatterInterface + */ + protected $formatter; + protected $processors = array(); + + /** + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct($level = Logger::DEBUG, $bubble = true) + { + $this->level = $level; + $this->bubble = $bubble; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) + { + return $record['level'] >= $this->level; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + foreach ($records as $record) { + $this->handle($record); + } + } + + /** + * Closes the handler. + * + * This will be called automatically when the object is destroyed + */ + public function close() + { + } + + /** + * {@inheritdoc} + */ + public function pushProcessor($callback) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); + } + array_unshift($this->processors, $callback); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function popProcessor() + { + if (!$this->processors) { + throw new \LogicException('You tried to pop from an empty processor stack.'); + } + + return array_shift($this->processors); + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->formatter = $formatter; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + if (!$this->formatter) { + $this->formatter = $this->getDefaultFormatter(); + } + + return $this->formatter; + } + + /** + * Sets minimum logging level at which this handler will be triggered. + * + * @param integer $level + * @return self + */ + public function setLevel($level) + { + $this->level = $level; + + return $this; + } + + /** + * Gets minimum logging level at which this handler will be triggered. + * + * @return integer + */ + public function getLevel() + { + return $this->level; + } + + /** + * Sets the bubbling behavior. + * + * @param Boolean $bubble true means that this handler allows bubbling. + * false means that bubbling is not permitted. + * @return self + */ + public function setBubble($bubble) + { + $this->bubble = $bubble; + + return $this; + } + + /** + * Gets the bubbling behavior. + * + * @return Boolean true means that this handler allows bubbling. + * false means that bubbling is not permitted. + */ + public function getBubble() + { + return $this->bubble; + } + + public function __destruct() + { + try { + $this->close(); + } catch (\Exception $e) { + // do nothing + } + } + + /** + * Gets the default formatter. + * + * @return FormatterInterface + */ + protected function getDefaultFormatter() + { + return new LineFormatter(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php new file mode 100644 index 00000000..6f18f72e --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Base Handler class providing the Handler structure + * + * Classes extending it should (in most cases) only implement write($record) + * + * @author Jordi Boggiano + * @author Christophe Coevoet + */ +abstract class AbstractProcessingHandler extends AbstractHandler +{ + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if (!$this->isHandling($record)) { + return false; + } + + $record = $this->processRecord($record); + + $record['formatted'] = $this->getFormatter()->format($record); + + $this->write($record); + + return false === $this->bubble; + } + + /** + * Writes the record down to the log of the implementing handler + * + * @param array $record + * @return void + */ + abstract protected function write(array $record); + + /** + * Processes a record. + * + * @param array $record + * @return array + */ + protected function processRecord(array $record) + { + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php new file mode 100644 index 00000000..3eb83bd4 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\LineFormatter; + +/** + * Common syslog functionality + */ +abstract class AbstractSyslogHandler extends AbstractProcessingHandler +{ + protected $facility; + + /** + * Translates Monolog log levels to syslog log priorities. + */ + protected $logLevels = array( + Logger::DEBUG => LOG_DEBUG, + Logger::INFO => LOG_INFO, + Logger::NOTICE => LOG_NOTICE, + Logger::WARNING => LOG_WARNING, + Logger::ERROR => LOG_ERR, + Logger::CRITICAL => LOG_CRIT, + Logger::ALERT => LOG_ALERT, + Logger::EMERGENCY => LOG_EMERG, + ); + + /** + * List of valid log facility names. + */ + protected $facilities = array( + 'auth' => LOG_AUTH, + 'authpriv' => LOG_AUTHPRIV, + 'cron' => LOG_CRON, + 'daemon' => LOG_DAEMON, + 'kern' => LOG_KERN, + 'lpr' => LOG_LPR, + 'mail' => LOG_MAIL, + 'news' => LOG_NEWS, + 'syslog' => LOG_SYSLOG, + 'user' => LOG_USER, + 'uucp' => LOG_UUCP, + ); + + /** + * @param mixed $facility + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + + if (!defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->facilities['local0'] = LOG_LOCAL0; + $this->facilities['local1'] = LOG_LOCAL1; + $this->facilities['local2'] = LOG_LOCAL2; + $this->facilities['local3'] = LOG_LOCAL3; + $this->facilities['local4'] = LOG_LOCAL4; + $this->facilities['local5'] = LOG_LOCAL5; + $this->facilities['local6'] = LOG_LOCAL6; + $this->facilities['local7'] = LOG_LOCAL7; + } + + // convert textual description of facility to syslog constant + if (array_key_exists(strtolower($facility), $this->facilities)) { + $facility = $this->facilities[strtolower($facility)]; + } elseif (!in_array($facility, array_values($this->facilities), true)) { + throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given'); + } + + $this->facility = $facility; + } + + /** + * {@inheritdoc} + */ + protected function getDefaultFormatter() + { + return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%'); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php new file mode 100644 index 00000000..2db0d08d --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\JsonFormatter; + +class AmqpHandler extends AbstractProcessingHandler +{ + /** + * @var \AMQPExchange $exchange + */ + protected $exchange; + + /** + * @param \AMQPExchange $exchange AMQP exchange, ready for use + * @param string $exchangeName + * @param int $level + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(\AMQPExchange $exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true) + { + $this->exchange = $exchange; + $this->exchange->setName($exchangeName); + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $data = $record["formatted"]; + + $routingKey = sprintf( + '%s.%s', + substr($record['level_name'], 0, 4), + $record['channel'] + ); + + $this->exchange->publish( + $data, + strtolower($routingKey), + 0, + array( + 'delivery_mode' => 2, + 'Content-type' => 'application/json' + ) + ); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php new file mode 100644 index 00000000..43190b92 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php @@ -0,0 +1,184 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\LineFormatter; + +/** + * Handler sending logs to browser's javascript console with no browser extension required + * + * @author Olivier Poitrey + */ +class BrowserConsoleHandler extends AbstractProcessingHandler +{ + protected static $initialized = false; + protected static $records = array(); + + /** + * {@inheritDoc} + * + * Formatted output may contain some formatting markers to be transfered to `console.log` using the %c format. + * + * Example of formatted string: + * + * You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white} + * + */ + protected function getDefaultFormatter() + { + return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%'); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + // Accumulate records + self::$records[] = $record; + + // Register shutdown handler if not already done + if (PHP_SAPI !== 'cli' && !self::$initialized) { + self::$initialized = true; + register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send')); + } + } + + /** + * Convert records to javascript console commands and send it to the browser. + * This method is automatically called on PHP shutdown if output is HTML. + */ + public static function send() + { + // Check content type + foreach (headers_list() as $header) { + if (stripos($header, 'content-type:') === 0) { + if (stripos($header, 'text/html') === false) { + // This handler only works with HTML outputs + return; + } + break; + } + } + + if (count(self::$records)) { + echo ''; + self::reset(); + } + } + + /** + * Forget all logged records + */ + public static function reset() + { + self::$records = array(); + } + + private static function generateScript() + { + $script = array(); + foreach (self::$records as $record) { + $context = self::dump('Context', $record['context']); + $extra = self::dump('Extra', $record['extra']); + + if (empty($context) && empty($extra)) { + $script[] = self::call_array('log', self::handleStyles($record['formatted'])); + } else { + $script = array_merge($script, + array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))), + $context, + $extra, + array(self::call('groupEnd')) + ); + } + } + + return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);"; + } + + private static function handleStyles($formatted) + { + $args = array(self::quote('font-weight: normal')); + $format = '%c' . $formatted; + preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); + + foreach (array_reverse($matches) as $match) { + $args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0])); + $args[] = '"font-weight: normal"'; + + $pos = $match[0][1]; + $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0])); + } + + array_unshift($args, self::quote($format)); + + return $args; + } + + private static function handleCustomStyles($style, $string) + { + static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey'); + static $labels = array(); + + return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) { + if (trim($m[1]) === 'autolabel') { + // Format the string as a label with consistent auto assigned background color + if (!isset($labels[$string])) { + $labels[$string] = $colors[count($labels) % count($colors)]; + } + $color = $labels[$string]; + + return "background-color: $color; color: white; border-radius: 3px; padding: 0 2px 0 2px"; + } + + return $m[1]; + }, $style); + } + + private static function dump($title, array $dict) + { + $script = array(); + $dict = array_filter($dict); + if (empty($dict)) { + return $script; + } + $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title)); + foreach ($dict as $key => $value) { + $value = json_encode($value); + if (empty($value)) { + $value = self::quote(''); + } + $script[] = self::call('log', self::quote('%s: %o'), self::quote($key), $value); + } + + return $script; + } + + private static function quote($arg) + { + return '"' . addcslashes($arg, "\"\n") . '"'; + } + + private static function call() + { + $args = func_get_args(); + $method = array_shift($args); + + return self::call_array($method, $args); + } + + private static function call_array($method, array $args) + { + return 'c.' . $method . '(' . implode(', ', $args) . ');'; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php new file mode 100644 index 00000000..183d239a --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Buffers all records until closing the handler and then pass them as batch. + * + * This is useful for a MailHandler to send only one mail per request instead of + * sending one per log message. + * + * @author Christophe Coevoet + */ +class BufferHandler extends AbstractHandler +{ + protected $handler; + protected $bufferSize = 0; + protected $bufferLimit; + protected $flushOnOverflow; + protected $buffer = array(); + protected $initialized = false; + + /** + * @param HandlerInterface $handler Handler. + * @param integer $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded + */ + public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false) + { + parent::__construct($level, $bubble); + $this->handler = $handler; + $this->bufferLimit = (int) $bufferLimit; + $this->flushOnOverflow = $flushOnOverflow; + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($record['level'] < $this->level) { + return false; + } + + if (!$this->initialized) { + // __destructor() doesn't get called on Fatal errors + register_shutdown_function(array($this, 'close')); + $this->initialized = true; + } + + if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) { + if ($this->flushOnOverflow) { + $this->flush(); + } else { + array_shift($this->buffer); + $this->bufferSize--; + } + } + + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + $this->buffer[] = $record; + $this->bufferSize++; + + return false === $this->bubble; + } + + public function flush() + { + if ($this->bufferSize === 0) { + return; + } + + $this->handler->handleBatch($this->buffer); + $this->bufferSize = 0; + $this->buffer = array(); + } + + /** + * {@inheritdoc} + */ + public function close() + { + $this->flush(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php new file mode 100644 index 00000000..ff7a7809 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php @@ -0,0 +1,192 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\ChromePHPFormatter; +use Monolog\Logger; + +/** + * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) + * + * @author Christophe Coevoet + */ +class ChromePHPHandler extends AbstractProcessingHandler +{ + /** + * Version of the extension + */ + const VERSION = '4.0'; + + /** + * Header name + */ + const HEADER_NAME = 'X-ChromeLogger-Data'; + + protected static $initialized = false; + + /** + * Tracks whether we sent too much data + * + * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending + * + * @var Boolean + */ + protected static $overflowed = false; + + protected static $json = array( + 'version' => self::VERSION, + 'columns' => array('label', 'log', 'backtrace', 'type'), + 'rows' => array(), + ); + + protected static $sendHeaders = true; + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $messages = array(); + + foreach ($records as $record) { + if ($record['level'] < $this->level) { + continue; + } + $messages[] = $this->processRecord($record); + } + + if (!empty($messages)) { + $messages = $this->getFormatter()->formatBatch($messages); + self::$json['rows'] = array_merge(self::$json['rows'], $messages); + $this->send(); + } + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new ChromePHPFormatter(); + } + + /** + * Creates & sends header for a record + * + * @see sendHeader() + * @see send() + * @param array $record + */ + protected function write(array $record) + { + self::$json['rows'][] = $record['formatted']; + + $this->send(); + } + + /** + * Sends the log header + * + * @see sendHeader() + */ + protected function send() + { + if (self::$overflowed || !self::$sendHeaders) { + return; + } + + if (!self::$initialized) { + self::$initialized = true; + + self::$sendHeaders = $this->headersAccepted(); + if (!self::$sendHeaders) { + return; + } + + self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + } + + $json = @json_encode(self::$json); + $data = base64_encode(utf8_encode($json)); + if (strlen($data) > 240*1024) { + self::$overflowed = true; + + $record = array( + 'message' => 'Incomplete logs, chrome header size limit reached', + 'context' => array(), + 'level' => Logger::WARNING, + 'level_name' => Logger::getLevelName(Logger::WARNING), + 'channel' => 'monolog', + 'datetime' => new \DateTime(), + 'extra' => array(), + ); + self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); + $json = @json_encode(self::$json); + $data = base64_encode(utf8_encode($json)); + } + + if (trim($data) !== '') { + $this->sendHeader(self::HEADER_NAME, $data); + } + } + + /** + * Send header string to the client + * + * @param string $header + * @param string $content + */ + protected function sendHeader($header, $content) + { + if (!headers_sent() && self::$sendHeaders) { + header(sprintf('%s: %s', $header, $content)); + } + } + + /** + * Verifies if the headers are accepted by the current user agent + * + * @return Boolean + */ + protected function headersAccepted() + { + if (empty($_SERVER['HTTP_USER_AGENT'])) { + return false; + } + + return preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']); + } + + /** + * BC getter for the sendHeaders property that has been made static + */ + public function __get($property) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + return static::$sendHeaders; + } + + /** + * BC setter for the sendHeaders property that has been made static + */ + public function __set($property, $value) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + static::$sendHeaders = $value; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php new file mode 100644 index 00000000..b3687c3d --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\JsonFormatter; +use Monolog\Logger; + +/** + * CouchDB handler + * + * @author Markus Bachmann + */ +class CouchDBHandler extends AbstractProcessingHandler +{ + private $options; + + public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true) + { + $this->options = array_merge(array( + 'host' => 'localhost', + 'port' => 5984, + 'dbname' => 'logger', + 'username' => null, + 'password' => null, + ), $options); + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $basicAuth = null; + if ($this->options['username']) { + $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']); + } + + $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname']; + $context = stream_context_create(array( + 'http' => array( + 'method' => 'POST', + 'content' => $record['formatted'], + 'ignore_errors' => true, + 'max_redirects' => 0, + 'header' => 'Content-type: application/json', + ) + )); + + if (false === @file_get_contents($url, null, $context)) { + throw new \RuntimeException(sprintf('Could not connect to %s', $url)); + } + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php new file mode 100644 index 00000000..d968720c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Logs to Cube. + * + * @link http://square.github.com/cube/ + * @author Wan Chen + */ +class CubeHandler extends AbstractProcessingHandler +{ + private $udpConnection = null; + private $httpConnection = null; + private $scheme = null; + private $host = null; + private $port = null; + private $acceptedSchemes = array('http', 'udp'); + + /** + * Create a Cube handler + * + * @throws UnexpectedValueException when given url is not a valid url. + * A valid url must consists of three parts : protocol://host:port + * Only valid protocol used by Cube are http and udp + */ + public function __construct($url, $level = Logger::DEBUG, $bubble = true) + { + $urlInfos = parse_url($url); + + if (!isset($urlInfos['scheme']) || !isset($urlInfos['host']) || !isset($urlInfos['port'])) { + throw new \UnexpectedValueException('URL "'.$url.'" is not valid'); + } + + if (!in_array($urlInfos['scheme'], $this->acceptedSchemes)) { + throw new \UnexpectedValueException( + 'Invalid protocol (' . $urlInfos['scheme'] . ').' + . ' Valid options are ' . implode(', ', $this->acceptedSchemes)); + } + + $this->scheme = $urlInfos['scheme']; + $this->host = $urlInfos['host']; + $this->port = $urlInfos['port']; + + parent::__construct($level, $bubble); + } + + /** + * Establish a connection to an UDP socket + * + * @throws LogicException when unable to connect to the socket + */ + protected function connectUdp() + { + if (!extension_loaded('sockets')) { + throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); + } + + $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); + if (!$this->udpConnection) { + throw new \LogicException('Unable to create a socket'); + } + + if (!socket_connect($this->udpConnection, $this->host, $this->port)) { + throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port); + } + } + + /** + * Establish a connection to a http server + */ + protected function connectHttp() + { + if (!extension_loaded('curl')) { + throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler'); + } + + $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); + + if (!$this->httpConnection) { + throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port); + } + + curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST"); + curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $date = $record['datetime']; + + $data = array('time' => $date->format('Y-m-d\TH:i:s.uO')); + unset($record['datetime']); + + if (isset($record['context']['type'])) { + $data['type'] = $record['context']['type']; + unset($record['context']['type']); + } else { + $data['type'] = $record['channel']; + } + + $data['data'] = $record['context']; + $data['data']['level'] = $record['level']; + + $this->{'write'.$this->scheme}(json_encode($data)); + } + + private function writeUdp($data) + { + if (!$this->udpConnection) { + $this->connectUdp(); + } + + socket_send($this->udpConnection, $data, strlen($data), 0); + } + + private function writeHttp($data) + { + if (!$this->httpConnection) { + $this->connectHttp(); + } + + curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); + curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json', + 'Content-Length: ' . strlen('['.$data.']')) + ); + + return curl_exec($this->httpConnection); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php new file mode 100644 index 00000000..b91ffec9 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\NormalizerFormatter; +use Doctrine\CouchDB\CouchDBClient; + +/** + * CouchDB handler for Doctrine CouchDB ODM + * + * @author Markus Bachmann + */ +class DoctrineCouchDBHandler extends AbstractProcessingHandler +{ + private $client; + + public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true) + { + $this->client = $client; + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $this->client->postDocument($record['formatted']); + } + + protected function getDefaultFormatter() + { + return new NormalizerFormatter; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php new file mode 100644 index 00000000..e7f843c8 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Aws\Common\Aws; +use Aws\DynamoDb\DynamoDbClient; +use Monolog\Formatter\ScalarFormatter; +use Monolog\Logger; + +/** + * Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/) + * + * @link https://github.com/aws/aws-sdk-php/ + * @author Andrew Lawson + */ +class DynamoDbHandler extends AbstractProcessingHandler +{ + const DATE_FORMAT = 'Y-m-d\TH:i:s.uO'; + + /** + * @var DynamoDbClient + */ + protected $client; + + /** + * @var string + */ + protected $table; + + /** + * @param DynamoDbClient $client + * @param string $table + * @param integer $level + * @param boolean $bubble + */ + public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true) + { + if (!defined('Aws\Common\Aws::VERSION') || version_compare('3.0', Aws::VERSION, '<=')) { + throw new \RuntimeException('The DynamoDbHandler is only known to work with the AWS SDK 2.x releases'); + } + + $this->client = $client; + $this->table = $table; + + parent::__construct($level, $bubble); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $filtered = $this->filterEmptyFields($record['formatted']); + $formatted = $this->client->formatAttributes($filtered); + + $this->client->putItem(array( + 'TableName' => $this->table, + 'Item' => $formatted + )); + } + + /** + * @param array $record + * @return array + */ + protected function filterEmptyFields(array $record) + { + return array_filter($record, function ($value) { + return !empty($value) || false === $value || 0 === $value; + }); + } + + /** + * {@inheritdoc} + */ + protected function getDefaultFormatter() + { + return new ScalarFormatter(self::DATE_FORMAT); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php new file mode 100644 index 00000000..96e5d57f --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\ElasticaFormatter; +use Monolog\Logger; +use Elastica\Client; +use Elastica\Exception\ExceptionInterface; + +/** + * Elastic Search handler + * + * Usage example: + * + * $client = new \Elastica\Client(); + * $options = array( + * 'index' => 'elastic_index_name', + * 'type' => 'elastic_doc_type', + * ); + * $handler = new ElasticSearchHandler($client, $options); + * $log = new Logger('application'); + * $log->pushHandler($handler); + * + * @author Jelle Vink + */ +class ElasticSearchHandler extends AbstractProcessingHandler +{ + /** + * @var Client + */ + protected $client; + + /** + * @var array Handler config options + */ + protected $options = array(); + + /** + * @param Client $client Elastica Client object + * @param array $options Handler configuration + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + $this->client = $client; + $this->options = array_merge( + array( + 'index' => 'monolog', // Elastic index name + 'type' => 'record', // Elastic document type + 'ignore_error' => false, // Suppress Elastica exceptions + ), + $options + ); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $this->bulkSend(array($record['formatted'])); + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + if ($formatter instanceof ElasticaFormatter) { + return parent::setFormatter($formatter); + } + throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter'); + } + + /** + * Getter options + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new ElasticaFormatter($this->options['index'], $this->options['type']); + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $documents = $this->getFormatter()->formatBatch($records); + $this->bulkSend($documents); + } + + /** + * Use Elasticsearch bulk API to send list of documents + * @param array $documents + * @throws \RuntimeException + */ + protected function bulkSend(array $documents) + { + try { + $this->client->addDocuments($documents); + } catch (ExceptionInterface $e) { + if (!$this->options['ignore_error']) { + throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e); + } + } + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php new file mode 100644 index 00000000..d1e1ee60 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\LineFormatter; +use Monolog\Logger; + +/** + * Stores to PHP error_log() handler. + * + * @author Elan Ruusamäe + */ +class ErrorLogHandler extends AbstractProcessingHandler +{ + const OPERATING_SYSTEM = 0; + const SAPI = 4; + + protected $messageType; + protected $expandNewlines; + + /** + * @param integer $messageType Says where the error should go. + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param Boolean $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries + */ + public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false) + { + parent::__construct($level, $bubble); + + if (false === in_array($messageType, self::getAvailableTypes())) { + $message = sprintf('The given message type "%s" is not supported', print_r($messageType, true)); + throw new \InvalidArgumentException($message); + } + + $this->messageType = $messageType; + $this->expandNewlines = $expandNewlines; + } + + /** + * @return array With all available types + */ + public static function getAvailableTypes() + { + return array( + self::OPERATING_SYSTEM, + self::SAPI, + ); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new LineFormatter('[%datetime%] %channel%.%level_name%: %message% %context% %extra%'); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + if ($this->expandNewlines) { + $lines = preg_split('{[\r\n]+}', (string) $record['formatted']); + foreach ($lines as $line) { + error_log($line, $this->messageType); + } + } else { + error_log((string) $record['formatted'], $this->messageType); + } + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php new file mode 100644 index 00000000..597db732 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php @@ -0,0 +1,131 @@ + + */ +class FilterHandler extends AbstractHandler +{ + /** + * Handler or factory callable($record, $this) + * + * @var callable|\Monolog\Handler\HandlerInterface + */ + protected $handler; + + /** + * Minimum level for logs that are passes to handler + * + * @var int + */ + protected $acceptedLevels; + + /** + * Whether the messages that are handled can bubble up the stack or not + * + * @var Boolean + */ + protected $bubble; + + /** + * @param callable|HandlerInterface $handler Handler or factory callable($record, $this). + * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided + * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true) + { + $this->handler = $handler; + $this->bubble = $bubble; + $this->setAcceptedLevels($minLevelOrList, $maxLevel); + } + + /** + * @return array + */ + public function getAcceptedLevels() + { + return array_flip($this->acceptedLevels); + } + + /** + * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided + * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array + */ + public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY) + { + if (is_array($minLevelOrList)) { + $acceptedLevels = $minLevelOrList; + } else { + $acceptedLevels = array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) { + return $level >= $minLevelOrList && $level <= $maxLevel; + }); + } + $this->acceptedLevels = array_flip($acceptedLevels); + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) + { + return isset($this->acceptedLevels[$record['level']]); + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if (!$this->isHandling($record)) { + return false; + } + + // The same logic as in FingersCrossedHandler + if (!$this->handler instanceof HandlerInterface) { + if (!is_callable($this->handler)) { + throw new \RuntimeException( + "The given handler (" . json_encode($this->handler) + . ") is not a callable nor a Monolog\\Handler\\HandlerInterface object" + ); + } + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + $this->handler->handle($record); + + return false === $this->bubble; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $filtered = array(); + foreach ($records as $record) { + if ($this->isHandling($record)) { + $filtered[] = $record; + } + } + + $this->handler->handleBatch($filtered); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php new file mode 100644 index 00000000..c3e42efe --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler\FingersCrossed; + +/** + * Interface for activation strategies for the FingersCrossedHandler. + * + * @author Johannes M. Schmitt + */ +interface ActivationStrategyInterface +{ + /** + * Returns whether the given record activates the handler. + * + * @param array $record + * @return Boolean + */ + public function isHandlerActivated(array $record); +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php new file mode 100644 index 00000000..646d57a8 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -0,0 +1,57 @@ + +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +namespace Monolog\Handler\FingersCrossed; + +/** + * Channel and Error level based monolog activation strategy. Allows to trigger activation + * based on level per channel. e.g. trigger activation on level 'ERROR' by default, except + * for records of the 'sql' channel; those should trigger activation on level 'WARN'. + * + * Example: + * + * + * $activationStrategy = new ChannelLevelActivationStrategy( + * Logger::CRITICAL, + * array( + * 'request' => Logger::ALERT, + * 'sensitive' => Logger::ERROR, + * ) + * ); + * $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy); + * + * + * @author Mike Meessen + */ +class ChannelLevelActivationStrategy implements ActivationStrategyInterface +{ + private $defaultActionLevel; + private $channelToActionLevel; + + /** + * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param array $categoryToActionLevel An array that maps channel names to action levels. + */ + public function __construct($defaultActionLevel, $channelToActionLevel = array()) + { + $this->defaultActionLevel = $defaultActionLevel; + $this->channelToActionLevel = $channelToActionLevel; + } + + public function isHandlerActivated(array $record) + { + if (isset($this->channelToActionLevel[$record['channel']])) { + return $record['level'] >= $this->channelToActionLevel[$record['channel']]; + } + + return $record['level'] >= $this->defaultActionLevel; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php new file mode 100644 index 00000000..7cd8ef1b --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler\FingersCrossed; + +/** + * Error level based activation strategy. + * + * @author Johannes M. Schmitt + */ +class ErrorLevelActivationStrategy implements ActivationStrategyInterface +{ + private $actionLevel; + + public function __construct($actionLevel) + { + $this->actionLevel = $actionLevel; + } + + public function isHandlerActivated(array $record) + { + return $record['level'] >= $this->actionLevel; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php new file mode 100644 index 00000000..9cf75edb --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php @@ -0,0 +1,138 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; +use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; +use Monolog\Logger; + +/** + * Buffers all records until a certain level is reached + * + * The advantage of this approach is that you don't get any clutter in your log files. + * Only requests which actually trigger an error (or whatever your actionLevel is) will be + * in the logs, but they will contain all records, not only those above the level threshold. + * + * You can find the various activation strategies in the + * Monolog\Handler\FingersCrossed\ namespace. + * + * @author Jordi Boggiano + */ +class FingersCrossedHandler extends AbstractHandler +{ + protected $handler; + protected $activationStrategy; + protected $buffering = true; + protected $bufferSize; + protected $buffer = array(); + protected $stopBuffering; + protected $passthruLevel; + + /** + * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). + * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action + * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true) + * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered + */ + public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = NULL) + { + if (null === $activationStrategy) { + $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING); + } + + // convert simple int activationStrategy to an object + if (!$activationStrategy instanceof ActivationStrategyInterface) { + $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy); + } + + $this->handler = $handler; + $this->activationStrategy = $activationStrategy; + $this->bufferSize = $bufferSize; + $this->bubble = $bubble; + $this->stopBuffering = $stopBuffering; + $this->passthruLevel = $passthruLevel; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + if ($this->buffering) { + $this->buffer[] = $record; + if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) { + array_shift($this->buffer); + } + if ($this->activationStrategy->isHandlerActivated($record)) { + if ($this->stopBuffering) { + $this->buffering = false; + } + if (!$this->handler instanceof HandlerInterface) { + if (!is_callable($this->handler)) { + throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object"); + } + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + $this->handler->handleBatch($this->buffer); + $this->buffer = array(); + } + } else { + $this->handler->handle($record); + } + + return false === $this->bubble; + } + + /** + * {@inheritdoc} + */ + public function close() + { + if (NULL !== $this->passthruLevel) { + $level = $this->passthruLevel; + $this->buffer = array_filter($this->buffer, function ($record) use ($level) { + return $record['level'] >= $level; + }); + if (count($this->buffer) > 0) { + $this->handler->handleBatch($this->buffer); + $this->buffer = array(); + } + } + } + + /** + * Resets the state of the handler. Stops forwarding records to the wrapped handler. + */ + public function reset() + { + $this->buffering = true; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php new file mode 100644 index 00000000..fee47950 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php @@ -0,0 +1,195 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\WildfireFormatter; + +/** + * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. + * + * @author Eric Clemmons (@ericclemmons) + */ +class FirePHPHandler extends AbstractProcessingHandler +{ + /** + * WildFire JSON header message format + */ + const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; + + /** + * FirePHP structure for parsing messages & their presentation + */ + const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; + + /** + * Must reference a "known" plugin, otherwise headers won't display in FirePHP + */ + const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; + + /** + * Header prefix for Wildfire to recognize & parse headers + */ + const HEADER_PREFIX = 'X-Wf'; + + /** + * Whether or not Wildfire vendor-specific headers have been generated & sent yet + */ + protected static $initialized = false; + + /** + * Shared static message index between potentially multiple handlers + * @var int + */ + protected static $messageIndex = 1; + + protected static $sendHeaders = true; + + /** + * Base header creation function used by init headers & record headers + * + * @param array $meta Wildfire Plugin, Protocol & Structure Indexes + * @param string $message Log message + * @return array Complete header string ready for the client as key and message as value + */ + protected function createHeader(array $meta, $message) + { + $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta)); + + return array($header => $message); + } + + /** + * Creates message header from record + * + * @see createHeader() + * @param array $record + * @return string + */ + protected function createRecordHeader(array $record) + { + // Wildfire is extensible to support multiple protocols & plugins in a single request, + // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake. + return $this->createHeader( + array(1, 1, 1, self::$messageIndex++), + $record['formatted'] + ); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new WildfireFormatter(); + } + + /** + * Wildfire initialization headers to enable message parsing + * + * @see createHeader() + * @see sendHeader() + * @return array + */ + protected function getInitHeaders() + { + // Initial payload consists of required headers for Wildfire + return array_merge( + $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI), + $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI), + $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI) + ); + } + + /** + * Send header string to the client + * + * @param string $header + * @param string $content + */ + protected function sendHeader($header, $content) + { + if (!headers_sent() && self::$sendHeaders) { + header(sprintf('%s: %s', $header, $content)); + } + } + + /** + * Creates & sends header for a record, ensuring init headers have been sent prior + * + * @see sendHeader() + * @see sendInitHeaders() + * @param array $record + */ + protected function write(array $record) + { + if (!self::$sendHeaders) { + return; + } + + // WildFire-specific headers must be sent prior to any messages + if (!self::$initialized) { + self::$initialized = true; + + self::$sendHeaders = $this->headersAccepted(); + if (!self::$sendHeaders) { + return; + } + + foreach ($this->getInitHeaders() as $header => $content) { + $this->sendHeader($header, $content); + } + } + + $header = $this->createRecordHeader($record); + if (trim(current($header)) !== '') { + $this->sendHeader(key($header), current($header)); + } + } + + /** + * Verifies if the headers are accepted by the current user agent + * + * @return Boolean + */ + protected function headersAccepted() + { + if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) { + return true; + } + + return isset($_SERVER['HTTP_X_FIREPHP_VERSION']); + } + + /** + * BC getter for the sendHeaders property that has been made static + */ + public function __get($property) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + return static::$sendHeaders; + } + + /** + * BC setter for the sendHeaders property that has been made static + */ + public function __set($property, $value) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + static::$sendHeaders = $value; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php new file mode 100644 index 00000000..0916343c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Sends notifications through the Flowdock push API + * + * This must be configured with a FlowdockFormatter instance via setFormatter() + * + * Notes: + * API token - Flowdock API token + * + * @author Dominik Liebler + * @see https://www.flowdock.com/api/push + */ +class FlowdockHandler extends SocketHandler +{ + /** + * @var string + */ + protected $apiToken; + + /** + * @param string $apiToken + * @param bool|int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * + * @throws MissingExtensionException if OpenSSL is missing + */ + public function __construct($apiToken, $level = Logger::DEBUG, $bubble = true) + { + if (!extension_loaded('openssl')) { + throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler'); + } + + parent::__construct('ssl://api.flowdock.com:443', $level, $bubble); + $this->apiToken = $apiToken; + } + + /** + * {@inheritdoc} + * + * @param array $record + */ + public function write(array $record) + { + parent::write($record); + + $this->closeSocket(); + } + + /** + * {@inheritdoc} + * + * @param array $record + * @return string + */ + protected function generateDataStream($record) + { + $content = $this->buildContent($record); + + return $this->buildHeader($content) . $content; + } + + /** + * Builds the body of API call + * + * @param array $record + * @return string + */ + private function buildContent($record) + { + return json_encode($record['formatted']['flowdock']); + } + + /** + * Builds the header of the API Call + * + * @param string $content + * @return string + */ + private function buildHeader($content) + { + $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n"; + $header .= "Host: api.flowdock.com\r\n"; + $header .= "Content-Type: application/json\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "\r\n"; + + return $header; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php new file mode 100644 index 00000000..790f6364 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Gelf\IMessagePublisher; +use Gelf\PublisherInterface; +use InvalidArgumentException; +use Monolog\Logger; +use Monolog\Formatter\GelfMessageFormatter; + +/** + * Handler to send messages to a Graylog2 (http://www.graylog2.org) server + * + * @author Matt Lehner + * @author Benjamin Zikarsky + */ +class GelfHandler extends AbstractProcessingHandler +{ + /** + * @var Publisher the publisher object that sends the message to the server + */ + protected $publisher; + + /** + * @param PublisherInterface|IMessagePublisher $publisher a publisher object + * @param integer $level The minimum logging level at which this handler will be triggered + * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct($publisher, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + + if (!$publisher instanceof IMessagePublisher && !$publisher instanceof PublisherInterface) { + throw new InvalidArgumentException("Invalid publisher, expected a Gelf\IMessagePublisher or Gelf\PublisherInterface instance"); + } + + $this->publisher = $publisher; + } + + /** + * {@inheritdoc} + */ + public function close() + { + $this->publisher = null; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->publisher->publish($record['formatted']); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new GelfMessageFormatter(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php new file mode 100644 index 00000000..99384d35 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Forwards records to multiple handlers + * + * @author Lenar Lõhmus + */ +class GroupHandler extends AbstractHandler +{ + protected $handlers; + + /** + * @param array $handlers Array of Handlers. + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(array $handlers, $bubble = true) + { + foreach ($handlers as $handler) { + if (!$handler instanceof HandlerInterface) { + throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.'); + } + } + + $this->handlers = $handlers; + $this->bubble = $bubble; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) + { + foreach ($this->handlers as $handler) { + if ($handler->isHandling($record)) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + foreach ($this->handlers as $handler) { + $handler->handle($record); + } + + return false === $this->bubble; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + foreach ($this->handlers as $handler) { + $handler->handleBatch($records); + } + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php new file mode 100644 index 00000000..accff037 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; + +/** + * Interface that all Monolog Handlers must implement + * + * @author Jordi Boggiano + */ +interface HandlerInterface +{ + /** + * Checks whether the given record will be handled by this handler. + * + * This is mostly done for performance reasons, to avoid calling processors for nothing. + * + * Handlers should still check the record levels within handle(), returning false in isHandling() + * is no guarantee that handle() will not be called, and isHandling() might not be called + * for a given record. + * + * @param array $record + * + * @return Boolean + */ + public function isHandling(array $record); + + /** + * Handles a record. + * + * All records may be passed to this method, and the handler should discard + * those that it does not want to handle. + * + * The return value of this function controls the bubbling process of the handler stack. + * Unless the bubbling is interrupted (by returning true), the Logger class will keep on + * calling further handlers in the stack with a given log record. + * + * @param array $record The record to handle + * @return Boolean true means that this handler handled the record, and that bubbling is not permitted. + * false means the record was either not processed or that this handler allows bubbling. + */ + public function handle(array $record); + + /** + * Handles a set of records at once. + * + * @param array $records The records to handle (an array of record arrays) + */ + public function handleBatch(array $records); + + /** + * Adds a processor in the stack. + * + * @param callable $callback + * @return self + */ + public function pushProcessor($callback); + + /** + * Removes the processor on top of the stack and returns it. + * + * @return callable + */ + public function popProcessor(); + + /** + * Sets the formatter. + * + * @param FormatterInterface $formatter + * @return self + */ + public function setFormatter(FormatterInterface $formatter); + + /** + * Gets the formatter. + * + * @return FormatterInterface + */ + public function getFormatter(); +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php new file mode 100644 index 00000000..38ce931c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php @@ -0,0 +1,300 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Sends notifications through the hipchat api to a hipchat room + * + * Notes: + * API token - HipChat API token + * Room - HipChat Room Id or name, where messages are sent + * Name - Name used to send the message (from) + * notify - Should the message trigger a notification in the clients + * + * @author Rafael Dohms + * @see https://www.hipchat.com/docs/api + */ +class HipChatHandler extends SocketHandler +{ + /** + * The maximum allowed length for the name used in the "from" field. + */ + const MAXIMUM_NAME_LENGTH = 15; + + /** + * The maximum allowed length for the message. + */ + const MAXIMUM_MESSAGE_LENGTH = 9500; + + /** + * @var string + */ + private $token; + + /** + * @var array + */ + private $room; + + /** + * @var string + */ + private $name; + + /** + * @var boolean + */ + private $notify; + + /** + * @var string + */ + private $format; + + /** + * @param string $token HipChat API Token + * @param string $room The room that should be alerted of the message (Id or Name) + * @param string $name Name used in the "from" field + * @param bool $notify Trigger a notification in clients or not + * @param int $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param Boolean $useSSL Whether to connect via SSL. + * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) + */ + public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text') + { + if (!$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) { + throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.'); + } + + $connectionString = $useSSL ? 'ssl://api.hipchat.com:443' : 'api.hipchat.com:80'; + parent::__construct($connectionString, $level, $bubble); + + $this->token = $token; + $this->name = $name; + $this->notify = $notify; + $this->room = $room; + $this->format = $format; + } + + /** + * {@inheritdoc} + * + * @param array $record + * @return string + */ + protected function generateDataStream($record) + { + $content = $this->buildContent($record); + + return $this->buildHeader($content) . $content; + } + + /** + * Builds the body of API call + * + * @param array $record + * @return string + */ + private function buildContent($record) + { + $dataArray = array( + 'from' => $this->name, + 'room_id' => $this->room, + 'notify' => $this->notify, + 'message' => $record['formatted'], + 'message_format' => $this->format, + 'color' => $this->getAlertColor($record['level']), + ); + + return http_build_query($dataArray); + } + + /** + * Builds the header of the API Call + * + * @param string $content + * @return string + */ + private function buildHeader($content) + { + $header = "POST /v1/rooms/message?format=json&auth_token=".$this->token." HTTP/1.1\r\n"; + $header .= "Host: api.hipchat.com\r\n"; + $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "\r\n"; + + return $header; + } + + /** + * Assigns a color to each level of log records. + * + * @param integer $level + * @return string + */ + protected function getAlertColor($level) + { + switch (true) { + case $level >= Logger::ERROR: + return 'red'; + case $level >= Logger::WARNING: + return 'yellow'; + case $level >= Logger::INFO: + return 'green'; + case $level == Logger::DEBUG: + return 'gray'; + default: + return 'yellow'; + } + } + + /** + * {@inheritdoc} + * + * @param array $record + */ + public function write(array $record) + { + parent::write($record); + $this->closeSocket(); + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + if (count($records) == 0) { + return true; + } + + $batchRecords = $this->combineRecords($records); + + $handled = false; + foreach ($batchRecords as $batchRecord) { + if ($this->isHandling($batchRecord)) { + $this->write($batchRecord); + $handled = true; + } + } + + if (!$handled) { + return false; + } + + return false === $this->bubble; + } + + /** + * Combines multiple records into one. Error level of the combined record + * will be the highest level from the given records. Datetime will be taken + * from the first record. + * + * @param $records + * @return array + */ + private function combineRecords($records) + { + $batchRecord = null; + $batchRecords = array(); + $batchedMessages = array(); + $messages = array(); + $formattedMessages = array(); + $level = 0; + $levelName = null; + $datetime = null; + + foreach ($records as $record) { + $record = $this->processRecord($record); + + if ($record['level'] > $level) { + $level = $record['level']; + $levelName = $record['level_name']; + } + + if (null === $datetime) { + $datetime = $record['datetime']; + } + + $messages[] = $record['message']; + $messgeStr = implode(PHP_EOL, $messages); + $formattedMessages[] = $this->getFormatter()->format($record); + $formattedMessageStr = implode('', $formattedMessages); + + $batchRecord = array( + 'message' => $messgeStr, + 'formatted' => $formattedMessageStr, + 'context' => array(), + 'extra' => array(), + ); + + if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) { + // Pop the last message and implode the remainging messages + $lastMessage = array_pop($messages); + $lastFormattedMessage = array_pop($formattedMessages); + $batchRecord['message'] = implode(PHP_EOL, $messages); + $batchRecord['formatted'] = implode('', $formattedMessages); + + $batchRecords[] = $batchRecord; + $messages = array($lastMessage); + $formattedMessages = array($lastFormattedMessage); + + $batchRecord = null; + } + } + + if (null !== $batchRecord) { + $batchRecords[] = $batchRecord; + } + + // Set the max level and datetime for all records + foreach ($batchRecords as &$batchRecord) { + $batchRecord = array_merge( + $batchRecord, + array( + 'level' => $level, + 'level_name' => $levelName, + 'datetime' => $datetime + ) + ); + } + + return $batchRecords; + } + + /** + * Validates the length of a string. + * + * If the `mb_strlen()` function is available, it will use that, as HipChat + * allows UTF-8 characters. Otherwise, it will fall back to `strlen()`. + * + * Note that this might cause false failures in the specific case of using + * a valid name with less than 16 characters, but 16 or more bytes, on a + * system where `mb_strlen()` is unavailable. + * + * @param string $str + * @param int $length + * + * @return bool + */ + private function validateStringLength($str, $length) + { + if (function_exists('mb_strlen')) { + return (mb_strlen($str) <= $length); + } + + return (strlen($str) <= $length); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php new file mode 100644 index 00000000..18b3fa4f --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * @author Robert Kaufmann III + */ +class LogEntriesHandler extends SocketHandler +{ + + /** + * @var string + */ + protected $logToken; + + /** + * @param string $token Log token supplied by LogEntries + * @param boolean $useSSL Whether or not SSL encryption should be used. + * @param int $level The minimum logging level to trigger this handler + * @param boolean $bubble Whether or not messages that are handled should bubble up the stack. + * + * @throws MissingExtensionExcpetion If SSL encryption is set to true and OpenSSL is missing + */ + public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true) + { + if ($useSSL && !extension_loaded('openssl')) { + throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); + } + + $endpoint = $useSSL ? 'ssl://api.logentries.com:20000' : 'data.logentries.com:80'; + parent::__construct($endpoint, $level, $bubble); + $this->logToken = $token; + } + + /** + * {@inheritdoc} + * + * @param array $record + * @return string + */ + protected function generateDataStream($record) + { + return $this->logToken . ' ' . $record['formatted']; + } + +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php new file mode 100644 index 00000000..9a3de6e6 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\LogglyFormatter; + +/** + * Sends errors to Loggly. + * + * @author Przemek Sobstel + * @author Adam Pancutt + */ +class LogglyHandler extends AbstractProcessingHandler +{ + const HOST = 'logs-01.loggly.com'; + const ENDPOINT_SINGLE = 'inputs'; + const ENDPOINT_BATCH = 'bulk'; + + protected $token; + + protected $tag; + + public function __construct($token, $level = Logger::DEBUG, $bubble = true) + { + if (!extension_loaded('curl')) { + throw new \LogicException('The curl extension is needed to use the LogglyHandler'); + } + + $this->token = $token; + + parent::__construct($level, $bubble); + } + + public function setTag($tag) + { + $this->tag = $tag; + } + + protected function write(array $record) + { + $this->send($record["formatted"], self::ENDPOINT_SINGLE); + } + + public function handleBatch(array $records) + { + $level = $this->level; + + $records = array_filter($records, function ($record) use ($level) { + return ($record['level'] >= $level); + }); + + if ($records) { + $this->send($this->getFormatter()->formatBatch($records), self::ENDPOINT_BATCH); + } + } + + protected function send($data, $endpoint) + { + $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token); + + $headers = array('Content-Type: application/json'); + + if ($this->tag) { + $headers[] = "X-LOGGLY-TAG: {$this->tag}"; + } + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + curl_exec($ch); + curl_close($ch); + } + + protected function getDefaultFormatter() + { + return new LogglyFormatter(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php new file mode 100644 index 00000000..86292727 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Base class for all mail handlers + * + * @author Gyula Sallai + */ +abstract class MailHandler extends AbstractProcessingHandler +{ + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $messages = array(); + + foreach ($records as $record) { + if ($record['level'] < $this->level) { + continue; + } + $messages[] = $this->processRecord($record); + } + + if (!empty($messages)) { + $this->send((string) $this->getFormatter()->formatBatch($messages), $messages); + } + } + + /** + * Send a mail with the given content + * + * @param string $content + * @param array $records the array of log records that formed this content + */ + abstract protected function send($content, array $records); + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->send((string) $record['formatted'], array($record)); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php new file mode 100644 index 00000000..0cb21cd2 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Exception can be thrown if an extension for an handler is missing + * + * @author Christian Bergau + */ +class MissingExtensionException extends \Exception +{ + +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php new file mode 100644 index 00000000..6c431f2b --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\NormalizerFormatter; + +/** + * Logs to a MongoDB database. + * + * usage example: + * + * $log = new Logger('application'); + * $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod"); + * $log->pushHandler($mongodb); + * + * @author Thomas Tourlourat + */ +class MongoDBHandler extends AbstractProcessingHandler +{ + protected $mongoCollection; + + public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true) + { + if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { + throw new \InvalidArgumentException('MongoClient or Mongo instance required'); + } + + $this->mongoCollection = $mongo->selectCollection($database, $collection); + + parent::__construct($level, $bubble); + } + + protected function write(array $record) + { + $this->mongoCollection->save($record["formatted"]); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new NormalizerFormatter(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php new file mode 100644 index 00000000..f97df482 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * NativeMailerHandler uses the mail() function to send the emails + * + * @author Christophe Coevoet + * @author Mark Garrett + */ +class NativeMailerHandler extends MailHandler +{ + /** + * The email address to which the message is delivered + * @var string + */ + protected $to; + + /** + * The subject of the email + * @var string + */ + protected $subject; + + /** + * Optional headers for the message + * @var array + */ + protected $headers = array(); + + /** + * The wordwrap length for the message + * @var integer + */ + protected $maxColumnWidth; + + /** + * The Content-type for the message + * @var string + */ + protected $contentType = 'text/plain'; + + /** + * The encoding for the message + * @var string + */ + protected $encoding = 'utf-8'; + + /** + * @param string|array $to The receiver of the mail + * @param string $subject The subject of the mail + * @param string $from The sender of the mail + * @param integer $level The minimum logging level at which this handler will be triggered + * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param int $maxColumnWidth The maximum column width that the message lines will have + */ + public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70) + { + parent::__construct($level, $bubble); + $this->to = is_array($to) ? $to : array($to); + $this->subject = $subject; + $this->addHeader(sprintf('From: %s', $from)); + $this->maxColumnWidth = $maxColumnWidth; + } + + /** + * Add headers to the message + * + * @param string|array $headers Custom added headers + * @return null + */ + public function addHeader($headers) + { + foreach ((array) $headers as $header) { + if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) { + throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons'); + } + $this->headers[] = $header; + } + } + + /** + * {@inheritdoc} + */ + protected function send($content, array $records) + { + $content = wordwrap($content, $this->maxColumnWidth); + $headers = ltrim(implode("\r\n", $this->headers) . "\r\n", "\r\n"); + $headers .= 'Content-type: ' . $this->getContentType() . '; charset=' . $this->getEncoding() . "\r\n"; + if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) { + $headers .= 'MIME-Version: 1.0' . "\r\n"; + } + foreach ($this->to as $to) { + mail($to, $this->subject, $content, $headers); + } + } + + /** + * @return string $contentType + */ + public function getContentType() + { + return $this->contentType; + } + + /** + * @return string $encoding + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML + * messages. + * @return self + */ + public function setContentType($contentType) + { + $this->contentType = $contentType; + + return $this; + } + + /** + * @param string $encoding + * @return self + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + + return $this; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php new file mode 100644 index 00000000..f7055cc1 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Class to record a log on a NewRelic application + * + * @see https://newrelic.com/docs/php/new-relic-for-php + */ +class NewRelicHandler extends AbstractProcessingHandler +{ + /** + * Name of the New Relic application that will receive logs from this handler. + * + * @var string + */ + protected $appName; + + /** + * {@inheritDoc} + * + * @param string $appName + */ + public function __construct($level = Logger::ERROR, $bubble = true, $appName = null) + { + parent::__construct($level, $bubble); + + $this->appName = $appName; + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + if (!$this->isNewRelicEnabled()) { + throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); + } + + if ($appName = $this->getAppName($record['context'])) { + $this->setNewRelicAppName($appName); + } + + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { + newrelic_notice_error($record['message'], $record['context']['exception']); + unset($record['context']['exception']); + } else { + newrelic_notice_error($record['message']); + } + + foreach ($record['context'] as $key => $parameter) { + newrelic_add_custom_parameter($key, $parameter); + } + + foreach ($record['extra'] as $key => $parameter) { + newrelic_add_custom_parameter($key, $parameter); + } + } + + /** + * Checks whether the NewRelic extension is enabled in the system. + * + * @return bool + */ + protected function isNewRelicEnabled() + { + return extension_loaded('newrelic'); + } + + /** + * Returns the appname where this log should be sent. Each log can override the default appname, set in this + * handler's constructor, by providing the appname in its context. + * + * @param array $context + * @return null|string + */ + protected function getAppName(array $context) + { + if (isset($context['appname'])) { + return $context['appname']; + } + + return $this->appName; + } + + /** + * Sets the NewRelic application that should receive this log. + * + * @param string $appName + */ + protected function setNewRelicAppName($appName) + { + newrelic_set_appname($appName); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php new file mode 100644 index 00000000..3754e45d --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Blackhole + * + * Any record it can handle will be thrown away. This can be used + * to put on top of an existing stack to override it temporarily. + * + * @author Jordi Boggiano + */ +class NullHandler extends AbstractHandler +{ + /** + * @param integer $level The minimum logging level at which this handler will be triggered + */ + public function __construct($level = Logger::DEBUG) + { + parent::__construct($level, false); + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($record['level'] < $this->level) { + return false; + } + + return true; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php new file mode 100644 index 00000000..2c80afe7 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Sends notifications through the pushover api to mobile phones + * + * @author Sebastian Göttschkes + * @see https://www.pushover.net/api + */ +class PushoverHandler extends SocketHandler +{ + private $token; + private $users; + private $title; + private $user; + private $retry; + private $expire; + + private $highPriorityLevel; + private $emergencyLevel; + + /** + * Sounds the api supports by default + * @see https://pushover.net/api#sounds + * @var array + */ + private $sounds = array( + 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming', + 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb', + 'persistent', 'echo', 'updown', 'none', + ); + + /** + * @param string $token Pushover api token + * @param string|array $users Pushover user id or array of ids the message will be sent to + * @param string $title Title sent to the Pushover API + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not + * the pushover.net app owner. OpenSSL is required for this option. + * @param integer $highPriorityLevel The minimum logging level at which this handler will start + * sending "high priority" requests to the Pushover API + * @param integer $emergencyLevel The minimum logging level at which this handler will start + * sending "emergency" requests to the Pushover API + * @param integer $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user. + * @param integer $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds). + */ + public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200) + { + $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; + parent::__construct($connectionString, $level, $bubble); + + $this->token = $token; + $this->users = (array) $users; + $this->title = $title ?: gethostname(); + $this->highPriorityLevel = $highPriorityLevel; + $this->emergencyLevel = $emergencyLevel; + $this->retry = $retry; + $this->expire = $expire; + } + + protected function generateDataStream($record) + { + $content = $this->buildContent($record); + + return $this->buildHeader($content) . $content; + } + + private function buildContent($record) + { + // Pushover has a limit of 512 characters on title and message combined. + $maxMessageLength = 512 - strlen($this->title); + $message = substr($record['message'], 0, $maxMessageLength); + $timestamp = $record['datetime']->getTimestamp(); + + $dataArray = array( + 'token' => $this->token, + 'user' => $this->user, + 'message' => $message, + 'title' => $this->title, + 'timestamp' => $timestamp + ); + + if ($record['level'] >= $this->emergencyLevel) { + $dataArray['priority'] = 2; + $dataArray['retry'] = $this->retry; + $dataArray['expire'] = $this->expire; + } elseif ($record['level'] >= $this->highPriorityLevel) { + $dataArray['priority'] = 1; + } + + if (isset($record['context']['sound']) && in_array($record['context']['sound'], $this->sounds)) { + $dataArray['sound'] = $record['context']['sound']; + } elseif (isset($record['extra']['sound']) && in_array($record['extra']['sound'], $this->sounds)) { + $dataArray['sound'] = $record['extra']['sound']; + } + + return http_build_query($dataArray); + } + + private function buildHeader($content) + { + $header = "POST /1/messages.json HTTP/1.1\r\n"; + $header .= "Host: api.pushover.net\r\n"; + $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "\r\n"; + + return $header; + } + + public function write(array $record) + { + foreach ($this->users as $user) { + $this->user = $user; + + parent::write($record); + $this->closeSocket(); + } + + $this->user = null; + } + + public function setHighPriorityLevel($value) + { + $this->highPriorityLevel = $value; + } + + public function setEmergencyLevel($value) + { + $this->emergencyLevel = $value; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php new file mode 100644 index 00000000..2b32c321 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\LineFormatter; +use Monolog\Formatter\FormatterInterface; +use Monolog\Logger; +use Raven_Client; + +/** + * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server + * using raven-php (https://github.com/getsentry/raven-php) + * + * @author Marc Abramowitz + */ +class RavenHandler extends AbstractProcessingHandler +{ + /** + * Translates Monolog log levels to Raven log levels. + */ + private $logLevels = array( + Logger::DEBUG => Raven_Client::DEBUG, + Logger::INFO => Raven_Client::INFO, + Logger::NOTICE => Raven_Client::INFO, + Logger::WARNING => Raven_Client::WARNING, + Logger::ERROR => Raven_Client::ERROR, + Logger::CRITICAL => Raven_Client::FATAL, + Logger::ALERT => Raven_Client::FATAL, + Logger::EMERGENCY => Raven_Client::FATAL, + ); + + /** + * @var Raven_Client the client object that sends the message to the server + */ + protected $ravenClient; + + /** + * @var LineFormatter The formatter to use for the logs generated via handleBatch() + */ + protected $batchFormatter; + + /** + * @param Raven_Client $ravenClient + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + + $this->ravenClient = $ravenClient; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $level = $this->level; + + // filter records based on their level + $records = array_filter($records, function ($record) use ($level) { + return $record['level'] >= $level; + }); + + if (!$records) { + return; + } + + // the record with the highest severity is the "main" one + $record = array_reduce($records, function ($highest, $record) { + if ($record['level'] >= $highest['level']) { + return $record; + } + + return $highest; + }); + + // the other ones are added as a context item + $logs = array(); + foreach ($records as $r) { + $logs[] = $this->processRecord($r); + } + + if ($logs) { + $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs); + } + + $this->handle($record); + } + + /** + * Sets the formatter for the logs generated by handleBatch(). + * + * @param FormatterInterface $formatter + */ + public function setBatchFormatter(FormatterInterface $formatter) + { + $this->batchFormatter = $formatter; + } + + /** + * Gets the formatter for the logs generated by handleBatch(). + * + * @return FormatterInterface + */ + public function getBatchFormatter() + { + if (!$this->batchFormatter) { + $this->batchFormatter = $this->getDefaultBatchFormatter(); + } + + return $this->batchFormatter; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $options = array(); + $options['level'] = $this->logLevels[$record['level']]; + $options['tags'] = array(); + if (!empty($record['extra']['tags'])) { + $options['tags'] = array_merge($options['tags'], $record['extra']['tags']); + unset($record['extra']['tags']); + } + if (!empty($record['context']['tags'])) { + $options['tags'] = array_merge($options['tags'], $record['context']['tags']); + unset($record['context']['tags']); + } + if (!empty($record['context'])) { + $options['extra']['context'] = $record['context']; + } + if (!empty($record['extra'])) { + $options['extra']['extra'] = $record['extra']; + } + + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { + $options['extra']['message'] = $record['formatted']; + $this->ravenClient->captureException($record['context']['exception'], $options); + + return; + } + + $this->ravenClient->captureMessage($record['formatted'], array(), $options); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new LineFormatter('[%channel%] %message%'); + } + + /** + * Gets the default formatter for the logs generated by handleBatch(). + * + * @return FormatterInterface + */ + protected function getDefaultBatchFormatter() + { + return new LineFormatter(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php new file mode 100644 index 00000000..3fc7f34b --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\LineFormatter; + +/** + * Logs to a Redis key using rpush + * + * usage example: + * + * $log = new Logger('application'); + * $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod"); + * $log->pushHandler($redis); + * + * @author Thomas Tourlourat + */ +class RedisHandler extends AbstractProcessingHandler +{ + private $redisClient; + private $redisKey; + + # redis instance, key to use + public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true) + { + if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { + throw new \InvalidArgumentException('Predis\Client or Redis instance required'); + } + + $this->redisClient = $redis; + $this->redisKey = $key; + + parent::__construct($level, $bubble); + } + + protected function write(array $record) + { + $this->redisClient->rpush($this->redisKey, $record["formatted"]); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new LineFormatter(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php new file mode 100644 index 00000000..fb02ad60 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php @@ -0,0 +1,64 @@ + + */ +class RollbarHandler extends AbstractProcessingHandler +{ + /** + * Rollbar notifier + * + * @var RollbarNotifier + */ + protected $rollbarNotifier; + + /** + * @param RollbarNotifier $rollbarNotifier RollbarNotifier object constructed with valid token + * @param integer $level The minimum logging level at which this handler will be triggered + * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(RollbarNotifier $rollbarNotifier, $level = Logger::ERROR, $bubble = true) + { + $this->rollbarNotifier = $rollbarNotifier; + + parent::__construct($level, $bubble); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) { + $this->rollbarNotifier->report_exception($record['context']['exception']); + } else { + $extraData = array( + 'level' => $record['level'], + 'channel' => $record['channel'], + 'datetime' => $record['datetime']->format('U'), + ); + + $this->rollbarNotifier->report_message( + $record['message'], + $record['level_name'], + array_merge($record['context'], $record['extra'], $extraData) + ); + } + } + + /** + * {@inheritdoc} + */ + public function close() + { + $this->rollbarNotifier->flush(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php new file mode 100644 index 00000000..f8800bc8 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Stores logs to files that are rotated every day and a limited number of files are kept. + * + * This rotation is only intended to be used as a workaround. Using logrotate to + * handle the rotation is strongly encouraged when you can use it. + * + * @author Christophe Coevoet + * @author Jordi Boggiano + */ +class RotatingFileHandler extends StreamHandler +{ + protected $filename; + protected $maxFiles; + protected $mustRotate; + protected $nextRotation; + protected $filenameFormat; + protected $dateFormat; + + /** + * @param string $filename + * @param integer $maxFiles The maximal amount of files to keep (0 means unlimited) + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param int $filePermission Optional file permissions (default (0644) are only for owner read/write) + */ + public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null) + { + $this->filename = $filename; + $this->maxFiles = (int) $maxFiles; + $this->nextRotation = new \DateTime('tomorrow'); + $this->filenameFormat = '{filename}-{date}'; + $this->dateFormat = 'Y-m-d'; + + parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission); + } + + /** + * {@inheritdoc} + */ + public function close() + { + parent::close(); + + if (true === $this->mustRotate) { + $this->rotate(); + } + } + + public function setFilenameFormat($filenameFormat, $dateFormat) + { + $this->filenameFormat = $filenameFormat; + $this->dateFormat = $dateFormat; + $this->url = $this->getTimedFilename(); + $this->close(); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + // on the first record written, if the log is new, we should rotate (once per day) + if (null === $this->mustRotate) { + $this->mustRotate = !file_exists($this->url); + } + + if ($this->nextRotation < $record['datetime']) { + $this->mustRotate = true; + $this->close(); + } + + parent::write($record); + } + + /** + * Rotates the files. + */ + protected function rotate() + { + // update filename + $this->url = $this->getTimedFilename(); + $this->nextRotation = new \DateTime('tomorrow'); + + // skip GC of old logs if files are unlimited + if (0 === $this->maxFiles) { + return; + } + + $logFiles = glob($this->getGlobPattern()); + if ($this->maxFiles >= count($logFiles)) { + // no files to remove + return; + } + + // Sorting the files by name to remove the older ones + usort($logFiles, function ($a, $b) { + return strcmp($b, $a); + }); + + foreach (array_slice($logFiles, $this->maxFiles) as $file) { + if (is_writable($file)) { + unlink($file); + } + } + } + + protected function getTimedFilename() + { + $fileInfo = pathinfo($this->filename); + $timedFilename = str_replace( + array('{filename}', '{date}'), + array($fileInfo['filename'], date($this->dateFormat)), + $fileInfo['dirname'] . '/' . $this->filenameFormat + ); + + if (!empty($fileInfo['extension'])) { + $timedFilename .= '.'.$fileInfo['extension']; + } + + return $timedFilename; + } + + protected function getGlobPattern() + { + $fileInfo = pathinfo($this->filename); + $glob = str_replace( + array('{filename}', '{date}'), + array($fileInfo['filename'], '*'), + $fileInfo['dirname'] . '/' . $this->filenameFormat + ); + if (!empty($fileInfo['extension'])) { + $glob .= '.'.$fileInfo['extension']; + } + + return $glob; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php new file mode 100644 index 00000000..4faa327d --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php @@ -0,0 +1,285 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Stores to any socket - uses fsockopen() or pfsockopen(). + * + * @author Pablo de Leon Belloc + * @see http://php.net/manual/en/function.fsockopen.php + */ +class SocketHandler extends AbstractProcessingHandler +{ + private $connectionString; + private $connectionTimeout; + private $resource; + private $timeout = 0; + private $persistent = false; + private $errno; + private $errstr; + + /** + * @param string $connectionString Socket connection string + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + $this->connectionString = $connectionString; + $this->connectionTimeout = (float) ini_get('default_socket_timeout'); + } + + /** + * Connect (if necessary) and write to the socket + * + * @param array $record + * + * @throws \UnexpectedValueException + * @throws \RuntimeException + */ + public function write(array $record) + { + $this->connectIfNotConnected(); + $data = $this->generateDataStream($record); + $this->writeToSocket($data); + } + + /** + * We will not close a PersistentSocket instance so it can be reused in other requests. + */ + public function close() + { + if (!$this->isPersistent()) { + $this->closeSocket(); + } + } + + /** + * Close socket, if open + */ + public function closeSocket() + { + if (is_resource($this->resource)) { + fclose($this->resource); + $this->resource = null; + } + } + + /** + * Set socket connection to nbe persistent. It only has effect before the connection is initiated. + * + * @param type $boolean + */ + public function setPersistent($boolean) + { + $this->persistent = (boolean) $boolean; + } + + /** + * Set connection timeout. Only has effect before we connect. + * + * @param float $seconds + * + * @see http://php.net/manual/en/function.fsockopen.php + */ + public function setConnectionTimeout($seconds) + { + $this->validateTimeout($seconds); + $this->connectionTimeout = (float) $seconds; + } + + /** + * Set write timeout. Only has effect before we connect. + * + * @param float $seconds + * + * @see http://php.net/manual/en/function.stream-set-timeout.php + */ + public function setTimeout($seconds) + { + $this->validateTimeout($seconds); + $this->timeout = (float) $seconds; + } + + /** + * Get current connection string + * + * @return string + */ + public function getConnectionString() + { + return $this->connectionString; + } + + /** + * Get persistent setting + * + * @return boolean + */ + public function isPersistent() + { + return $this->persistent; + } + + /** + * Get current connection timeout setting + * + * @return float + */ + public function getConnectionTimeout() + { + return $this->connectionTimeout; + } + + /** + * Get current in-transfer timeout + * + * @return float + */ + public function getTimeout() + { + return $this->timeout; + } + + /** + * Check to see if the socket is currently available. + * + * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details. + * + * @return boolean + */ + public function isConnected() + { + return is_resource($this->resource) + && !feof($this->resource); // on TCP - other party can close connection. + } + + /** + * Wrapper to allow mocking + */ + protected function pfsockopen() + { + return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); + } + + /** + * Wrapper to allow mocking + */ + protected function fsockopen() + { + return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); + } + + /** + * Wrapper to allow mocking + * + * @see http://php.net/manual/en/function.stream-set-timeout.php + */ + protected function streamSetTimeout() + { + $seconds = floor($this->timeout); + $microseconds = round(($this->timeout - $seconds)*1e6); + + return stream_set_timeout($this->resource, $seconds, $microseconds); + } + + /** + * Wrapper to allow mocking + */ + protected function fwrite($data) + { + return @fwrite($this->resource, $data); + } + + /** + * Wrapper to allow mocking + */ + protected function streamGetMetadata() + { + return stream_get_meta_data($this->resource); + } + + private function validateTimeout($value) + { + $ok = filter_var($value, FILTER_VALIDATE_FLOAT); + if ($ok === false || $value < 0) { + throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)"); + } + } + + private function connectIfNotConnected() + { + if ($this->isConnected()) { + return; + } + $this->connect(); + } + + protected function generateDataStream($record) + { + return (string) $record['formatted']; + } + + private function connect() + { + $this->createSocketResource(); + $this->setSocketTimeout(); + } + + private function createSocketResource() + { + if ($this->isPersistent()) { + $resource = $this->pfsockopen(); + } else { + $resource = $this->fsockopen(); + } + if (!$resource) { + throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)"); + } + $this->resource = $resource; + } + + private function setSocketTimeout() + { + if (!$this->streamSetTimeout()) { + throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()"); + } + } + + private function writeToSocket($data) + { + $length = strlen($data); + $sent = 0; + while ($this->isConnected() && $sent < $length) { + if (0 == $sent) { + $chunk = $this->fwrite($data); + } else { + $chunk = $this->fwrite(substr($data, $sent)); + } + if ($chunk === false) { + throw new \RuntimeException("Could not write to socket"); + } + $sent += $chunk; + $socketInfo = $this->streamGetMetadata(); + if ($socketInfo['timed_out']) { + throw new \RuntimeException("Write timed-out"); + } + } + if (!$this->isConnected() && $sent < $length) { + throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)"); + } + } + +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php new file mode 100644 index 00000000..5c8fc1fc --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Stores to any stream resource + * + * Can be used to store into php://stderr, remote and local files, etc. + * + * @author Jordi Boggiano + */ +class StreamHandler extends AbstractProcessingHandler +{ + protected $stream; + protected $url; + private $errorMessage; + protected $filePermission; + + /** + * @param string $stream + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param int $filePermissions Optional file permissions (default (0644) are only for owner read/write) + */ + public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null) + { + parent::__construct($level, $bubble); + if (is_resource($stream)) { + $this->stream = $stream; + } else { + $this->url = $stream; + } + + $this->filePermission = $filePermission; + } + + /** + * {@inheritdoc} + */ + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->stream = null; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + if (!is_resource($this->stream)) { + if (!$this->url) { + throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); + } + $this->errorMessage = null; + set_error_handler(array($this, 'customErrorHandler')); + $this->stream = fopen($this->url, 'a'); + if ($this->filePermission !== null) { + @chmod($this->url, $this->filePermission); + } + restore_error_handler(); + if (!is_resource($this->stream)) { + $this->stream = null; + throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url)); + } + } + fwrite($this->stream, (string) $record['formatted']); + } + + private function customErrorHandler($code, $msg) + { + $this->errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php new file mode 100644 index 00000000..ca03ccaa --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * SwiftMailerHandler uses Swift_Mailer to send the emails + * + * @author Gyula Sallai + */ +class SwiftMailerHandler extends MailHandler +{ + protected $mailer; + protected $message; + + /** + * @param \Swift_Mailer $mailer The mailer to use + * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true) + { + parent::__construct($level, $bubble); + $this->mailer = $mailer; + if (!$message instanceof \Swift_Message && is_callable($message)) { + $message = call_user_func($message); + } + if (!$message instanceof \Swift_Message) { + throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it'); + } + $this->message = $message; + } + + /** + * {@inheritdoc} + */ + protected function send($content, array $records) + { + $message = clone $this->message; + $message->setBody($content); + + $this->mailer->send($message); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php new file mode 100644 index 00000000..47c73e12 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Logs to syslog service. + * + * usage example: + * + * $log = new Logger('application'); + * $syslog = new SyslogHandler('myfacility', 'local6'); + * $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%"); + * $syslog->setFormatter($formatter); + * $log->pushHandler($syslog); + * + * @author Sven Paulus + */ +class SyslogHandler extends AbstractSyslogHandler +{ + protected $ident; + protected $logopts; + + /** + * @param string $ident + * @param mixed $facility + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID + */ + public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) + { + parent::__construct($facility, $level, $bubble); + + $this->ident = $ident; + $this->logopts = $logopts; + } + + /** + * {@inheritdoc} + */ + public function close() + { + closelog(); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + if (!openlog($this->ident, $this->logopts, $this->facility)) { + throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"'); + } + syslog($this->logLevels[$record['level']], (string) $record['formatted']); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php new file mode 100644 index 00000000..d87ab9d3 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler\SyslogUdp; + +class UdpSocket +{ + const DATAGRAM_MAX_LENGTH = 2048; + + public function __construct($ip, $port = 514) + { + $this->ip = $ip; + $this->port = $port; + $this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + } + + public function write($line, $header = "") + { + $remaining = $line; + while (!is_null($remaining)) { + list($chunk, $remaining) = $this->splitLineIfNessesary($remaining, $header); + $this->send($chunk); + } + } + + public function close() + { + socket_close($this->socket); + } + + protected function send($chunk) + { + socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); + } + + protected function splitLineIfNessesary($line, $header) + { + if ($this->shouldSplitLine($line, $header)) { + $chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header); + $chunk = $header . substr($line, 0, $chunkSize); + $remaining = substr($line, $chunkSize); + } else { + $chunk = $header . $line; + $remaining = null; + } + + return array($chunk, $remaining); + } + + protected function shouldSplitLine($remaining, $header) + { + return strlen($header.$remaining) > self::DATAGRAM_MAX_LENGTH; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php new file mode 100644 index 00000000..4aadffc5 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Handler\SyslogUdp\UdpSocket; + +/** + * A Handler for logging to a remote syslogd server. + * + * @author Jesper Skovgaard Nielsen + */ +class SyslogUdpHandler extends AbstractSyslogHandler +{ + /** + * @param string $host + * @param int $port + * @param mixed $facility + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($facility, $level, $bubble); + + $this->socket = new UdpSocket($host, $port ?: 514); + } + + protected function write(array $record) + { + $lines = $this->splitMessageIntoLines($record['formatted']); + + $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']]); + + foreach ($lines as $line) { + $this->socket->write($line, $header); + } + } + + public function close() + { + $this->socket->close(); + } + + private function splitMessageIntoLines($message) + { + if (is_array($message)) { + $message = implode("\n", $message); + } + + return preg_split('/$\R?^/m', $message); + } + + /** + * Make common syslog header (see rfc5424) + */ + private function makeCommonSyslogHeader($severity) + { + $priority = $severity + $this->facility; + + return "<$priority>: "; + } + + /** + * Inject your own socket, mainly used for testing + */ + public function setSocket($socket) + { + $this->socket = $socket; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php new file mode 100644 index 00000000..085d9e17 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Used for testing purposes. + * + * It records all records and gives you access to them for verification. + * + * @author Jordi Boggiano + */ +class TestHandler extends AbstractProcessingHandler +{ + protected $records = array(); + protected $recordsByLevel = array(); + + public function getRecords() + { + return $this->records; + } + + public function hasEmergency($record) + { + return $this->hasRecord($record, Logger::EMERGENCY); + } + + public function hasAlert($record) + { + return $this->hasRecord($record, Logger::ALERT); + } + + public function hasCritical($record) + { + return $this->hasRecord($record, Logger::CRITICAL); + } + + public function hasError($record) + { + return $this->hasRecord($record, Logger::ERROR); + } + + public function hasWarning($record) + { + return $this->hasRecord($record, Logger::WARNING); + } + + public function hasNotice($record) + { + return $this->hasRecord($record, Logger::NOTICE); + } + + public function hasInfo($record) + { + return $this->hasRecord($record, Logger::INFO); + } + + public function hasDebug($record) + { + return $this->hasRecord($record, Logger::DEBUG); + } + + public function hasEmergencyRecords() + { + return isset($this->recordsByLevel[Logger::EMERGENCY]); + } + + public function hasAlertRecords() + { + return isset($this->recordsByLevel[Logger::ALERT]); + } + + public function hasCriticalRecords() + { + return isset($this->recordsByLevel[Logger::CRITICAL]); + } + + public function hasErrorRecords() + { + return isset($this->recordsByLevel[Logger::ERROR]); + } + + public function hasWarningRecords() + { + return isset($this->recordsByLevel[Logger::WARNING]); + } + + public function hasNoticeRecords() + { + return isset($this->recordsByLevel[Logger::NOTICE]); + } + + public function hasInfoRecords() + { + return isset($this->recordsByLevel[Logger::INFO]); + } + + public function hasDebugRecords() + { + return isset($this->recordsByLevel[Logger::DEBUG]); + } + + protected function hasRecord($record, $level) + { + if (!isset($this->recordsByLevel[$level])) { + return false; + } + + if (is_array($record)) { + $record = $record['message']; + } + + foreach ($this->recordsByLevel[$level] as $rec) { + if ($rec['message'] === $record) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->recordsByLevel[$record['level']][] = $record; + $this->records[] = $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php new file mode 100644 index 00000000..f22cf218 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\NormalizerFormatter; +use Monolog\Logger; + +/** + * Handler sending logs to Zend Monitor + * + * @author Christian Bergau + */ +class ZendMonitorHandler extends AbstractProcessingHandler +{ + /** + * Monolog level / ZendMonitor Custom Event priority map + * + * @var array + */ + protected $levelMap = array( + Logger::DEBUG => 1, + Logger::INFO => 2, + Logger::NOTICE => 3, + Logger::WARNING => 4, + Logger::ERROR => 5, + Logger::CRITICAL => 6, + Logger::ALERT => 7, + Logger::EMERGENCY => 0, + ); + + /** + * Construct + * + * @param int $level + * @param bool $bubble + * @throws MissingExtensionException + */ + public function __construct($level = Logger::DEBUG, $bubble = true) + { + if (!function_exists('zend_monitor_custom_event')) { + throw new MissingExtensionException('You must have Zend Server installed in order to use this handler'); + } + parent::__construct($level, $bubble); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->writeZendMonitorCustomEvent( + $this->levelMap[$record['level']], + $record['message'], + $record['formatted'] + ); + } + + /** + * Write a record to Zend Monitor + * + * @param int $level + * @param string $message + * @param array $formatted + */ + protected function writeZendMonitorCustomEvent($level, $message, $formatted) + { + zend_monitor_custom_event($level, $message, $formatted); + } + + /** + * {@inheritdoc} + */ + public function getDefaultFormatter() + { + return new NormalizerFormatter(); + } + + /** + * Get the level map + * + * @return array + */ + public function getLevelMap() + { + return $this->levelMap; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Logger.php b/src/lib/vendor/monolog/monolog/src/Monolog/Logger.php new file mode 100644 index 00000000..3e3f95ce --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Logger.php @@ -0,0 +1,598 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Monolog\Handler\HandlerInterface; +use Monolog\Handler\StreamHandler; +use Psr\Log\LoggerInterface; +use Psr\Log\InvalidArgumentException; + +/** + * Monolog log channel + * + * It contains a stack of Handlers and a stack of Processors, + * and uses them to store records that are added to it. + * + * @author Jordi Boggiano + */ +class Logger implements LoggerInterface +{ + /** + * Detailed debug information + */ + const DEBUG = 100; + + /** + * Interesting events + * + * Examples: User logs in, SQL logs. + */ + const INFO = 200; + + /** + * Uncommon events + */ + const NOTICE = 250; + + /** + * Exceptional occurrences that are not errors + * + * Examples: Use of deprecated APIs, poor use of an API, + * undesirable things that are not necessarily wrong. + */ + const WARNING = 300; + + /** + * Runtime errors + */ + const ERROR = 400; + + /** + * Critical conditions + * + * Example: Application component unavailable, unexpected exception. + */ + const CRITICAL = 500; + + /** + * Action must be taken immediately + * + * Example: Entire website down, database unavailable, etc. + * This should trigger the SMS alerts and wake you up. + */ + const ALERT = 550; + + /** + * Urgent alert. + */ + const EMERGENCY = 600; + + /** + * Monolog API version + * + * This is only bumped when API breaks are done and should + * follow the major version of the library + * + * @var int + */ + const API = 1; + + /** + * Logging levels from syslog protocol defined in RFC 5424 + * + * @var array $levels Logging levels + */ + protected static $levels = array( + 100 => 'DEBUG', + 200 => 'INFO', + 250 => 'NOTICE', + 300 => 'WARNING', + 400 => 'ERROR', + 500 => 'CRITICAL', + 550 => 'ALERT', + 600 => 'EMERGENCY', + ); + + /** + * @var \DateTimeZone + */ + protected static $timezone; + + /** + * @var string + */ + protected $name; + + /** + * The handler stack + * + * @var HandlerInterface[] + */ + protected $handlers; + + /** + * Processors that will process all log records + * + * To process records of a single handler instead, add the processor on that specific handler + * + * @var callable[] + */ + protected $processors; + + /** + * @param string $name The logging channel + * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. + * @param callable[] $processors Optional array of processors + */ + public function __construct($name, array $handlers = array(), array $processors = array()) + { + $this->name = $name; + $this->handlers = $handlers; + $this->processors = $processors; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Pushes a handler on to the stack. + * + * @param HandlerInterface $handler + */ + public function pushHandler(HandlerInterface $handler) + { + array_unshift($this->handlers, $handler); + } + + /** + * Pops a handler from the stack + * + * @return HandlerInterface + */ + public function popHandler() + { + if (!$this->handlers) { + throw new \LogicException('You tried to pop from an empty handler stack.'); + } + + return array_shift($this->handlers); + } + + /** + * @return HandlerInterface[] + */ + public function getHandlers() + { + return $this->handlers; + } + + /** + * Adds a processor on to the stack. + * + * @param callable $callback + */ + public function pushProcessor($callback) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); + } + array_unshift($this->processors, $callback); + } + + /** + * Removes the processor on top of the stack and returns it. + * + * @return callable + */ + public function popProcessor() + { + if (!$this->processors) { + throw new \LogicException('You tried to pop from an empty processor stack.'); + } + + return array_shift($this->processors); + } + + /** + * @return callable[] + */ + public function getProcessors() + { + return $this->processors; + } + + /** + * Adds a log record. + * + * @param integer $level The logging level + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addRecord($level, $message, array $context = array()) + { + if (!$this->handlers) { + $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG)); + } + + if (!static::$timezone) { + static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC'); + } + + $record = array( + 'message' => (string) $message, + 'context' => $context, + 'level' => $level, + 'level_name' => static::getLevelName($level), + 'channel' => $this->name, + 'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone)->setTimezone(static::$timezone), + 'extra' => array(), + ); + // check if any handler will handle this message + $handlerKey = null; + foreach ($this->handlers as $key => $handler) { + if ($handler->isHandling($record)) { + $handlerKey = $key; + break; + } + } + // none found + if (null === $handlerKey) { + return false; + } + + // found at least one, process message and dispatch it + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + while (isset($this->handlers[$handlerKey]) && + false === $this->handlers[$handlerKey]->handle($record)) { + $handlerKey++; + } + + return true; + } + + /** + * Adds a log record at the DEBUG level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addDebug($message, array $context = array()) + { + return $this->addRecord(static::DEBUG, $message, $context); + } + + /** + * Adds a log record at the INFO level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addInfo($message, array $context = array()) + { + return $this->addRecord(static::INFO, $message, $context); + } + + /** + * Adds a log record at the NOTICE level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addNotice($message, array $context = array()) + { + return $this->addRecord(static::NOTICE, $message, $context); + } + + /** + * Adds a log record at the WARNING level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addWarning($message, array $context = array()) + { + return $this->addRecord(static::WARNING, $message, $context); + } + + /** + * Adds a log record at the ERROR level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addError($message, array $context = array()) + { + return $this->addRecord(static::ERROR, $message, $context); + } + + /** + * Adds a log record at the CRITICAL level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addCritical($message, array $context = array()) + { + return $this->addRecord(static::CRITICAL, $message, $context); + } + + /** + * Adds a log record at the ALERT level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addAlert($message, array $context = array()) + { + return $this->addRecord(static::ALERT, $message, $context); + } + + /** + * Adds a log record at the EMERGENCY level. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addEmergency($message, array $context = array()) + { + return $this->addRecord(static::EMERGENCY, $message, $context); + } + + /** + * Gets all supported logging levels. + * + * @return array Assoc array with human-readable level names => level codes. + */ + public static function getLevels() + { + return array_flip(static::$levels); + } + + /** + * Gets the name of the logging level. + * + * @param integer $level + * @return string + */ + public static function getLevelName($level) + { + if (!isset(static::$levels[$level])) { + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + } + + return static::$levels[$level]; + } + + /** + * Checks whether the Logger has a handler that listens on the given level + * + * @param integer $level + * @return Boolean + */ + public function isHandling($level) + { + $record = array( + 'level' => $level, + ); + + foreach ($this->handlers as $handler) { + if ($handler->isHandling($record)) { + return true; + } + } + + return false; + } + + /** + * Adds a log record at an arbitrary level. + * + * This method allows for compatibility with common interfaces. + * + * @param mixed $level The log level + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function log($level, $message, array $context = array()) + { + if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) { + $level = constant(__CLASS__.'::'.strtoupper($level)); + } + + return $this->addRecord($level, $message, $context); + } + + /** + * Adds a log record at the DEBUG level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function debug($message, array $context = array()) + { + return $this->addRecord(static::DEBUG, $message, $context); + } + + /** + * Adds a log record at the INFO level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function info($message, array $context = array()) + { + return $this->addRecord(static::INFO, $message, $context); + } + + /** + * Adds a log record at the INFO level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function notice($message, array $context = array()) + { + return $this->addRecord(static::NOTICE, $message, $context); + } + + /** + * Adds a log record at the WARNING level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function warn($message, array $context = array()) + { + return $this->addRecord(static::WARNING, $message, $context); + } + + /** + * Adds a log record at the WARNING level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function warning($message, array $context = array()) + { + return $this->addRecord(static::WARNING, $message, $context); + } + + /** + * Adds a log record at the ERROR level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function err($message, array $context = array()) + { + return $this->addRecord(static::ERROR, $message, $context); + } + + /** + * Adds a log record at the ERROR level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function error($message, array $context = array()) + { + return $this->addRecord(static::ERROR, $message, $context); + } + + /** + * Adds a log record at the CRITICAL level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function crit($message, array $context = array()) + { + return $this->addRecord(static::CRITICAL, $message, $context); + } + + /** + * Adds a log record at the CRITICAL level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function critical($message, array $context = array()) + { + return $this->addRecord(static::CRITICAL, $message, $context); + } + + /** + * Adds a log record at the ALERT level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function alert($message, array $context = array()) + { + return $this->addRecord(static::ALERT, $message, $context); + } + + /** + * Adds a log record at the EMERGENCY level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function emerg($message, array $context = array()) + { + return $this->addRecord(static::EMERGENCY, $message, $context); + } + + /** + * Adds a log record at the EMERGENCY level. + * + * This method allows for compatibility with common interfaces. + * + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function emergency($message, array $context = array()) + { + return $this->addRecord(static::EMERGENCY, $message, $context); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php new file mode 100644 index 00000000..96c2abfe --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\Logger; + +/** + * Injects Git branch and Git commit SHA in all records + * + * @author Nick Otter + * @author Jordi Boggiano + */ +class GitProcessor +{ + private $level; + private static $cache; + + public function __construct($level = Logger::DEBUG) + { + $this->level = $level; + } + + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + // return if the level is not high enough + if ($record['level'] < $this->level) { + return $record; + } + + $record['extra']['git'] = self::getGitInfo(); + + return $record; + } + + private static function getGitInfo() + { + if (self::$cache) { + return self::$cache; + } + + $branches = `git branch -v --no-abbrev`; + if (preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) { + return self::$cache = array( + 'branch' => $matches[1], + 'commit' => $matches[2], + ); + } + + return self::$cache = array(); + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php new file mode 100644 index 00000000..a2c48ce6 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\Logger; + +/** + * Injects line/file:class/function where the log message came from + * + * Warning: This only works if the handler processes the logs directly. + * If you put the processor on a handler that is behind a FingersCrossedHandler + * for example, the processor will only be called once the trigger level is reached, + * and all the log records will have the same file/line/.. data from the call that + * triggered the FingersCrossedHandler. + * + * @author Jordi Boggiano + */ +class IntrospectionProcessor +{ + private $level; + + private $skipClassesPartials; + + public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array('Monolog\\')) + { + $this->level = $level; + $this->skipClassesPartials = $skipClassesPartials; + } + + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + // return if the level is not high enough + if ($record['level'] < $this->level) { + return $record; + } + + $trace = debug_backtrace(); + + // skip first since it's always the current method + array_shift($trace); + // the call_user_func call is also skipped + array_shift($trace); + + $i = 0; + + while (isset($trace[$i]['class'])) { + foreach ($this->skipClassesPartials as $part) { + if (strpos($trace[$i]['class'], $part) !== false) { + $i++; + continue 2; + } + } + break; + } + + // we should have the call source now + $record['extra'] = array_merge( + $record['extra'], + array( + 'file' => isset($trace[$i-1]['file']) ? $trace[$i-1]['file'] : null, + 'line' => isset($trace[$i-1]['line']) ? $trace[$i-1]['line'] : null, + 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null, + 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null, + ) + ); + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php new file mode 100644 index 00000000..552fd709 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Injects memory_get_peak_usage in all records + * + * @see Monolog\Processor\MemoryProcessor::__construct() for options + * @author Rob Jensen + */ +class MemoryPeakUsageProcessor extends MemoryProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + $bytes = memory_get_peak_usage($this->realUsage); + $formatted = $this->formatBytes($bytes); + + $record['extra'] = array_merge( + $record['extra'], + array( + 'memory_peak_usage' => $formatted, + ) + ); + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php new file mode 100644 index 00000000..7e53f470 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Some methods that are common for all memory processors + * + * @author Rob Jensen + */ +abstract class MemoryProcessor +{ + /** + * @var boolean If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported. + */ + protected $realUsage; + + /** + * @var boolean If true, then format memory size to human readable string (MB, KB, B depending on size) + */ + protected $useFormatting; + + /** + * @param boolean $realUsage Set this to true to get the real size of memory allocated from system. + * @param boolean $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size) + */ + public function __construct($realUsage = true, $useFormatting = true) + { + $this->realUsage = (boolean) $realUsage; + $this->useFormatting = (boolean) $useFormatting; + } + + /** + * Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is + * + * @param int $bytes + * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as is + */ + protected function formatBytes($bytes) + { + $bytes = (int) $bytes; + + if (!$this->useFormatting) { + return $bytes; + } + + if ($bytes > 1024*1024) { + return round($bytes/1024/1024, 2).' MB'; + } elseif ($bytes > 1024) { + return round($bytes/1024, 2).' KB'; + } + + return $bytes . ' B'; + } + +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php new file mode 100644 index 00000000..0c4dd9ab --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Injects memory_get_usage in all records + * + * @see Monolog\Processor\MemoryProcessor::__construct() for options + * @author Rob Jensen + */ +class MemoryUsageProcessor extends MemoryProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + $bytes = memory_get_usage($this->realUsage); + $formatted = $this->formatBytes($bytes); + + $record['extra'] = array_merge( + $record['extra'], + array( + 'memory_usage' => $formatted, + ) + ); + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php new file mode 100644 index 00000000..9d3f5590 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Adds value of getmypid into records + * + * @author Andreas Hörnicke + */ +class ProcessIdProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + $record['extra']['process_id'] = getmypid(); + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php new file mode 100644 index 00000000..b63fcccc --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Processes a record's message according to PSR-3 rules + * + * It replaces {foo} with the value from $context['foo'] + * + * @author Jordi Boggiano + */ +class PsrLogMessageProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + if (false === strpos($record['message'], '{')) { + return $record; + } + + $replacements = array(); + foreach ($record['context'] as $key => $val) { + $replacements['{'.$key.'}'] = $val; + } + + $record['message'] = strtr($record['message'], $replacements); + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php new file mode 100644 index 00000000..2784cef4 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Adds a tags array into record + * + * @author Martijn Riemers + */ +class TagProcessor +{ + private $tags; + + public function __construct(array $tags = array()) + { + $this->tags = $tags; + } + + public function __invoke(array $record) + { + $record['extra']['tags'] = $this->tags; + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php new file mode 100644 index 00000000..80270d08 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Adds a unique identifier into records + * + * @author Simon Mönch + */ +class UidProcessor +{ + private $uid; + + public function __construct($length = 7) + { + if (!is_int($length) || $length > 32 || $length < 1) { + throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); + } + + $this->uid = substr(hash('md5', uniqid('', true)), 0, $length); + } + + public function __invoke(array $record) + { + $record['extra']['uid'] = $this->uid; + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php new file mode 100644 index 00000000..4c2bc191 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Injects url/method and remote IP of the current web request in all records + * + * @author Jordi Boggiano + */ +class WebProcessor +{ + protected $serverData; + + /** + * @param mixed $serverData array or object w/ ArrayAccess that provides access to the $_SERVER data + */ + public function __construct($serverData = null) + { + if (null === $serverData) { + $this->serverData =& $_SERVER; + } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) { + $this->serverData = $serverData; + } else { + throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); + } + } + + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + // skip processing if for some reason request data + // is not present (CLI or wonky SAPIs) + if (!isset($this->serverData['REQUEST_URI'])) { + return $record; + } + + $record['extra'] = array_merge( + $record['extra'], + array( + 'url' => $this->serverData['REQUEST_URI'], + 'ip' => isset($this->serverData['REMOTE_ADDR']) ? $this->serverData['REMOTE_ADDR'] : null, + 'http_method' => isset($this->serverData['REQUEST_METHOD']) ? $this->serverData['REQUEST_METHOD'] : null, + 'server' => isset($this->serverData['SERVER_NAME']) ? $this->serverData['SERVER_NAME'] : null, + 'referrer' => isset($this->serverData['HTTP_REFERER']) ? $this->serverData['HTTP_REFERER'] : null, + ) + ); + + if (isset($this->serverData['UNIQUE_ID'])) { + $record['extra']['unique_id'] = $this->serverData['UNIQUE_ID']; + } + + return $record; + } +} diff --git a/src/lib/vendor/monolog/monolog/src/Monolog/Registry.php b/src/lib/vendor/monolog/monolog/src/Monolog/Registry.php new file mode 100644 index 00000000..a3eba079 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/src/Monolog/Registry.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use InvalidArgumentException; + +/** + * Monolog log registry + * + * Allows to get `Logger` instances in the global scope + * via static method calls on this class. + * + * + * $application = new Monolog\Logger('application'); + * $api = new Monolog\Logger('api'); + * + * Monolog\Registry::addLogger($application); + * Monolog\Registry::addLogger($api); + * + * function testLogger() + * { + * Monolog\Registry::api()->addError('Sent to $api Logger instance'); + * Monolog\Registry::application()->addError('Sent to $application Logger instance'); + * } + * + * + * @author Tomas Tatarko + */ +class Registry +{ + /** + * List of all loggers in the registry (ba named indexes) + * + * @var Logger[] + */ + private static $loggers = array(); + + /** + * Adds new logging channel to the registry + * + * @param Logger $logger Instance of the logging channel + * @param string|null $name Name of the logging channel ($logger->getName() by default) + * @param boolean $overwrite Overwrite instance in the registry if the given name already exists? + * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists + */ + public static function addLogger(Logger $logger, $name = null, $overwrite = false) + { + $name = $name ?: $logger->getName(); + + if (isset(self::$loggers[$name]) && !$overwrite) { + throw new InvalidArgumentException('Logger with the given name already exists'); + } + + self::$loggers[$name] = $logger; + } + + /** + * Removes instance from registry by name or instance + * + * @param string|Logger $logger Name or logger instance + */ + public static function removeLogger($logger) + { + if ($logger instanceof Logger) { + if (false !== ($idx = array_search($logger, self::$loggers, true))) { + unset(self::$loggers[$idx]); + } + } else { + unset(self::$loggers[$logger]); + } + } + + /** + * Clears the registry + */ + public static function clear() + { + self::$loggers = array(); + } + + /** + * Gets Logger instance from the registry + * + * @param string $name Name of the requested Logger instance + * @return Logger Requested instance of Logger + * @throws \InvalidArgumentException If named Logger instance is not in the registry + */ + public static function getInstance($name) + { + if (!isset(self::$loggers[$name])) { + throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name)); + } + + return self::$loggers[$name]; + } + + /** + * Gets Logger instance from the registry via static method call + * + * @param string $name Name of the requested Logger instance + * @param array $arguments Arguments passed to static method call + * @return Logger Requested instance of Logger + * @throws \InvalidArgumentException If named Logger instance is not in the registry + */ + public static function __callStatic($name, $arguments) + { + return self::getInstance($name); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php new file mode 100644 index 00000000..a9a3f301 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Monolog\Handler\TestHandler; + +class ErrorHandlerTest extends \PHPUnit_Framework_TestCase +{ + public function testHandleError() + { + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new ErrorHandler($logger); + + $errHandler->registerErrorHandler(array(E_USER_NOTICE => Logger::EMERGENCY), false); + trigger_error('Foo', E_USER_ERROR); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasErrorRecords()); + trigger_error('Foo', E_USER_NOTICE); + $this->assertCount(2, $handler->getRecords()); + $this->assertTrue($handler->hasEmergencyRecords()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php new file mode 100644 index 00000000..e7f7334e --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers Monolog\Formatter\ChromePHPFormatter::format + */ + public function testDefaultFormat() + { + $formatter = new ChromePHPFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('ip' => '127.0.0.1'), + 'message' => 'log', + ); + + $message = $formatter->format($record); + + $this->assertEquals( + array( + 'meh', + array( + 'message' => 'log', + 'context' => array('from' => 'logger'), + 'extra' => array('ip' => '127.0.0.1'), + ), + 'unknown', + 'error' + ), + $message + ); + } + + /** + * @covers Monolog\Formatter\ChromePHPFormatter::format + */ + public function testFormatWithFileAndLine() + { + $formatter = new ChromePHPFormatter(); + $record = array( + 'level' => Logger::CRITICAL, + 'level_name' => 'CRITICAL', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14), + 'message' => 'log', + ); + + $message = $formatter->format($record); + + $this->assertEquals( + array( + 'meh', + array( + 'message' => 'log', + 'context' => array('from' => 'logger'), + 'extra' => array('ip' => '127.0.0.1'), + ), + 'test : 14', + 'error' + ), + $message + ); + } + + /** + * @covers Monolog\Formatter\ChromePHPFormatter::format + */ + public function testFormatWithoutContext() + { + $formatter = new ChromePHPFormatter(); + $record = array( + 'level' => Logger::DEBUG, + 'level_name' => 'DEBUG', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + $message = $formatter->format($record); + + $this->assertEquals( + array( + 'meh', + 'log', + 'unknown', + 'log' + ), + $message + ); + } + + /** + * @covers Monolog\Formatter\ChromePHPFormatter::formatBatch + */ + public function testBatchFormatThrowException() + { + $formatter = new ChromePHPFormatter(); + $records = array( + array( + 'level' => Logger::INFO, + 'level_name' => 'INFO', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ), + array( + 'level' => Logger::WARNING, + 'level_name' => 'WARNING', + 'channel' => 'foo', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log2', + ), + ); + + $this->assertEquals( + array( + array( + 'meh', + 'log', + 'unknown', + 'info' + ), + array( + 'foo', + 'log2', + 'unknown', + 'warn' + ), + ), + $formatter->formatBatch($records) + ); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php new file mode 100644 index 00000000..546e5c26 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +class ElasticaFormatterTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!class_exists("Elastica\Document")) { + $this->markTestSkipped("ruflin/elastica not installed"); + } + } + + /** + * @covers Monolog\Formatter\ElasticaFormatter::__construct + * @covers Monolog\Formatter\ElasticaFormatter::format + * @covers Monolog\Formatter\ElasticaFormatter::getDocument + */ + public function testFormat() + { + // test log message + $msg = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + // expected values + $expected = $msg; + $expected['datetime'] = '1970-01-01T00:00:00+0000'; + $expected['context'] = array( + 'class' => '[object] (stdClass: {})', + 'foo' => 7, + 0 => 'bar', + ); + + // format log message + $formatter = new ElasticaFormatter('my_index', 'doc_type'); + $doc = $formatter->format($msg); + $this->assertInstanceOf('Elastica\Document', $doc); + + // Document parameters + $params = $doc->getParams(); + $this->assertEquals('my_index', $params['_index']); + $this->assertEquals('doc_type', $params['_type']); + + // Document data values + $data = $doc->getData(); + foreach (array_keys($expected) as $key) { + $this->assertEquals($expected[$key], $data[$key]); + } + } + + /** + * @covers Monolog\Formatter\ElasticaFormatter::getIndex + * @covers Monolog\Formatter\ElasticaFormatter::getType + */ + public function testGetters() + { + $formatter = new ElasticaFormatter('my_index', 'doc_type'); + $this->assertEquals('my_index', $formatter->getIndex()); + $this->assertEquals('doc_type', $formatter->getType()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php new file mode 100644 index 00000000..1b2fd97a --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; +use Monolog\TestCase; + +class FlowdockFormatterTest extends TestCase +{ + /** + * @covers Monolog\Formatter\FlowdockFormatter::format + */ + public function testFormat() + { + $formatter = new FlowdockFormatter('test_source', 'source@test.com'); + $record = $this->getRecord(); + + $expected = array( + 'source' => 'test_source', + 'from_address' => 'source@test.com', + 'subject' => 'in test_source: WARNING - test', + 'content' => 'test', + 'tags' => array('#logs', '#warning', '#test'), + 'project' => 'test_source', + ); + $formatted = $formatter->format($record); + + $this->assertEquals($expected, $formatted['flowdock']); + } + + /** + * @ covers Monolog\Formatter\FlowdockFormatter::formatBatch + */ + public function testFormatBatch() + { + $formatter = new FlowdockFormatter('test_source', 'source@test.com'); + $records = array( + $this->getRecord(Logger::WARNING), + $this->getRecord(Logger::DEBUG), + ); + $formatted = $formatter->formatBatch($records); + + $this->assertArrayHasKey('flowdock', $formatted[0]); + $this->assertArrayHasKey('flowdock', $formatted[1]); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php new file mode 100644 index 00000000..d47ba91c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!class_exists('\Gelf\Message')) { + $this->markTestSkipped("graylog2/gelf-php or mlehner/gelf-php is not installed"); + } + } + + /** + * @covers Monolog\Formatter\GelfMessageFormatter::format + */ + public function testDefaultFormatter() + { + $formatter = new GelfMessageFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + $this->assertEquals(0, $message->getTimestamp()); + $this->assertEquals('log', $message->getShortMessage()); + $this->assertEquals('meh', $message->getFacility()); + $this->assertEquals(null, $message->getLine()); + $this->assertEquals(null, $message->getFile()); + $this->assertEquals($this->isLegacy() ? 3 : 'error', $message->getLevel()); + $this->assertNotEmpty($message->getHost()); + + $formatter = new GelfMessageFormatter('mysystem'); + + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + $this->assertEquals('mysystem', $message->getHost()); + } + + /** + * @covers Monolog\Formatter\GelfMessageFormatter::format + */ + public function testFormatWithFileAndLine() + { + $formatter = new GelfMessageFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('file' => 'test', 'line' => 14), + 'message' => 'log', + ); + + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + $this->assertEquals('test', $message->getFile()); + $this->assertEquals(14, $message->getLine()); + } + + /** + * @covers Monolog\Formatter\GelfMessageFormatter::format + */ + public function testFormatWithContext() + { + $formatter = new GelfMessageFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + + $message_array = $message->toArray(); + + $this->assertArrayHasKey('_ctxt_from', $message_array); + $this->assertEquals('logger', $message_array['_ctxt_from']); + + // Test with extraPrefix + $formatter = new GelfMessageFormatter(null, null, 'CTX'); + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + + $message_array = $message->toArray(); + + $this->assertArrayHasKey('_CTXfrom', $message_array); + $this->assertEquals('logger', $message_array['_CTXfrom']); + + } + + /** + * @covers Monolog\Formatter\GelfMessageFormatter::format + */ + public function testFormatWithContextContainingException() + { + $formatter = new GelfMessageFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger', 'exception' => array( + 'class' => '\Exception', + 'file' => '/some/file/in/dir.php:56', + 'trace' => array('/some/file/1.php:23', '/some/file/2.php:3') + )), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log' + ); + + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + + $this->assertEquals("/some/file/in/dir.php", $message->getFile()); + $this->assertEquals("56", $message->getLine()); + + } + + /** + * @covers Monolog\Formatter\GelfMessageFormatter::format + */ + public function testFormatWithExtra() + { + $formatter = new GelfMessageFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + + $message_array = $message->toArray(); + + $this->assertArrayHasKey('_key', $message_array); + $this->assertEquals('pair', $message_array['_key']); + + // Test with extraPrefix + $formatter = new GelfMessageFormatter(null, 'EXT'); + $message = $formatter->format($record); + + $this->assertInstanceOf('Gelf\Message', $message); + + $message_array = $message->toArray(); + + $this->assertArrayHasKey('_EXTkey', $message_array); + $this->assertEquals('pair', $message_array['_EXTkey']); + } + + private function isLegacy() + { + return interface_exists('\Gelf\IMessagePublisher'); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php new file mode 100644 index 00000000..d18c4763 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; +use Monolog\TestCase; + +class JsonFormatterTest extends TestCase +{ + /** + * @covers Monolog\Formatter\JsonFormatter::__construct + * @covers Monolog\Formatter\JsonFormatter::getBatchMode + * @covers Monolog\Formatter\JsonFormatter::isAppendingNewlines + */ + public function testConstruct() + { + $formatter = new JsonFormatter(); + $this->assertEquals(JsonFormatter::BATCH_MODE_JSON, $formatter->getBatchMode()); + $this->assertEquals(true, $formatter->isAppendingNewlines()); + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES, false); + $this->assertEquals(JsonFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode()); + $this->assertEquals(false, $formatter->isAppendingNewlines()); + } + + /** + * @covers Monolog\Formatter\JsonFormatter::format + */ + public function testFormat() + { + $formatter = new JsonFormatter(); + $record = $this->getRecord(); + $this->assertEquals(json_encode($record)."\n", $formatter->format($record)); + + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); + $record = $this->getRecord(); + $this->assertEquals(json_encode($record), $formatter->format($record)); + } + + /** + * @covers Monolog\Formatter\JsonFormatter::formatBatch + * @covers Monolog\Formatter\JsonFormatter::formatBatchJson + */ + public function testFormatBatch() + { + $formatter = new JsonFormatter(); + $records = array( + $this->getRecord(Logger::WARNING), + $this->getRecord(Logger::DEBUG), + ); + $this->assertEquals(json_encode($records), $formatter->formatBatch($records)); + } + + /** + * @covers Monolog\Formatter\JsonFormatter::formatBatch + * @covers Monolog\Formatter\JsonFormatter::formatBatchNewlines + */ + public function testFormatBatchNewlines() + { + + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES); + $records = $expected = array( + $this->getRecord(Logger::WARNING), + $this->getRecord(Logger::DEBUG), + ); + array_walk($expected, function (&$value, $key) { + $value = json_encode($value); + }); + $this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records)); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php new file mode 100644 index 00000000..096e5644 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php @@ -0,0 +1,194 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * @covers Monolog\Formatter\LineFormatter + */ +class LineFormatterTest extends \PHPUnit_Framework_TestCase +{ + public function testDefFormatWithString() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->format(array( + 'level_name' => 'WARNING', + 'channel' => 'log', + 'context' => array(), + 'message' => 'foo', + 'datetime' => new \DateTime, + 'extra' => array(), + )); + $this->assertEquals('['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message); + } + + public function testDefFormatWithArrayContext() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->format(array( + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'message' => 'foo', + 'datetime' => new \DateTime, + 'extra' => array(), + 'context' => array( + 'foo' => 'bar', + 'baz' => 'qux', + 'bool' => false, + 'null' => null, + ) + )); + $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foo {"foo":"bar","baz":"qux","bool":false,"null":null} []'."\n", $message); + } + + public function testDefFormatExtras() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->format(array( + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime, + 'extra' => array('ip' => '127.0.0.1'), + 'message' => 'log', + )); + $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] {"ip":"127.0.0.1"}'."\n", $message); + } + + public function testFormatExtras() + { + $formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context% %extra.file% %extra%\n", 'Y-m-d'); + $message = $formatter->format(array( + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime, + 'extra' => array('ip' => '127.0.0.1', 'file' => 'test'), + 'message' => 'log', + )); + $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] test {"ip":"127.0.0.1"}'."\n", $message); + } + + public function testDefFormatWithObject() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->format(array( + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime, + 'extra' => array('foo' => new TestFoo, 'bar' => new TestBar, 'baz' => array(), 'res' => fopen('php://memory', 'rb')), + 'message' => 'foobar', + )); + + $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foobar [] {"foo":"[object] (Monolog\\\\Formatter\\\\TestFoo: {\\"foo\\":\\"foo\\"})","bar":"[object] (Monolog\\\\Formatter\\\\TestBar: {})","baz":[],"res":"[resource]"}'."\n", $message); + } + + public function testDefFormatWithException() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->format(array( + 'level_name' => 'CRITICAL', + 'channel' => 'core', + 'context' => array('exception' => new \RuntimeException('Foo')), + 'datetime' => new \DateTime, + 'extra' => array(), + 'message' => 'foobar', + )); + + $path = str_replace('\\/', '/', json_encode(__FILE__)); + + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException: Foo at '.substr($path, 1, -1).':'.(__LINE__-8).')"} []'."\n", $message); + } + + public function testDefFormatWithPreviousException() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $previous = new \LogicException('Wut?'); + $message = $formatter->format(array( + 'level_name' => 'CRITICAL', + 'channel' => 'core', + 'context' => array('exception' => new \RuntimeException('Foo', 0, $previous)), + 'datetime' => new \DateTime, + 'extra' => array(), + 'message' => 'foobar', + )); + + $path = str_replace('\\/', '/', json_encode(__FILE__)); + + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException: Foo at '.substr($path, 1, -1).':'.(__LINE__-8).', LogicException: Wut? at '.substr($path, 1, -1).':'.(__LINE__-12).')"} []'."\n", $message); + } + + public function testBatchFormat() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->formatBatch(array( + array( + 'level_name' => 'CRITICAL', + 'channel' => 'test', + 'message' => 'bar', + 'context' => array(), + 'datetime' => new \DateTime, + 'extra' => array(), + ), + array( + 'level_name' => 'WARNING', + 'channel' => 'log', + 'message' => 'foo', + 'context' => array(), + 'datetime' => new \DateTime, + 'extra' => array(), + ), + )); + $this->assertEquals('['.date('Y-m-d').'] test.CRITICAL: bar [] []'."\n".'['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message); + } + + public function testFormatShouldStripInlineLineBreaks() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->format( + array( + 'message' => "foo\nbar", + 'context' => array(), + 'extra' => array(), + ) + ); + + $this->assertRegExp('/foo bar/', $message); + } + + public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet() + { + $formatter = new LineFormatter(null, 'Y-m-d', true); + $message = $formatter->format( + array( + 'message' => "foo\nbar", + 'context' => array(), + 'extra' => array(), + ) + ); + + $this->assertRegExp('/foo\nbar/', $message); + } +} + +class TestFoo +{ + public $foo = 'foo'; +} + +class TestBar +{ + public function __toString() + { + return 'bar'; + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php new file mode 100644 index 00000000..6d59b3f3 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\TestCase; + +class LogglyFormatterTest extends TestCase +{ + /** + * @covers Monolog\Formatter\LogglyFormatter::__construct + */ + public function testConstruct() + { + $formatter = new LogglyFormatter(); + $this->assertEquals(LogglyFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode()); + $formatter = new LogglyFormatter(LogglyFormatter::BATCH_MODE_JSON); + $this->assertEquals(LogglyFormatter::BATCH_MODE_JSON, $formatter->getBatchMode()); + } + + /** + * @covers Monolog\Formatter\LogglyFormatter::format + */ + public function testFormat() + { + $formatter = new LogglyFormatter(); + $record = $this->getRecord(); + $formatted_decoded = json_decode($formatter->format($record), true); + $this->assertArrayHasKey("timestamp", $formatted_decoded); + $this->assertEquals(new \DateTime($formatted_decoded["timestamp"]), $record["datetime"]); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php new file mode 100644 index 00000000..5776ab72 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php @@ -0,0 +1,292 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +class LogstashFormatterTest extends \PHPUnit_Framework_TestCase +{ + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testDefaultFormatter() + { + $formatter = new LogstashFormatter('test', 'hostname'); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']); + $this->assertEquals('log', $message['@message']); + $this->assertEquals('meh', $message['@fields']['channel']); + $this->assertContains('meh', $message['@tags']); + $this->assertEquals(Logger::ERROR, $message['@fields']['level']); + $this->assertEquals('test', $message['@type']); + $this->assertEquals('hostname', $message['@source']); + + $formatter = new LogstashFormatter('mysystem'); + + $message = json_decode($formatter->format($record), true); + + $this->assertEquals('mysystem', $message['@type']); + } + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testFormatWithFileAndLine() + { + $formatter = new LogstashFormatter('test'); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('file' => 'test', 'line' => 14), + 'message' => 'log', + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertEquals('test', $message['@fields']['file']); + $this->assertEquals(14, $message['@fields']['line']); + } + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testFormatWithContext() + { + $formatter = new LogstashFormatter('test'); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = json_decode($formatter->format($record), true); + + $message_array = $message['@fields']; + + $this->assertArrayHasKey('ctxt_from', $message_array); + $this->assertEquals('logger', $message_array['ctxt_from']); + + // Test with extraPrefix + $formatter = new LogstashFormatter('test', null, null, 'CTX'); + $message = json_decode($formatter->format($record), true); + + $message_array = $message['@fields']; + + $this->assertArrayHasKey('CTXfrom', $message_array); + $this->assertEquals('logger', $message_array['CTXfrom']); + + } + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testFormatWithExtra() + { + $formatter = new LogstashFormatter('test'); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = json_decode($formatter->format($record), true); + + $message_array = $message['@fields']; + + $this->assertArrayHasKey('key', $message_array); + $this->assertEquals('pair', $message_array['key']); + + // Test with extraPrefix + $formatter = new LogstashFormatter('test', null, 'EXT'); + $message = json_decode($formatter->format($record), true); + + $message_array = $message['@fields']; + + $this->assertArrayHasKey('EXTkey', $message_array); + $this->assertEquals('pair', $message_array['EXTkey']); + } + + public function testFormatWithApplicationName() + { + $formatter = new LogstashFormatter('app', 'test'); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertArrayHasKey('@type', $message); + $this->assertEquals('app', $message['@type']); + } + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testDefaultFormatterV1() + { + $formatter = new LogstashFormatter('test', 'hostname', null, 'ctxt_', LogstashFormatter::V1); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']); + $this->assertEquals("1", $message['@version']); + $this->assertEquals('log', $message['message']); + $this->assertEquals('meh', $message['channel']); + $this->assertEquals('ERROR', $message['level']); + $this->assertEquals('test', $message['type']); + $this->assertEquals('hostname', $message['host']); + + $formatter = new LogstashFormatter('mysystem', null, null, 'ctxt_', LogstashFormatter::V1); + + $message = json_decode($formatter->format($record), true); + + $this->assertEquals('mysystem', $message['type']); + } + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testFormatWithFileAndLineV1() + { + $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('file' => 'test', 'line' => 14), + 'message' => 'log', + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertEquals('test', $message['file']); + $this->assertEquals(14, $message['line']); + } + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testFormatWithContextV1() + { + $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertArrayHasKey('ctxt_from', $message); + $this->assertEquals('logger', $message['ctxt_from']); + + // Test with extraPrefix + $formatter = new LogstashFormatter('test', null, null, 'CTX', LogstashFormatter::V1); + $message = json_decode($formatter->format($record), true); + + $this->assertArrayHasKey('CTXfrom', $message); + $this->assertEquals('logger', $message['CTXfrom']); + + } + + /** + * @covers Monolog\Formatter\LogstashFormatter::format + */ + public function testFormatWithExtraV1() + { + $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertArrayHasKey('key', $message); + $this->assertEquals('pair', $message['key']); + + // Test with extraPrefix + $formatter = new LogstashFormatter('test', null, 'EXT', 'ctxt_', LogstashFormatter::V1); + $message = json_decode($formatter->format($record), true); + + $this->assertArrayHasKey('EXTkey', $message); + $this->assertEquals('pair', $message['EXTkey']); + } + + public function testFormatWithApplicationNameV1() + { + $formatter = new LogstashFormatter('app', 'test', null, 'ctxt_', LogstashFormatter::V1); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => 'pair'), + 'message' => 'log' + ); + + $message = json_decode($formatter->format($record), true); + + $this->assertArrayHasKey('type', $message); + $this->assertEquals('app', $message['type']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php new file mode 100644 index 00000000..74778712 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -0,0 +1,182 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * @covers Monolog\Formatter\NormalizerFormatter + */ +class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase +{ + public function testFormat() + { + $formatter = new NormalizerFormatter('Y-m-d'); + $formatted = $formatter->format(array( + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'message' => 'foo', + 'datetime' => new \DateTime, + 'extra' => array('foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => array(), 'res' => fopen('php://memory', 'rb')), + 'context' => array( + 'foo' => 'bar', + 'baz' => 'qux', + ), + )); + + $this->assertEquals(array( + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'message' => 'foo', + 'datetime' => date('Y-m-d'), + 'extra' => array( + 'foo' => '[object] (Monolog\\Formatter\\TestFooNorm: {"foo":"foo"})', + 'bar' => '[object] (Monolog\\Formatter\\TestBarNorm: {})', + 'baz' => array(), + 'res' => '[resource]', + ), + 'context' => array( + 'foo' => 'bar', + 'baz' => 'qux', + ) + ), $formatted); + } + + public function testFormatExceptions() + { + $formatter = new NormalizerFormatter('Y-m-d'); + $e = new \LogicException('bar'); + $e2 = new \RuntimeException('foo', 0, $e); + $formatted = $formatter->format(array( + 'exception' => $e2, + )); + + $this->assertGreaterThan(5, count($formatted['exception']['trace'])); + $this->assertTrue(isset($formatted['exception']['previous'])); + unset($formatted['exception']['trace'], $formatted['exception']['previous']); + + $this->assertEquals(array( + 'exception' => array( + 'class' => get_class($e2), + 'message' => $e2->getMessage(), + 'file' => $e2->getFile().':'.$e2->getLine(), + ) + ), $formatted); + } + + public function testBatchFormat() + { + $formatter = new NormalizerFormatter('Y-m-d'); + $formatted = $formatter->formatBatch(array( + array( + 'level_name' => 'CRITICAL', + 'channel' => 'test', + 'message' => 'bar', + 'context' => array(), + 'datetime' => new \DateTime, + 'extra' => array(), + ), + array( + 'level_name' => 'WARNING', + 'channel' => 'log', + 'message' => 'foo', + 'context' => array(), + 'datetime' => new \DateTime, + 'extra' => array(), + ), + )); + $this->assertEquals(array( + array( + 'level_name' => 'CRITICAL', + 'channel' => 'test', + 'message' => 'bar', + 'context' => array(), + 'datetime' => date('Y-m-d'), + 'extra' => array(), + ), + array( + 'level_name' => 'WARNING', + 'channel' => 'log', + 'message' => 'foo', + 'context' => array(), + 'datetime' => date('Y-m-d'), + 'extra' => array(), + ), + ), $formatted); + } + + /** + * Test issue #137 + */ + public function testIgnoresRecursiveObjectReferences() + { + // set up the recursion + $foo = new \stdClass(); + $bar = new \stdClass(); + + $foo->bar = $bar; + $bar->foo = $foo; + + // set an error handler to assert that the error is not raised anymore + $that = $this; + set_error_handler(function ($level, $message, $file, $line, $context) use ($that) { + if (error_reporting() & $level) { + restore_error_handler(); + $that->fail("$message should not be raised"); + } + }); + + $formatter = new NormalizerFormatter(); + $reflMethod = new \ReflectionMethod($formatter, 'toJson'); + $reflMethod->setAccessible(true); + $res = $reflMethod->invoke($formatter, array($foo, $bar), true); + + restore_error_handler(); + + $this->assertEquals(@json_encode(array($foo, $bar)), $res); + } + + public function testIgnoresInvalidTypes() + { + // set up the recursion + $resource = fopen(__FILE__, 'r'); + + // set an error handler to assert that the error is not raised anymore + $that = $this; + set_error_handler(function ($level, $message, $file, $line, $context) use ($that) { + if (error_reporting() & $level) { + restore_error_handler(); + $that->fail("$message should not be raised"); + } + }); + + $formatter = new NormalizerFormatter(); + $reflMethod = new \ReflectionMethod($formatter, 'toJson'); + $reflMethod->setAccessible(true); + $res = $reflMethod->invoke($formatter, array($resource), true); + + restore_error_handler(); + + $this->assertEquals(@json_encode(array($resource)), $res); + } +} + +class TestFooNorm +{ + public $foo = 'foo'; +} + +class TestBarNorm +{ + public function __toString() + { + return 'bar'; + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php new file mode 100644 index 00000000..b8cbb132 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -0,0 +1,96 @@ +formatter = new ScalarFormatter(); + } + + public function buildTrace(\Exception $e) + { + $data = array(); + $trace = $e->getTrace(); + foreach ($trace as $frame) { + if (isset($frame['file'])) { + $data[] = $frame['file'].':'.$frame['line']; + } else { + $data[] = json_encode($frame); + } + } + + return $data; + } + + public function encodeJson($data) + { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return json_encode($data); + } + + public function testFormat() + { + $exception = new \Exception('foo'); + $formatted = $this->formatter->format(array( + 'foo' => 'string', + 'bar' => 1, + 'baz' => false, + 'bam' => array(1,2,3), + 'bat' => array('foo' => 'bar'), + 'bap' => \DateTime::createFromFormat(\DateTime::ISO8601, '1970-01-01T00:00:00+0000'), + 'ban' => $exception + )); + + $this->assertSame(array( + 'foo' => 'string', + 'bar' => 1, + 'baz' => false, + 'bam' => $this->encodeJson(array(1,2,3)), + 'bat' => $this->encodeJson(array('foo' => 'bar')), + 'bap' => '1970-01-01 00:00:00', + 'ban' => $this->encodeJson(array( + 'class' => get_class($exception), + 'message' => $exception->getMessage(), + 'file' => $exception->getFile() . ':' . $exception->getLine(), + 'trace' => $this->buildTrace($exception) + )) + ), $formatted); + } + + public function testFormatWithErrorContext() + { + $context = array('file' => 'foo', 'line' => 1); + $formatted = $this->formatter->format(array( + 'context' => $context + )); + + $this->assertSame(array( + 'context' => $this->encodeJson($context) + ), $formatted); + } + + public function testFormatWithExceptionContext() + { + $exception = new \Exception('foo'); + $formatted = $this->formatter->format(array( + 'context' => array( + 'exception' => $exception + ) + )); + + $this->assertSame(array( + 'context' => $this->encodeJson(array( + 'exception' => array( + 'class' => get_class($exception), + 'message' => $exception->getMessage(), + 'file' => $exception->getFile() . ':' . $exception->getLine(), + 'trace' => $this->buildTrace($exception) + ) + )) + ), $formatted); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php new file mode 100644 index 00000000..52f15a36 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +class WildfireFormatterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers Monolog\Formatter\WildfireFormatter::format + */ + public function testDefaultFormat() + { + $wildfire = new WildfireFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('ip' => '127.0.0.1'), + 'message' => 'log', + ); + + $message = $wildfire->format($record); + + $this->assertEquals( + '125|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},' + .'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|', + $message + ); + } + + /** + * @covers Monolog\Formatter\WildfireFormatter::format + */ + public function testFormatWithFileAndLine() + { + $wildfire = new WildfireFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('from' => 'logger'), + 'datetime' => new \DateTime("@0"), + 'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14), + 'message' => 'log', + ); + + $message = $wildfire->format($record); + + $this->assertEquals( + '129|[{"Type":"ERROR","File":"test","Line":14,"Label":"meh"},' + .'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|', + $message + ); + } + + /** + * @covers Monolog\Formatter\WildfireFormatter::format + */ + public function testFormatWithoutContext() + { + $wildfire = new WildfireFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + $message = $wildfire->format($record); + + $this->assertEquals( + '58|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},"log"]|', + $message + ); + } + + /** + * @covers Monolog\Formatter\WildfireFormatter::formatBatch + * @expectedException BadMethodCallException + */ + public function testBatchFormatThrowException() + { + $wildfire = new WildfireFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array(), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + $wildfire->formatBatch(array($record)); + } + + /** + * @covers Monolog\Formatter\WildfireFormatter::format + */ + public function testTableFormat() + { + $wildfire = new WildfireFormatter(); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'table-channel', + 'context' => array( + WildfireFormatter::TABLE => array( + array('col1', 'col2', 'col3'), + array('val1', 'val2', 'val3'), + array('foo1', 'foo2', 'foo3'), + array('bar1', 'bar2', 'bar3'), + ), + ), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'table-message', + ); + + $message = $wildfire->format($record); + + $this->assertEquals( + '171|[{"Type":"TABLE","File":"","Line":"","Label":"table-channel: table-message"},[["col1","col2","col3"],["val1","val2","val3"],["foo1","foo2","foo3"],["bar1","bar2","bar3"]]]|', + $message + ); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php new file mode 100644 index 00000000..7e4e7eb5 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +spl_autoload_register(function ($class) { + $file = __DIR__.'/../../../../src/'.strtr($class, '\\', '/').'.php'; + if (file_exists($file)) { + require $file; + + return true; + } +}); + +use Monolog\Logger; +use Monolog\Handler\FirePHPHandler; +use Monolog\Handler\ChromePHPHandler; + +$logger = new Logger('firephp'); +$logger->pushHandler(new FirePHPHandler); +$logger->pushHandler(new ChromePHPHandler()); + +$logger->addDebug('Debug'); +$logger->addInfo('Info'); +$logger->addWarning('Warning'); +$logger->addError('Error'); diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php new file mode 100644 index 00000000..01d522fa --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; +use Monolog\Formatter\LineFormatter; +use Monolog\Processor\WebProcessor; + +class AbstractHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\AbstractHandler::__construct + * @covers Monolog\Handler\AbstractHandler::getLevel + * @covers Monolog\Handler\AbstractHandler::setLevel + * @covers Monolog\Handler\AbstractHandler::getBubble + * @covers Monolog\Handler\AbstractHandler::setBubble + * @covers Monolog\Handler\AbstractHandler::getFormatter + * @covers Monolog\Handler\AbstractHandler::setFormatter + */ + public function testConstructAndGetSet() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false)); + $this->assertEquals(Logger::WARNING, $handler->getLevel()); + $this->assertEquals(false, $handler->getBubble()); + + $handler->setLevel(Logger::ERROR); + $handler->setBubble(true); + $handler->setFormatter($formatter = new LineFormatter); + $this->assertEquals(Logger::ERROR, $handler->getLevel()); + $this->assertEquals(true, $handler->getBubble()); + $this->assertSame($formatter, $handler->getFormatter()); + } + + /** + * @covers Monolog\Handler\AbstractHandler::handleBatch + */ + public function testHandleBatch() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); + $handler->expects($this->exactly(2)) + ->method('handle'); + $handler->handleBatch(array($this->getRecord(), $this->getRecord())); + } + + /** + * @covers Monolog\Handler\AbstractHandler::isHandling + */ + public function testIsHandling() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false)); + $this->assertTrue($handler->isHandling($this->getRecord())); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + } + + /** + * @covers Monolog\Handler\AbstractHandler::getFormatter + * @covers Monolog\Handler\AbstractHandler::getDefaultFormatter + */ + public function testGetFormatterInitializesDefault() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); + $this->assertInstanceOf('Monolog\Formatter\LineFormatter', $handler->getFormatter()); + } + + /** + * @covers Monolog\Handler\AbstractHandler::pushProcessor + * @covers Monolog\Handler\AbstractHandler::popProcessor + * @expectedException LogicException + */ + public function testPushPopProcessor() + { + $logger = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); + $processor1 = new WebProcessor; + $processor2 = new WebProcessor; + + $logger->pushProcessor($processor1); + $logger->pushProcessor($processor2); + + $this->assertEquals($processor2, $logger->popProcessor()); + $this->assertEquals($processor1, $logger->popProcessor()); + $logger->popProcessor(); + } + + /** + * @covers Monolog\Handler\AbstractHandler::pushProcessor + * @expectedException InvalidArgumentException + */ + public function testPushProcessorWithNonCallable() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); + + $handler->pushProcessor(new \stdClass()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php new file mode 100644 index 00000000..24d4f63c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; +use Monolog\Processor\WebProcessor; + +class AbstractProcessingHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\AbstractProcessingHandler::handle + */ + public function testHandleLowerLevelMessage() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, true)); + $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + } + + /** + * @covers Monolog\Handler\AbstractProcessingHandler::handle + */ + public function testHandleBubbling() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, true)); + $this->assertFalse($handler->handle($this->getRecord())); + } + + /** + * @covers Monolog\Handler\AbstractProcessingHandler::handle + */ + public function testHandleNotBubbling() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, false)); + $this->assertTrue($handler->handle($this->getRecord())); + } + + /** + * @covers Monolog\Handler\AbstractProcessingHandler::handle + */ + public function testHandleIsFalseWhenNotHandled() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, false)); + $this->assertTrue($handler->handle($this->getRecord())); + $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + } + + /** + * @covers Monolog\Handler\AbstractProcessingHandler::processRecord + */ + public function testProcessRecord() + { + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler'); + $handler->pushProcessor(new WebProcessor(array( + 'REQUEST_URI' => '', + 'REQUEST_METHOD' => '', + 'REMOTE_ADDR' => '', + 'SERVER_NAME' => '', + 'UNIQUE_ID' => '', + ))); + $handledRecord = null; + $handler->expects($this->once()) + ->method('write') + ->will($this->returnCallback(function ($record) use (&$handledRecord) { + $handledRecord = $record; + })) + ; + $handler->handle($this->getRecord()); + $this->assertEquals(6, count($handledRecord['extra'])); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php new file mode 100644 index 00000000..249f2b72 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @covers Monolog\Handler\RotatingFileHandler + */ +class AmqpHandlerTest extends TestCase +{ + public function setUp() + { + if (!class_exists('AMQPConnection') || !class_exists('AMQPExchange')) { + $this->markTestSkipped("amqp-php not installed"); + } + + if (!class_exists('AMQPChannel')) { + $this->markTestSkipped("Please update AMQP to version >= 1.0"); + } + } + + public function testHandle() + { + $messages = array(); + + $exchange = $this->getMock('AMQPExchange', array('publish', 'setName'), array(), '', false); + $exchange->expects($this->once()) + ->method('setName') + ->with('log') + ; + $exchange->expects($this->any()) + ->method('publish') + ->will($this->returnCallback(function ($message, $routing_key, $flags = 0, $attributes = array()) use (&$messages) { + $messages[] = array($message, $routing_key, $flags, $attributes); + })) + ; + + $handler = new AmqpHandler($exchange, 'log'); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $expected = array( + array( + 'message' => 'test', + 'context' => array( + 'data' => array(), + 'foo' => 34, + ), + 'level' => 300, + 'level_name' => 'WARNING', + 'channel' => 'test', + 'extra' => array(), + ), + 'warn.test', + 0, + array( + 'delivery_mode' => 2, + 'Content-type' => 'application/json' + ) + ); + + $handler->handle($record); + + $this->assertCount(1, $messages); + $messages[0][0] = json_decode($messages[0][0], true); + unset($messages[0][0]['datetime']); + $this->assertEquals($expected, $messages[0]); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php new file mode 100644 index 00000000..f3d8038c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @covers Monolog\Handler\BrowserConsoleHandlerTest + */ +class BrowserConsoleHandlerTest extends TestCase +{ + protected function setUp() + { + BrowserConsoleHandler::reset(); + } + + protected function generateScript() + { + $reflMethod = new \ReflectionMethod('Monolog\Handler\BrowserConsoleHandler', 'generateScript'); + $reflMethod->setAccessible(true); + + return $reflMethod->invoke(null); + } + + public function testStyling() + { + $handler = new BrowserConsoleHandler(); + $handler->setFormatter($this->getIdentityFormatter()); + + $handler->handle($this->getRecord(Logger::DEBUG, 'foo[[bar]]{color: red}')); + + $expected = <<assertEquals($expected, $this->generateScript()); + } + + public function testEscaping() + { + $handler = new BrowserConsoleHandler(); + $handler->setFormatter($this->getIdentityFormatter()); + + $handler->handle($this->getRecord(Logger::DEBUG, "[foo] [[\"bar\n[baz]\"]]{color: red}")); + + $expected = <<assertEquals($expected, $this->generateScript()); + } + + + public function testAutolabel() + { + $handler = new BrowserConsoleHandler(); + $handler->setFormatter($this->getIdentityFormatter()); + + $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}')); + $handler->handle($this->getRecord(Logger::DEBUG, '[[bar]]{macro: autolabel}')); + $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}')); + + $expected = <<assertEquals($expected, $this->generateScript()); + } + + public function testContext() + { + $handler = new BrowserConsoleHandler(); + $handler->setFormatter($this->getIdentityFormatter()); + + $handler->handle($this->getRecord(Logger::DEBUG, 'test', array('foo' => 'bar'))); + + $expected = <<assertEquals($expected, $this->generateScript()); + } + + public function testConcurrentHandlers() + { + $handler1 = new BrowserConsoleHandler(); + $handler1->setFormatter($this->getIdentityFormatter()); + + $handler2 = new BrowserConsoleHandler(); + $handler2->setFormatter($this->getIdentityFormatter()); + + $handler1->handle($this->getRecord(Logger::DEBUG, 'test1')); + $handler2->handle($this->getRecord(Logger::DEBUG, 'test2')); + $handler1->handle($this->getRecord(Logger::DEBUG, 'test3')); + $handler2->handle($this->getRecord(Logger::DEBUG, 'test4')); + + $expected = <<assertEquals($expected, $this->generateScript()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php new file mode 100644 index 00000000..beb08cf8 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class BufferHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\BufferHandler::__construct + * @covers Monolog\Handler\BufferHandler::handle + * @covers Monolog\Handler\BufferHandler::close + */ + public function testHandleBuffers() + { + $test = new TestHandler(); + $handler = new BufferHandler($test); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertFalse($test->hasDebugRecords()); + $this->assertFalse($test->hasInfoRecords()); + $handler->close(); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue(count($test->getRecords()) === 2); + } + + /** + * @covers Monolog\Handler\BufferHandler::close + * @covers Monolog\Handler\BufferHandler::flush + */ + public function testDestructPropagatesRecords() + { + $test = new TestHandler(); + $handler = new BufferHandler($test); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->__destruct(); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + } + + /** + * @covers Monolog\Handler\BufferHandler::handle + */ + public function testHandleBufferLimit() + { + $test = new TestHandler(); + $handler = new BufferHandler($test, 2); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->close(); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasInfoRecords()); + $this->assertFalse($test->hasDebugRecords()); + } + + /** + * @covers Monolog\Handler\BufferHandler::handle + */ + public function testHandleBufferLimitWithFlushOnOverflow() + { + $test = new TestHandler(); + $handler = new BufferHandler($test, 3, Logger::DEBUG, true, true); + + // send two records + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $this->assertFalse($test->hasDebugRecords()); + $this->assertCount(0, $test->getRecords()); + + // overflow + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertTrue($test->hasDebugRecords()); + $this->assertCount(3, $test->getRecords()); + + // should buffer again + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertCount(3, $test->getRecords()); + + $handler->close(); + $this->assertCount(5, $test->getRecords()); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasInfoRecords()); + } + + /** + * @covers Monolog\Handler\BufferHandler::handle + */ + public function testHandleLevel() + { + $test = new TestHandler(); + $handler = new BufferHandler($test, 0, Logger::INFO); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->close(); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasInfoRecords()); + $this->assertFalse($test->hasDebugRecords()); + } + + /** + * @covers Monolog\Handler\BufferHandler::flush + */ + public function testFlush() + { + $test = new TestHandler(); + $handler = new BufferHandler($test, 0); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $handler->flush(); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue($test->hasDebugRecords()); + $this->assertFalse($test->hasWarningRecords()); + } + + /** + * @covers Monolog\Handler\BufferHandler::handle + */ + public function testHandleUsesProcessors() + { + $test = new TestHandler(); + $handler = new BufferHandler($test); + $handler->pushProcessor(function ($record) { + $record['extra']['foo'] = true; + + return $record; + }); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->flush(); + $this->assertTrue($test->hasWarningRecords()); + $records = $test->getRecords(); + $this->assertTrue($records[0]['extra']['foo']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php new file mode 100644 index 00000000..2f55faf8 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @covers Monolog\Handler\ChromePHPHandler + */ +class ChromePHPHandlerTest extends TestCase +{ + protected function setUp() + { + TestChromePHPHandler::reset(); + $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0'; + } + + public function testHeaders() + { + $handler = new TestChromePHPHandler(); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::WARNING)); + + $expected = array( + 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array( + 'version' => ChromePHPHandler::VERSION, + 'columns' => array('label', 'log', 'backtrace', 'type'), + 'rows' => array( + 'test', + 'test', + ), + 'request_uri' => '', + )))) + ); + + $this->assertEquals($expected, $handler->getHeaders()); + } + + public function testHeadersOverflow() + { + $handler = new TestChromePHPHandler(); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 150*1024))); + + // overflow chrome headers limit + $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 100*1024))); + + $expected = array( + 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array( + 'version' => ChromePHPHandler::VERSION, + 'columns' => array('label', 'log', 'backtrace', 'type'), + 'rows' => array( + array( + 'test', + 'test', + 'unknown', + 'log', + ), + array( + 'test', + str_repeat('a', 150*1024), + 'unknown', + 'warn', + ), + array( + 'monolog', + 'Incomplete logs, chrome header size limit reached', + 'unknown', + 'warn', + ), + ), + 'request_uri' => '', + )))) + ); + + $this->assertEquals($expected, $handler->getHeaders()); + } + + public function testConcurrentHandlers() + { + $handler = new TestChromePHPHandler(); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::WARNING)); + + $handler2 = new TestChromePHPHandler(); + $handler2->setFormatter($this->getIdentityFormatter()); + $handler2->handle($this->getRecord(Logger::DEBUG)); + $handler2->handle($this->getRecord(Logger::WARNING)); + + $expected = array( + 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array( + 'version' => ChromePHPHandler::VERSION, + 'columns' => array('label', 'log', 'backtrace', 'type'), + 'rows' => array( + 'test', + 'test', + 'test', + 'test', + ), + 'request_uri' => '', + )))) + ); + + $this->assertEquals($expected, $handler2->getHeaders()); + } +} + +class TestChromePHPHandler extends ChromePHPHandler +{ + protected $headers = array(); + + public static function reset() + { + self::$initialized = false; + self::$overflowed = false; + self::$sendHeaders = true; + self::$json['rows'] = array(); + } + + protected function sendHeader($header, $content) + { + $this->headers[$header] = $content; + } + + public function getHeaders() + { + return $this->headers; + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php new file mode 100644 index 00000000..78a1d15c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class CouchDBHandlerTest extends TestCase +{ + public function testHandle() + { + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $expected = array( + 'message' => 'test', + 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34), + 'level' => Logger::WARNING, + 'level_name' => 'WARNING', + 'channel' => 'test', + 'datetime' => $record['datetime']->format('Y-m-d H:i:s'), + 'extra' => array(), + ); + + $handler = new CouchDBHandler(); + + try { + $handler->handle($record); + } catch (\RuntimeException $e) { + $this->markTestSkipped('Could not connect to couchdb server on http://localhost:5984'); + } + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php new file mode 100644 index 00000000..d67da90a --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class DoctrineCouchDBHandlerTest extends TestCase +{ + protected function setup() + { + if (!class_exists('Doctrine\CouchDB\CouchDBClient')) { + $this->markTestSkipped('The "doctrine/couchdb" package is not installed'); + } + } + + public function testHandle() + { + $client = $this->getMockBuilder('Doctrine\\CouchDB\\CouchDBClient') + ->setMethods(array('postDocument')) + ->disableOriginalConstructor() + ->getMock(); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $expected = array( + 'message' => 'test', + 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34), + 'level' => Logger::WARNING, + 'level_name' => 'WARNING', + 'channel' => 'test', + 'datetime' => $record['datetime']->format('Y-m-d H:i:s'), + 'extra' => array(), + ); + + $client->expects($this->once()) + ->method('postDocument') + ->with($expected); + + $handler = new DoctrineCouchDBHandler($client); + $handler->handle($record); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php new file mode 100644 index 00000000..a38a8cb7 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; + +class DynamoDbHandlerTest extends TestCase +{ + public function setUp() + { + if (!class_exists('Aws\DynamoDb\DynamoDbClient')) { + $this->markTestSkipped('aws/aws-sdk-php not installed'); + } + + $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') + ->setMethods(array('formatAttributes', '__call')) + ->disableOriginalConstructor()->getMock(); + } + + public function testConstruct() + { + $this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo')); + } + + public function testInterface() + { + $this->assertInstanceOf('Monolog\Handler\HandlerInterface', new DynamoDbHandler($this->client, 'foo')); + } + + public function testGetFormatter() + { + $handler = new DynamoDbHandler($this->client, 'foo'); + $this->assertInstanceOf('Monolog\Formatter\ScalarFormatter', $handler->getFormatter()); + } + + public function testHandle() + { + $record = $this->getRecord(); + $formatter = $this->getMock('Monolog\Formatter\FormatterInterface'); + $formatted = array('foo' => 1, 'bar' => 2); + $handler = new DynamoDbHandler($this->client, 'foo'); + $handler->setFormatter($formatter); + + $formatter + ->expects($this->once()) + ->method('format') + ->with($record) + ->will($this->returnValue($formatted)); + $this->client + ->expects($this->once()) + ->method('formatAttributes') + ->with($this->isType('array')) + ->will($this->returnValue($formatted)); + $this->client + ->expects($this->once()) + ->method('__call') + ->with('putItem', array(array( + 'TableName' => 'foo', + 'Item' => $formatted + ))); + + $handler->handle($record); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php new file mode 100644 index 00000000..1687074b --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php @@ -0,0 +1,239 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\ElasticaFormatter; +use Monolog\Formatter\NormalizerFormatter; +use Monolog\TestCase; +use Monolog\Logger; +use Elastica\Client; +use Elastica\Request; +use Elastica\Response; + +class ElasticSearchHandlerTest extends TestCase +{ + /** + * @var Client mock + */ + protected $client; + + /** + * @var array Default handler options + */ + protected $options = array( + 'index' => 'my_index', + 'type' => 'doc_type', + ); + + public function setUp() + { + // Elastica lib required + if (!class_exists("Elastica\Client")) { + $this->markTestSkipped("ruflin/elastica not installed"); + } + + // base mock Elastica Client object + $this->client = $this->getMockBuilder('Elastica\Client') + ->setMethods(array('addDocuments')) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::write + * @covers Monolog\Handler\ElasticSearchHandler::handleBatch + * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + */ + public function testHandle() + { + // log message + $msg = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + // format expected result + $formatter = new ElasticaFormatter($this->options['index'], $this->options['type']); + $expected = array($formatter->format($msg)); + + // setup ES client mock + $this->client->expects($this->any()) + ->method('addDocuments') + ->with($expected); + + // perform tests + $handler = new ElasticSearchHandler($this->client, $this->options); + $handler->handle($msg); + $handler->handleBatch(array($msg)); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + */ + public function testSetFormatter() + { + $handler = new ElasticSearchHandler($this->client); + $formatter = new ElasticaFormatter('index_new', 'type_new'); + $handler->setFormatter($formatter); + $this->assertInstanceOf('Monolog\Formatter\ElasticaFormatter', $handler->getFormatter()); + $this->assertEquals('index_new', $handler->getFormatter()->getIndex()); + $this->assertEquals('type_new', $handler->getFormatter()->getType()); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + * @expectedException InvalidArgumentException + * @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticaFormatter + */ + public function testSetFormatterInvalid() + { + $handler = new ElasticSearchHandler($this->client); + $formatter = new NormalizerFormatter(); + $handler->setFormatter($formatter); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::__construct + * @covers Monolog\Handler\ElasticSearchHandler::getOptions + */ + public function testOptions() + { + $expected = array( + 'index' => $this->options['index'], + 'type' => $this->options['type'], + 'ignore_error' => false, + ); + $handler = new ElasticSearchHandler($this->client, $this->options); + $this->assertEquals($expected, $handler->getOptions()); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @dataProvider providerTestConnectionErrors + */ + public function testConnectionErrors($ignore, $expectedError) + { + $clientOpts = array('host' => '127.0.0.1', 'port' => 1); + $client = new Client($clientOpts); + $handlerOpts = array('ignore_error' => $ignore); + $handler = new ElasticSearchHandler($client, $handlerOpts); + + if ($expectedError) { + $this->setExpectedException($expectedError[0], $expectedError[1]); + $handler->handle($this->getRecord()); + } else { + $this->assertFalse($handler->handle($this->getRecord())); + } + } + + /** + * @return array + */ + public function providerTestConnectionErrors() + { + return array( + array(false, array('RuntimeException', 'Error sending messages to Elasticsearch')), + array(true, false), + ); + } + + /** + * Integration test using localhost Elastic Search server + * + * @covers Monolog\Handler\ElasticSearchHandler::__construct + * @covers Monolog\Handler\ElasticSearchHandler::handleBatch + * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + */ + public function testHandleIntegration() + { + $msg = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass), + 'datetime' => new \DateTime("@0"), + 'extra' => array(), + 'message' => 'log', + ); + + $expected = $msg; + $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); + $expected['context'] = array( + 'class' => '[object] (stdClass: {})', + 'foo' => 7, + 0 => 'bar', + ); + + $client = new Client(); + $handler = new ElasticSearchHandler($client, $this->options); + try { + $handler->handleBatch(array($msg)); + } catch (\RuntimeException $e) { + $this->markTestSkipped("Cannot connect to Elastic Search server on localhost"); + } + + // check document id from ES server response + $documentId = $this->getCreatedDocId($client->getLastResponse()); + $this->assertNotEmpty($documentId, 'No elastic document id received'); + + // retrieve document source from ES and validate + $document = $this->getDocSourceFromElastic( + $client, + $this->options['index'], + $this->options['type'], + $documentId + ); + $this->assertEquals($expected, $document); + + // remove test index from ES + $client->request("/{$this->options['index']}", Request::DELETE); + } + + /** + * Return last created document id from ES response + * @param Response $response Elastica Response object + * @return string|null + */ + protected function getCreatedDocId(Response $response) + { + $data = $response->getData(); + if (!empty($data['items'][0]['create']['_id'])) { + return $data['items'][0]['create']['_id']; + } + } + + /** + * Retrieve document by id from Elasticsearch + * @param Client $client Elastica client + * @param string $index + * @param string $type + * @param string $documentId + * @return array + */ + protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) + { + $resp = $client->request("/{$index}/{$type}/{$documentId}", Request::GET); + $data = $resp->getData(); + if (!empty($data['_source'])) { + return $data['_source']; + } + + return array(); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php new file mode 100644 index 00000000..626f5f9f --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php @@ -0,0 +1,58 @@ +setFormatter(new LineFormatter('%channel%.%level_name%: %message% %context% %extra%', null, true)); + $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); + + $this->assertSame("test.ERROR: Foo\nBar\r\n\r\nBaz [] []", $GLOBALS['error_log'][0][0]); + $this->assertSame($GLOBALS['error_log'][0][1], $type); + + $handler = new ErrorLogHandler($type, Logger::DEBUG, true, true); + $handler->setFormatter(new LineFormatter(null, null, true)); + $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); + + $this->assertStringMatchesFormat('[%s] test.ERROR: Foo', $GLOBALS['error_log'][1][0]); + $this->assertSame($GLOBALS['error_log'][1][1], $type); + + $this->assertStringMatchesFormat('Bar', $GLOBALS['error_log'][2][0]); + $this->assertSame($GLOBALS['error_log'][2][1], $type); + + $this->assertStringMatchesFormat('Baz [] []', $GLOBALS['error_log'][3][0]); + $this->assertSame($GLOBALS['error_log'][3][1], $type); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php new file mode 100644 index 00000000..1f86c8ec --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php @@ -0,0 +1,151 @@ +assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + $this->assertTrue($handler->isHandling($this->getRecord(Logger::INFO))); + $this->assertTrue($handler->isHandling($this->getRecord(Logger::NOTICE))); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::WARNING))); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::ERROR))); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::CRITICAL))); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::ALERT))); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::EMERGENCY))); + } + + /** + * @covers Monolog\Handler\FilterHandler::handle + * @covers Monolog\Handler\FilterHandler::setAcceptedLevels + * @covers Monolog\Handler\FilterHandler::isHandling + */ + public function testHandleProcessOnlyNeededLevels() + { + $test = new TestHandler(); + $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE); + + $handler->handle($this->getRecord(Logger::DEBUG)); + $this->assertFalse($test->hasDebugRecords()); + + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertTrue($test->hasInfoRecords()); + $handler->handle($this->getRecord(Logger::NOTICE)); + $this->assertTrue($test->hasNoticeRecords()); + + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertFalse($test->hasWarningRecords()); + $handler->handle($this->getRecord(Logger::ERROR)); + $this->assertFalse($test->hasErrorRecords()); + $handler->handle($this->getRecord(Logger::CRITICAL)); + $this->assertFalse($test->hasCriticalRecords()); + $handler->handle($this->getRecord(Logger::ALERT)); + $this->assertFalse($test->hasAlertRecords()); + $handler->handle($this->getRecord(Logger::EMERGENCY)); + $this->assertFalse($test->hasEmergencyRecords()); + + $test = new TestHandler(); + $handler = new FilterHandler($test, array(Logger::INFO, Logger::ERROR)); + + $handler->handle($this->getRecord(Logger::DEBUG)); + $this->assertFalse($test->hasDebugRecords()); + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertTrue($test->hasInfoRecords()); + $handler->handle($this->getRecord(Logger::NOTICE)); + $this->assertFalse($test->hasNoticeRecords()); + $handler->handle($this->getRecord(Logger::ERROR)); + $this->assertTrue($test->hasErrorRecords()); + $handler->handle($this->getRecord(Logger::CRITICAL)); + $this->assertFalse($test->hasCriticalRecords()); + } + + /** + * @covers Monolog\Handler\FilterHandler::setAcceptedLevels + * @covers Monolog\Handler\FilterHandler::getAcceptedLevels + */ + public function testAcceptedLevelApi() + { + $test = new TestHandler(); + $handler = new FilterHandler($test); + + $levels = array(Logger::INFO, Logger::ERROR); + $handler->setAcceptedLevels($levels); + $this->assertSame($levels, $handler->getAcceptedLevels()); + } + + /** + * @covers Monolog\Handler\FilterHandler::handle + */ + public function testHandleUsesProcessors() + { + $test = new TestHandler(); + $handler = new FilterHandler($test, Logger::DEBUG, Logger::EMERGENCY); + $handler->pushProcessor( + function ($record) { + $record['extra']['foo'] = true; + + return $record; + } + ); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertTrue($test->hasWarningRecords()); + $records = $test->getRecords(); + $this->assertTrue($records[0]['extra']['foo']); + } + + /** + * @covers Monolog\Handler\FilterHandler::handle + */ + public function testHandleRespectsBubble() + { + $test = new TestHandler(); + + $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, false); + $this->assertTrue($handler->handle($this->getRecord(Logger::INFO))); + $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING))); + + $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, true); + $this->assertFalse($handler->handle($this->getRecord(Logger::INFO))); + $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING))); + } + + /** + * @covers Monolog\Handler\FilterHandler::handle + */ + public function testHandleWithCallback() + { + $test = new TestHandler(); + $handler = new FilterHandler( + function ($record, $handler) use ($test) { + return $test; + }, Logger::INFO, Logger::NOTICE, false + ); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertFalse($test->hasDebugRecords()); + $this->assertTrue($test->hasInfoRecords()); + } + + /** + * @covers Monolog\Handler\FilterHandler::handle + * @expectedException \RuntimeException + */ + public function testHandleWithBadCallbackThrowsException() + { + $handler = new FilterHandler( + function ($record, $handler) { + return 'foo'; + } + ); + $handler->handle($this->getRecord(Logger::WARNING)); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php new file mode 100644 index 00000000..d02fef99 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -0,0 +1,207 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; +use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; +use Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy; + +class FingersCrossedHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\FingersCrossedHandler::__construct + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + public function testHandleBuffers() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertFalse($test->hasDebugRecords()); + $this->assertFalse($test->hasInfoRecords()); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->close(); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue(count($test->getRecords()) === 3); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + public function testHandleStopsBufferingAfterTrigger() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->close(); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + * @covers Monolog\Handler\FingersCrossedHandler::reset + */ + public function testHandleRestartBufferingAfterReset() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->reset(); + $handler->handle($this->getRecord(Logger::INFO)); + $handler->close(); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + $this->assertFalse($test->hasInfoRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + public function testHandleRestartBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::INFO)); + $handler->close(); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + $this->assertFalse($test->hasInfoRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + public function testHandleBufferLimit() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, Logger::WARNING, 2); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasInfoRecords()); + $this->assertFalse($test->hasDebugRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + public function testHandleWithCallback() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler(function ($record, $handler) use ($test) { + return $test; + }); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertFalse($test->hasDebugRecords()); + $this->assertFalse($test->hasInfoRecords()); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue(count($test->getRecords()) === 3); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + * @expectedException RuntimeException + */ + public function testHandleWithBadCallbackThrowsException() + { + $handler = new FingersCrossedHandler(function ($record, $handler) { + return 'foo'; + }); + $handler->handle($this->getRecord(Logger::WARNING)); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::isHandling + */ + public function testIsHandlingAlways() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, Logger::ERROR); + $this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG))); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::__construct + * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct + * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated + */ + public function testErrorLevelActivationStrategy() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $this->assertFalse($test->hasDebugRecords()); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertTrue($test->hasDebugRecords()); + $this->assertTrue($test->hasWarningRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct + * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated + */ + public function testChannelLevelActivationStrategy() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Logger::ERROR, array('othertest' => Logger::DEBUG))); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertFalse($test->hasWarningRecords()); + $record = $this->getRecord(Logger::DEBUG); + $record['channel'] = 'othertest'; + $handler->handle($record); + $this->assertTrue($test->hasDebugRecords()); + $this->assertTrue($test->hasWarningRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + public function testHandleUsesProcessors() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, Logger::INFO); + $handler->pushProcessor(function ($record) { + $record['extra']['foo'] = true; + + return $record; + }); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertTrue($test->hasWarningRecords()); + $records = $test->getRecords(); + $this->assertTrue($records[0]['extra']['foo']); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::close + */ + public function testPassthruOnClose() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, Logger::INFO); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + $handler->close(); + $this->assertFalse($test->hasDebugRecords()); + $this->assertTrue($test->hasInfoRecords()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php new file mode 100644 index 00000000..0eb10a63 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @covers Monolog\Handler\FirePHPHandler + */ +class FirePHPHandlerTest extends TestCase +{ + public function setUp() + { + TestFirePHPHandler::reset(); + $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0'; + } + + public function testHeaders() + { + $handler = new TestFirePHPHandler; + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::WARNING)); + + $expected = array( + 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2', + 'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1', + 'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3', + 'X-Wf-1-1-1-1' => 'test', + 'X-Wf-1-1-1-2' => 'test', + ); + + $this->assertEquals($expected, $handler->getHeaders()); + } + + public function testConcurrentHandlers() + { + $handler = new TestFirePHPHandler; + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::WARNING)); + + $handler2 = new TestFirePHPHandler; + $handler2->setFormatter($this->getIdentityFormatter()); + $handler2->handle($this->getRecord(Logger::DEBUG)); + $handler2->handle($this->getRecord(Logger::WARNING)); + + $expected = array( + 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2', + 'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1', + 'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3', + 'X-Wf-1-1-1-1' => 'test', + 'X-Wf-1-1-1-2' => 'test', + ); + + $expected2 = array( + 'X-Wf-1-1-1-3' => 'test', + 'X-Wf-1-1-1-4' => 'test', + ); + + $this->assertEquals($expected, $handler->getHeaders()); + $this->assertEquals($expected2, $handler2->getHeaders()); + } +} + +class TestFirePHPHandler extends FirePHPHandler +{ + protected $headers = array(); + + public static function reset() + { + self::$initialized = false; + self::$sendHeaders = true; + self::$messageIndex = 1; + } + + protected function sendHeader($header, $content) + { + $this->headers[$header] = $content; + } + + public function getHeaders() + { + return $this->headers; + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php new file mode 100644 index 00000000..4b120d51 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FlowdockFormatter; +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @author Dominik Liebler + * @see https://www.hipchat.com/docs/api + */ +class FlowdockHandlerTest extends TestCase +{ + /** + * @var resource + */ + private $res; + + /** + * @var FlowdockHandler + */ + private $handler; + + public function setUp() + { + if (!extension_loaded('openssl')) { + $this->markTestSkipped('This test requires openssl to run'); + } + } + + public function testWriteHeader() + { + $this->createHandler(); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/POST \/v1\/messages\/team_inbox\/.* HTTP\/1.1\\r\\nHost: api.flowdock.com\\r\\nContent-Type: application\/json\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); + + return $content; + } + + /** + * @depends testWriteHeader + */ + public function testWriteContent($content) + { + $this->assertRegexp('/"source":"test_source"/', $content); + $this->assertRegexp('/"from_address":"source@test\.com"/', $content); + } + + private function createHandler($token = 'myToken') + { + $constructorArgs = array($token, Logger::DEBUG); + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMock( + '\Monolog\Handler\FlowdockHandler', + array('fsockopen', 'streamSetTimeout', 'closeSocket'), + $constructorArgs + ); + + $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); + + $this->handler->setFormatter(new FlowdockFormatter('test_source', 'source@test.com')); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php new file mode 100644 index 00000000..d60a6db3 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Gelf\Message; +use Monolog\TestCase; +use Monolog\Logger; +use Monolog\Formatter\GelfMessageFormatter; + +class GelfHandlerLegacyTest extends TestCase +{ + public function setUp() + { + if (!class_exists('Gelf\MessagePublisher') || !class_exists('Gelf\Message')) { + $this->markTestSkipped("mlehner/gelf-php not installed"); + } + } + + /** + * @covers Monolog\Handler\GelfHandler::__construct + */ + public function testConstruct() + { + $handler = new GelfHandler($this->getMessagePublisher()); + $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler); + } + + protected function getHandler($messagePublisher) + { + $handler = new GelfHandler($messagePublisher); + + return $handler; + } + + protected function getMessagePublisher() + { + return new MockMessagePublisher('localhost'); + } + + public function testDebug() + { + $messagePublisher = $this->getMessagePublisher(); + $handler = $this->getHandler($messagePublisher); + + $record = $this->getRecord(Logger::DEBUG, "A test debug message"); + $handler->handle($record); + + $this->assertEquals(7, $messagePublisher->lastMessage->getLevel()); + $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); + $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); + $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage()); + } + + public function testWarning() + { + $messagePublisher = $this->getMessagePublisher(); + $handler = $this->getHandler($messagePublisher); + + $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $handler->handle($record); + + $this->assertEquals(4, $messagePublisher->lastMessage->getLevel()); + $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); + $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); + $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage()); + } + + public function testInjectedGelfMessageFormatter() + { + $messagePublisher = $this->getMessagePublisher(); + $handler = $this->getHandler($messagePublisher); + + $handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX')); + + $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $record['extra']['blarg'] = 'yep'; + $record['context']['from'] = 'logger'; + $handler->handle($record); + + $this->assertEquals('mysystem', $messagePublisher->lastMessage->getHost()); + $this->assertArrayHasKey('_EXTblarg', $messagePublisher->lastMessage->toArray()); + $this->assertArrayHasKey('_CTXfrom', $messagePublisher->lastMessage->toArray()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php new file mode 100644 index 00000000..83136875 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Gelf\Message; +use Monolog\TestCase; +use Monolog\Logger; +use Monolog\Formatter\GelfMessageFormatter; + +class GelfHandlerTest extends TestCase +{ + public function setUp() + { + if (!class_exists('Gelf\Publisher') || !class_exists('Gelf\Message')) { + $this->markTestSkipped("graylog2/gelf-php not installed"); + } + } + + /** + * @covers Monolog\Handler\GelfHandler::__construct + */ + public function testConstruct() + { + $handler = new GelfHandler($this->getMessagePublisher()); + $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler); + } + + protected function getHandler($messagePublisher) + { + $handler = new GelfHandler($messagePublisher); + + return $handler; + } + + protected function getMessagePublisher() + { + return $this->getMock('Gelf\Publisher', array('publish'), array(), '', false); + } + + public function testDebug() + { + $record = $this->getRecord(Logger::DEBUG, "A test debug message"); + $expectedMessage = new Message(); + $expectedMessage + ->setLevel(7) + ->setFacility("test") + ->setShortMessage($record['message']) + ->setTimestamp($record['datetime']) + ; + + $messagePublisher = $this->getMessagePublisher(); + $messagePublisher->expects($this->once()) + ->method('publish') + ->with($expectedMessage); + + $handler = $this->getHandler($messagePublisher); + + $handler->handle($record); + + } + + public function testWarning() + { + $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $expectedMessage = new Message(); + $expectedMessage + ->setLevel(4) + ->setFacility("test") + ->setShortMessage($record['message']) + ->setTimestamp($record['datetime']) + ; + + $messagePublisher = $this->getMessagePublisher(); + $messagePublisher->expects($this->once()) + ->method('publish') + ->with($expectedMessage); + + $handler = $this->getHandler($messagePublisher); + + $handler->handle($record); + } + + public function testInjectedGelfMessageFormatter() + { + $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $record['extra']['blarg'] = 'yep'; + $record['context']['from'] = 'logger'; + + $expectedMessage = new Message(); + $expectedMessage + ->setLevel(4) + ->setFacility("test") + ->setHost("mysystem") + ->setShortMessage($record['message']) + ->setTimestamp($record['datetime']) + ->setAdditional("EXTblarg", 'yep') + ->setAdditional("CTXfrom", 'logger') + ; + + $messagePublisher = $this->getMessagePublisher(); + $messagePublisher->expects($this->once()) + ->method('publish') + ->with($expectedMessage); + + $handler = $this->getHandler($messagePublisher); + $handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX')); + $handler->handle($record); + + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php new file mode 100644 index 00000000..c6298a6e --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class GroupHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\GroupHandler::__construct + * @expectedException InvalidArgumentException + */ + public function testConstructorOnlyTakesHandler() + { + new GroupHandler(array(new TestHandler(), "foo")); + } + + /** + * @covers Monolog\Handler\GroupHandler::__construct + * @covers Monolog\Handler\GroupHandler::handle + */ + public function testHandle() + { + $testHandlers = array(new TestHandler(), new TestHandler()); + $handler = new GroupHandler($testHandlers); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + foreach ($testHandlers as $test) { + $this->assertTrue($test->hasDebugRecords()); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue(count($test->getRecords()) === 2); + } + } + + /** + * @covers Monolog\Handler\GroupHandler::handleBatch + */ + public function testHandleBatch() + { + $testHandlers = array(new TestHandler(), new TestHandler()); + $handler = new GroupHandler($testHandlers); + $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); + foreach ($testHandlers as $test) { + $this->assertTrue($test->hasDebugRecords()); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue(count($test->getRecords()) === 2); + } + } + + /** + * @covers Monolog\Handler\GroupHandler::isHandling + */ + public function testIsHandling() + { + $testHandlers = array(new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING)); + $handler = new GroupHandler($testHandlers); + $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR))); + $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING))); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + } + + /** + * @covers Monolog\Handler\GroupHandler::handle + */ + public function testHandleUsesProcessors() + { + $test = new TestHandler(); + $handler = new GroupHandler(array($test)); + $handler->pushProcessor(function ($record) { + $record['extra']['foo'] = true; + + return $record; + }); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertTrue($test->hasWarningRecords()); + $records = $test->getRecords(); + $this->assertTrue($records[0]['extra']['foo']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php new file mode 100644 index 00000000..8b9e4d44 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @author Rafael Dohms + * @see https://www.hipchat.com/docs/api + */ +class HipChatHandlerTest extends TestCase +{ + + private $res; + private $handler; + + public function testWriteHeader() + { + $this->createHandler(); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: api.hipchat.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); + + return $content; + } + + /** + * @depends testWriteHeader + */ + public function testWriteContent($content) + { + $this->assertRegexp('/from=Monolog&room_id=room1¬ify=0&message=test1&message_format=text&color=red$/', $content); + } + + public function testWriteWithComplexMessage() + { + $this->createHandler(); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); + } + + /** + * @dataProvider provideLevelColors + */ + public function testWriteWithErrorLevelsAndColors($level, $expectedColor) + { + $this->createHandler(); + $this->handler->handle($this->getRecord($level, 'Backup of database "example" finished in 16 minutes.')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/color='.$expectedColor.'/', $content); + } + + public function provideLevelColors() + { + return array( + array(Logger::DEBUG, 'gray'), + array(Logger::INFO, 'green'), + array(Logger::WARNING, 'yellow'), + array(Logger::ERROR, 'red'), + array(Logger::CRITICAL, 'red'), + array(Logger::ALERT, 'red'), + array(Logger::EMERGENCY,'red'), + array(Logger::NOTICE, 'green'), + ); + } + + /** + * @dataProvider provideBatchRecords + */ + public function testHandleBatch($records, $expectedColor) + { + $this->createHandler(); + + $this->handler->handleBatch($records); + + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/color='.$expectedColor.'/', $content); + } + + public function provideBatchRecords() + { + return array( + array( + array( + array('level' => Logger::WARNING, 'message' => 'Oh bugger!', 'level_name' => 'warning', 'datetime' => new \DateTime()), + array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()), + array('level' => Logger::CRITICAL, 'message' => 'Everything is broken!', 'level_name' => 'critical', 'datetime' => new \DateTime()) + ), + 'red', + ), + array( + array( + array('level' => Logger::WARNING, 'message' => 'Oh bugger!', 'level_name' => 'warning', 'datetime' => new \DateTime()), + array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()), + ), + 'yellow', + ), + array( + array( + array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()), + array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()), + ), + 'green', + ), + array( + array( + array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()), + ), + 'gray', + ), + ); + } + + private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false) + { + $constructorArgs = array($token, $room, $name, $notify, Logger::DEBUG); + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMock( + '\Monolog\Handler\HipChatHandler', + array('fsockopen', 'streamSetTimeout', 'closeSocket'), + $constructorArgs + ); + + $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); + + $this->handler->setFormatter($this->getIdentityFormatter()); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testCreateWithTooLongName() + { + $hipChatHandler = new \Monolog\Handler\HipChatHandler('token', 'room', 'SixteenCharsHere'); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php new file mode 100644 index 00000000..7af60be8 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @author Robert Kaufmann III + */ +class LogEntriesHandlerTest extends TestCase +{ + /** + * @var resource + */ + private $res; + + /** + * @var LogEntriesHandler + */ + private $handler; + + public function testWriteContent() + { + $this->createHandler(); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); + + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] test.CRITICAL: Critical write test/', $content); + } + + public function testWriteBatchContent() + { + $records = array( + $this->getRecord(), + $this->getRecord(), + $this->getRecord() + ); + $this->createHandler(); + $this->handler->handleBatch($records); + + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] .* \[\] \[\]\n){3}/', $content); + } + + private function createHandler() + { + $useSSL = extension_loaded('openssl'); + $args = array('testToken', $useSSL, Logger::DEBUG, true); + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMock( + '\Monolog\Handler\LogEntriesHandler', + array('fsockopen', 'streamSetTimeout', 'closeSocket'), + $args + ); + + $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php new file mode 100644 index 00000000..6754f3d6 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\TestCase; + +class MailHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\MailHandler::handleBatch + */ + public function testHandleBatch() + { + $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); + $formatter->expects($this->once()) + ->method('formatBatch'); // Each record is formatted + + $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler'); + $handler->expects($this->once()) + ->method('send'); + $handler->expects($this->never()) + ->method('write'); // write is for individual records + + $handler->setFormatter($formatter); + + $handler->handleBatch($this->getMultipleRecords()); + } + + /** + * @covers Monolog\Handler\MailHandler::handleBatch + */ + public function testHandleBatchNotSendsMailIfMessagesAreBelowLevel() + { + $records = array( + $this->getRecord(Logger::DEBUG, 'debug message 1'), + $this->getRecord(Logger::DEBUG, 'debug message 2'), + $this->getRecord(Logger::INFO, 'information'), + ); + + $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler'); + $handler->expects($this->never()) + ->method('send'); + $handler->setLevel(Logger::ERROR); + + $handler->handleBatch($records); + } + + /** + * @covers Monolog\Handler\MailHandler::write + */ + public function testHandle() + { + $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler'); + + $record = $this->getRecord(); + $records = array($record); + $records[0]['formatted'] = '['.$record['datetime']->format('Y-m-d H:i:s').'] test.WARNING: test [] []'."\n"; + + $handler->expects($this->once()) + ->method('send') + ->with($records[0]['formatted'], $records); + + $handler->handle($record); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php new file mode 100644 index 00000000..fbaab9bc --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Raven_Client; + +class MockRavenClient extends Raven_Client +{ + public function capture($data, $stack, $vars = null) + { + $this->lastData = $data; + $this->lastStack = $stack; + } + + public $lastData; + public $lastStack; +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php new file mode 100644 index 00000000..7f06d666 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class MongoDBHandlerTest extends TestCase +{ + /** + * @expectedException InvalidArgumentException + */ + public function testConstructorShouldThrowExceptionForInvalidMongo() + { + new MongoDBHandler(new \stdClass(), 'DB', 'Collection'); + } + + public function testHandle() + { + $mongo = $this->getMock('Mongo', array('selectCollection'), array(), '', false); + $collection = $this->getMock('stdClass', array('save')); + + $mongo->expects($this->once()) + ->method('selectCollection') + ->with('DB', 'Collection') + ->will($this->returnValue($collection)); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $expected = array( + 'message' => 'test', + 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34), + 'level' => Logger::WARNING, + 'level_name' => 'WARNING', + 'channel' => 'test', + 'datetime' => $record['datetime']->format('Y-m-d H:i:s'), + 'extra' => array(), + ); + + $collection->expects($this->once()) + ->method('save') + ->with($expected); + + $handler = new MongoDBHandler($mongo, 'DB', 'Collection'); + $handler->handle($record); + } +} + +if (!class_exists('Mongo')) { + class Mongo + { + public function selectCollection() {} + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php new file mode 100644 index 00000000..50ceace0 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; + +class NativeMailerHandlerTest extends TestCase +{ + /** + * @expectedException InvalidArgumentException + */ + public function testConstructorHeaderInjection() + { + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', "receiver@example.org\r\nFrom: faked@attacker.org"); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testSetterHeaderInjection() + { + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); + $mailer->addHeader("Content-Type: text/html\r\nFrom: faked@attacker.org"); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testSetterArrayHeaderInjection() + { + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); + $mailer->addHeader(array("Content-Type: text/html\r\nFrom: faked@attacker.org")); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php new file mode 100644 index 00000000..2e059684 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; +use Psr\Log\LogLevel; + +class NewRelicHandlerTest extends TestCase +{ + public static $appname; + public static $customParameters; + + public function setUp() + { + self::$appname = null; + self::$customParameters = array(); + } + + /** + * @expectedException Monolog\Handler\MissingExtensionException + */ + public function testThehandlerThrowsAnExceptionIfTheNRExtensionIsNotLoaded() + { + $handler = new StubNewRelicHandlerWithoutExtension(); + $handler->handle($this->getRecord(Logger::ERROR)); + } + + public function testThehandlerCanHandleTheRecord() + { + $handler = new StubNewRelicHandler(); + $handler->handle($this->getRecord(Logger::ERROR)); + } + + public function testThehandlerCanAddContextParamsToTheNewRelicTrace() + { + $handler = new StubNewRelicHandler(); + $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('a' => 'b'))); + $this->assertEquals(array('a' => 'b'), self::$customParameters); + } + + public function testThehandlerCanAddExtraParamsToTheNewRelicTrace() + { + $record = $this->getRecord(Logger::ERROR, 'log message'); + $record['extra'] = array('c' => 'd'); + + $handler = new StubNewRelicHandler(); + $handler->handle($record); + + $this->assertEquals(array('c' => 'd'), self::$customParameters); + } + + public function testThehandlerCanAddExtraContextAndParamsToTheNewRelicTrace() + { + $record = $this->getRecord(Logger::ERROR, 'log message', array('a' => 'b')); + $record['extra'] = array('c' => 'd'); + + $handler = new StubNewRelicHandler(); + $handler->handle($record); + + $expected = array( + 'a' => 'b', + 'c' => 'd', + ); + + $this->assertEquals($expected, self::$customParameters); + } + + public function testTheAppNameIsNullByDefault() + { + $handler = new StubNewRelicHandler(); + $handler->handle($this->getRecord(Logger::ERROR, 'log message')); + + $this->assertEquals(null, self::$appname); + } + + public function testTheAppNameCanBeInjectedFromtheConstructor() + { + $handler = new StubNewRelicHandler(LogLevel::ALERT, false, 'myAppName'); + $handler->handle($this->getRecord(Logger::ERROR, 'log message')); + + $this->assertEquals('myAppName', self::$appname); + } + + public function testTheAppNameCanBeOverriddenFromEachLog() + { + $handler = new StubNewRelicHandler(LogLevel::ALERT, false, 'myAppName'); + $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('appname' => 'logAppName'))); + + $this->assertEquals('logAppName', self::$appname); + } +} + +class StubNewRelicHandlerWithoutExtension extends NewRelicHandler +{ + protected function isNewRelicEnabled() + { + return false; + } +} + +class StubNewRelicHandler extends NewRelicHandler +{ + protected function isNewRelicEnabled() + { + return true; + } +} + +function newrelic_notice_error() +{ + return true; +} + +function newrelic_set_appname($appname) +{ + return NewRelicHandlerTest::$appname = $appname; +} + +function newrelic_add_custom_parameter($key, $value) +{ + NewRelicHandlerTest::$customParameters[$key] = $value; + + return true; +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php new file mode 100644 index 00000000..292df78c --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @covers Monolog\Handler\NullHandler::handle + */ +class NullHandlerTest extends TestCase +{ + public function testHandle() + { + $handler = new NullHandler(); + $this->assertTrue($handler->handle($this->getRecord())); + } + + public function testHandleLowerLevelRecord() + { + $handler = new NullHandler(Logger::WARNING); + $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php new file mode 100644 index 00000000..e048a02a --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * Almost all examples (expected header, titles, messages) taken from + * https://www.pushover.net/api + * @author Sebastian Göttschkes + * @see https://www.pushover.net/api + */ +class PushoverHandlerTest extends TestCase +{ + + private $res; + private $handler; + + public function testWriteHeader() + { + $this->createHandler(); + $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/POST \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); + + return $content; + } + + /** + * @depends testWriteHeader + */ + public function testWriteContent($content) + { + $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}$/', $content); + } + + public function testWriteWithComplexTitle() + { + $this->createHandler('myToken', 'myUser', 'Backup finished - SQL1', Logger::EMERGENCY); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/title=Backup\+finished\+-\+SQL1/', $content); + } + + public function testWriteWithComplexMessage() + { + $this->createHandler(); + $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); + } + + public function testWriteWithTooLongMessage() + { + $message = str_pad('test', 520, 'a'); + $this->createHandler(); + $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications + $this->handler->handle($this->getRecord(Logger::CRITICAL, $message)); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $expectedMessage = substr($message, 0, 505); + + $this->assertRegexp('/message=' . $expectedMessage . '&title/', $content); + } + + public function testWriteWithHighPriority() + { + $this->createHandler(); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=1$/', $content); + } + + public function testWriteWithEmergencyPriority() + { + $this->createHandler(); + $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); + } + + public function testWriteToMultipleUsers() + { + $this->createHandler('myToken', array('userA', 'userB')); + $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('/token=myToken&user=userA&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200POST/', $content); + $this->assertRegexp('/token=myToken&user=userB&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); + } + + private function createHandler($token = 'myToken', $user = 'myUser', $title = 'Monolog') + { + $constructorArgs = array($token, $user, $title); + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMock( + '\Monolog\Handler\PushoverHandler', + array('fsockopen', 'streamSetTimeout', 'closeSocket'), + $constructorArgs + ); + + $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); + + $this->handler->setFormatter($this->getIdentityFormatter()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php new file mode 100644 index 00000000..8fe86961 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; +use Monolog\Formatter\LineFormatter; + +class RavenHandlerTest extends TestCase +{ + public function setUp() + { + if (!class_exists("Raven_Client")) { + $this->markTestSkipped("raven/raven not installed"); + } + + require_once __DIR__ . '/MockRavenClient.php'; + } + + /** + * @covers Monolog\Handler\RavenHandler::__construct + */ + public function testConstruct() + { + $handler = new RavenHandler($this->getRavenClient()); + $this->assertInstanceOf('Monolog\Handler\RavenHandler', $handler); + } + + protected function getHandler($ravenClient) + { + $handler = new RavenHandler($ravenClient); + + return $handler; + } + + protected function getRavenClient() + { + $dsn = 'http://43f6017361224d098402974103bfc53d:a6a0538fc2934ba2bed32e08741b2cd3@marca.python.live.cheggnet.com:9000/1'; + + return new MockRavenClient($dsn); + } + + public function testDebug() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + + $record = $this->getRecord(Logger::DEBUG, "A test debug message"); + $handler->handle($record); + + $this->assertEquals($ravenClient::DEBUG, $ravenClient->lastData['level']); + $this->assertContains($record['message'], $ravenClient->lastData['message']); + } + + public function testWarning() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + + $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $handler->handle($record); + + $this->assertEquals($ravenClient::WARNING, $ravenClient->lastData['level']); + $this->assertContains($record['message'], $ravenClient->lastData['message']); + } + + public function testTag() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + + $tags = array(1, 2, 'foo'); + $record = $this->getRecord(Logger::INFO, "test", array('tags' => $tags)); + $handler->handle($record); + + $this->assertEquals($tags, $ravenClient->lastData['tags']); + } + + public function testException() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + + try { + $this->methodThatThrowsAnException(); + } catch (\Exception $e) { + $record = $this->getRecord(Logger::ERROR, $e->getMessage(), array('exception' => $e)); + $handler->handle($record); + } + + $this->assertEquals($record['message'], $ravenClient->lastData['message']); + } + + public function testHandleBatch() + { + $records = $this->getMultipleRecords(); + $records[] = $this->getRecord(Logger::WARNING, 'warning'); + $records[] = $this->getRecord(Logger::WARNING, 'warning'); + + $logFormatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); + $logFormatter->expects($this->once())->method('formatBatch'); + + $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); + $formatter->expects($this->once())->method('format')->with($this->callback(function ($record) { + return $record['level'] == 400; + })); + + $handler = $this->getHandler($this->getRavenClient()); + $handler->setBatchFormatter($logFormatter); + $handler->setFormatter($formatter); + $handler->handleBatch($records); + } + + public function testHandleBatchDoNothingIfRecordsAreBelowLevel() + { + $records = array( + $this->getRecord(Logger::DEBUG, 'debug message 1'), + $this->getRecord(Logger::DEBUG, 'debug message 2'), + $this->getRecord(Logger::INFO, 'information'), + ); + + $handler = $this->getMock('Monolog\Handler\RavenHandler', null, array($this->getRavenClient())); + $handler->expects($this->never())->method('handle'); + $handler->setLevel(Logger::ERROR); + $handler->handleBatch($records); + } + + public function testGetSetBatchFormatter() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + + $handler->setBatchFormatter($formatter = new LineFormatter()); + $this->assertSame($formatter, $handler->getBatchFormatter()); + } + + private function methodThatThrowsAnException() + { + throw new \Exception('This is an exception'); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php new file mode 100644 index 00000000..3629f8a2 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; +use Monolog\Formatter\LineFormatter; + +class RedisHandlerTest extends TestCase +{ + /** + * @expectedException InvalidArgumentException + */ + public function testConstructorShouldThrowExceptionForInvalidRedis() + { + new RedisHandler(new \stdClass(), 'key'); + } + + public function testConstructorShouldWorkWithPredis() + { + $redis = $this->getMock('Predis\Client'); + $this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key')); + } + + public function testConstructorShouldWorkWithRedis() + { + $redis = $this->getMock('Redis'); + $this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key')); + } + + public function testPredisHandle() + { + $redis = $this->getMock('Predis\Client', array('rpush')); + + // Predis\Client uses rpush + $redis->expects($this->once()) + ->method('rpush') + ->with('key', 'test'); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $handler = new RedisHandler($redis, 'key'); + $handler->setFormatter(new LineFormatter("%message%")); + $handler->handle($record); + } + + public function testRedisHandle() + { + $redis = $this->getMock('Redis', array('rpush')); + + // Redis uses rPush + $redis->expects($this->once()) + ->method('rPush') + ->with('key', 'test'); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $handler = new RedisHandler($redis, 'key'); + $handler->setFormatter(new LineFormatter("%message%")); + $handler->handle($record); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php new file mode 100644 index 00000000..f4cefda1 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; + +/** + * @covers Monolog\Handler\RotatingFileHandler + */ +class RotatingFileHandlerTest extends TestCase +{ + public function setUp() + { + $dir = __DIR__.'/Fixtures'; + chmod($dir, 0777); + if (!is_writable($dir)) { + $this->markTestSkipped($dir.' must be writeable to test the RotatingFileHandler.'); + } + } + + public function testRotationCreatesNewFile() + { + touch(__DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot'); + + $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot'); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord()); + + $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; + $this->assertTrue(file_exists($log)); + $this->assertEquals('test', file_get_contents($log)); + } + + /** + * @dataProvider rotationTests + */ + public function testRotation($createFile) + { + touch($old1 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot'); + touch($old2 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 2).'.rot'); + touch($old3 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 3).'.rot'); + touch($old4 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 4).'.rot'); + + $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; + + if ($createFile) { + touch($log); + } + + $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord()); + + $handler->close(); + + $this->assertTrue(file_exists($log)); + $this->assertTrue(file_exists($old1)); + $this->assertEquals($createFile, file_exists($old2)); + $this->assertEquals($createFile, file_exists($old3)); + $this->assertEquals($createFile, file_exists($old4)); + $this->assertEquals('test', file_get_contents($log)); + } + + public function rotationTests() + { + return array( + 'Rotation is triggered when the file of the current day is not present' + => array(true), + 'Rotation is not triggered when the file is already present' + => array(false), + ); + } + + public function testReuseCurrentFile() + { + $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; + file_put_contents($log, "foo"); + $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot'); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord()); + $this->assertEquals('footest', file_get_contents($log)); + } + + public function tearDown() + { + foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { + unlink($file); + } + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php new file mode 100644 index 00000000..3a925eb5 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php @@ -0,0 +1,283 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @author Pablo de Leon Belloc + */ +class SocketHandlerTest extends TestCase +{ + /** + * @var Monolog\Handler\SocketHandler + */ + private $handler; + + /** + * @var resource + */ + private $res; + + /** + * @expectedException UnexpectedValueException + */ + public function testInvalidHostname() + { + $this->createHandler('garbage://here'); + $this->writeRecord('data'); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testBadConnectionTimeout() + { + $this->createHandler('localhost:1234'); + $this->handler->setConnectionTimeout(-1); + } + + public function testSetConnectionTimeout() + { + $this->createHandler('localhost:1234'); + $this->handler->setConnectionTimeout(10.1); + $this->assertEquals(10.1, $this->handler->getConnectionTimeout()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testBadTimeout() + { + $this->createHandler('localhost:1234'); + $this->handler->setTimeout(-1); + } + + public function testSetTimeout() + { + $this->createHandler('localhost:1234'); + $this->handler->setTimeout(10.25); + $this->assertEquals(10.25, $this->handler->getTimeout()); + } + + public function testSetConnectionString() + { + $this->createHandler('tcp://localhost:9090'); + $this->assertEquals('tcp://localhost:9090', $this->handler->getConnectionString()); + } + + /** + * @expectedException UnexpectedValueException + */ + public function testExceptionIsThrownOnFsockopenError() + { + $this->setMockHandler(array('fsockopen')); + $this->handler->expects($this->once()) + ->method('fsockopen') + ->will($this->returnValue(false)); + $this->writeRecord('Hello world'); + } + + /** + * @expectedException UnexpectedValueException + */ + public function testExceptionIsThrownOnPfsockopenError() + { + $this->setMockHandler(array('pfsockopen')); + $this->handler->expects($this->once()) + ->method('pfsockopen') + ->will($this->returnValue(false)); + $this->handler->setPersistent(true); + $this->writeRecord('Hello world'); + } + + /** + * @expectedException UnexpectedValueException + */ + public function testExceptionIsThrownIfCannotSetTimeout() + { + $this->setMockHandler(array('streamSetTimeout')); + $this->handler->expects($this->once()) + ->method('streamSetTimeout') + ->will($this->returnValue(false)); + $this->writeRecord('Hello world'); + } + + /** + * @expectedException RuntimeException + */ + public function testWriteFailsOnIfFwriteReturnsFalse() + { + $this->setMockHandler(array('fwrite')); + + $callback = function ($arg) { + $map = array( + 'Hello world' => 6, + 'world' => false, + ); + + return $map[$arg]; + }; + + $this->handler->expects($this->exactly(2)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + + $this->writeRecord('Hello world'); + } + + /** + * @expectedException RuntimeException + */ + public function testWriteFailsIfStreamTimesOut() + { + $this->setMockHandler(array('fwrite', 'streamGetMetadata')); + + $callback = function ($arg) { + $map = array( + 'Hello world' => 6, + 'world' => 5, + ); + + return $map[$arg]; + }; + + $this->handler->expects($this->exactly(1)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + $this->handler->expects($this->exactly(1)) + ->method('streamGetMetadata') + ->will($this->returnValue(array('timed_out' => true))); + + $this->writeRecord('Hello world'); + } + + /** + * @expectedException RuntimeException + */ + public function testWriteFailsOnIncompleteWrite() + { + $this->setMockHandler(array('fwrite', 'streamGetMetadata')); + + $res = $this->res; + $callback = function ($string) use ($res) { + fclose($res); + + return strlen('Hello'); + }; + + $this->handler->expects($this->exactly(1)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + $this->handler->expects($this->exactly(1)) + ->method('streamGetMetadata') + ->will($this->returnValue(array('timed_out' => false))); + + $this->writeRecord('Hello world'); + } + + public function testWriteWithMemoryFile() + { + $this->setMockHandler(); + $this->writeRecord('test1'); + $this->writeRecord('test2'); + $this->writeRecord('test3'); + fseek($this->res, 0); + $this->assertEquals('test1test2test3', fread($this->res, 1024)); + } + + public function testWriteWithMock() + { + $this->setMockHandler(array('fwrite')); + + $callback = function ($arg) { + $map = array( + 'Hello world' => 6, + 'world' => 5, + ); + + return $map[$arg]; + }; + + $this->handler->expects($this->exactly(2)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + + $this->writeRecord('Hello world'); + } + + public function testClose() + { + $this->setMockHandler(); + $this->writeRecord('Hello world'); + $this->assertInternalType('resource', $this->res); + $this->handler->close(); + $this->assertFalse(is_resource($this->res), "Expected resource to be closed after closing handler"); + } + + public function testCloseDoesNotClosePersistentSocket() + { + $this->setMockHandler(); + $this->handler->setPersistent(true); + $this->writeRecord('Hello world'); + $this->assertTrue(is_resource($this->res)); + $this->handler->close(); + $this->assertTrue(is_resource($this->res)); + } + + private function createHandler($connectionString) + { + $this->handler = new SocketHandler($connectionString); + $this->handler->setFormatter($this->getIdentityFormatter()); + } + + private function writeRecord($string) + { + $this->handler->handle($this->getRecord(Logger::WARNING, $string)); + } + + private function setMockHandler(array $methods = array()) + { + $this->res = fopen('php://memory', 'a'); + + $defaultMethods = array('fsockopen', 'pfsockopen', 'streamSetTimeout'); + $newMethods = array_diff($methods, $defaultMethods); + + $finalMethods = array_merge($defaultMethods, $newMethods); + + $this->handler = $this->getMock( + '\Monolog\Handler\SocketHandler', $finalMethods, array('localhost:1234') + ); + + if (!in_array('fsockopen', $methods)) { + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + } + + if (!in_array('pfsockopen', $methods)) { + $this->handler->expects($this->any()) + ->method('pfsockopen') + ->will($this->returnValue($this->res)); + } + + if (!in_array('streamSetTimeout', $methods)) { + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + } + + $this->handler->setFormatter($this->getIdentityFormatter()); + } + +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php new file mode 100644 index 00000000..63d4fef6 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class StreamHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\StreamHandler::__construct + * @covers Monolog\Handler\StreamHandler::write + */ + public function testWrite() + { + $handle = fopen('php://memory', 'a+'); + $handler = new StreamHandler($handle); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord(Logger::WARNING, 'test')); + $handler->handle($this->getRecord(Logger::WARNING, 'test2')); + $handler->handle($this->getRecord(Logger::WARNING, 'test3')); + fseek($handle, 0); + $this->assertEquals('testtest2test3', fread($handle, 100)); + } + + /** + * @covers Monolog\Handler\StreamHandler::close + */ + public function testClose() + { + $handle = fopen('php://memory', 'a+'); + $handler = new StreamHandler($handle); + $this->assertTrue(is_resource($handle)); + $handler->close(); + $this->assertFalse(is_resource($handle)); + } + + /** + * @covers Monolog\Handler\StreamHandler::write + */ + public function testWriteCreatesTheStreamResource() + { + $handler = new StreamHandler('php://memory'); + $handler->handle($this->getRecord()); + } + + /** + * @expectedException LogicException + * @covers Monolog\Handler\StreamHandler::__construct + * @covers Monolog\Handler\StreamHandler::write + */ + public function testWriteMissingResource() + { + $handler = new StreamHandler(null); + $handler->handle($this->getRecord()); + } + + /** + * @expectedException UnexpectedValueException + * @covers Monolog\Handler\StreamHandler::__construct + * @covers Monolog\Handler\StreamHandler::write + */ + public function testWriteInvalidResource() + { + $handler = new StreamHandler('bogus://url'); + $handler->handle($this->getRecord()); + } + + /** + * @expectedException UnexpectedValueException + * @covers Monolog\Handler\StreamHandler::__construct + * @covers Monolog\Handler\StreamHandler::write + */ + public function testWriteNonExistingResource() + { + $handler = new StreamHandler('/foo/bar/baz/'.rand(0, 10000)); + $handler->handle($this->getRecord()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php new file mode 100644 index 00000000..98219ac1 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; +use Monolog\Logger; + +class SyslogHandlerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers Monolog\Handler\SyslogHandler::__construct + */ + public function testConstruct() + { + $handler = new SyslogHandler('test'); + $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); + + $handler = new SyslogHandler('test', LOG_USER); + $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); + + $handler = new SyslogHandler('test', 'user'); + $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); + + $handler = new SyslogHandler('test', LOG_USER, Logger::DEBUG, true, LOG_PERROR); + $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); + } + + /** + * @covers Monolog\Handler\SyslogHandler::__construct + */ + public function testConstructInvalidFacility() + { + $this->setExpectedException('UnexpectedValueException'); + $handler = new SyslogHandler('test', 'unknown'); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php new file mode 100644 index 00000000..269a296e --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -0,0 +1,37 @@ +setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); + + $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('write'), array('lol', 'lol')); + $socket->expects($this->at(0)) + ->method('write') + ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">: "); + $socket->expects($this->at(1)) + ->method('write') + ->with("hej", "<".(LOG_AUTHPRIV + LOG_WARNING).">: "); + + $handler->setSocket($socket); + + $handler->handle($this->getRecordWithMessage("hej\nlol")); + } + + protected function getRecordWithMessage($msg) + { + return array('message' => $msg, 'level' => \Monolog\Logger::WARNING, 'context' => null, 'extra' => array(), 'channel' => 'lol'); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php new file mode 100644 index 00000000..801d80a9 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +/** + * @covers Monolog\Handler\TestHandler + */ +class TestHandlerTest extends TestCase +{ + /** + * @dataProvider methodProvider + */ + public function testHandler($method, $level) + { + $handler = new TestHandler; + $record = $this->getRecord($level, 'test'.$method); + $this->assertFalse($handler->{'has'.$method}($record)); + $this->assertFalse($handler->{'has'.$method.'Records'}()); + $handler->handle($record); + + $this->assertFalse($handler->{'has'.$method}('bar')); + $this->assertTrue($handler->{'has'.$method}($record)); + $this->assertTrue($handler->{'has'.$method}('test'.$method)); + $this->assertTrue($handler->{'has'.$method.'Records'}()); + + $records = $handler->getRecords(); + unset($records[0]['formatted']); + $this->assertEquals(array($record), $records); + } + + public function methodProvider() + { + return array( + array('Emergency', Logger::EMERGENCY), + array('Alert' , Logger::ALERT), + array('Critical' , Logger::CRITICAL), + array('Error' , Logger::ERROR), + array('Warning' , Logger::WARNING), + array('Info' , Logger::INFO), + array('Notice' , Logger::NOTICE), + array('Debug' , Logger::DEBUG), + ); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php new file mode 100644 index 00000000..d16b0a3d --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php @@ -0,0 +1,45 @@ +getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('send'), array('lol', 'lol')); + + $socket->expects($this->at(0)) + ->method('send') + ->with("HEADER: The quick brown fox jumps over the lazy dog"); + + $socket->write("The quick brown fox jumps over the lazy dog", "HEADER: "); + } + + public function testWeSplitLongMessages() + { + $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('send'), array('lol', 'lol')); + + $socket->expects($this->at(1)) + ->method('send') + ->with("The quick brown fox jumps over the lazy dog"); + + $aStringOfLength2048 = str_repeat("derp", 2048/4); + + $socket->write($aStringOfLength2048."The quick brown fox jumps over the lazy dog"); + } + + public function testAllSplitMessagesHasAHeader() + { + $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('send'), array('lol', 'lol')); + + $socket->expects($this->exactly(5)) + ->method('send') + ->with($this->stringStartsWith("HEADER")); + + $aStringOfLength8192 = str_repeat("derp", 2048); + + $socket->write($aStringOfLength8192, "HEADER"); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php new file mode 100644 index 00000000..416039e6 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; + +class ZendMonitorHandlerTest extends TestCase +{ + protected $zendMonitorHandler; + + public function setUp() + { + if (!function_exists('zend_monitor_custom_event')) { + $this->markTestSkipped('ZendServer is not installed'); + } + } + + /** + * @covers Monolog\Handler\ZendMonitorHandler::write + */ + public function testWrite() + { + $record = $this->getRecord(); + $formatterResult = array( + 'message' => $record['message'] + ); + + $zendMonitor = $this->getMockBuilder('Monolog\Handler\ZendMonitorHandler') + ->setMethods(array('writeZendMonitorCustomEvent', 'getDefaultFormatter')) + ->getMock(); + + $formatterMock = $this->getMockBuilder('Monolog\Formatter\NormalizerFormatter') + ->disableOriginalConstructor() + ->getMock(); + + $formatterMock->expects($this->once()) + ->method('format') + ->will($this->returnValue($formatterResult)); + + $zendMonitor->expects($this->once()) + ->method('getDefaultFormatter') + ->will($this->returnValue($formatterMock)); + + $levelMap = $zendMonitor->getLevelMap(); + + $zendMonitor->expects($this->once()) + ->method('writeZendMonitorCustomEvent') + ->with($levelMap[$record['level']], $record['message'], $formatterResult); + + $zendMonitor->handle($record); + } + + /** + * @covers Monolog\Handler\ZendMonitorHandler::getDefaultFormatter + */ + public function testGetDefaultFormatterReturnsNormalizerFormatter() + { + $zendMonitor = new ZendMonitorHandler(); + $this->assertInstanceOf('Monolog\Formatter\NormalizerFormatter', $zendMonitor->getDefaultFormatter()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/LoggerTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/LoggerTest.php new file mode 100644 index 00000000..7a19c0b4 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/LoggerTest.php @@ -0,0 +1,409 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Monolog\Processor\WebProcessor; +use Monolog\Handler\TestHandler; + +class LoggerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers Monolog\Logger::getName + */ + public function testGetName() + { + $logger = new Logger('foo'); + $this->assertEquals('foo', $logger->getName()); + } + + /** + * @covers Monolog\Logger::getLevelName + */ + public function testGetLevelName() + { + $this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR)); + } + + /** + * @covers Monolog\Logger::getLevelName + * @expectedException InvalidArgumentException + */ + public function testGetLevelNameThrows() + { + Logger::getLevelName(5); + } + + /** + * @covers Monolog\Logger::__construct + */ + public function testChannel() + { + $logger = new Logger('foo'); + $handler = new TestHandler; + $logger->pushHandler($handler); + $logger->addWarning('test'); + list($record) = $handler->getRecords(); + $this->assertEquals('foo', $record['channel']); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testLog() + { + $logger = new Logger(__METHOD__); + + $handler = $this->getMock('Monolog\Handler\NullHandler', array('handle')); + $handler->expects($this->once()) + ->method('handle'); + $logger->pushHandler($handler); + + $this->assertTrue($logger->addWarning('test')); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testLogNotHandled() + { + $logger = new Logger(__METHOD__); + + $handler = $this->getMock('Monolog\Handler\NullHandler', array('handle'), array(Logger::ERROR)); + $handler->expects($this->never()) + ->method('handle'); + $logger->pushHandler($handler); + + $this->assertFalse($logger->addWarning('test')); + } + + public function testHandlersInCtor() + { + $handler1 = new TestHandler; + $handler2 = new TestHandler; + $logger = new Logger(__METHOD__, array($handler1, $handler2)); + + $this->assertEquals($handler1, $logger->popHandler()); + $this->assertEquals($handler2, $logger->popHandler()); + } + + public function testProcessorsInCtor() + { + $processor1 = new WebProcessor; + $processor2 = new WebProcessor; + $logger = new Logger(__METHOD__, array(), array($processor1, $processor2)); + + $this->assertEquals($processor1, $logger->popProcessor()); + $this->assertEquals($processor2, $logger->popProcessor()); + } + + /** + * @covers Monolog\Logger::pushHandler + * @covers Monolog\Logger::popHandler + * @expectedException LogicException + */ + public function testPushPopHandler() + { + $logger = new Logger(__METHOD__); + $handler1 = new TestHandler; + $handler2 = new TestHandler; + + $logger->pushHandler($handler1); + $logger->pushHandler($handler2); + + $this->assertEquals($handler2, $logger->popHandler()); + $this->assertEquals($handler1, $logger->popHandler()); + $logger->popHandler(); + } + + /** + * @covers Monolog\Logger::pushProcessor + * @covers Monolog\Logger::popProcessor + * @expectedException LogicException + */ + public function testPushPopProcessor() + { + $logger = new Logger(__METHOD__); + $processor1 = new WebProcessor; + $processor2 = new WebProcessor; + + $logger->pushProcessor($processor1); + $logger->pushProcessor($processor2); + + $this->assertEquals($processor2, $logger->popProcessor()); + $this->assertEquals($processor1, $logger->popProcessor()); + $logger->popProcessor(); + } + + /** + * @covers Monolog\Logger::pushProcessor + * @expectedException InvalidArgumentException + */ + public function testPushProcessorWithNonCallable() + { + $logger = new Logger(__METHOD__); + + $logger->pushProcessor(new \stdClass()); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testProcessorsAreExecuted() + { + $logger = new Logger(__METHOD__); + $handler = new TestHandler; + $logger->pushHandler($handler); + $logger->pushProcessor(function ($record) { + $record['extra']['win'] = true; + + return $record; + }); + $logger->addError('test'); + list($record) = $handler->getRecords(); + $this->assertTrue($record['extra']['win']); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testProcessorsAreCalledOnlyOnce() + { + $logger = new Logger(__METHOD__); + $handler = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler->expects($this->any()) + ->method('handle') + ->will($this->returnValue(true)) + ; + $logger->pushHandler($handler); + + $processor = $this->getMockBuilder('Monolog\Processor\WebProcessor') + ->disableOriginalConstructor() + ->setMethods(array('__invoke')) + ->getMock() + ; + $processor->expects($this->once()) + ->method('__invoke') + ->will($this->returnArgument(0)) + ; + $logger->pushProcessor($processor); + + $logger->addError('test'); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testProcessorsNotCalledWhenNotHandled() + { + $logger = new Logger(__METHOD__); + $handler = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler->expects($this->once()) + ->method('isHandling') + ->will($this->returnValue(false)) + ; + $logger->pushHandler($handler); + $that = $this; + $logger->pushProcessor(function ($record) use ($that) { + $that->fail('The processor should not be called'); + }); + $logger->addAlert('test'); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testHandlersNotCalledBeforeFirstHandling() + { + $logger = new Logger(__METHOD__); + + $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler1->expects($this->never()) + ->method('isHandling') + ->will($this->returnValue(false)) + ; + $handler1->expects($this->once()) + ->method('handle') + ->will($this->returnValue(false)) + ; + $logger->pushHandler($handler1); + + $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler2->expects($this->once()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler2->expects($this->once()) + ->method('handle') + ->will($this->returnValue(false)) + ; + $logger->pushHandler($handler2); + + $handler3 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler3->expects($this->once()) + ->method('isHandling') + ->will($this->returnValue(false)) + ; + $handler3->expects($this->never()) + ->method('handle') + ; + $logger->pushHandler($handler3); + + $logger->debug('test'); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testBubblingWhenTheHandlerReturnsFalse() + { + $logger = new Logger(__METHOD__); + + $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler1->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler1->expects($this->once()) + ->method('handle') + ->will($this->returnValue(false)) + ; + $logger->pushHandler($handler1); + + $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler2->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler2->expects($this->once()) + ->method('handle') + ->will($this->returnValue(false)) + ; + $logger->pushHandler($handler2); + + $logger->debug('test'); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testNotBubblingWhenTheHandlerReturnsTrue() + { + $logger = new Logger(__METHOD__); + + $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler1->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler1->expects($this->never()) + ->method('handle') + ; + $logger->pushHandler($handler1); + + $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler2->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler2->expects($this->once()) + ->method('handle') + ->will($this->returnValue(true)) + ; + $logger->pushHandler($handler2); + + $logger->debug('test'); + } + + /** + * @covers Monolog\Logger::isHandling + */ + public function testIsHandling() + { + $logger = new Logger(__METHOD__); + + $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler1->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(false)) + ; + + $logger->pushHandler($handler1); + $this->assertFalse($logger->isHandling(Logger::DEBUG)); + + $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler2->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + + $logger->pushHandler($handler2); + $this->assertTrue($logger->isHandling(Logger::DEBUG)); + } + + /** + * @dataProvider logMethodProvider + * @covers Monolog\Logger::addDebug + * @covers Monolog\Logger::addInfo + * @covers Monolog\Logger::addNotice + * @covers Monolog\Logger::addWarning + * @covers Monolog\Logger::addError + * @covers Monolog\Logger::addCritical + * @covers Monolog\Logger::addAlert + * @covers Monolog\Logger::addEmergency + * @covers Monolog\Logger::debug + * @covers Monolog\Logger::info + * @covers Monolog\Logger::notice + * @covers Monolog\Logger::warn + * @covers Monolog\Logger::err + * @covers Monolog\Logger::crit + * @covers Monolog\Logger::alert + * @covers Monolog\Logger::emerg + */ + public function testLogMethods($method, $expectedLevel) + { + $logger = new Logger('foo'); + $handler = new TestHandler; + $logger->pushHandler($handler); + $logger->{$method}('test'); + list($record) = $handler->getRecords(); + $this->assertEquals($expectedLevel, $record['level']); + } + + public function logMethodProvider() + { + return array( + // monolog methods + array('addDebug', Logger::DEBUG), + array('addInfo', Logger::INFO), + array('addNotice', Logger::NOTICE), + array('addWarning', Logger::WARNING), + array('addError', Logger::ERROR), + array('addCritical', Logger::CRITICAL), + array('addAlert', Logger::ALERT), + array('addEmergency', Logger::EMERGENCY), + + // ZF/Sf2 compat methods + array('debug', Logger::DEBUG), + array('info', Logger::INFO), + array('notice', Logger::NOTICE), + array('warn', Logger::WARNING), + array('err', Logger::ERROR), + array('crit', Logger::CRITICAL), + array('alert', Logger::ALERT), + array('emerg', Logger::EMERGENCY), + ); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php new file mode 100644 index 00000000..5adb505d --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\TestCase; + +class GitProcessorTest extends TestCase +{ + /** + * @covers Monolog\Processor\GitProcessor::__invoke + */ + public function testProcessor() + { + $processor = new GitProcessor(); + $record = $processor($this->getRecord()); + + $this->assertArrayHasKey('git', $record['extra']); + $this->assertTrue(!is_array($record['extra']['git']['branch'])); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php new file mode 100644 index 00000000..0dd411d7 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Acme; + +class Tester +{ + public function test($handler, $record) + { + $handler->handle($record); + } +} + +function tester($handler, $record) +{ + $handler->handle($record); +} + +namespace Monolog\Processor; + +use Monolog\Logger; +use Monolog\TestCase; +use Monolog\Handler\TestHandler; + +class IntrospectionProcessorTest extends TestCase +{ + public function getHandler() + { + $processor = new IntrospectionProcessor(); + $handler = new TestHandler(); + $handler->pushProcessor($processor); + + return $handler; + } + + public function testProcessorFromClass() + { + $handler = $this->getHandler(); + $tester = new \Acme\Tester; + $tester->test($handler, $this->getRecord()); + list($record) = $handler->getRecords(); + $this->assertEquals(__FILE__, $record['extra']['file']); + $this->assertEquals(18, $record['extra']['line']); + $this->assertEquals('Acme\Tester', $record['extra']['class']); + $this->assertEquals('test', $record['extra']['function']); + } + + public function testProcessorFromFunc() + { + $handler = $this->getHandler(); + \Acme\tester($handler, $this->getRecord()); + list($record) = $handler->getRecords(); + $this->assertEquals(__FILE__, $record['extra']['file']); + $this->assertEquals(24, $record['extra']['line']); + $this->assertEquals(null, $record['extra']['class']); + $this->assertEquals('Acme\tester', $record['extra']['function']); + } + + public function testLevelTooLow() + { + $input = array( + 'level' => Logger::DEBUG, + 'extra' => array(), + ); + + $expected = $input; + + $processor = new IntrospectionProcessor(Logger::CRITICAL); + $actual = $processor($input); + + $this->assertEquals($expected, $actual); + } + + public function testLevelEqual() + { + $input = array( + 'level' => Logger::CRITICAL, + 'extra' => array(), + ); + + $expected = $input; + $expected['extra'] = array( + 'file' => null, + 'line' => null, + 'class' => 'ReflectionMethod', + 'function' => 'invokeArgs', + ); + + $processor = new IntrospectionProcessor(Logger::CRITICAL); + $actual = $processor($input); + + $this->assertEquals($expected, $actual); + } + + public function testLevelHigher() + { + $input = array( + 'level' => Logger::EMERGENCY, + 'extra' => array(), + ); + + $expected = $input; + $expected['extra'] = array( + 'file' => null, + 'line' => null, + 'class' => 'ReflectionMethod', + 'function' => 'invokeArgs', + ); + + $processor = new IntrospectionProcessor(Logger::CRITICAL); + $actual = $processor($input); + + $this->assertEquals($expected, $actual); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php new file mode 100644 index 00000000..eb666144 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\TestCase; + +class MemoryPeakUsageProcessorTest extends TestCase +{ + /** + * @covers Monolog\Processor\MemoryPeakUsageProcessor::__invoke + * @covers Monolog\Processor\MemoryProcessor::formatBytes + */ + public function testProcessor() + { + $processor = new MemoryPeakUsageProcessor(); + $record = $processor($this->getRecord()); + $this->assertArrayHasKey('memory_peak_usage', $record['extra']); + $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_peak_usage']); + } + + /** + * @covers Monolog\Processor\MemoryPeakUsageProcessor::__invoke + * @covers Monolog\Processor\MemoryProcessor::formatBytes + */ + public function testProcessorWithoutFormatting() + { + $processor = new MemoryPeakUsageProcessor(true, false); + $record = $processor($this->getRecord()); + $this->assertArrayHasKey('memory_peak_usage', $record['extra']); + $this->assertInternalType('int', $record['extra']['memory_peak_usage']); + $this->assertGreaterThan(0, $record['extra']['memory_peak_usage']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php new file mode 100644 index 00000000..4692dbfc --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\TestCase; + +class MemoryUsageProcessorTest extends TestCase +{ + /** + * @covers Monolog\Processor\MemoryUsageProcessor::__invoke + * @covers Monolog\Processor\MemoryProcessor::formatBytes + */ + public function testProcessor() + { + $processor = new MemoryUsageProcessor(); + $record = $processor($this->getRecord()); + $this->assertArrayHasKey('memory_usage', $record['extra']); + $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_usage']); + } + + /** + * @covers Monolog\Processor\MemoryUsageProcessor::__invoke + * @covers Monolog\Processor\MemoryProcessor::formatBytes + */ + public function testProcessorWithoutFormatting() + { + $processor = new MemoryUsageProcessor(true, false); + $record = $processor($this->getRecord()); + $this->assertArrayHasKey('memory_usage', $record['extra']); + $this->assertInternalType('int', $record['extra']['memory_usage']); + $this->assertGreaterThan(0, $record['extra']['memory_usage']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php new file mode 100644 index 00000000..458d2a33 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\TestCase; + +class ProcessIdProcessorTest extends TestCase +{ + /** + * @covers Monolog\Processor\ProcessIdProcessor::__invoke + */ + public function testProcessor() + { + $processor = new ProcessIdProcessor(); + $record = $processor($this->getRecord()); + $this->assertArrayHasKey('process_id', $record['extra']); + $this->assertInternalType('int', $record['extra']['process_id']); + $this->assertGreaterThan(0, $record['extra']['process_id']); + $this->assertEquals(getmypid(), $record['extra']['process_id']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php new file mode 100644 index 00000000..851a9dc2 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\TestCase; + +class TagProcessorTest extends TestCase +{ + /** + * @covers Monolog\Processor\TagProcessor::__invoke + */ + public function testProcessor() + { + $tags = array(1, 2, 3); + $processor = new TagProcessor($tags); + $record = $processor($this->getRecord()); + + $this->assertEquals($tags, $record['extra']['tags']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php new file mode 100644 index 00000000..7ced62ca --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\TestCase; + +class UidProcessorTest extends TestCase +{ + /** + * @covers Monolog\Processor\UidProcessor::__invoke + */ + public function testProcessor() + { + $processor = new UidProcessor(); + $record = $processor($this->getRecord()); + $this->assertArrayHasKey('uid', $record['extra']); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php new file mode 100644 index 00000000..df29fdd6 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +use Monolog\TestCase; + +class WebProcessorTest extends TestCase +{ + public function testProcessor() + { + $server = array( + 'REQUEST_URI' => 'A', + 'REMOTE_ADDR' => 'B', + 'REQUEST_METHOD' => 'C', + 'HTTP_REFERER' => 'D', + 'SERVER_NAME' => 'F', + 'UNIQUE_ID' => 'G', + ); + + $processor = new WebProcessor($server); + $record = $processor($this->getRecord()); + $this->assertEquals($server['REQUEST_URI'], $record['extra']['url']); + $this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']); + $this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']); + $this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']); + $this->assertEquals($server['SERVER_NAME'], $record['extra']['server']); + $this->assertEquals($server['UNIQUE_ID'], $record['extra']['unique_id']); + } + + public function testProcessorDoNothingIfNoRequestUri() + { + $server = array( + 'REMOTE_ADDR' => 'B', + 'REQUEST_METHOD' => 'C', + ); + $processor = new WebProcessor($server); + $record = $processor($this->getRecord()); + $this->assertEmpty($record['extra']); + } + + public function testProcessorReturnNullIfNoHttpReferer() + { + $server = array( + 'REQUEST_URI' => 'A', + 'REMOTE_ADDR' => 'B', + 'REQUEST_METHOD' => 'C', + 'SERVER_NAME' => 'F', + ); + $processor = new WebProcessor($server); + $record = $processor($this->getRecord()); + $this->assertNull($record['extra']['referrer']); + } + + public function testProcessorDoesNotAddUniqueIdIfNotPresent() + { + $server = array( + 'REQUEST_URI' => 'A', + 'REMOTE_ADDR' => 'B', + 'REQUEST_METHOD' => 'C', + 'SERVER_NAME' => 'F', + ); + $processor = new WebProcessor($server); + $record = $processor($this->getRecord()); + $this->assertFalse(isset($record['extra']['unique_id'])); + } + + /** + * @expectedException UnexpectedValueException + */ + public function testInvalidData() + { + new WebProcessor(new \stdClass); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php b/src/lib/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php new file mode 100644 index 00000000..ab899449 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Monolog\Handler\TestHandler; +use Monolog\Formatter\LineFormatter; +use Monolog\Processor\PsrLogMessageProcessor; +use Psr\Log\Test\LoggerInterfaceTest; + +class PsrLogCompatTest extends LoggerInterfaceTest +{ + private $handler; + + public function getLogger() + { + $logger = new Logger('foo'); + $logger->pushHandler($handler = new TestHandler); + $logger->pushProcessor(new PsrLogMessageProcessor); + $handler->setFormatter(new LineFormatter('%level_name% %message%')); + + $this->handler = $handler; + + return $logger; + } + + public function getLogs() + { + $convert = function ($record) { + $lower = function ($match) { + return strtolower($match[0]); + }; + + return preg_replace_callback('{^[A-Z]+}', $lower, $record['formatted']); + }; + + return array_map($convert, $this->handler->getRecords()); + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/Monolog/TestCase.php b/src/lib/vendor/monolog/monolog/tests/Monolog/TestCase.php new file mode 100644 index 00000000..cae79340 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/Monolog/TestCase.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +class TestCase extends \PHPUnit_Framework_TestCase +{ + /** + * @return array Record + */ + protected function getRecord($level = Logger::WARNING, $message = 'test', $context = array()) + { + return array( + 'message' => $message, + 'context' => $context, + 'level' => $level, + 'level_name' => Logger::getLevelName($level), + 'channel' => 'test', + 'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true))), + 'extra' => array(), + ); + } + + /** + * @return array + */ + protected function getMultipleRecords() + { + return array( + $this->getRecord(Logger::DEBUG, 'debug message 1'), + $this->getRecord(Logger::DEBUG, 'debug message 2'), + $this->getRecord(Logger::INFO, 'information'), + $this->getRecord(Logger::WARNING, 'warning'), + $this->getRecord(Logger::ERROR, 'error') + ); + } + + /** + * @return Monolog\Formatter\FormatterInterface + */ + protected function getIdentityFormatter() + { + $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); + $formatter->expects($this->any()) + ->method('format') + ->will($this->returnCallback(function ($record) { return $record['message']; })); + + return $formatter; + } +} diff --git a/src/lib/vendor/monolog/monolog/tests/bootstrap.php b/src/lib/vendor/monolog/monolog/tests/bootstrap.php new file mode 100644 index 00000000..b78740e2 --- /dev/null +++ b/src/lib/vendor/monolog/monolog/tests/bootstrap.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$loader = require __DIR__ . "/../vendor/autoload.php"; +$loader->addPsr4('Monolog\\', __DIR__.'/Monolog'); + +date_default_timezone_set('UTC'); diff --git a/src/lib/vendor/pimple/pimple/.gitignore b/src/lib/vendor/pimple/pimple/.gitignore new file mode 100644 index 00000000..c089b095 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/.gitignore @@ -0,0 +1,3 @@ +phpunit.xml +composer.lock +/vendor/ diff --git a/src/lib/vendor/pimple/pimple/.travis.yml b/src/lib/vendor/pimple/pimple/.travis.yml new file mode 100644 index 00000000..5f8bb7c9 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/.travis.yml @@ -0,0 +1,32 @@ +language: php + +env: + matrix: + - PIMPLE_EXT=no + - PIMPLE_EXT=yes + global: + - REPORT_EXIT_STATUS=1 + +php: + - 5.3 + - 5.4 + - 5.5 + - 5.6 + - hhvm + +before_script: + - composer self-update + - COMPOSER_ROOT_VERSION=dev-master composer dump-autoload + - if [ "$PIMPLE_EXT" == "yes" ]; then sh -c "cd ext/pimple && phpize && ./configure && make && sudo make install"; fi + - if [ "$PIMPLE_EXT" == "yes" ]; then echo "extension=pimple.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi + +script: + - cd ext/pimple + - if [ "$PIMPLE_EXT" == "yes" ]; then yes n | make test | tee output ; grep -E 'Tests failed +. +0' output; fi + - cd ../.. + - phpunit + +matrix: + exclude: + - php: hhvm + env: PIMPLE_EXT=yes diff --git a/src/lib/vendor/pimple/pimple/CHANGELOG b/src/lib/vendor/pimple/pimple/CHANGELOG new file mode 100644 index 00000000..084ec80a --- /dev/null +++ b/src/lib/vendor/pimple/pimple/CHANGELOG @@ -0,0 +1,21 @@ +* 2.1.1 (2014-07-24) + + * fixed compiler warnings for the C extension + * fixed code when dealing with circular references + +* 2.1.0 (2014-06-24) + + * moved the Pimple to Pimple\Container (with a BC layer -- Pimple is now a + deprecated alias which will be removed in Pimple 3.0) + * added Pimple\ServiceProviderInterface (and Pimple::register()) + +* 2.0.0 (2014-02-10) + + * changed extend to automatically re-assign the extended service and keep it as shared or factory + (to keep BC, extend still returns the extended service) + * changed services to be shared by default (use factory() for factory + services) + +* 1.0.0 + + * initial version diff --git a/src/lib/vendor/pimple/pimple/LICENSE b/src/lib/vendor/pimple/pimple/LICENSE new file mode 100644 index 00000000..86b4721b --- /dev/null +++ b/src/lib/vendor/pimple/pimple/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2009-2014 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/lib/vendor/pimple/pimple/README.rst b/src/lib/vendor/pimple/pimple/README.rst new file mode 100644 index 00000000..217885d8 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/README.rst @@ -0,0 +1,210 @@ +Pimple +====== + +.. caution:: + + This is the documentation for Pimple 2.x. If you are using Pimple 1.x, read + the `Pimple 1.x documentation`_. Reading the Pimple 1.x code is also a good + way to learn more about how to create a simple Dependency Injection + Container (Pimple 2.x implementation being more focused on performance). + +Pimple is a small Dependency Injection Container for PHP. + +Installation +------------ + +Before using Pimple in your project, add it to your ``composer.json`` file: + +.. code-block:: bash + + $ ./composer.phar require pimple/pimple ~2.1 + +Alternatively, Pimple is also available as a PHP C extension: + +.. code-block:: bash + + $ cd ext/pimple + $ phpize + $ ./configure + $ make + $ make install + +Usage +----- + +Creating a container is a matter of creating a ``Container`` instance: + +.. code-block:: php + + use Pimple\Container; + + $container = new Container(); + +.. note:: + + In Pimple 2.0, the class ``Pimple\Container`` was named ``Pimple`` (a class + alias is automatically registered to keep backward compatibility, but you + should upgrade your code.) + +As many other dependency injection containers, Pimple manages two different +kind of data: **services** and **parameters**. + +Defining Services +~~~~~~~~~~~~~~~~~ + +A service is an object that does something as part of a larger system. Examples +of services: a database connection, a templating engine, or a mailer. Almost +any **global** object can be a service. + +Services are defined by **anonymous functions** that return an instance of an +object: + +.. code-block:: php + + // define some services + $container['session_storage'] = function ($c) { + return new SessionStorage('SESSION_ID'); + }; + + $container['session'] = function ($c) { + return new Session($c['session_storage']); + }; + +Notice that the anonymous function has access to the current container +instance, allowing references to other services or parameters. + +As objects are only created when you get them, the order of the definitions +does not matter. + +Using the defined services is also very easy: + +.. code-block:: php + + // get the session object + $session = $container['session']; + + // the above call is roughly equivalent to the following code: + // $storage = new SessionStorage('SESSION_ID'); + // $session = new Session($storage); + +Defining Factory Services +~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, each time you get a service, Pimple returns the **same instance** +of it. If you want a different instance to be returned for all calls, wrap your +anonymous function with the ``factory()`` method + +.. code-block:: php + + $container['session'] = $container->factory(function ($c) { + return new Session($c['session_storage']); + }); + +Now, each call to ``$container['session']`` returns a new instance of the +session. + +Defining Parameters +~~~~~~~~~~~~~~~~~~~ + +Defining a parameter allows to ease the configuration of your container from +the outside and to store global values: + +.. code-block:: php + + // define some parameters + $container['cookie_name'] = 'SESSION_ID'; + $container['session_storage_class'] = 'SessionStorage'; + +If you change the ``session_storage`` service definition like below: + +.. code-block:: php + + $container['session_storage'] = function ($c) { + return new $c['session_storage_class']($c['cookie_name']); + }; + +You can now easily change the cookie name by overriding the +``session_storage_class`` parameter instead of redefining the service +definition. + +Protecting Parameters +~~~~~~~~~~~~~~~~~~~~~ + +Because Pimple sees anonymous functions as service definitions, you need to +wrap anonymous functions with the ``protect()`` method to store them as +parameters: + +.. code-block:: php + + $container['random_func'] = $container->protect(function () { + return rand(); + }); + +Modifying Services after Definition +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases you may want to modify a service definition after it has been +defined. You can use the ``extend()`` method to define additional code to be +run on your service just after it is created: + +.. code-block:: php + + $container['session_storage'] = function ($c) { + return new $c['session_storage_class']($c['cookie_name']); + }; + + $container->extend('session_storage', function ($storage, $c) { + $storage->...(); + + return $storage; + }; + +The first argument is the name of the service to extend, the second a function +that gets access to the object instance and the container. + +Extending a Container +~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.1 + + Support for extending a container was introduced in Pimple 2.1. + +If you use the same libraries over and over, you might want to reuse some +services from one project to the next one; package your services into a +**provider** by implementing ``Pimple\ServiceProviderInterface``: + +.. code-block:: php + + use Pimple\Container; + + class FooProvider implements Pimple\ServiceProviderInterface + { + public function register(Container $pimple) + { + // register some services and parameters + // on $pimple + } + } + +Then, register the provider on a Container: + +.. code-block:: php + + $pimple->register(new FooProvider()); + +Fetching the Service Creation Function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you access an object, Pimple automatically calls the anonymous function +that you defined, which creates the service object for you. If you want to get +raw access to this function, you can use the ``raw()`` method: + +.. code-block:: php + + $container['session'] = function ($c) { + return new Session($c['session_storage']); + }; + + $sessionFunction = $container->raw('session'); + +.. _Pimple 1.x documentation: https://github.com/fabpot/Pimple/tree/1.1 diff --git a/src/lib/vendor/pimple/pimple/composer.json b/src/lib/vendor/pimple/pimple/composer.json new file mode 100644 index 00000000..1a14653e --- /dev/null +++ b/src/lib/vendor/pimple/pimple/composer.json @@ -0,0 +1,28 @@ +{ + "name": "pimple/pimple", + "type": "library", + "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", + "keywords": ["dependency injection", "container"], + "homepage": "http://pimple.sensiolabs.org", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-0": { "Pimple": "src/" } + }, + "autoload-dev": { + "psr-4": { "Pimple\\Tests\\": "tests/" } + }, + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + } +} diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/.gitignore b/src/lib/vendor/pimple/pimple/ext/pimple/.gitignore new file mode 100644 index 00000000..1861088a --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/.gitignore @@ -0,0 +1,30 @@ +*.sw* +.deps +Makefile +Makefile.fragments +Makefile.global +Makefile.objects +acinclude.m4 +aclocal.m4 +build/ +config.cache +config.guess +config.h +config.h.in +config.log +config.nice +config.status +config.sub +configure +configure.in +install-sh +libtool +ltmain.sh +missing +mkinstalldirs +run-tests.php +*.loT +.libs/ +modules/ +*.la +*.lo diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/README.md b/src/lib/vendor/pimple/pimple/ext/pimple/README.md new file mode 100644 index 00000000..7b39eb29 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/README.md @@ -0,0 +1,12 @@ +This is Pimple 2 implemented in C + +* PHP >= 5.3 +* Not tested under Windows, might work + +Install +======= + + > phpize + > ./configure + > make + > make install diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/config.m4 b/src/lib/vendor/pimple/pimple/ext/pimple/config.m4 new file mode 100644 index 00000000..c9ba17dd --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/config.m4 @@ -0,0 +1,63 @@ +dnl $Id$ +dnl config.m4 for extension pimple + +dnl Comments in this file start with the string 'dnl'. +dnl Remove where necessary. This file will not work +dnl without editing. + +dnl If your extension references something external, use with: + +dnl PHP_ARG_WITH(pimple, for pimple support, +dnl Make sure that the comment is aligned: +dnl [ --with-pimple Include pimple support]) + +dnl Otherwise use enable: + +PHP_ARG_ENABLE(pimple, whether to enable pimple support, +dnl Make sure that the comment is aligned: +[ --enable-pimple Enable pimple support]) + +if test "$PHP_PIMPLE" != "no"; then + dnl Write more examples of tests here... + + dnl # --with-pimple -> check with-path + dnl SEARCH_PATH="/usr/local /usr" # you might want to change this + dnl SEARCH_FOR="/include/pimple.h" # you most likely want to change this + dnl if test -r $PHP_PIMPLE/$SEARCH_FOR; then # path given as parameter + dnl PIMPLE_DIR=$PHP_PIMPLE + dnl else # search default path list + dnl AC_MSG_CHECKING([for pimple files in default path]) + dnl for i in $SEARCH_PATH ; do + dnl if test -r $i/$SEARCH_FOR; then + dnl PIMPLE_DIR=$i + dnl AC_MSG_RESULT(found in $i) + dnl fi + dnl done + dnl fi + dnl + dnl if test -z "$PIMPLE_DIR"; then + dnl AC_MSG_RESULT([not found]) + dnl AC_MSG_ERROR([Please reinstall the pimple distribution]) + dnl fi + + dnl # --with-pimple -> add include path + dnl PHP_ADD_INCLUDE($PIMPLE_DIR/include) + + dnl # --with-pimple -> check for lib and symbol presence + dnl LIBNAME=pimple # you may want to change this + dnl LIBSYMBOL=pimple # you most likely want to change this + + dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, + dnl [ + dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $PIMPLE_DIR/lib, PIMPLE_SHARED_LIBADD) + dnl AC_DEFINE(HAVE_PIMPLELIB,1,[ ]) + dnl ],[ + dnl AC_MSG_ERROR([wrong pimple lib version or lib not found]) + dnl ],[ + dnl -L$PIMPLE_DIR/lib -lm + dnl ]) + dnl + dnl PHP_SUBST(PIMPLE_SHARED_LIBADD) + + PHP_NEW_EXTENSION(pimple, pimple.c, $ext_shared) +fi diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/config.w32 b/src/lib/vendor/pimple/pimple/ext/pimple/config.w32 new file mode 100644 index 00000000..39857b32 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/config.w32 @@ -0,0 +1,13 @@ +// $Id$ +// vim:ft=javascript + +// If your extension references something external, use ARG_WITH +// ARG_WITH("pimple", "for pimple support", "no"); + +// Otherwise, use ARG_ENABLE +// ARG_ENABLE("pimple", "enable pimple support", "no"); + +if (PHP_PIMPLE != "no") { + EXTENSION("pimple", "pimple.c"); +} + diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/php_pimple.h b/src/lib/vendor/pimple/pimple/ext/pimple/php_pimple.h new file mode 100644 index 00000000..619ccb6d --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/php_pimple.h @@ -0,0 +1,122 @@ + +/* + * This file is part of Pimple. + * + * Copyright (c) 2014 Fabien Potencier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef PHP_PIMPLE_H +#define PHP_PIMPLE_H + +extern zend_module_entry pimple_module_entry; +#define phpext_pimple_ptr &pimple_module_entry + +#ifdef PHP_WIN32 +# define PHP_PIMPLE_API __declspec(dllexport) +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define PHP_PIMPLE_API __attribute__ ((visibility("default"))) +#else +# define PHP_PIMPLE_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +#define PIMPLE_VERSION "2.1.1" +#define PIMPLE_NS "Pimple" + +#define PIMPLE_DEFAULT_ZVAL_CACHE_NUM 5 +#define PIMPLE_DEFAULT_ZVAL_VALUES_NUM 10 + +PHP_MINIT_FUNCTION(pimple); +PHP_MSHUTDOWN_FUNCTION(pimple); +PHP_RINIT_FUNCTION(pimple); +PHP_RSHUTDOWN_FUNCTION(pimple); +PHP_MINFO_FUNCTION(pimple); + +PHP_METHOD(Pimple, __construct); +PHP_METHOD(Pimple, factory); +PHP_METHOD(Pimple, protect); +PHP_METHOD(Pimple, raw); +PHP_METHOD(Pimple, extend); +PHP_METHOD(Pimple, keys); +PHP_METHOD(Pimple, register); +PHP_METHOD(Pimple, offsetSet); +PHP_METHOD(Pimple, offsetUnset); +PHP_METHOD(Pimple, offsetGet); +PHP_METHOD(Pimple, offsetExists); + +PHP_METHOD(PimpleClosure, __invoke); + +typedef struct _pimple_bucket_value { + zval *value; /* Must be the first element */ + zval *raw; + zend_fcall_info_cache *fcc; + zend_object_handle handle_num; + enum { + PIMPLE_IS_PARAM = 0, + PIMPLE_IS_SERVICE = 2 + } type; + zend_bool initialized; +} pimple_bucket_value; + +typedef struct _pimple_object { + zend_object zobj; + HashTable values; + HashTable factories; + HashTable protected; +} pimple_object; + +typedef struct _pimple_closure_object { + zend_object zobj; + zval *callable; + zval *factory; +} pimple_closure_object; + +static const char sensiolabs_logo[] = ""; + +static int pimple_zval_to_pimpleval(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC); +static int pimple_zval_is_valid_callback(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC); + +static void pimple_init_bucket(pimple_bucket_value *bucket); +static void pimple_bucket_dtor(pimple_bucket_value *bucket); +static void pimple_free_bucket(pimple_bucket_value *bucket); + +static zval *pimple_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC); +static void pimple_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC); +static int pimple_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC); +static void pimple_object_unset_dimension(zval *object, zval *offset TSRMLS_DC); +static zend_object_value pimple_object_create(zend_class_entry *ce TSRMLS_DC); +static void pimple_free_object_storage(pimple_object *obj TSRMLS_DC); + +static void pimple_closure_free_object_storage(pimple_closure_object *obj TSRMLS_DC); +static zend_object_value pimple_closure_object_create(zend_class_entry *ce TSRMLS_DC); +static zend_function *pimple_closure_get_constructor(zval * TSRMLS_DC); + +#ifdef ZTS +#define PIMPLE_G(v) TSRMG(pimple_globals_id, zend_pimple_globals *, v) +#else +#define PIMPLE_G(v) (pimple_globals.v) +#endif + +#endif /* PHP_PIMPLE_H */ + diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/pimple.c b/src/lib/vendor/pimple/pimple/ext/pimple/pimple.c new file mode 100644 index 00000000..44eb8da7 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/pimple.c @@ -0,0 +1,940 @@ + +/* + * This file is part of Pimple. + * + * Copyright (c) 2014 Fabien Potencier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_pimple.h" +#include "pimple_compat.h" +#include "zend_interfaces.h" +#include "zend.h" +#include "ext/spl/spl_exceptions.h" +#include "Zend/zend_exceptions.h" +#include "main/php_output.h" +#include "SAPI.h" + +static zend_class_entry *pimple_ce; +static zend_object_handlers pimple_object_handlers; +static zend_class_entry *pimple_closure_ce; +static zend_class_entry *pimple_serviceprovider_ce; +static zend_object_handlers pimple_closure_object_handlers; + +#define FETCH_DIM_HANDLERS_VARS pimple_object *pimple_obj = NULL; \ + ulong index; \ + pimple_obj = (pimple_object *)zend_object_store_get_object(object TSRMLS_CC); \ + +#define PIMPLE_OBJECT_HANDLE_INHERITANCE_OBJECT_HANDLERS do { \ + if (ce != pimple_ce) { \ + zend_hash_find(&ce->function_table, ZEND_STRS("offsetget"), (void **)&function); \ + if (function->common.scope != ce) { /* if the function is not defined in this actual class */ \ + pimple_object_handlers.read_dimension = pimple_object_read_dimension; /* then overwrite the handler to use custom one */ \ + } \ + zend_hash_find(&ce->function_table, ZEND_STRS("offsetset"), (void **)&function); \ + if (function->common.scope != ce) { \ + pimple_object_handlers.write_dimension = pimple_object_write_dimension; \ + } \ + zend_hash_find(&ce->function_table, ZEND_STRS("offsetexists"), (void **)&function); \ + if (function->common.scope != ce) { \ + pimple_object_handlers.has_dimension = pimple_object_has_dimension; \ + } \ + zend_hash_find(&ce->function_table, ZEND_STRS("offsetunset"), (void **)&function); \ + if (function->common.scope != ce) { \ + pimple_object_handlers.unset_dimension = pimple_object_unset_dimension; \ + } \ + } else { \ + pimple_object_handlers.read_dimension = pimple_object_read_dimension; \ + pimple_object_handlers.write_dimension = pimple_object_write_dimension; \ + pimple_object_handlers.has_dimension = pimple_object_has_dimension; \ + pimple_object_handlers.unset_dimension = pimple_object_unset_dimension; \ + }\ + } while(0); + +#define PIMPLE_CALL_CB do { \ + zend_fcall_info_argn(&fci TSRMLS_CC, 1, &object); \ + fci.size = sizeof(fci); \ + fci.object_ptr = retval->fcc->object_ptr; \ + fci.function_name = retval->value; \ + fci.no_separation = 1; \ + fci.retval_ptr_ptr = &retval_ptr_ptr; \ +\ + zend_call_function(&fci, retval->fcc TSRMLS_CC); \ + efree(fci.params); \ + if (EG(exception)) { \ + return EG(uninitialized_zval_ptr); \ + } \ + } while(0); + +ZEND_BEGIN_ARG_INFO_EX(arginfo___construct, 0, 0, 0) +ZEND_ARG_ARRAY_INFO(0, value, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetset, 0, 0, 2) +ZEND_ARG_INFO(0, offset) +ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetget, 0, 0, 1) +ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetexists, 0, 0, 1) +ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetunset, 0, 0, 1) +ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_factory, 0, 0, 1) +ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_protect, 0, 0, 1) +ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_raw, 0, 0, 1) +ZEND_ARG_INFO(0, id) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_extend, 0, 0, 2) +ZEND_ARG_INFO(0, id) +ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_keys, 0, 0, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_register, 0, 0, 1) +ZEND_ARG_OBJ_INFO(0, provider, Pimple\\ServiceProviderInterface, 0) +ZEND_ARG_ARRAY_INFO(0, values, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pimpleclosure___invoke, 0, 0, 1) +ZEND_ARG_INFO(0, callarg) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_serviceprovider_register, 0, 0, 1) +ZEND_ARG_OBJ_INFO(0, pimple, Pimple\\Container, 0) +ZEND_END_ARG_INFO() + +static const zend_function_entry pimple_ce_functions[] = { + PHP_ME(Pimple, __construct, arginfo___construct, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, factory, arginfo_factory, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, protect, arginfo_protect, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, raw, arginfo_raw, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, extend, arginfo_extend, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, keys, arginfo_keys, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, register, arginfo_register, ZEND_ACC_PUBLIC) + + PHP_ME(Pimple, offsetSet, arginfo_offsetset, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, offsetGet, arginfo_offsetget, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, offsetExists, arginfo_offsetexists, ZEND_ACC_PUBLIC) + PHP_ME(Pimple, offsetUnset, arginfo_offsetunset, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static const zend_function_entry pimple_closure_ce_functions[] = { + PHP_ME(PimpleClosure, __invoke, arginfo_pimpleclosure___invoke, ZEND_ACC_PRIVATE) + PHP_FE_END +}; + +static const zend_function_entry pimple_serviceprovider_iface_ce_functions[] = { + PHP_ABSTRACT_ME(ServiceProviderInterface, register, arginfo_serviceprovider_register) + PHP_FE_END +}; + +static void pimple_closure_free_object_storage(pimple_closure_object *obj TSRMLS_DC) +{ + zend_object_std_dtor(&obj->zobj TSRMLS_CC); + if (obj->factory) { + zval_ptr_dtor(&obj->factory); + } + if (obj->callable) { + zval_ptr_dtor(&obj->callable); + } + efree(obj); +} + +static void pimple_free_object_storage(pimple_object *obj TSRMLS_DC) +{ + zend_hash_destroy(&obj->factories); + zend_hash_destroy(&obj->protected); + zend_hash_destroy(&obj->values); + zend_object_std_dtor(&obj->zobj TSRMLS_CC); + efree(obj); +} + +static void pimple_free_bucket(pimple_bucket_value *bucket) +{ + if (bucket->fcc) { + efree(bucket->fcc); + bucket->fcc = NULL; + } + if (bucket->raw) { + zval_ptr_dtor(&bucket->raw); + } +} + +static zend_object_value pimple_closure_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + pimple_closure_object *pimple_closure_obj = NULL; + + pimple_closure_obj = ecalloc(1, sizeof(pimple_closure_object)); + ZEND_OBJ_INIT(&pimple_closure_obj->zobj, ce); + + pimple_closure_object_handlers.get_constructor = pimple_closure_get_constructor; + retval.handlers = &pimple_closure_object_handlers; + retval.handle = zend_objects_store_put(pimple_closure_obj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) pimple_closure_free_object_storage, NULL TSRMLS_CC); + + return retval; +} + +static zend_function *pimple_closure_get_constructor(zval *obj TSRMLS_DC) +{ + zend_error(E_ERROR, "Pimple\\ContainerClosure is an internal class and cannot be instantiated"); + + return NULL; +} + +static zend_object_value pimple_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + pimple_object *pimple_obj = NULL; + zend_function *function = NULL; + + pimple_obj = emalloc(sizeof(pimple_object)); + ZEND_OBJ_INIT(&pimple_obj->zobj, ce); + + PIMPLE_OBJECT_HANDLE_INHERITANCE_OBJECT_HANDLERS + + retval.handlers = &pimple_object_handlers; + retval.handle = zend_objects_store_put(pimple_obj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) pimple_free_object_storage, NULL TSRMLS_CC); + + zend_hash_init(&pimple_obj->factories, PIMPLE_DEFAULT_ZVAL_CACHE_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0); + zend_hash_init(&pimple_obj->protected, PIMPLE_DEFAULT_ZVAL_CACHE_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0); + zend_hash_init(&pimple_obj->values, PIMPLE_DEFAULT_ZVAL_VALUES_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0); + + return retval; +} + +static void pimple_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) +{ + FETCH_DIM_HANDLERS_VARS + + pimple_bucket_value pimple_value = {0}, *found_value = NULL; + ulong hash; + + pimple_init_bucket(&pimple_value); + pimple_zval_to_pimpleval(value, &pimple_value TSRMLS_CC); + + if (!offset) {/* $p[] = 'foo' when not overloaded */ + zend_hash_next_index_insert(&pimple_obj->values, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL); + Z_ADDREF_P(value); + return; + } + + switch (Z_TYPE_P(offset)) { + case IS_STRING: + hash = zend_hash_func(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); + zend_hash_quick_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hash, (void **)&found_value); + if (found_value && found_value->type == PIMPLE_IS_SERVICE && found_value->initialized == 1) { + pimple_free_bucket(&pimple_value); + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot override frozen service \"%s\".", Z_STRVAL_P(offset)); + return; + } + if (zend_hash_quick_update(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hash, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL) == FAILURE) { + pimple_free_bucket(&pimple_value); + return; + } + Z_ADDREF_P(value); + break; + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + if (Z_TYPE_P(offset) == IS_DOUBLE) { + index = (ulong)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + zend_hash_index_find(&pimple_obj->values, index, (void **)&found_value); + if (found_value && found_value->type == PIMPLE_IS_SERVICE && found_value->initialized == 1) { + pimple_free_bucket(&pimple_value); + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot override frozen service \"%ld\".", index); + return; + } + if (zend_hash_index_update(&pimple_obj->values, index, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL) == FAILURE) { + pimple_free_bucket(&pimple_value); + return; + } + Z_ADDREF_P(value); + break; + case IS_NULL: /* $p[] = 'foo' when overloaded */ + zend_hash_next_index_insert(&pimple_obj->values, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL); + Z_ADDREF_P(value); + break; + default: + pimple_free_bucket(&pimple_value); + zend_error(E_WARNING, "Unsupported offset type"); + } +} + +static void pimple_object_unset_dimension(zval *object, zval *offset TSRMLS_DC) +{ + FETCH_DIM_HANDLERS_VARS + + switch (Z_TYPE_P(offset)) { + case IS_STRING: + zend_symtable_del(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); + zend_symtable_del(&pimple_obj->factories, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); + zend_symtable_del(&pimple_obj->protected, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); + break; + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + if (Z_TYPE_P(offset) == IS_DOUBLE) { + index = (ulong)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + zend_hash_index_del(&pimple_obj->values, index); + zend_hash_index_del(&pimple_obj->factories, index); + zend_hash_index_del(&pimple_obj->protected, index); + break; + default: + zend_error(E_WARNING, "Unsupported offset type"); + } +} + +static int pimple_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) +{ + FETCH_DIM_HANDLERS_VARS + + pimple_bucket_value *retval = NULL; + + switch (Z_TYPE_P(offset)) { + case IS_STRING: + if (zend_symtable_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **)&retval) == SUCCESS) { + switch (check_empty) { + case 0: /* isset */ + return 1; /* Differs from PHP behavior (Z_TYPE_P(retval->value) != IS_NULL;) */ + case 1: /* empty */ + default: + return zend_is_true(retval->value); + } + } + return 0; + break; + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + if (Z_TYPE_P(offset) == IS_DOUBLE) { + index = (ulong)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + if (zend_hash_index_find(&pimple_obj->values, index, (void **)&retval) == SUCCESS) { + switch (check_empty) { + case 0: /* isset */ + return 1; /* Differs from PHP behavior (Z_TYPE_P(retval->value) != IS_NULL;)*/ + case 1: /* empty */ + default: + return zend_is_true(retval->value); + } + } + return 0; + break; + default: + zend_error(E_WARNING, "Unsupported offset type"); + return 0; + } +} + +static zval *pimple_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) +{ + FETCH_DIM_HANDLERS_VARS + + pimple_bucket_value *retval = NULL; + zend_fcall_info fci = {0}; + zval *retval_ptr_ptr = NULL; + + switch (Z_TYPE_P(offset)) { + case IS_STRING: + if (zend_symtable_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **)&retval) == FAILURE) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" is not defined.", Z_STRVAL_P(offset)); + return EG(uninitialized_zval_ptr); + } + break; + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + if (Z_TYPE_P(offset) == IS_DOUBLE) { + index = (ulong)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + if (zend_hash_index_find(&pimple_obj->values, index, (void **)&retval) == FAILURE) { + return EG(uninitialized_zval_ptr); + } + break; + case IS_NULL: /* $p[][3] = 'foo' first dim access */ + return EG(uninitialized_zval_ptr); + break; + default: + zend_error(E_WARNING, "Unsupported offset type"); + return EG(uninitialized_zval_ptr); + } + + if(retval->type == PIMPLE_IS_PARAM) { + return retval->value; + } + + if (zend_hash_index_exists(&pimple_obj->protected, retval->handle_num)) { + /* Service is protected, return the value every time */ + return retval->value; + } + + if (zend_hash_index_exists(&pimple_obj->factories, retval->handle_num)) { + /* Service is a factory, call it everytime and never cache its result */ + PIMPLE_CALL_CB + Z_DELREF_P(retval_ptr_ptr); /* fetch dim addr will increment refcount */ + return retval_ptr_ptr; + } + + if (retval->initialized == 1) { + /* Service has already been called, return its cached value */ + return retval->value; + } + + ALLOC_INIT_ZVAL(retval->raw); + MAKE_COPY_ZVAL(&retval->value, retval->raw); + + PIMPLE_CALL_CB + + retval->initialized = 1; + zval_ptr_dtor(&retval->value); + retval->value = retval_ptr_ptr; + + return retval->value; +} + +static int pimple_zval_is_valid_callback(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC) +{ + if (Z_TYPE_P(_zval) != IS_OBJECT) { + return FAILURE; + } + + if (_pimple_bucket_value->fcc->called_scope) { + return SUCCESS; + } + + if (Z_OBJ_HANDLER_P(_zval, get_closure) && Z_OBJ_HANDLER_P(_zval, get_closure)(_zval, &_pimple_bucket_value->fcc->calling_scope, &_pimple_bucket_value->fcc->function_handler, &_pimple_bucket_value->fcc->object_ptr TSRMLS_CC) == SUCCESS) { + _pimple_bucket_value->fcc->called_scope = _pimple_bucket_value->fcc->calling_scope; + return SUCCESS; + } else { + return FAILURE; + } +} + +static void pimple_init_bucket(pimple_bucket_value *bucket) +{ + memset(bucket, 0, sizeof(pimple_bucket_value)); + bucket->fcc = ecalloc(1, sizeof(zend_fcall_info_cache)); +} + +static int pimple_zval_to_pimpleval(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC) +{ + _pimple_bucket_value->value = _zval; + + if (Z_TYPE_P(_zval) != IS_OBJECT) { + return PIMPLE_IS_PARAM; + } + + if (pimple_zval_is_valid_callback(_zval, _pimple_bucket_value TSRMLS_CC) == SUCCESS) { + _pimple_bucket_value->type = PIMPLE_IS_SERVICE; + _pimple_bucket_value->handle_num = Z_OBJ_HANDLE_P(_zval); + } + + return PIMPLE_IS_SERVICE; +} + +static void pimple_bucket_dtor(pimple_bucket_value *bucket) +{ + zval_ptr_dtor(&bucket->value); + pimple_free_bucket(bucket); +} + +PHP_METHOD(Pimple, protect) +{ + zval *protected = NULL; + pimple_object *pobj = NULL; + pimple_bucket_value bucket = {0}; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &protected) == FAILURE) { + return; + } + + pimple_init_bucket(&bucket); + + if (pimple_zval_is_valid_callback(protected, &bucket TSRMLS_CC) == FAILURE) { + pimple_free_bucket(&bucket); + zend_throw_exception(spl_ce_InvalidArgumentException, "Callable is not a Closure or invokable object.", 0 TSRMLS_CC); + return; + } + + pimple_zval_to_pimpleval(protected, &bucket TSRMLS_CC); + pobj = (pimple_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_hash_index_update(&pobj->protected, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL) == SUCCESS) { + RETURN_ZVAL(protected, 1 , 0); + } else { + pimple_free_bucket(&bucket); + } + RETURN_FALSE; +} + +PHP_METHOD(Pimple, raw) +{ + zval *offset = NULL; + pimple_object *pobj = NULL; + pimple_bucket_value *value = NULL; + ulong index; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { + return; + } + + pobj = zend_object_store_get_object(getThis() TSRMLS_CC); + + switch (Z_TYPE_P(offset)) { + case IS_STRING: + if (zend_symtable_find(&pobj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void *)&value) == FAILURE) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" is not defined.", Z_STRVAL_P(offset)); + RETURN_NULL(); + } + break; + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + if (Z_TYPE_P(offset) == IS_DOUBLE) { + index = (ulong)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + if (zend_hash_index_find(&pobj->values, index, (void *)&value) == FAILURE) { + RETURN_NULL(); + } + break; + case IS_NULL: + default: + zend_error(E_WARNING, "Unsupported offset type"); + } + + if (value->raw) { + RETVAL_ZVAL(value->raw, 1, 0); + } else { + RETVAL_ZVAL(value->value, 1, 0); + } +} + +PHP_METHOD(Pimple, extend) +{ + zval *offset = NULL, *callable = NULL, *pimple_closure_obj = NULL; + pimple_bucket_value bucket = {0}, *value = NULL; + pimple_object *pobj = NULL; + pimple_closure_object *pcobj = NULL; + ulong index; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &offset, &callable) == FAILURE) { + return; + } + + pobj = zend_object_store_get_object(getThis() TSRMLS_CC); + + switch (Z_TYPE_P(offset)) { + case IS_STRING: + if (zend_symtable_find(&pobj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void *)&value) == FAILURE) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" is not defined.", Z_STRVAL_P(offset)); + RETURN_NULL(); + } + if (value->type != PIMPLE_IS_SERVICE) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" does not contain an object definition.", Z_STRVAL_P(offset)); + RETURN_NULL(); + } + break; + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + if (Z_TYPE_P(offset) == IS_DOUBLE) { + index = (ulong)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + if (zend_hash_index_find(&pobj->values, index, (void *)&value) == FAILURE) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%ld\" is not defined.", index); + RETURN_NULL(); + } + if (value->type != PIMPLE_IS_SERVICE) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%ld\" does not contain an object definition.", index); + RETURN_NULL(); + } + break; + case IS_NULL: + default: + zend_error(E_WARNING, "Unsupported offset type"); + } + + pimple_init_bucket(&bucket); + + if (pimple_zval_is_valid_callback(callable, &bucket TSRMLS_CC) == FAILURE) { + pimple_free_bucket(&bucket); + zend_throw_exception(spl_ce_InvalidArgumentException, "Extension service definition is not a Closure or invokable object.", 0 TSRMLS_CC); + RETURN_NULL(); + } + pimple_free_bucket(&bucket); + + ALLOC_INIT_ZVAL(pimple_closure_obj); + object_init_ex(pimple_closure_obj, pimple_closure_ce); + + pcobj = zend_object_store_get_object(pimple_closure_obj TSRMLS_CC); + pcobj->callable = callable; + pcobj->factory = value->value; + Z_ADDREF_P(callable); + Z_ADDREF_P(value->value); + + if (zend_hash_index_exists(&pobj->factories, value->handle_num)) { + pimple_init_bucket(&bucket); + pimple_zval_to_pimpleval(pimple_closure_obj, &bucket TSRMLS_CC); + zend_hash_index_del(&pobj->factories, value->handle_num); + zend_hash_index_update(&pobj->factories, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL); + Z_ADDREF_P(pimple_closure_obj); + } + + pimple_object_write_dimension(getThis(), offset, pimple_closure_obj TSRMLS_CC); + + RETVAL_ZVAL(pimple_closure_obj, 1, 1); +} + +PHP_METHOD(Pimple, keys) +{ + HashPosition pos; + pimple_object *pobj = NULL; + zval **value = NULL; + zval *endval = NULL; + char *str_index = NULL; + int str_len; + ulong num_index; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + pobj = zend_object_store_get_object(getThis() TSRMLS_CC); + array_init_size(return_value, zend_hash_num_elements(&pobj->values)); + + zend_hash_internal_pointer_reset_ex(&pobj->values, &pos); + + while(zend_hash_get_current_data_ex(&pobj->values, (void **)&value, &pos) == SUCCESS) { + MAKE_STD_ZVAL(endval); + switch (zend_hash_get_current_key_ex(&pobj->values, &str_index, (uint *)&str_len, &num_index, 0, &pos)) { + case HASH_KEY_IS_STRING: + ZVAL_STRINGL(endval, str_index, str_len - 1, 1); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &endval, sizeof(zval *), NULL); + break; + case HASH_KEY_IS_LONG: + ZVAL_LONG(endval, num_index); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &endval, sizeof(zval *), NULL); + break; + } + zend_hash_move_forward_ex(&pobj->values, &pos); + } +} + +PHP_METHOD(Pimple, factory) +{ + zval *factory = NULL; + pimple_object *pobj = NULL; + pimple_bucket_value bucket = {0}; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &factory) == FAILURE) { + return; + } + + pimple_init_bucket(&bucket); + + if (pimple_zval_is_valid_callback(factory, &bucket TSRMLS_CC) == FAILURE) { + pimple_free_bucket(&bucket); + zend_throw_exception(spl_ce_InvalidArgumentException, "Service definition is not a Closure or invokable object.", 0 TSRMLS_CC); + return; + } + + pimple_zval_to_pimpleval(factory, &bucket TSRMLS_CC); + pobj = (pimple_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_hash_index_update(&pobj->factories, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL) == SUCCESS) { + Z_ADDREF_P(factory); + RETURN_ZVAL(factory, 1 , 0); + } else { + pimple_free_bucket(&bucket); + } + + RETURN_FALSE; +} + +PHP_METHOD(Pimple, offsetSet) +{ + zval *offset = NULL, *value = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &offset, &value) == FAILURE) { + return; + } + + pimple_object_write_dimension(getThis(), offset, value TSRMLS_CC); +} + +PHP_METHOD(Pimple, offsetGet) +{ + zval *offset = NULL, *retval = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { + return; + } + + retval = pimple_object_read_dimension(getThis(), offset, 0 TSRMLS_CC); + + RETVAL_ZVAL(retval, 1, 0); +} + +PHP_METHOD(Pimple, offsetUnset) +{ + zval *offset = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { + return; + } + + pimple_object_unset_dimension(getThis(), offset TSRMLS_CC); +} + +PHP_METHOD(Pimple, offsetExists) +{ + zval *offset = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { + return; + } + + RETVAL_BOOL(pimple_object_has_dimension(getThis(), offset, 1 TSRMLS_CC)); +} + +PHP_METHOD(Pimple, register) +{ + zval *provider; + zval **data; + zval *retval = NULL; + zval key; + + HashTable *array = NULL; + HashPosition pos; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|h", &provider, pimple_serviceprovider_ce, &array) == FAILURE) { + return; + } + + zend_call_method_with_1_params(&provider, Z_OBJCE_P(provider), NULL, "register", &retval, getThis()); + + if (retval) { + zval_ptr_dtor(&retval); + } + + if (!array) { + return; + } + + zend_hash_internal_pointer_reset_ex(array, &pos); + + while(zend_hash_get_current_data_ex(array, (void **)&data, &pos) == SUCCESS) { + zend_hash_get_current_key_zval_ex(array, &key, &pos); + pimple_object_write_dimension(getThis(), &key, *data TSRMLS_CC); + zend_hash_move_forward_ex(array, &pos); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +PHP_METHOD(Pimple, __construct) +{ + zval *values = NULL, **pData = NULL, offset = {0}; + HashPosition pos; + char *str_index = NULL; + zend_uint str_length; + ulong num_index; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &values) == FAILURE || !values) { + return; + } + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos); + while (zend_hash_has_more_elements_ex(Z_ARRVAL_P(values), &pos) == SUCCESS) { + zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&pData, &pos); + zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &str_index, &str_length, &num_index, 0, &pos); + if (zend_hash_get_current_key_type_ex(Z_ARRVAL_P(values), &pos) == HASH_KEY_IS_LONG) { + ZVAL_LONG(&offset, num_index); + } else { + ZVAL_STRINGL(&offset, str_index, (str_length - 1), 0); + } + pimple_object_write_dimension(getThis(), &offset, *pData TSRMLS_CC); + zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos); + } +} + +/* + * This is PHP code snippet handling extend()s calls : + + $extended = function ($c) use ($callable, $factory) { + return $callable($factory($c), $c); + }; + + */ +PHP_METHOD(PimpleClosure, __invoke) +{ + pimple_closure_object *pcobj = NULL; + zval *arg = NULL, *retval = NULL, *newretval = NULL; + zend_fcall_info fci = {0}; + zval **args[2]; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) { + return; + } + + pcobj = zend_object_store_get_object(getThis() TSRMLS_CC); + + fci.function_name = pcobj->factory; + args[0] = &arg; + zend_fcall_info_argp(&fci TSRMLS_CC, 1, args); + fci.retval_ptr_ptr = &retval; + fci.size = sizeof(fci); + + if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE || EG(exception)) { + efree(fci.params); + return; /* Should here return default zval */ + } + + efree(fci.params); + memset(&fci, 0, sizeof(fci)); + fci.size = sizeof(fci); + + fci.function_name = pcobj->callable; + args[0] = &retval; + args[1] = &arg; + zend_fcall_info_argp(&fci TSRMLS_CC, 2, args); + fci.retval_ptr_ptr = &newretval; + + if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE || EG(exception)) { + efree(fci.params); + zval_ptr_dtor(&retval); + return; + } + + efree(fci.params); + zval_ptr_dtor(&retval); + RETVAL_ZVAL(newretval, 1 ,1); +} + +PHP_MINIT_FUNCTION(pimple) +{ + zend_class_entry tmp_pimple_ce, tmp_pimple_closure_ce, tmp_pimple_serviceprovider_iface_ce; + INIT_NS_CLASS_ENTRY(tmp_pimple_ce, PIMPLE_NS, "Container", pimple_ce_functions); + INIT_NS_CLASS_ENTRY(tmp_pimple_closure_ce, PIMPLE_NS, "ContainerClosure", pimple_closure_ce_functions); + INIT_NS_CLASS_ENTRY(tmp_pimple_serviceprovider_iface_ce, PIMPLE_NS, "ServiceProviderInterface", pimple_serviceprovider_iface_ce_functions); + + tmp_pimple_ce.create_object = pimple_object_create; + tmp_pimple_closure_ce.create_object = pimple_closure_object_create; + + pimple_ce = zend_register_internal_class(&tmp_pimple_ce TSRMLS_CC); + zend_class_implements(pimple_ce TSRMLS_CC, 1, zend_ce_arrayaccess); + + pimple_closure_ce = zend_register_internal_class(&tmp_pimple_closure_ce TSRMLS_CC); + pimple_closure_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; + + pimple_serviceprovider_ce = zend_register_internal_interface(&tmp_pimple_serviceprovider_iface_ce TSRMLS_CC); + + pimple_closure_object_handlers = std_object_handlers; + pimple_object_handlers = std_object_handlers; + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(pimple) +{ + return SUCCESS; +} + +PHP_RINIT_FUNCTION(pimple) +{ + return SUCCESS; +} + +PHP_RSHUTDOWN_FUNCTION(pimple) +{ + return SUCCESS; +} + +PHP_MINFO_FUNCTION(pimple) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "SensioLabs Pimple C support", "enabled"); + php_info_print_table_row(2, "Pimple supported version", PIMPLE_VERSION); + php_info_print_table_end(); + + php_info_print_box_start(0); + php_write((void *)ZEND_STRL("SensioLabs Pimple C support developed by Julien Pauli") TSRMLS_CC); + if (!sapi_module.phpinfo_as_text) { + php_write((void *)ZEND_STRL(sensiolabs_logo) TSRMLS_CC); + } + php_info_print_box_end(); +} + +zend_module_entry pimple_module_entry = { + STANDARD_MODULE_HEADER, + "pimple", + NULL, + PHP_MINIT(pimple), + PHP_MSHUTDOWN(pimple), + PHP_RINIT(pimple), + PHP_RSHUTDOWN(pimple), + PHP_MINFO(pimple), + PIMPLE_VERSION, + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_PIMPLE +ZEND_GET_MODULE(pimple) +#endif diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/pimple_compat.h b/src/lib/vendor/pimple/pimple/ext/pimple/pimple_compat.h new file mode 100644 index 00000000..d234e174 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/pimple_compat.h @@ -0,0 +1,81 @@ + +/* + * This file is part of Pimple. + * + * Copyright (c) 2014 Fabien Potencier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef PIMPLE_COMPAT_H_ +#define PIMPLE_COMPAT_H_ + +#include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */ + +#define PHP_5_0_X_API_NO 220040412 +#define PHP_5_1_X_API_NO 220051025 +#define PHP_5_2_X_API_NO 220060519 +#define PHP_5_3_X_API_NO 220090626 +#define PHP_5_4_X_API_NO 220100525 +#define PHP_5_5_X_API_NO 220121212 +#define PHP_5_6_X_API_NO 220131226 + +#define IS_PHP_56 ZEND_EXTENSION_API_NO == PHP_5_6_X_API_NO +#define IS_AT_LEAST_PHP_56 ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO + +#define IS_PHP_55 ZEND_EXTENSION_API_NO == PHP_5_5_X_API_NO +#define IS_AT_LEAST_PHP_55 ZEND_EXTENSION_API_NO >= PHP_5_5_X_API_NO + +#define IS_PHP_54 ZEND_EXTENSION_API_NO == PHP_5_4_X_API_NO +#define IS_AT_LEAST_PHP_54 ZEND_EXTENSION_API_NO >= PHP_5_4_X_API_NO + +#define IS_PHP_53 ZEND_EXTENSION_API_NO == PHP_5_3_X_API_NO +#define IS_AT_LEAST_PHP_53 ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO + +#if IS_PHP_53 +#define object_properties_init(obj, ce) do { \ + zend_hash_copy(obj->properties, &ce->default_properties, zval_copy_property_ctor(ce), NULL, sizeof(zval *)); \ + } while (0); +#endif + +#define ZEND_OBJ_INIT(obj, ce) do { \ + zend_object_std_init(obj, ce TSRMLS_CC); \ + object_properties_init((obj), (ce)); \ + } while(0); + +#if IS_PHP_53 || IS_PHP_54 +static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) { + Bucket *p; + + p = pos ? (*pos) : ht->pInternalPointer; + + if (!p) { + Z_TYPE_P(key) = IS_NULL; + } else if (p->nKeyLength) { + Z_TYPE_P(key) = IS_STRING; + Z_STRVAL_P(key) = estrndup(p->arKey, p->nKeyLength - 1); + Z_STRLEN_P(key) = p->nKeyLength - 1; + } else { + Z_TYPE_P(key) = IS_LONG; + Z_LVAL_P(key) = p->h; + } +} +#endif + +#endif /* PIMPLE_COMPAT_H_ */ diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/001.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/001.phpt new file mode 100644 index 00000000..0809ea23 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/001.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test for read_dim/write_dim handlers +--SKIPIF-- + +--FILE-- + + +--EXPECTF-- +foo +42 +foo2 +foo99 +baz +strstr \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/002.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/002.phpt new file mode 100644 index 00000000..7b56d2c1 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/002.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test for constructor +--SKIPIF-- + +--FILE-- +'foo')); +var_dump($p[42]); +?> +--EXPECT-- +NULL +string(3) "foo" diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/003.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/003.phpt new file mode 100644 index 00000000..a22cfa35 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/003.phpt @@ -0,0 +1,16 @@ +--TEST-- +Test empty dimensions +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(42) +string(3) "bar" \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/004.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/004.phpt new file mode 100644 index 00000000..1e1d2513 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/004.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test has/unset dim handlers +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(42) +NULL +bool(true) +bool(false) +bool(true) +bool(true) \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/005.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/005.phpt new file mode 100644 index 00000000..0479ee05 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/005.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test simple class inheritance +--SKIPIF-- + +--FILE-- +someAttr; +?> +--EXPECT-- +string(3) "hit" +foo +fooAttr \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/006.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/006.phpt new file mode 100644 index 00000000..cfe8a119 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/006.phpt @@ -0,0 +1,51 @@ +--TEST-- +Test complex class inheritance +--SKIPIF-- + +--FILE-- + 'bar', 88 => 'baz'); + +$p = new TestPimple($defaultValues); +$p[42] = 'foo'; +var_dump($p[42]); +var_dump($p[0]); +?> +--EXPECT-- +string(13) "hit offsetset" +string(27) "hit offsetget in TestPimple" +string(25) "hit offsetget in MyPimple" +string(3) "foo" +string(27) "hit offsetget in TestPimple" +string(25) "hit offsetget in MyPimple" +string(3) "baz" \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/007.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/007.phpt new file mode 100644 index 00000000..5aac6838 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/007.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test for read_dim/write_dim handlers +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +foo +42 \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/008.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/008.phpt new file mode 100644 index 00000000..db7eeec4 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/008.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test frozen services +--SKIPIF-- + +--FILE-- + +--EXPECTF-- diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/009.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/009.phpt new file mode 100644 index 00000000..bb05ea29 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/009.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test service is called as callback, and only once +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/010.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/010.phpt new file mode 100644 index 00000000..badce014 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/010.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test service is called as callback for every callback type +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +callme +called +Foo::bar +array(2) { + [0]=> + string(3) "Foo" + [1]=> + string(3) "bar" +} \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/011.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/011.phpt new file mode 100644 index 00000000..6682ab8e --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/011.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test service callback throwing an exception +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +all right! \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/012.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/012.phpt new file mode 100644 index 00000000..4c6ac486 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/012.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test service factory +--SKIPIF-- + +--FILE-- +factory($f = function() { var_dump('called-1'); return 'ret-1';}); + +$p[] = $f; + +$p[] = function () { var_dump('called-2'); return 'ret-2'; }; + +var_dump($p[0]); +var_dump($p[0]); +var_dump($p[1]); +var_dump($p[1]); +?> +--EXPECTF-- +string(8) "called-1" +string(5) "ret-1" +string(8) "called-1" +string(5) "ret-1" +string(8) "called-2" +string(5) "ret-2" +string(5) "ret-2" \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/013.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/013.phpt new file mode 100644 index 00000000..f419958c --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/013.phpt @@ -0,0 +1,33 @@ +--TEST-- +Test keys() +--SKIPIF-- + +--FILE-- +keys()); + +$p['foo'] = 'bar'; +$p[] = 'foo'; + +var_dump($p->keys()); + +unset($p['foo']); + +var_dump($p->keys()); +?> +--EXPECTF-- +array(0) { +} +array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) +} +array(1) { + [0]=> + int(0) +} \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/014.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/014.phpt new file mode 100644 index 00000000..ac937213 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/014.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test raw() +--SKIPIF-- + +--FILE-- +raw('foo')); +var_dump($p[42]); + +unset($p['foo']); + +try { + $p->raw('foo'); + echo "expected exception"; +} catch (InvalidArgumentException $e) { } +--EXPECTF-- +string(8) "called-2" +string(5) "ret-2" +object(Closure)#%i (0) { +} +string(8) "called-2" +string(5) "ret-2" \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/015.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/015.phpt new file mode 100644 index 00000000..314f008a --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/015.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test protect() +--SKIPIF-- + +--FILE-- +protect($f); + +var_dump($p['foo']); +--EXPECTF-- +object(Closure)#%i (0) { +} \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/016.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/016.phpt new file mode 100644 index 00000000..e55edb0a --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/016.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test extend() +--SKIPIF-- + +--FILE-- +extend(12, function ($w) { var_dump($w); return 'bar'; }); /* $callable in code above */ + +var_dump($c('param')); +--EXPECTF-- +string(5) "param" +string(3) "foo" +string(3) "bar" \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/017.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/017.phpt new file mode 100644 index 00000000..bac23ce0 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/017.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test extend() with exception in service extension +--SKIPIF-- + +--FILE-- +extend(12, function ($w) { throw new BadMethodCallException; }); + +try { + $p[12]; + echo "Exception expected"; +} catch (BadMethodCallException $e) { } +--EXPECTF-- diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/017_1.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/017_1.phpt new file mode 100644 index 00000000..8f881d6e --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/017_1.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test extend() with exception in service factory +--SKIPIF-- + +--FILE-- +extend(12, function ($w) { return 'foobar'; }); + +try { + $p[12]; + echo "Exception expected"; +} catch (BadMethodCallException $e) { } +--EXPECTF-- diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/018.phpt b/src/lib/vendor/pimple/pimple/ext/pimple/tests/018.phpt new file mode 100644 index 00000000..27c12a14 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/018.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test register() +--SKIPIF-- + +--FILE-- +register(new Foo, array(42 => 'bar')); + +var_dump($p[42]); +--EXPECTF-- +object(Pimple\Container)#1 (0) { +} +string(3) "bar" \ No newline at end of file diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/bench.phpb b/src/lib/vendor/pimple/pimple/ext/pimple/tests/bench.phpb new file mode 100644 index 00000000..8ddd6e3b --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/bench.phpb @@ -0,0 +1,51 @@ +factory($factory); + +$p['factory'] = $factory; + +echo $p['factory']; +echo $p['factory']; +echo $p['factory']; + +} + +echo microtime(true) - $time; diff --git a/src/lib/vendor/pimple/pimple/ext/pimple/tests/bench_shared.phpb b/src/lib/vendor/pimple/pimple/ext/pimple/tests/bench_shared.phpb new file mode 100644 index 00000000..0fbc8391 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/ext/pimple/tests/bench_shared.phpb @@ -0,0 +1,25 @@ + diff --git a/src/lib/vendor/pimple/pimple/phpunit.xml.dist b/src/lib/vendor/pimple/pimple/phpunit.xml.dist new file mode 100644 index 00000000..550fe8dc --- /dev/null +++ b/src/lib/vendor/pimple/pimple/phpunit.xml.dist @@ -0,0 +1,19 @@ + + + + + + ./tests/ + + + diff --git a/src/lib/vendor/pimple/pimple/src/Pimple.php b/src/lib/vendor/pimple/pimple/src/Pimple.php new file mode 100644 index 00000000..2a45cadf --- /dev/null +++ b/src/lib/vendor/pimple/pimple/src/Pimple.php @@ -0,0 +1,27 @@ +factories = new \SplObjectStorage(); + $this->protected = new \SplObjectStorage(); + + foreach ($values as $key => $value) { + $this->offsetSet($key, $value); + } + } + + /** + * Sets a parameter or an object. + * + * Objects must be defined as Closures. + * + * Allowing any PHP callable leads to difficult to debug problems + * as function names (strings) are callable (creating a function with + * the same name as an existing parameter would break your container). + * + * @param string $id The unique identifier for the parameter or object + * @param mixed $value The value of the parameter or a closure to define an object + * @throws \RuntimeException Prevent override of a frozen service + */ + public function offsetSet($id, $value) + { + if (isset($this->frozen[$id])) { + throw new \RuntimeException(sprintf('Cannot override frozen service "%s".', $id)); + } + + $this->values[$id] = $value; + $this->keys[$id] = true; + } + + /** + * Gets a parameter or an object. + * + * @param string $id The unique identifier for the parameter or object + * + * @return mixed The value of the parameter or an object + * + * @throws \InvalidArgumentException if the identifier is not defined + */ + public function offsetGet($id) + { + if (!isset($this->keys[$id])) { + throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); + } + + if ( + isset($this->raw[$id]) + || !is_object($this->values[$id]) + || isset($this->protected[$this->values[$id]]) + || !method_exists($this->values[$id], '__invoke') + ) { + return $this->values[$id]; + } + + if (isset($this->factories[$this->values[$id]])) { + return $this->values[$id]($this); + } + + $raw = $this->values[$id]; + $val = $this->values[$id] = $raw($this); + $this->raw[$id] = $raw; + + $this->frozen[$id] = true; + + return $val; + } + + /** + * Checks if a parameter or an object is set. + * + * @param string $id The unique identifier for the parameter or object + * + * @return bool + */ + public function offsetExists($id) + { + return isset($this->keys[$id]); + } + + /** + * Unsets a parameter or an object. + * + * @param string $id The unique identifier for the parameter or object + */ + public function offsetUnset($id) + { + if (isset($this->keys[$id])) { + if (is_object($this->values[$id])) { + unset($this->factories[$this->values[$id]], $this->protected[$this->values[$id]]); + } + + unset($this->values[$id], $this->frozen[$id], $this->raw[$id], $this->keys[$id]); + } + } + + /** + * Marks a callable as being a factory service. + * + * @param callable $callable A service definition to be used as a factory + * + * @return callable The passed callable + * + * @throws \InvalidArgumentException Service definition has to be a closure of an invokable object + */ + public function factory($callable) + { + if (!is_object($callable) || !method_exists($callable, '__invoke')) { + throw new \InvalidArgumentException('Service definition is not a Closure or invokable object.'); + } + + $this->factories->attach($callable); + + return $callable; + } + + /** + * Protects a callable from being interpreted as a service. + * + * This is useful when you want to store a callable as a parameter. + * + * @param callable $callable A callable to protect from being evaluated + * + * @return callable The passed callable + * + * @throws \InvalidArgumentException Service definition has to be a closure of an invokable object + */ + public function protect($callable) + { + if (!is_object($callable) || !method_exists($callable, '__invoke')) { + throw new \InvalidArgumentException('Callable is not a Closure or invokable object.'); + } + + $this->protected->attach($callable); + + return $callable; + } + + /** + * Gets a parameter or the closure defining an object. + * + * @param string $id The unique identifier for the parameter or object + * + * @return mixed The value of the parameter or the closure defining an object + * + * @throws \InvalidArgumentException if the identifier is not defined + */ + public function raw($id) + { + if (!isset($this->keys[$id])) { + throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); + } + + if (isset($this->raw[$id])) { + return $this->raw[$id]; + } + + return $this->values[$id]; + } + + /** + * Extends an object definition. + * + * Useful when you want to extend an existing object definition, + * without necessarily loading that object. + * + * @param string $id The unique identifier for the object + * @param callable $callable A service definition to extend the original + * + * @return callable The wrapped callable + * + * @throws \InvalidArgumentException if the identifier is not defined or not a service definition + */ + public function extend($id, $callable) + { + if (!isset($this->keys[$id])) { + throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); + } + + if (!is_object($this->values[$id]) || !method_exists($this->values[$id], '__invoke')) { + throw new \InvalidArgumentException(sprintf('Identifier "%s" does not contain an object definition.', $id)); + } + + if (!is_object($callable) || !method_exists($callable, '__invoke')) { + throw new \InvalidArgumentException('Extension service definition is not a Closure or invokable object.'); + } + + $factory = $this->values[$id]; + + $extended = function ($c) use ($callable, $factory) { + return $callable($factory($c), $c); + }; + + if (isset($this->factories[$factory])) { + $this->factories->detach($factory); + $this->factories->attach($extended); + } + + return $this[$id] = $extended; + } + + /** + * Returns all defined value names. + * + * @return array An array of value names + */ + public function keys() + { + return array_keys($this->values); + } + + /** + * Registers a service provider. + * + * @param ServiceProviderInterface $provider A ServiceProviderInterface instance + * @param array $values An array of values that customizes the provider + * + * @return static + */ + public function register(ServiceProviderInterface $provider, array $values = array()) + { + $provider->register($this); + + foreach ($values as $key => $value) { + $this[$key] = $value; + } + + return $this; + } +} diff --git a/src/lib/vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.php b/src/lib/vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.php new file mode 100644 index 00000000..9b122bd4 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.php @@ -0,0 +1,46 @@ +value = $value; + + return $service; + } +} diff --git a/src/lib/vendor/pimple/pimple/tests/Fixtures/NonInvokable.php b/src/lib/vendor/pimple/pimple/tests/Fixtures/NonInvokable.php new file mode 100644 index 00000000..33cd4e54 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/tests/Fixtures/NonInvokable.php @@ -0,0 +1,34 @@ +factory(function () { + return new Service(); + }); + } +} diff --git a/src/lib/vendor/pimple/pimple/tests/Fixtures/Service.php b/src/lib/vendor/pimple/pimple/tests/Fixtures/Service.php new file mode 100644 index 00000000..d71b184d --- /dev/null +++ b/src/lib/vendor/pimple/pimple/tests/Fixtures/Service.php @@ -0,0 +1,35 @@ + + */ +class Service +{ + public $value; +} diff --git a/src/lib/vendor/pimple/pimple/tests/PimpleServiceProviderInterfaceTest.php b/src/lib/vendor/pimple/pimple/tests/PimpleServiceProviderInterfaceTest.php new file mode 100644 index 00000000..69f76f84 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/tests/PimpleServiceProviderInterfaceTest.php @@ -0,0 +1,76 @@ + + */ +class PimpleServiceProviderInterfaceTest extends \PHPUnit_Framework_TestCase +{ + public function testProvider() + { + $pimple = new Container(); + + $pimpleServiceProvider = new Fixtures\PimpleServiceProvider(); + $pimpleServiceProvider->register($pimple); + + $this->assertEquals('value', $pimple['param']); + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']); + + $serviceOne = $pimple['factory']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); + + $serviceTwo = $pimple['factory']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); + + $this->assertNotSame($serviceOne, $serviceTwo); + } + + public function testProviderWithRegisterMethod() + { + $pimple = new Container(); + + $pimple->register(new Fixtures\PimpleServiceProvider(), array( + 'anotherParameter' => 'anotherValue' + )); + + $this->assertEquals('value', $pimple['param']); + $this->assertEquals('anotherValue', $pimple['anotherParameter']); + + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']); + + $serviceOne = $pimple['factory']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); + + $serviceTwo = $pimple['factory']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); + + $this->assertNotSame($serviceOne, $serviceTwo); + } +} diff --git a/src/lib/vendor/pimple/pimple/tests/PimpleTest.php b/src/lib/vendor/pimple/pimple/tests/PimpleTest.php new file mode 100644 index 00000000..30ca3912 --- /dev/null +++ b/src/lib/vendor/pimple/pimple/tests/PimpleTest.php @@ -0,0 +1,434 @@ + + */ +class PimpleTest extends \PHPUnit_Framework_TestCase +{ + public function testWithString() + { + $pimple = new Container(); + $pimple['param'] = 'value'; + + $this->assertEquals('value', $pimple['param']); + } + + public function testWithClosure() + { + $pimple = new Container(); + $pimple['service'] = function () { + return new Fixtures\Service(); + }; + + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']); + } + + public function testServicesShouldBeDifferent() + { + $pimple = new Container(); + $pimple['service'] = $pimple->factory(function () { + return new Fixtures\Service(); + }); + + $serviceOne = $pimple['service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); + + $serviceTwo = $pimple['service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); + + $this->assertNotSame($serviceOne, $serviceTwo); + } + + public function testShouldPassContainerAsParameter() + { + $pimple = new Container(); + $pimple['service'] = function () { + return new Fixtures\Service(); + }; + $pimple['container'] = function ($container) { + return $container; + }; + + $this->assertNotSame($pimple, $pimple['service']); + $this->assertSame($pimple, $pimple['container']); + } + + public function testIsset() + { + $pimple = new Container(); + $pimple['param'] = 'value'; + $pimple['service'] = function () { + return new Fixtures\Service(); + }; + + $pimple['null'] = null; + + $this->assertTrue(isset($pimple['param'])); + $this->assertTrue(isset($pimple['service'])); + $this->assertTrue(isset($pimple['null'])); + $this->assertFalse(isset($pimple['non_existent'])); + } + + public function testConstructorInjection() + { + $params = array("param" => "value"); + $pimple = new Container($params); + + $this->assertSame($params['param'], $pimple['param']); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Identifier "foo" is not defined. + */ + public function testOffsetGetValidatesKeyIsPresent() + { + $pimple = new Container(); + echo $pimple['foo']; + } + + public function testOffsetGetHonorsNullValues() + { + $pimple = new Container(); + $pimple['foo'] = null; + $this->assertNull($pimple['foo']); + } + + public function testUnset() + { + $pimple = new Container(); + $pimple['param'] = 'value'; + $pimple['service'] = function () { + return new Fixtures\Service(); + }; + + unset($pimple['param'], $pimple['service']); + $this->assertFalse(isset($pimple['param'])); + $this->assertFalse(isset($pimple['service'])); + } + + /** + * @dataProvider serviceDefinitionProvider + */ + public function testShare($service) + { + $pimple = new Container(); + $pimple['shared_service'] = $service; + + $serviceOne = $pimple['shared_service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); + + $serviceTwo = $pimple['shared_service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); + + $this->assertSame($serviceOne, $serviceTwo); + } + + /** + * @dataProvider serviceDefinitionProvider + */ + public function testProtect($service) + { + $pimple = new Container(); + $pimple['protected'] = $pimple->protect($service); + + $this->assertSame($service, $pimple['protected']); + } + + public function testGlobalFunctionNameAsParameterValue() + { + $pimple = new Container(); + $pimple['global_function'] = 'strlen'; + $this->assertSame('strlen', $pimple['global_function']); + } + + public function testRaw() + { + $pimple = new Container(); + $pimple['service'] = $definition = $pimple->factory(function () { return 'foo'; }); + $this->assertSame($definition, $pimple->raw('service')); + } + + public function testRawHonorsNullValues() + { + $pimple = new Container(); + $pimple['foo'] = null; + $this->assertNull($pimple->raw('foo')); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Identifier "foo" is not defined. + */ + public function testRawValidatesKeyIsPresent() + { + $pimple = new Container(); + $pimple->raw('foo'); + } + + /** + * @dataProvider serviceDefinitionProvider + */ + public function testExtend($service) + { + $pimple = new Container(); + $pimple['shared_service'] = function () { + return new Fixtures\Service(); + }; + $pimple['factory_service'] = $pimple->factory(function () { + return new Fixtures\Service(); + }); + + $pimple->extend('shared_service', $service); + $serviceOne = $pimple['shared_service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); + $serviceTwo = $pimple['shared_service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); + $this->assertSame($serviceOne, $serviceTwo); + $this->assertSame($serviceOne->value, $serviceTwo->value); + + $pimple->extend('factory_service', $service); + $serviceOne = $pimple['factory_service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); + $serviceTwo = $pimple['factory_service']; + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); + $this->assertNotSame($serviceOne, $serviceTwo); + $this->assertNotSame($serviceOne->value, $serviceTwo->value); + } + + public function testExtendDoesNotLeakWithFactories() + { + if (extension_loaded('pimple')) { + $this->markTestSkipped('Pimple extension does not support this test'); + } + $pimple = new Container(); + + $pimple['foo'] = $pimple->factory(function () { return; }); + $pimple['foo'] = $pimple->extend('foo', function ($foo, $pimple) { return; }); + unset($pimple['foo']); + + $p = new \ReflectionProperty($pimple, 'values'); + $p->setAccessible(true); + $this->assertEmpty($p->getValue($pimple)); + + $p = new \ReflectionProperty($pimple, 'factories'); + $p->setAccessible(true); + $this->assertCount(0, $p->getValue($pimple)); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Identifier "foo" is not defined. + */ + public function testExtendValidatesKeyIsPresent() + { + $pimple = new Container(); + $pimple->extend('foo', function () {}); + } + + public function testKeys() + { + $pimple = new Container(); + $pimple['foo'] = 123; + $pimple['bar'] = 123; + + $this->assertEquals(array('foo', 'bar'), $pimple->keys()); + } + + /** @test */ + public function settingAnInvokableObjectShouldTreatItAsFactory() + { + $pimple = new Container(); + $pimple['invokable'] = new Fixtures\Invokable(); + + $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['invokable']); + } + + /** @test */ + public function settingNonInvokableObjectShouldTreatItAsParameter() + { + $pimple = new Container(); + $pimple['non_invokable'] = new Fixtures\NonInvokable(); + + $this->assertInstanceOf('Pimple\Tests\Fixtures\NonInvokable', $pimple['non_invokable']); + } + + /** + * @dataProvider badServiceDefinitionProvider + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Service definition is not a Closure or invokable object. + */ + public function testFactoryFailsForInvalidServiceDefinitions($service) + { + $pimple = new Container(); + $pimple->factory($service); + } + + /** + * @dataProvider badServiceDefinitionProvider + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Callable is not a Closure or invokable object. + */ + public function testProtectFailsForInvalidServiceDefinitions($service) + { + $pimple = new Container(); + $pimple->protect($service); + } + + /** + * @dataProvider badServiceDefinitionProvider + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Identifier "foo" does not contain an object definition. + */ + public function testExtendFailsForKeysNotContainingServiceDefinitions($service) + { + $pimple = new Container(); + $pimple['foo'] = $service; + $pimple->extend('foo', function () {}); + } + + /** + * @dataProvider badServiceDefinitionProvider + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Extension service definition is not a Closure or invokable object. + */ + public function testExtendFailsForInvalidServiceDefinitions($service) + { + $pimple = new Container(); + $pimple['foo'] = function () {}; + $pimple->extend('foo', $service); + } + + /** + * Provider for invalid service definitions + */ + public function badServiceDefinitionProvider() + { + return array( + array(123), + array(new Fixtures\NonInvokable()) + ); + } + + /** + * Provider for service definitions + */ + public function serviceDefinitionProvider() + { + return array( + array(function ($value) { + $service = new Fixtures\Service(); + $service->value = $value; + + return $service; + }), + array(new Fixtures\Invokable()) + ); + } + + public function testDefiningNewServiceAfterFreeze() + { + $pimple = new Container(); + $pimple['foo'] = function () { + return 'foo'; + }; + $foo = $pimple['foo']; + + $pimple['bar'] = function () { + return 'bar'; + }; + $this->assertSame('bar', $pimple['bar']); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage Cannot override frozen service "foo". + */ + public function testOverridingServiceAfterFreeze() + { + $pimple = new Container(); + $pimple['foo'] = function () { + return 'foo'; + }; + $foo = $pimple['foo']; + + $pimple['foo'] = function () { + return 'bar'; + }; + } + + public function testRemovingServiceAfterFreeze() + { + $pimple = new Container(); + $pimple['foo'] = function () { + return 'foo'; + }; + $foo = $pimple['foo']; + + unset($pimple['foo']); + $pimple['foo'] = function () { + return 'bar'; + }; + $this->assertSame('bar', $pimple['foo']); + } + + public function testExtendingService() + { + $pimple = new Container(); + $pimple['foo'] = function () { + return 'foo'; + }; + $pimple['foo'] = $pimple->extend('foo', function ($foo, $app) { + return "$foo.bar"; + }); + $pimple['foo'] = $pimple->extend('foo', function ($foo, $app) { + return "$foo.baz"; + }); + $this->assertSame('foo.bar.baz', $pimple['foo']); + } + + public function testExtendingServiceAfterOtherServiceFreeze() + { + $pimple = new Container(); + $pimple['foo'] = function () { + return 'foo'; + }; + $pimple['bar'] = function () { + return 'bar'; + }; + $foo = $pimple['foo']; + + $pimple['bar'] = $pimple->extend('bar', function ($bar, $app) { + return "$bar.baz"; + }); + $this->assertSame('bar.baz', $pimple['bar']); + } +} diff --git a/src/lib/vendor/psr/log/.gitignore b/src/lib/vendor/psr/log/.gitignore new file mode 100644 index 00000000..22d0d82f --- /dev/null +++ b/src/lib/vendor/psr/log/.gitignore @@ -0,0 +1 @@ +vendor diff --git a/src/lib/vendor/psr/log/LICENSE b/src/lib/vendor/psr/log/LICENSE new file mode 100644 index 00000000..474c952b --- /dev/null +++ b/src/lib/vendor/psr/log/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/lib/vendor/psr/log/Psr/Log/AbstractLogger.php b/src/lib/vendor/psr/log/Psr/Log/AbstractLogger.php new file mode 100644 index 00000000..00f90345 --- /dev/null +++ b/src/lib/vendor/psr/log/Psr/Log/AbstractLogger.php @@ -0,0 +1,120 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * @return null + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * @return null + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * @return null + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * @return null + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * @return null + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * @return null + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * @return null + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } +} diff --git a/src/lib/vendor/psr/log/Psr/Log/InvalidArgumentException.php b/src/lib/vendor/psr/log/Psr/Log/InvalidArgumentException.php new file mode 100644 index 00000000..67f852d1 --- /dev/null +++ b/src/lib/vendor/psr/log/Psr/Log/InvalidArgumentException.php @@ -0,0 +1,7 @@ +logger = $logger; + } +} diff --git a/src/lib/vendor/psr/log/Psr/Log/LoggerInterface.php b/src/lib/vendor/psr/log/Psr/Log/LoggerInterface.php new file mode 100644 index 00000000..476bb962 --- /dev/null +++ b/src/lib/vendor/psr/log/Psr/Log/LoggerInterface.php @@ -0,0 +1,114 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * @return null + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * @return null + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * @return null + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * @return null + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * @return null + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * @return null + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * @return null + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null + */ + abstract public function log($level, $message, array $context = array()); +} diff --git a/src/lib/vendor/psr/log/Psr/Log/NullLogger.php b/src/lib/vendor/psr/log/Psr/Log/NullLogger.php new file mode 100644 index 00000000..553a3c59 --- /dev/null +++ b/src/lib/vendor/psr/log/Psr/Log/NullLogger.php @@ -0,0 +1,27 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null + */ + public function log($level, $message, array $context = array()) + { + // noop + } +} diff --git a/src/lib/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php b/src/lib/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php new file mode 100644 index 00000000..a9328151 --- /dev/null +++ b/src/lib/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php @@ -0,0 +1,116 @@ + " + * + * Example ->error('Foo') would yield "error Foo" + * + * @return string[] + */ + abstract function getLogs(); + + public function testImplements() + { + $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @dataProvider provideLevelsAndMessages + */ + public function testLogsAtAllLevels($level, $message) + { + $logger = $this->getLogger(); + $logger->{$level}($message, array('user' => 'Bob')); + $logger->log($level, $message, array('user' => 'Bob')); + + $expected = array( + $level.' message of level '.$level.' with context: Bob', + $level.' message of level '.$level.' with context: Bob', + ); + $this->assertEquals($expected, $this->getLogs()); + } + + public function provideLevelsAndMessages() + { + return array( + LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), + LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), + LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), + LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), + LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), + LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), + LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), + LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), + ); + } + + /** + * @expectedException Psr\Log\InvalidArgumentException + */ + public function testThrowsOnInvalidLevel() + { + $logger = $this->getLogger(); + $logger->log('invalid level', 'Foo'); + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + + $expected = array('info {Message {nothing} Bob Bar a}'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testObjectCastToString() + { + $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString')); + $dummy->expects($this->once()) + ->method('__toString') + ->will($this->returnValue('DUMMY')); + + $this->getLogger()->warning($dummy); + } + + public function testContextCanContainAnything() + { + $context = array( + 'bool' => true, + 'null' => null, + 'string' => 'Foo', + 'int' => 0, + 'float' => 0.5, + 'nested' => array('with object' => new DummyTest), + 'object' => new \DateTime, + 'resource' => fopen('php://memory', 'r'), + ); + + $this->getLogger()->warning('Crazy context data', $context); + } + + public function testContextExceptionKeyCanBeExceptionOrOtherValues() + { + $this->getLogger()->warning('Random message', array('exception' => 'oops')); + $this->getLogger()->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + } +} + +class DummyTest +{ +} \ No newline at end of file diff --git a/src/lib/vendor/psr/log/README.md b/src/lib/vendor/psr/log/README.md new file mode 100644 index 00000000..574bc1cb --- /dev/null +++ b/src/lib/vendor/psr/log/README.md @@ -0,0 +1,45 @@ +PSR Log +======= + +This repository holds all interfaces/classes/traits related to +[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md). + +Note that this is not a logger of its own. It is merely an interface that +describes a logger. See the specification for more details. + +Usage +----- + +If you need a logger, you can use the interface like this: + +```php +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/src/lib/vendor/psr/log/composer.json b/src/lib/vendor/psr/log/composer.json new file mode 100644 index 00000000..6bdcc219 --- /dev/null +++ b/src/lib/vendor/psr/log/composer.json @@ -0,0 +1,17 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore new file mode 100644 index 00000000..c49a5d8d --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md new file mode 100644 index 00000000..bb42ee19 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md @@ -0,0 +1,23 @@ +CHANGELOG +========= + +2.5.0 +----- + + * added Debug\TraceableEventDispatcher (originally in HttpKernel) + * changed Debug\TraceableEventDispatcherInterface to extend EventDispatcherInterface + * added RegisterListenersPass (originally in HttpKernel) + +2.1.0 +----- + + * added TraceableEventDispatcherInterface + * added ContainerAwareEventDispatcher + * added a reference to the EventDispatcher on the Event + * added a reference to the Event name on the event + * added fluid interface to the dispatch() method which now returns the Event + object + * added GenericEvent event class + * added the possibility for subscribers to subscribe several times for the + same event + * added ImmutableEventDispatcher diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php new file mode 100644 index 00000000..e97d427e --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php @@ -0,0 +1,202 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Lazily loads listeners and subscribers from the dependency injection + * container + * + * @author Fabien Potencier + * @author Bernhard Schussek + * @author Jordan Alliot + */ +class ContainerAwareEventDispatcher extends EventDispatcher +{ + /** + * The container from where services are loaded + * @var ContainerInterface + */ + private $container; + + /** + * The service IDs of the event listeners and subscribers + * @var array + */ + private $listenerIds = array(); + + /** + * The services registered as listeners + * @var array + */ + private $listeners = array(); + + /** + * Constructor. + * + * @param ContainerInterface $container A ContainerInterface instance + */ + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + /** + * Adds a service as event listener + * + * @param string $eventName Event for which the listener is added + * @param array $callback The service ID of the listener service & the method + * name that has to be called + * @param int $priority The higher this value, the earlier an event listener + * will be triggered in the chain. + * Defaults to 0. + * + * @throws \InvalidArgumentException + */ + public function addListenerService($eventName, $callback, $priority = 0) + { + if (!is_array($callback) || 2 !== count($callback)) { + throw new \InvalidArgumentException('Expected an array("service", "method") argument'); + } + + $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority); + } + + public function removeListener($eventName, $listener) + { + $this->lazyLoad($eventName); + + if (isset($this->listeners[$eventName])) { + foreach ($this->listeners[$eventName] as $key => $l) { + foreach ($this->listenerIds[$eventName] as $i => $args) { + list($serviceId, $method, $priority) = $args; + if ($key === $serviceId.'.'.$method) { + if ($listener === array($l, $method)) { + unset($this->listeners[$eventName][$key]); + if (empty($this->listeners[$eventName])) { + unset($this->listeners[$eventName]); + } + unset($this->listenerIds[$eventName][$i]); + if (empty($this->listenerIds[$eventName])) { + unset($this->listenerIds[$eventName]); + } + } + } + } + } + } + + parent::removeListener($eventName, $listener); + } + + /** + * @see EventDispatcherInterface::hasListeners + */ + public function hasListeners($eventName = null) + { + if (null === $eventName) { + return (bool) count($this->listenerIds) || (bool) count($this->listeners); + } + + if (isset($this->listenerIds[$eventName])) { + return true; + } + + return parent::hasListeners($eventName); + } + + /** + * @see EventDispatcherInterface::getListeners + */ + public function getListeners($eventName = null) + { + if (null === $eventName) { + foreach (array_keys($this->listenerIds) as $serviceEventName) { + $this->lazyLoad($serviceEventName); + } + } else { + $this->lazyLoad($eventName); + } + + return parent::getListeners($eventName); + } + + /** + * Adds a service as event subscriber + * + * @param string $serviceId The service ID of the subscriber service + * @param string $class The service's class name (which must implement EventSubscriberInterface) + */ + public function addSubscriberService($serviceId, $class) + { + foreach ($class::getSubscribedEvents() as $eventName => $params) { + if (is_string($params)) { + $this->listenerIds[$eventName][] = array($serviceId, $params, 0); + } elseif (is_string($params[0])) { + $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0); + } else { + foreach ($params as $listener) { + $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0); + } + } + } + } + + /** + * {@inheritdoc} + * + * Lazily loads listeners for this event from the dependency injection + * container. + * + * @throws \InvalidArgumentException if the service is not defined + */ + public function dispatch($eventName, Event $event = null) + { + $this->lazyLoad($eventName); + + return parent::dispatch($eventName, $event); + } + + public function getContainer() + { + return $this->container; + } + + /** + * Lazily loads listeners for this event from the dependency injection + * container. + * + * @param string $eventName The name of the event to dispatch. The name of + * the event is the name of the method that is + * invoked on listeners. + */ + protected function lazyLoad($eventName) + { + if (isset($this->listenerIds[$eventName])) { + foreach ($this->listenerIds[$eventName] as $args) { + list($serviceId, $method, $priority) = $args; + $listener = $this->container->get($serviceId); + + $key = $serviceId.'.'.$method; + if (!isset($this->listeners[$eventName][$key])) { + $this->addListener($eventName, array($listener, $method), $priority); + } elseif ($listener !== $this->listeners[$eventName][$key]) { + parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method)); + $this->addListener($eventName, array($listener, $method), $priority); + } + + $this->listeners[$eventName][$key] = $listener; + } + } + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php new file mode 100644 index 00000000..410226bb --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -0,0 +1,317 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Stopwatch\Stopwatch; +use Psr\Log\LoggerInterface; + +/** + * Collects some data about event listeners. + * + * This event dispatcher delegates the dispatching to another one. + * + * @author Fabien Potencier + */ +class TraceableEventDispatcher implements TraceableEventDispatcherInterface +{ + protected $logger; + protected $stopwatch; + + private $called; + private $dispatcher; + + /** + * Constructor. + * + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + * @param Stopwatch $stopwatch A Stopwatch instance + * @param LoggerInterface $logger A LoggerInterface instance + */ + public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null) + { + $this->dispatcher = $dispatcher; + $this->stopwatch = $stopwatch; + $this->logger = $logger; + $this->called = array(); + } + + /** + * {@inheritdoc} + */ + public function addListener($eventName, $listener, $priority = 0) + { + $this->dispatcher->addListener($eventName, $listener, $priority); + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->dispatcher->addSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function removeListener($eventName, $listener) + { + return $this->dispatcher->removeListener($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + return $this->dispatcher->removeSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function getListeners($eventName = null) + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function hasListeners($eventName = null) + { + return $this->dispatcher->hasListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function dispatch($eventName, Event $event = null) + { + if (null === $event) { + $event = new Event(); + } + + $this->preProcess($eventName); + $this->preDispatch($eventName, $event); + + $e = $this->stopwatch->start($eventName, 'section'); + + $this->dispatcher->dispatch($eventName, $event); + + if ($e->isStarted()) { + $e->stop(); + } + + $this->postDispatch($eventName, $event); + $this->postProcess($eventName); + + return $event; + } + + /** + * {@inheritdoc} + */ + public function getCalledListeners() + { + $called = array(); + foreach ($this->called as $eventName => $listeners) { + foreach ($listeners as $listener) { + $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName); + $called[$eventName.'.'.$info['pretty']] = $info; + } + } + + return $called; + } + + /** + * {@inheritdoc} + */ + public function getNotCalledListeners() + { + try { + $allListeners = $this->getListeners(); + } catch (\Exception $e) { + if (null !== $this->logger) { + $this->logger->info(sprintf('An exception was thrown while getting the uncalled listeners (%s)', $e->getMessage()), array('exception' => $e)); + } + + // unable to retrieve the uncalled listeners + return array(); + } + + $notCalled = array(); + foreach ($allListeners as $eventName => $listeners) { + foreach ($listeners as $listener) { + $called = false; + if (isset($this->called[$eventName])) { + foreach ($this->called[$eventName] as $l) { + if ($l->getWrappedListener() === $listener) { + $called = true; + + break; + } + } + } + + if (!$called) { + $info = $this->getListenerInfo($listener, $eventName); + $notCalled[$eventName.'.'.$info['pretty']] = $info; + } + } + } + + return $notCalled; + } + + /** + * Proxies all method calls to the original event dispatcher. + * + * @param string $method The method name + * @param array $arguments The method arguments + * + * @return mixed + */ + public function __call($method, $arguments) + { + return call_user_func_array(array($this->dispatcher, $method), $arguments); + } + + /** + * Called before dispatching the event. + * + * @param string $eventName The event name + * @param Event $event The event + */ + protected function preDispatch($eventName, Event $event) + { + } + + /** + * Called after dispatching the event. + * + * @param string $eventName The event name + * @param Event $event The event + */ + protected function postDispatch($eventName, Event $event) + { + } + + private function preProcess($eventName) + { + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + $this->dispatcher->removeListener($eventName, $listener); + $info = $this->getListenerInfo($listener, $eventName); + $name = isset($info['class']) ? $info['class'] : $info['type']; + $this->dispatcher->addListener($eventName, new WrappedListener($listener, $name, $this->stopwatch)); + } + } + + private function postProcess($eventName) + { + $skipped = false; + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + // Unwrap listener + $this->dispatcher->removeListener($eventName, $listener); + $this->dispatcher->addListener($eventName, $listener->getWrappedListener()); + + $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName); + if ($listener->wasCalled()) { + if (null !== $this->logger) { + $this->logger->debug(sprintf('Notified event "%s" to listener "%s".', $eventName, $info['pretty'])); + } + + if (!isset($this->called[$eventName])) { + $this->called[$eventName] = new \SplObjectStorage(); + } + + $this->called[$eventName]->attach($listener); + } + + if (null !== $this->logger && $skipped) { + $this->logger->debug(sprintf('Listener "%s" was not called for event "%s".', $info['pretty'], $eventName)); + } + + if ($listener->stoppedPropagation()) { + if (null !== $this->logger) { + $this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s".', $info['pretty'], $eventName)); + } + + $skipped = true; + } + } + } + + /** + * Returns information about the listener + * + * @param object $listener The listener + * @param string $eventName The event name + * + * @return array Information about the listener + */ + private function getListenerInfo($listener, $eventName) + { + $info = array( + 'event' => $eventName, + ); + if ($listener instanceof \Closure) { + $info += array( + 'type' => 'Closure', + 'pretty' => 'closure' + ); + } elseif (is_string($listener)) { + try { + $r = new \ReflectionFunction($listener); + $file = $r->getFileName(); + $line = $r->getStartLine(); + } catch (\ReflectionException $e) { + $file = null; + $line = null; + } + $info += array( + 'type' => 'Function', + 'function' => $listener, + 'file' => $file, + 'line' => $line, + 'pretty' => $listener, + ); + } elseif (is_array($listener) || (is_object($listener) && is_callable($listener))) { + if (!is_array($listener)) { + $listener = array($listener, '__invoke'); + } + $class = is_object($listener[0]) ? get_class($listener[0]) : $listener[0]; + try { + $r = new \ReflectionMethod($class, $listener[1]); + $file = $r->getFileName(); + $line = $r->getStartLine(); + } catch (\ReflectionException $e) { + $file = null; + $line = null; + } + $info += array( + 'type' => 'Method', + 'class' => $class, + 'method' => $listener[1], + 'file' => $file, + 'line' => $line, + 'pretty' => $class.'::'.$listener[1], + ); + } + + return $info; + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php new file mode 100644 index 00000000..5483e815 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * @author Fabien Potencier + */ +interface TraceableEventDispatcherInterface extends EventDispatcherInterface +{ + /** + * Gets the called listeners. + * + * @return array An array of called listeners + */ + public function getCalledListeners(); + + /** + * Gets the not called listeners. + * + * @return array An array of not called listeners + */ + public function getNotCalledListeners(); +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/WrappedListener.php new file mode 100644 index 00000000..c501662b --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * @author Fabien Potencier + */ +class WrappedListener +{ + private $listener; + private $name; + private $called; + private $stoppedPropagation; + private $stopwatch; + + public function __construct($listener, $name, Stopwatch $stopwatch) + { + $this->listener = $listener; + $this->name = $name; + $this->stopwatch = $stopwatch; + $this->called = false; + $this->stoppedPropagation = false; + } + + public function getWrappedListener() + { + return $this->listener; + } + + public function wasCalled() + { + return $this->called; + } + + public function stoppedPropagation() + { + return $this->stoppedPropagation; + } + + public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) + { + $this->called = true; + + $e = $this->stopwatch->start($this->name, 'event_listener'); + + call_user_func($this->listener, $event, $eventName, $dispatcher); + + if ($e->isStarted()) { + $e->stop(); + } + + if ($event->isPropagationStopped()) { + $this->stoppedPropagation = true; + } + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php new file mode 100644 index 00000000..afe3ecd1 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + +/** + * Compiler pass to register tagged services for an event dispatcher. + */ +class RegisterListenersPass implements CompilerPassInterface +{ + /** + * @var string + */ + protected $dispatcherService; + + /** + * @var string + */ + protected $listenerTag; + + /** + * @var string + */ + protected $subscriberTag; + + /** + * Constructor. + * + * @param string $dispatcherService Service name of the event dispatcher in processed container + * @param string $listenerTag Tag name used for listener + * @param string $subscriberTag Tag name used for subscribers + */ + public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber') + { + $this->dispatcherService = $dispatcherService; + $this->listenerTag = $listenerTag; + $this->subscriberTag = $subscriberTag; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) { + return; + } + + $definition = $container->findDefinition($this->dispatcherService); + + foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) { + $def = $container->getDefinition($id); + if (!$def->isPublic()) { + throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event listeners are lazy-loaded.', $id)); + } + + if ($def->isAbstract()) { + throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event listeners are lazy-loaded.', $id)); + } + + foreach ($events as $event) { + $priority = isset($event['priority']) ? $event['priority'] : 0; + + if (!isset($event['event'])) { + throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); + } + + if (!isset($event['method'])) { + $event['method'] = 'on'.preg_replace_callback(array( + '/(?<=\b)[a-z]/i', + '/[^a-z0-9]/i', + ), function ($matches) { return strtoupper($matches[0]); }, $event['event']); + $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); + } + + $definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority)); + } + } + + foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) { + $def = $container->getDefinition($id); + if (!$def->isPublic()) { + throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id)); + } + + // We must assume that the class value has been correctly filled, even if the service is created by a factory + $class = $def->getClass(); + + $refClass = new \ReflectionClass($class); + $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface'; + if (!$refClass->implementsInterface($interface)) { + throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface)); + } + + $definition->addMethodCall('addSubscriberService', array($id, $class)); + } + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php new file mode 100644 index 00000000..bf792a25 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * + * @api + */ +class Event +{ + /** + * @var bool Whether no further event listeners should be triggered + */ + private $propagationStopped = false; + + /** + * @var EventDispatcher Dispatcher that dispatched this event + */ + private $dispatcher; + + /** + * @var string This event's name + */ + private $name; + + /** + * Returns whether further event listeners should be triggered. + * + * @see Event::stopPropagation + * @return bool Whether propagation was already stopped for this event. + * + * @api + */ + public function isPropagationStopped() + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + * + * @api + */ + public function stopPropagation() + { + $this->propagationStopped = true; + } + + /** + * Stores the EventDispatcher that dispatches this Event + * + * @param EventDispatcherInterface $dispatcher + * + * @deprecated Deprecated in 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. + * + * @api + */ + public function setDispatcher(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + /** + * Returns the EventDispatcher that dispatches this Event + * + * @return EventDispatcherInterface + * + * @deprecated Deprecated in 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. + * + * @api + */ + public function getDispatcher() + { + return $this->dispatcher; + } + + /** + * Gets the event's name. + * + * @return string + * + * @deprecated Deprecated in 2.4, to be removed in 3.0. The event name is passed to the listener call. + * + * @api + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the event's name property. + * + * @param string $name The event name. + * + * @deprecated Deprecated in 2.4, to be removed in 3.0. The event name is passed to the listener call. + * + * @api + */ + public function setName($name) + { + $this->name = $name; + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php new file mode 100644 index 00000000..222a9371 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -0,0 +1,185 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Fabien Potencier + * @author Jordi Boggiano + * @author Jordan Alliot + * + * @api + */ +class EventDispatcher implements EventDispatcherInterface +{ + private $listeners = array(); + private $sorted = array(); + + /** + * @see EventDispatcherInterface::dispatch + * + * @api + */ + public function dispatch($eventName, Event $event = null) + { + if (null === $event) { + $event = new Event(); + } + + $event->setDispatcher($this); + $event->setName($eventName); + + if (!isset($this->listeners[$eventName])) { + return $event; + } + + $this->doDispatch($this->getListeners($eventName), $eventName, $event); + + return $event; + } + + /** + * @see EventDispatcherInterface::getListeners + */ + public function getListeners($eventName = null) + { + if (null !== $eventName) { + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + + return $this->sorted[$eventName]; + } + + foreach (array_keys($this->listeners) as $eventName) { + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + } + + return array_filter($this->sorted); + } + + /** + * @see EventDispatcherInterface::hasListeners + */ + public function hasListeners($eventName = null) + { + return (bool) count($this->getListeners($eventName)); + } + + /** + * @see EventDispatcherInterface::addListener + * + * @api + */ + public function addListener($eventName, $listener, $priority = 0) + { + $this->listeners[$eventName][$priority][] = $listener; + unset($this->sorted[$eventName]); + } + + /** + * @see EventDispatcherInterface::removeListener + */ + public function removeListener($eventName, $listener) + { + if (!isset($this->listeners[$eventName])) { + return; + } + + foreach ($this->listeners[$eventName] as $priority => $listeners) { + if (false !== ($key = array_search($listener, $listeners, true))) { + unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]); + } + } + } + + /** + * @see EventDispatcherInterface::addSubscriber + * + * @api + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (is_string($params)) { + $this->addListener($eventName, array($subscriber, $params)); + } elseif (is_string($params[0])) { + $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0); + } else { + foreach ($params as $listener) { + $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0); + } + } + } + } + + /** + * @see EventDispatcherInterface::removeSubscriber + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (is_array($params) && is_array($params[0])) { + foreach ($params as $listener) { + $this->removeListener($eventName, array($subscriber, $listener[0])); + } + } else { + $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0])); + } + } + } + + /** + * Triggers the listeners of an event. + * + * This method can be overridden to add functionality that is executed + * for each listener. + * + * @param callable[] $listeners The event listeners. + * @param string $eventName The name of the event to dispatch. + * @param Event $event The event object to pass to the event handlers/listeners. + */ + protected function doDispatch($listeners, $eventName, Event $event) + { + foreach ($listeners as $listener) { + call_user_func($listener, $event, $eventName, $this); + if ($event->isPropagationStopped()) { + break; + } + } + } + + /** + * Sorts the internal list of listeners for the given event by priority. + * + * @param string $eventName The name of the event. + */ + private function sortListeners($eventName) + { + $this->sorted[$eventName] = array(); + + if (isset($this->listeners[$eventName])) { + krsort($this->listeners[$eventName]); + $this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]); + } + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php new file mode 100644 index 00000000..3fdbfd88 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Bernhard Schussek + * + * @api + */ +interface EventDispatcherInterface +{ + /** + * Dispatches an event to all registered listeners. + * + * @param string $eventName The name of the event to dispatch. The name of + * the event is the name of the method that is + * invoked on listeners. + * @param Event $event The event to pass to the event handlers/listeners. + * If not supplied, an empty Event instance is created. + * + * @return Event + * + * @api + */ + public function dispatch($eventName, Event $event = null); + + /** + * Adds an event listener that listens on the specified events. + * + * @param string $eventName The event to listen on + * @param callable $listener The listener + * @param int $priority The higher this value, the earlier an event + * listener will be triggered in the chain (defaults to 0) + * + * @api + */ + public function addListener($eventName, $listener, $priority = 0); + + /** + * Adds an event subscriber. + * + * The subscriber is asked for all the events he is + * interested in and added as a listener for these events. + * + * @param EventSubscriberInterface $subscriber The subscriber. + * + * @api + */ + public function addSubscriber(EventSubscriberInterface $subscriber); + + /** + * Removes an event listener from the specified events. + * + * @param string|array $eventName The event(s) to remove a listener from + * @param callable $listener The listener to remove + */ + public function removeListener($eventName, $listener); + + /** + * Removes an event subscriber. + * + * @param EventSubscriberInterface $subscriber The subscriber + */ + public function removeSubscriber(EventSubscriberInterface $subscriber); + + /** + * Gets the listeners of a specific event or all listeners. + * + * @param string $eventName The name of the event + * + * @return array The event listeners for the specified event, or all event listeners by event name + */ + public function getListeners($eventName = null); + + /** + * Checks whether an event has any registered listeners. + * + * @param string $eventName The name of the event + * + * @return bool true if the specified event has any listeners, false otherwise + */ + public function hasListeners($eventName = null); +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php new file mode 100644 index 00000000..080f892f --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * An EventSubscriber knows himself what events he is interested in. + * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes + * {@link getSubscribedEvents} and registers the subscriber as a listener for all + * returned events. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * + * @api + */ +interface EventSubscriberInterface +{ + /** + * Returns an array of event names this subscriber wants to listen to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * array('eventName' => 'methodName') + * * array('eventName' => array('methodName', $priority)) + * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) + * + * @return array The event names to listen to + * + * @api + */ + public static function getSubscribedEvents(); +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php new file mode 100644 index 00000000..1e8c44a6 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * Event encapsulation class. + * + * Encapsulates events thus decoupling the observer from the subject they encapsulate. + * + * @author Drak + */ +class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate +{ + /** + * Event subject. + * + * @var mixed usually object or callable + */ + protected $subject; + + /** + * Array of arguments. + * + * @var array + */ + protected $arguments; + + /** + * Encapsulate an event with $subject and $args. + * + * @param mixed $subject The subject of the event, usually an object. + * @param array $arguments Arguments to store in the event. + */ + public function __construct($subject = null, array $arguments = array()) + { + $this->subject = $subject; + $this->arguments = $arguments; + } + + /** + * Getter for subject property. + * + * @return mixed $subject The observer subject. + */ + public function getSubject() + { + return $this->subject; + } + + /** + * Get argument by key. + * + * @param string $key Key. + * + * @throws \InvalidArgumentException If key is not found. + * + * @return mixed Contents of array key. + */ + public function getArgument($key) + { + if ($this->hasArgument($key)) { + return $this->arguments[$key]; + } + + throw new \InvalidArgumentException(sprintf('%s not found in %s', $key, $this->getName())); + } + + /** + * Add argument to event. + * + * @param string $key Argument name. + * @param mixed $value Value. + * + * @return GenericEvent + */ + public function setArgument($key, $value) + { + $this->arguments[$key] = $value; + + return $this; + } + + /** + * Getter for all arguments. + * + * @return array + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Set args property. + * + * @param array $args Arguments. + * + * @return GenericEvent + */ + public function setArguments(array $args = array()) + { + $this->arguments = $args; + + return $this; + } + + /** + * Has argument. + * + * @param string $key Key of arguments array. + * + * @return bool + */ + public function hasArgument($key) + { + return array_key_exists($key, $this->arguments); + } + + /** + * ArrayAccess for argument getter. + * + * @param string $key Array key. + * + * @throws \InvalidArgumentException If key does not exist in $this->args. + * + * @return mixed + */ + public function offsetGet($key) + { + return $this->getArgument($key); + } + + /** + * ArrayAccess for argument setter. + * + * @param string $key Array key to set. + * @param mixed $value Value. + */ + public function offsetSet($key, $value) + { + $this->setArgument($key, $value); + } + + /** + * ArrayAccess for unset argument. + * + * @param string $key Array key. + */ + public function offsetUnset($key) + { + if ($this->hasArgument($key)) { + unset($this->arguments[$key]); + } + } + + /** + * ArrayAccess has argument. + * + * @param string $key Array key. + * + * @return bool + */ + public function offsetExists($key) + { + return $this->hasArgument($key); + } + + /** + * IteratorAggregate for iterating over the object like an array + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new \ArrayIterator($this->arguments); + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php new file mode 100644 index 00000000..b70b81a8 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * A read-only proxy for an event dispatcher. + * + * @author Bernhard Schussek + */ +class ImmutableEventDispatcher implements EventDispatcherInterface +{ + /** + * The proxied dispatcher. + * @var EventDispatcherInterface + */ + private $dispatcher; + + /** + * Creates an unmodifiable proxy for an event dispatcher. + * + * @param EventDispatcherInterface $dispatcher The proxied event dispatcher. + */ + public function __construct(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + /** + * {@inheritdoc} + */ + public function dispatch($eventName, Event $event = null) + { + return $this->dispatcher->dispatch($eventName, $event); + } + + /** + * {@inheritdoc} + */ + public function addListener($eventName, $listener, $priority = 0) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function removeListener($eventName, $listener) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function getListeners($eventName = null) + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function hasListeners($eventName = null) + { + return $this->dispatcher->hasListeners($eventName); + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE new file mode 100644 index 00000000..0b3292cf --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2014 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md new file mode 100644 index 00000000..22bf74fd --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md @@ -0,0 +1,25 @@ +EventDispatcher Component +========================= + +The Symfony2 EventDispatcher component implements the Mediator pattern in a +simple and effective way to make your projects truly extensible. + + use Symfony\Component\EventDispatcher\EventDispatcher; + use Symfony\Component\EventDispatcher\Event; + + $dispatcher = new EventDispatcher(); + + $dispatcher->addListener('event_name', function (Event $event) { + // ... + }); + + $dispatcher->dispatch('event_name'); + +Resources +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/EventDispatcher/ + $ composer.phar install + $ phpunit diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php new file mode 100644 index 00000000..fb3b4caa --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php @@ -0,0 +1,244 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\Scope; +use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +class ContainerAwareEventDispatcherTest extends \PHPUnit_Framework_TestCase +{ + public function testAddAListenerService() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $dispatcher->dispatch('onEvent', $event); + } + + public function testAddASubscriberService() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\SubscriberService'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container = new Container(); + $container->set('service.subscriber', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService'); + + $dispatcher->dispatch('onEvent', $event); + } + + public function testPreventDuplicateListenerService() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 5); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 10); + + $dispatcher->dispatch('onEvent', $event); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testTriggerAListenerServiceOutOfScope() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $scope = new Scope('scope'); + $container = new Container(); + $container->addScope($scope); + $container->enterScope('scope'); + + $container->set('service.listener', $service, 'scope'); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $container->leaveScope('scope'); + $dispatcher->dispatch('onEvent'); + } + + public function testReEnteringAScope() + { + $event = new Event(); + + $service1 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service1 + ->expects($this->exactly(2)) + ->method('onEvent') + ->with($event) + ; + + $scope = new Scope('scope'); + $container = new Container(); + $container->addScope($scope); + $container->enterScope('scope'); + + $container->set('service.listener', $service1, 'scope'); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + $dispatcher->dispatch('onEvent', $event); + + $service2 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service2 + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container->enterScope('scope'); + $container->set('service.listener', $service2, 'scope'); + + $dispatcher->dispatch('onEvent', $event); + + $container->leaveScope('scope'); + + $dispatcher->dispatch('onEvent'); + } + + public function testHasListenersOnLazyLoad() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $event->setDispatcher($dispatcher); + $event->setName('onEvent'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $this->assertTrue($dispatcher->hasListeners()); + + if ($dispatcher->hasListeners('onEvent')) { + $dispatcher->dispatch('onEvent'); + } + } + + public function testGetListenersOnLazyLoad() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $listeners = $dispatcher->getListeners(); + + $this->assertTrue(isset($listeners['onEvent'])); + + $this->assertCount(1, $dispatcher->getListeners('onEvent')); + } + + public function testRemoveAfterDispatch() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $dispatcher->dispatch('onEvent', new Event()); + $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); + $this->assertFalse($dispatcher->hasListeners('onEvent')); + } + + public function testRemoveBeforeDispatch() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); + $this->assertFalse($dispatcher->hasListeners('onEvent')); + } +} + +class Service +{ + public function onEvent(Event $e) + { + } +} + +class SubscriberService implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array( + 'onEvent' => 'onEvent', + 'onEvent' => array('onEvent', 10), + 'onEvent' => array('onEvent'), + ); + } + + public function onEvent(Event $e) + { + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php new file mode 100644 index 00000000..8ccfabb1 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests\Debug; + +use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Stopwatch\Stopwatch; + +class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase +{ + public function testAddRemoveListener() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $tdispatcher->addListener('foo', $listener = function () { ; }); + $listeners = $dispatcher->getListeners('foo'); + $this->assertCount(1, $listeners); + $this->assertSame($listener, $listeners[0]); + + $tdispatcher->removeListener('foo', $listener); + $this->assertCount(0, $dispatcher->getListeners('foo')); + } + + public function testGetListeners() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $tdispatcher->addListener('foo', $listener = function () { ; }); + $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo')); + } + + public function testHasListeners() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $this->assertFalse($dispatcher->hasListeners('foo')); + $this->assertFalse($tdispatcher->hasListeners('foo')); + + $tdispatcher->addListener('foo', $listener = function () { ; }); + $this->assertTrue($dispatcher->hasListeners('foo')); + $this->assertTrue($tdispatcher->hasListeners('foo')); + } + + public function testAddRemoveSubscriber() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $subscriber = new EventSubscriber(); + + $tdispatcher->addSubscriber($subscriber); + $listeners = $dispatcher->getListeners('foo'); + $this->assertCount(1, $listeners); + $this->assertSame(array($subscriber, 'call'), $listeners[0]); + + $tdispatcher->removeSubscriber($subscriber); + $this->assertCount(0, $dispatcher->getListeners('foo')); + } + + public function testGetCalledListeners() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + $tdispatcher->addListener('foo', $listener = function () { ; }); + + $this->assertEquals(array(), $tdispatcher->getCalledListeners()); + $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getNotCalledListeners()); + + $tdispatcher->dispatch('foo'); + + $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getCalledListeners()); + $this->assertEquals(array(), $tdispatcher->getNotCalledListeners()); + } + + public function testLogger() + { + $logger = $this->getMock('Psr\Log\LoggerInterface'); + + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); + $tdispatcher->addListener('foo', $listener1 = function () { ; }); + $tdispatcher->addListener('foo', $listener2 = function () { ; }); + + $logger->expects($this->at(0))->method('debug')->with("Notified event \"foo\" to listener \"closure\"."); + $logger->expects($this->at(1))->method('debug')->with("Notified event \"foo\" to listener \"closure\"."); + + $tdispatcher->dispatch('foo'); + } + + public function testLoggerWithStoppedEvent() + { + $logger = $this->getMock('Psr\Log\LoggerInterface'); + + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); + $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); }); + $tdispatcher->addListener('foo', $listener2 = function () { ; }); + + $logger->expects($this->at(0))->method('debug')->with("Notified event \"foo\" to listener \"closure\"."); + $logger->expects($this->at(1))->method('debug')->with("Listener \"closure\" stopped propagation of the event \"foo\"."); + $logger->expects($this->at(2))->method('debug')->with("Listener \"closure\" was not called for event \"foo\"."); + + $tdispatcher->dispatch('foo'); + } + + public function testDispatchCallListeners() + { + $called = array(); + + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + $tdispatcher->addListener('foo', $listener1 = function () use (&$called) { $called[] = 'foo1'; }); + $tdispatcher->addListener('foo', $listener2 = function () use (&$called) { $called[] = 'foo2'; }); + + $tdispatcher->dispatch('foo'); + + $this->assertEquals(array('foo1', 'foo2'), $called); + } + + public function testDispatchNested() + { + $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $loop = 1; + $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) { + ++$loop; + if (2 == $loop) { + $dispatcher->dispatch('foo'); + } + }); + + $dispatcher->dispatch('foo'); + } + + public function testDispatchReusedEventNested() + { + $nestedCall = false; + $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) { + $dispatcher->dispatch('bar', $e); + }); + $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) { + $nestedCall = true; + }); + + $this->assertFalse($nestedCall); + $dispatcher->dispatch('foo'); + $this->assertTrue($nestedCall); + } +} + +class EventSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('foo' => 'call'); + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php new file mode 100644 index 00000000..5959db0d --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; + +class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase +{ + /** + * Tests that event subscribers not implementing EventSubscriberInterface + * trigger an exception. + * + * @expectedException \InvalidArgumentException + */ + public function testEventSubscriberWithoutInterface() + { + // one service, not implementing any interface + $services = array( + 'my_event_subscriber' => array(0 => array()), + ); + + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $definition->expects($this->atLeastOnce()) + ->method('isPublic') + ->will($this->returnValue(true)); + $definition->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue('stdClass')); + + $builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); + $builder->expects($this->any()) + ->method('hasDefinition') + ->will($this->returnValue(true)); + + // We don't test kernel.event_listener here + $builder->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->onConsecutiveCalls(array(), $services)); + + $builder->expects($this->atLeastOnce()) + ->method('getDefinition') + ->will($this->returnValue($definition)); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($builder); + } + + public function testValidEventSubscriber() + { + $services = array( + 'my_event_subscriber' => array(0 => array()), + ); + + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $definition->expects($this->atLeastOnce()) + ->method('isPublic') + ->will($this->returnValue(true)); + $definition->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue('Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService')); + + $builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); + $builder->expects($this->any()) + ->method('hasDefinition') + ->will($this->returnValue(true)); + + // We don't test kernel.event_listener here + $builder->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->onConsecutiveCalls(array(), $services)); + + $builder->expects($this->atLeastOnce()) + ->method('getDefinition') + ->will($this->returnValue($definition)); + + $builder->expects($this->atLeastOnce()) + ->method('findDefinition') + ->will($this->returnValue($definition)); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($builder); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The service "foo" must be public as event listeners are lazy-loaded. + */ + public function testPrivateEventListener() + { + $container = new ContainerBuilder(); + $container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_listener', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The service "foo" must be public as event subscribers are lazy-loaded. + */ + public function testPrivateEventSubscriber() + { + $container = new ContainerBuilder(); + $container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_subscriber', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The service "foo" must not be abstract as event listeners are lazy-loaded. + */ + public function testAbstractEventListener() + { + $container = new ContainerBuilder(); + $container->register('foo', 'stdClass')->setAbstract(true)->addTag('kernel.event_listener', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } +} + +class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface +{ + public static function getSubscribedEvents() {} +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php new file mode 100644 index 00000000..efc0c29f --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -0,0 +1,368 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +class EventDispatcherTest extends \PHPUnit_Framework_TestCase +{ + /* Some pseudo events */ + const preFoo = 'pre.foo'; + const postFoo = 'post.foo'; + const preBar = 'pre.bar'; + const postBar = 'post.bar'; + + /** + * @var EventDispatcher + */ + private $dispatcher; + + private $listener; + + protected function setUp() + { + $this->dispatcher = new EventDispatcher(); + $this->listener = new TestEventListener(); + } + + protected function tearDown() + { + $this->dispatcher = null; + $this->listener = null; + } + + public function testInitialState() + { + $this->assertEquals(array(), $this->dispatcher->getListeners()); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testAddListener() + { + $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo)); + $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo)); + $this->assertCount(2, $this->dispatcher->getListeners()); + } + + public function testGetListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener1->name = '1'; + $listener2->name = '2'; + $listener3->name = '3'; + + $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10); + $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10); + $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo')); + + $expected = array( + array($listener2, 'preFoo'), + array($listener3, 'preFoo'), + array($listener1, 'preFoo'), + ); + + $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); + } + + public function testGetAllListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener4 = new TestEventListener(); + $listener5 = new TestEventListener(); + $listener6 = new TestEventListener(); + + $this->dispatcher->addListener('pre.foo', $listener1, -10); + $this->dispatcher->addListener('pre.foo', $listener2); + $this->dispatcher->addListener('pre.foo', $listener3, 10); + $this->dispatcher->addListener('post.foo', $listener4, -10); + $this->dispatcher->addListener('post.foo', $listener5); + $this->dispatcher->addListener('post.foo', $listener6, 10); + + $expected = array( + 'pre.foo' => array($listener3, $listener2, $listener1), + 'post.foo' => array($listener6, $listener5, $listener4), + ); + + $this->assertSame($expected, $this->dispatcher->getListeners()); + } + + public function testDispatch() + { + $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->dispatcher->dispatch(self::preFoo); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertFalse($this->listener->postFooInvoked); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent')); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); + $event = new Event(); + $return = $this->dispatcher->dispatch(self::preFoo, $event); + $this->assertEquals('pre.foo', $event->getName()); + $this->assertSame($event, $return); + } + + public function testDispatchForClosure() + { + $invoked = 0; + $listener = function () use (&$invoked) { + $invoked++; + }; + $this->dispatcher->addListener('pre.foo', $listener); + $this->dispatcher->addListener('post.foo', $listener); + $this->dispatcher->dispatch(self::preFoo); + $this->assertEquals(1, $invoked); + } + + public function testStopEventPropagation() + { + $otherListener = new TestEventListener(); + + // postFoo() stops the propagation, so only one listener should + // be executed + // Manually set priority to enforce $this->listener to be called first + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10); + $this->dispatcher->addListener('post.foo', array($otherListener, 'preFoo')); + $this->dispatcher->dispatch(self::postFoo); + $this->assertTrue($this->listener->postFooInvoked); + $this->assertFalse($otherListener->postFooInvoked); + } + + public function testDispatchByPriority() + { + $invoked = array(); + $listener1 = function () use (&$invoked) { + $invoked[] = '1'; + }; + $listener2 = function () use (&$invoked) { + $invoked[] = '2'; + }; + $listener3 = function () use (&$invoked) { + $invoked[] = '3'; + }; + $this->dispatcher->addListener('pre.foo', $listener1, -10); + $this->dispatcher->addListener('pre.foo', $listener2); + $this->dispatcher->addListener('pre.foo', $listener3, 10); + $this->dispatcher->dispatch(self::preFoo); + $this->assertEquals(array('3', '2', '1'), $invoked); + } + + public function testRemoveListener() + { + $this->dispatcher->addListener('pre.bar', $this->listener); + $this->assertTrue($this->dispatcher->hasListeners(self::preBar)); + $this->dispatcher->removeListener('pre.bar', $this->listener); + $this->assertFalse($this->dispatcher->hasListeners(self::preBar)); + $this->dispatcher->removeListener('notExists', $this->listener); + } + + public function testAddSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testAddSubscriberWithPriorities() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $listeners = $this->dispatcher->getListeners('pre.foo'); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $listeners); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]); + } + + public function testAddSubscriberWithMultipleListeners() + { + $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $listeners = $this->dispatcher->getListeners('pre.foo'); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $listeners); + $this->assertEquals('preFoo2', $listeners[0][1]); + } + + public function testRemoveSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testRemoveSubscriberWithPriorities() + { + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + } + + public function testRemoveSubscriberWithMultipleListeners() + { + $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + } + + public function testEventReceivesTheDispatcherInstance() + { + $dispatcher = null; + $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) { + $dispatcher = $event->getDispatcher(); + }); + $this->dispatcher->dispatch('test'); + $this->assertSame($this->dispatcher, $dispatcher); + } + + public function testEventReceivesTheDispatcherInstanceAsArgument() + { + $listener = new TestWithDispatcher(); + $this->dispatcher->addListener('test', array($listener, 'foo')); + $this->assertNull($listener->name); + $this->assertNull($listener->dispatcher); + $this->dispatcher->dispatch('test'); + $this->assertEquals('test', $listener->name); + $this->assertSame($this->dispatcher, $listener->dispatcher); + } + + /** + * @see https://bugs.php.net/bug.php?id=62976 + * + * This bug affects: + * - The PHP 5.3 branch for versions < 5.3.18 + * - The PHP 5.4 branch for versions < 5.4.8 + * - The PHP 5.5 branch is not affected + */ + public function testWorkaroundForPhpBug62976() + { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('bug.62976', new CallableClass()); + $dispatcher->removeListener('bug.62976', function () {}); + $this->assertTrue($dispatcher->hasListeners('bug.62976')); + } + + public function testHasListenersWhenAddedCallbackListenerIsRemoved() + { + $listener = function () {}; + $this->dispatcher->addListener('foo', $listener); + $this->dispatcher->removeListener('foo', $listener); + $this->assertFalse($this->dispatcher->hasListeners()); + } + + public function testGetListenersWhenAddedCallbackListenerIsRemoved() + { + $listener = function () {}; + $this->dispatcher->addListener('foo', $listener); + $this->dispatcher->removeListener('foo', $listener); + $this->assertSame(array(), $this->dispatcher->getListeners()); + } + + public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() + { + $this->assertFalse($this->dispatcher->hasListeners('foo')); + $this->assertFalse($this->dispatcher->hasListeners()); + } +} + +class CallableClass +{ + public function __invoke() + { + } +} + +class TestEventListener +{ + public $preFooInvoked = false; + public $postFooInvoked = false; + + /* Listener methods */ + + public function preFoo(Event $e) + { + $this->preFooInvoked = true; + } + + public function postFoo(Event $e) + { + $this->postFooInvoked = true; + + $e->stopPropagation(); + } +} + +class TestWithDispatcher +{ + public $name; + public $dispatcher; + + public function foo(Event $e, $name, $dispatcher) + { + $this->name = $name; + $this->dispatcher = $dispatcher; + } +} + +class TestEventSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo'); + } +} + +class TestEventSubscriberWithPriorities implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array( + 'pre.foo' => array('preFoo', 10), + 'post.foo' => array('postFoo'), + ); + } +} + +class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('pre.foo' => array( + array('preFoo1'), + array('preFoo2', 10) + )); + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventTest.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventTest.php new file mode 100644 index 00000000..7a20fe6b --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventDispatcher; + +/** + * Test class for Event. + */ +class EventTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Symfony\Component\EventDispatcher\Event + */ + protected $event; + + /** + * @var \Symfony\Component\EventDispatcher\EventDispatcher + */ + protected $dispatcher; + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + $this->event = new Event(); + $this->dispatcher = new EventDispatcher(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + $this->event = null; + $this->dispatcher = null; + } + + public function testIsPropagationStopped() + { + $this->assertFalse($this->event->isPropagationStopped()); + } + + public function testStopPropagationAndIsPropagationStopped() + { + $this->event->stopPropagation(); + $this->assertTrue($this->event->isPropagationStopped()); + } + + public function testSetDispatcher() + { + $this->event->setDispatcher($this->dispatcher); + $this->assertSame($this->dispatcher, $this->event->getDispatcher()); + } + + public function testGetDispatcher() + { + $this->assertNull($this->event->getDispatcher()); + } + + public function testGetName() + { + $this->assertNull($this->event->getName()); + } + + public function testSetName() + { + $this->event->setName('foo'); + $this->assertEquals('foo', $this->event->getName()); + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php new file mode 100644 index 00000000..5dfda92f --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\GenericEvent; + +/** + * Test class for Event. + */ +class GenericEventTest extends \PHPUnit_Framework_TestCase +{ + + /** + * @var GenericEvent + */ + private $event; + + private $subject; + + /** + * Prepares the environment before running a test. + */ + protected function setUp() + { + parent::setUp(); + + $this->subject = new \stdClass(); + $this->event = new GenericEvent($this->subject, array('name' => 'Event')); + } + + /** + * Cleans up the environment after running a test. + */ + protected function tearDown() + { + $this->subject = null; + $this->event = null; + + parent::tearDown(); + } + + public function testConstruct() + { + $this->assertEquals($this->event, new GenericEvent($this->subject, array('name' => 'Event'))); + } + + /** + * Tests Event->getArgs() + */ + public function testGetArguments() + { + // test getting all + $this->assertSame(array('name' => 'Event'), $this->event->getArguments()); + } + + public function testSetArguments() + { + $result = $this->event->setArguments(array('foo' => 'bar')); + $this->assertAttributeSame(array('foo' => 'bar'), 'arguments', $this->event); + $this->assertSame($this->event, $result); + } + + public function testSetArgument() + { + $result = $this->event->setArgument('foo2', 'bar2'); + $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event); + $this->assertEquals($this->event, $result); + } + + public function testGetArgument() + { + // test getting key + $this->assertEquals('Event', $this->event->getArgument('name')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testGetArgException() + { + $this->event->getArgument('nameNotExist'); + } + + public function testOffsetGet() + { + // test getting key + $this->assertEquals('Event', $this->event['name']); + + // test getting invalid arg + $this->setExpectedException('InvalidArgumentException'); + $this->assertFalse($this->event['nameNotExist']); + } + + public function testOffsetSet() + { + $this->event['foo2'] = 'bar2'; + $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event); + } + + public function testOffsetUnset() + { + unset($this->event['name']); + $this->assertAttributeSame(array(), 'arguments', $this->event); + } + + public function testOffsetIsset() + { + $this->assertTrue(isset($this->event['name'])); + $this->assertFalse(isset($this->event['nameNotExist'])); + } + + public function testHasArgument() + { + $this->assertTrue($this->event->hasArgument('name')); + $this->assertFalse($this->event->hasArgument('nameNotExist')); + } + + public function testGetSubject() + { + $this->assertSame($this->subject, $this->event->getSubject()); + } + + public function testHasIterator() + { + $data = array(); + foreach ($this->event as $key => $value) { + $data[$key] = $value; + } + $this->assertEquals(array('name' => 'Event'), $data); + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ImmutableEventDispatcherTest.php b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ImmutableEventDispatcherTest.php new file mode 100644 index 00000000..80a7e43b --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ImmutableEventDispatcherTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\ImmutableEventDispatcher; + +/** + * @author Bernhard Schussek + */ +class ImmutableEventDispatcherTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $innerDispatcher; + + /** + * @var ImmutableEventDispatcher + */ + private $dispatcher; + + protected function setUp() + { + $this->innerDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $this->dispatcher = new ImmutableEventDispatcher($this->innerDispatcher); + } + + public function testDispatchDelegates() + { + $event = new Event(); + + $this->innerDispatcher->expects($this->once()) + ->method('dispatch') + ->with('event', $event) + ->will($this->returnValue('result')); + + $this->assertSame('result', $this->dispatcher->dispatch('event', $event)); + } + + public function testGetListenersDelegates() + { + $this->innerDispatcher->expects($this->once()) + ->method('getListeners') + ->with('event') + ->will($this->returnValue('result')); + + $this->assertSame('result', $this->dispatcher->getListeners('event')); + } + + public function testHasListenersDelegates() + { + $this->innerDispatcher->expects($this->once()) + ->method('hasListeners') + ->with('event') + ->will($this->returnValue('result')); + + $this->assertSame('result', $this->dispatcher->hasListeners('event')); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testAddListenerDisallowed() + { + $this->dispatcher->addListener('event', function () { return 'foo'; }); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testAddSubscriberDisallowed() + { + $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface'); + + $this->dispatcher->addSubscriber($subscriber); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testRemoveListenerDisallowed() + { + $this->dispatcher->removeListener('event', function () { return 'foo'; }); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testRemoveSubscriberDisallowed() + { + $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface'); + + $this->dispatcher->removeSubscriber($subscriber); + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/composer.json b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/composer.json new file mode 100644 index 00000000..3715ece3 --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/composer.json @@ -0,0 +1,41 @@ +{ + "name": "symfony/event-dispatcher", + "type": "library", + "description": "Symfony EventDispatcher Component", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/dependency-injection": "~2.0", + "symfony/config": "~2.0", + "symfony/stopwatch": "~2.2", + "psr/log": "~1.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "autoload": { + "psr-0": { "Symfony\\Component\\EventDispatcher\\": "" } + }, + "target-dir": "Symfony/Component/EventDispatcher", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + } +} diff --git a/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist new file mode 100644 index 00000000..cca1259b --- /dev/null +++ b/src/lib/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/skin/frontend/base/default/css/smile/elasticsearch.css b/src/skin/frontend/base/default/css/smile/elasticsearch.css new file mode 100644 index 00000000..92300c02 --- /dev/null +++ b/src/skin/frontend/base/default/css/smile/elasticsearch.css @@ -0,0 +1,40 @@ +/** + * ElasticSearch stylesheet + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Smile Searchandising Suite to newer + * versions in the future. + * + * @category Smile + * @package Smile_ElasticSearch + * @author Aurelien FOUCRET + * @copyright 2013 Smile + * @license Apache License Version 2.0 + */ + +/* Autocomplete styles */ +#search_autocomplete dl { background: #FFF; border: 1px solid #999; overflow: hidden; width: 100%; } +#search_autocomplete dl dt { background: #d12c01; color: #FFF; font-weight: bold; padding: 3px 3px; font-size: 110%; } +#search_autocomplete dl dd { background: #FFF; cursor: pointer; padding: 3px 5px; font-size: 110%; text-overflow: ellipsis; white-space: nowrap; width: 100%; } +#search_autocomplete dl dd.selected { background: rgb(253, 233, 229); } + +/* Price slider styles */ +.range-slider { padding: 5px 0 0; } +.range-slider .slider-bkg { margin:10px 0; background-color:#ccc; height:5px; position: relative; background: #BAA; cursor : pointer; } +.range-slider .handle { margin:-6px 0 0; width:10px; height:8px; background-color:#3399cc; cursor:move; position: absolute; } +.range-slider .handle:after { content: "-"; color: transparent; width: 0; height: 0; border-top: 8px solid #3399cc; border-left: 5px solid transparent; position: absolute; margin: 8px 0 0; border-right: 5px solid transparent; } +.range-slider .handle.min { margin-left: -4px; } +.range-slider .handle.max { margin-left: 4px; } +.range-slider .limits-container { margin: 0 0 0; } +.range-slider .validate-button { float: right; } +.range-slider .limits.min { float:left; margin-left: -5px; } +.range-slider .limits.max { float:right; margin-left: 5px; } +.range-slider .clear {clear: both;} +.range-slider .count.empty { line-height: 10px; color: #AA0000; margin: 0; text-align: center; } +.range-slider .count { line-height: 20px; margin: 0 50px 0 0; text-align: left; display: block; } + +#narrow-by-list .ratings { display: inline-block; margin: 0; } +#narrow-by-list .ratings .rating-box { margin: 0; } + +.block-layered-nav dl dd ol > li > span, .block-layered-nav dl dd ol > li > a { display: inline-block; } \ No newline at end of file