From be83910651163fcfabea33e8441bb3c4b61222e6 Mon Sep 17 00:00:00 2001
From: Tony Volpe ' . $date . ' ' . $date . ' ' . $date . ' ' . $date . ' ' . $date . ' ' . $date . ' ' . $date . ' ' . $date . '
(IPv4)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'ipv4_path',
+ 'value' => $db['ipv4_path'],
+ 'disabled' => TRUE,
+ 'after' => '
(IPv6)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'ipv6_path',
+ 'value' => $db['ipv6_path'],
+ 'disabled' => TRUE,
+ 'after' => '
(IPv4 and IPv6)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'ip_path',
+ 'value' => $db['ip_path'],
+ 'disabled' => TRUE,
+ 'after' => '
(ASN for IPv4 and IPv6)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'asn_path',
+ 'value' => $db['asn_path'],
+ 'disabled' => TRUE,
+ 'after' => '
(IPv4)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'ipv4_path',
+ 'value' => $db['ipv4_path'],
+ 'disabled' => TRUE,
+ 'after' => '
(IPv6)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'ipv6_path',
+ 'value' => $db['ipv6_path'],
+ 'disabled' => TRUE,
+ 'after' => '
(ASN for IPv4)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'asn4_path',
+ 'value' => $db['asn4_path'],
+ 'disabled' => TRUE,
+ 'after' => '
(ASN for IPv6)",
+ $callback,
+ $option_slug,
+ $section,
+ array(
+ 'type' => 'text',
+ 'option' => $option_name,
+ 'field' => $field,
+ 'sub-field' => 'asn6_path',
+ 'value' => $db['asn6_path'],
+ 'disabled' => TRUE,
+ 'after' => '
+ * This attribute is only available from the Insights web service and the + * GeoIP2 Enterprise database. + *
+ */ +class Traits extends AbstractRecord +{ + /** + * @ignore + */ + protected $validAttributes = [ + 'autonomousSystemNumber', + 'autonomousSystemOrganization', + 'connectionType', + 'domain', + 'ipAddress', + 'isAnonymous', + 'isAnonymousProxy', + 'isAnonymousVpn', + 'isHostingProvider', + 'isLegitimateProxy', + 'isp', + 'isPublicProxy', + 'isSatelliteProvider', + 'isTorExitNode', + 'organization', + 'userType', + ]; +} diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/geoip2/geoip2/src/WebService/Client.php b/wp/wp-content/ip-geo-api/maxmind/vendor/geoip2/geoip2/src/WebService/Client.php new file mode 100644 index 00000000..bac82f85 --- /dev/null +++ b/wp/wp-content/ip-geo-api/maxmind/vendor/geoip2/geoip2/src/WebService/Client.php @@ -0,0 +1,239 @@ +locales = $locales; + + // This is for backwards compatibility. Do not remove except for a + // major version bump. + if (is_string($options)) { + $options = ['host' => $options]; + } + + if (!isset($options['host'])) { + $options['host'] = 'geoip.maxmind.com'; + } + + $options['userAgent'] = $this->userAgent(); + + $this->client = new WsClient($userId, $licenseKey, $options); + } + + private function userAgent() + { + return 'GeoIP2-API/' . self::VERSION; + } + + /** + * This method calls the GeoIP2 Precision: City service. + * + * @param string $ipAddress IPv4 or IPv6 address as a string. If no + * address is provided, the address that the web service is called + * from will be used. + * + * @throws \GeoIp2\Exception\AddressNotFoundException if the address you + * provided is not in our database (e.g., a private address). + * @throws \GeoIp2\Exception\AuthenticationException if there is a problem + * with the user ID or license key that you provided + * @throws \GeoIp2\Exception\OutOfQueriesException if your account is out + * of queries + * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is + * invalid for some other reason. This may indicate an issue + * with this API. Please report the error to MaxMind. + * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned. + * This could indicate a problem with the connection between + * your server and the web service or that the web service + * returned an invalid document or 500 error code. + * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent + * class to the above exceptions. It will be thrown directly + * if a 200 status code is returned but the body is invalid. + * + * @return \GeoIp2\Model\City + */ + public function city($ipAddress = 'me') + { + return $this->responseFor('city', 'City', $ipAddress); + } + + /** + * This method calls the GeoIP2 Precision: Country service. + * + * @param string $ipAddress IPv4 or IPv6 address as a string. If no + * address is provided, the address that the web service is called + * from will be used. + * + * @throws \GeoIp2\Exception\AddressNotFoundException if the address you provided is not in our database (e.g., + * a private address). + * @throws \GeoIp2\Exception\AuthenticationException if there is a problem + * with the user ID or license key that you provided + * @throws \GeoIp2\Exception\OutOfQueriesException if your account is out of queries + * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is + * invalid for some other reason. This may indicate an + * issue with this API. Please report the error to MaxMind. + * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error + * code or message was returned. This could indicate a problem + * with the connection between your server and the web service + * or that the web service returned an invalid document or 500 + * error code. + * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent class to the above exceptions. It + * will be thrown directly if a 200 status code is returned but + * the body is invalid. + * + * @return \GeoIp2\Model\Country + */ + public function country($ipAddress = 'me') + { + return $this->responseFor('country', 'Country', $ipAddress); + } + + /** + * This method calls the GeoIP2 Precision: Insights service. + * + * @param string $ipAddress IPv4 or IPv6 address as a string. If no + * address is provided, the address that the web service is called + * from will be used. + * + * @throws \GeoIp2\Exception\AddressNotFoundException if the address you + * provided is not in our database (e.g., a private address). + * @throws \GeoIp2\Exception\AuthenticationException if there is a problem + * with the user ID or license key that you provided + * @throws \GeoIp2\Exception\OutOfQueriesException if your account is out + * of queries + * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is + * invalid for some other reason. This may indicate an + * issue with this API. Please report the error to MaxMind. + * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned. + * This could indicate a problem with the connection between + * your server and the web service or that the web service + * returned an invalid document or 500 error code. + * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent + * class to the above exceptions. It will be thrown directly + * if a 200 status code is returned but the body is invalid. + * + * @return \GeoIp2\Model\Insights + */ + public function insights($ipAddress = 'me') + { + return $this->responseFor('insights', 'Insights', $ipAddress); + } + + private function responseFor($endpoint, $class, $ipAddress) + { + $path = implode('/', [self::$basePath, $endpoint, $ipAddress]); + + try { + $body = $this->client->get('GeoIP2 ' . $class, $path); + } catch (\MaxMind\Exception\IpAddressNotFoundException $ex) { + throw new AddressNotFoundException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex + ); + } catch (\MaxMind\Exception\AuthenticationException $ex) { + throw new AuthenticationException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex + ); + } catch (\MaxMind\Exception\InsufficientFundsException $ex) { + throw new OutOfQueriesException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex + ); + } catch (\MaxMind\Exception\InvalidRequestException $ex) { + throw new InvalidRequestException( + $ex->getMessage(), + $ex->getErrorCode(), + $ex->getStatusCode(), + $ex->getUri(), + $ex + ); + } catch (\MaxMind\Exception\HttpException $ex) { + throw new HttpException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex->getUri(), + $ex + ); + } catch (\MaxMind\Exception\WebServiceException $ex) { + throw new GeoIp2Exception( + $ex->getMessage(), + $ex->getCode(), + $ex + ); + } + + $class = 'GeoIp2\\Model\\' . $class; + + return new $class($body, $this->locales); + } +} diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/CHANGELOG.md b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/CHANGELOG.md new file mode 100644 index 00000000..9d320ac5 --- /dev/null +++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/CHANGELOG.md @@ -0,0 +1,108 @@ +CHANGELOG +========= + +1.2.0 (2017-10-27) +------------------ + +* PHP 5.4 is now required. +* The `Reader` class for the `maxminddb` extension is no longer final. + This was change to match the behavior of the pure PHP class. + Reported and fixed by venyii. GitHub #52 & #54. + +1.1.3 (2017-01-19) +------------------ + +* Fix incorrect version in `ext/php_maxminddb.h`. GitHub #48. + +1.1.2 (2016-11-22) +------------------ + +* Searching for database metadata only occurs within the last 128KB + (128 * 1024 bytes) of the file, speeding detection of corrupt + datafiles. Reported by Eric Teubert. GitHub #42. +* Suggest relevant extensions when installing with Composer. GitHub #37. + +1.1.1 (2016-09-15) +------------------ + +* Development files were added to the `.gitattributes` as `export-ignore` so + that they are not part of the Composer release. Pull request by Michele + Locati. GitHub #39. + +1.1.0 (2016-01-04) +------------------ + +* The MaxMind DB extension now supports PHP 7. Pull request by John Boehr. + GitHub #27. + +1.0.3 (2015-03-13) +------------------ + +* All uses of `strlen` were removed. This should prevent issues in situations + where the function is overloaded or otherwise broken. + +1.0.2 (2015-01-19) +------------------ + +* Previously the MaxMind DB extension would cause a segfault if the Reader + object's destructor was called without first having called the constructor. + (Reported by Matthias Saou & Juan Peri. GitHub #20.) + +1.0.1 (2015-01-12) +------------------ + +* In the last several releases, the version number in the extension was + incorrect. This release is being done to correct it. No other code changes + are included. + +1.0.0 (2014-09-22) +------------------ + +* First production release. +* In the pure PHP reader, a string length test after `fread()` was replaced + with the difference between the start pointer and the end pointer. This + provided a 15% speed increase. + +0.3.3 (2014-09-15) +------------------ + +* Clarified behavior of 128-bit type in documentation. +* Updated phpunit and fixed some test breakage from the newer version. + +0.3.2 (2014-09-10) +------------------ + +* Fixed invalid reference to global class RuntimeException from namespaced + code. Fixed by Steven Don. GitHub issue #15. +* Additional documentation of `Metadata` class as well as misc. documentation + cleanup. + +0.3.1 (2014-05-01) +------------------ + +* The API now works when `mbstring.func_overload` is set. +* BCMath is no longer required. If the decoder encounters a big integer, + it will try to use GMP and then BCMath. If both of those fail, it will + throw an exception. No databases released by MaxMind currently use big + integers. +* The API now officially supports HHVM when using the pure PHP reader. + +0.3.0 (2014-02-19) +------------------ + +* This API is now licensed under the Apache License, Version 2.0. +* The code for the C extension was cleaned up, fixing several potential + issues. + +0.2.0 (2013-10-21) +------------------ + +* Added optional C extension for using libmaxminddb in place of the pure PHP + reader. +* Significantly improved error handling in pure PHP reader. +* Improved performance for IPv4 lookups in an IPv6 database. + +0.1.0 (2013-07-16) +------------------ + +* Initial release diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/LICENSE b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/LICENSE new file mode 100644 index 00000000..62589edd --- /dev/null +++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://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/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/README.md b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/README.md new file mode 100644 index 00000000..fb84ed30 --- /dev/null +++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/README.md @@ -0,0 +1,139 @@ +# MaxMind DB Reader PHP API # + +## Description ## + +This is the PHP API for reading MaxMind DB files. MaxMind DB is a binary file +format that stores data indexed by IP address subnets (IPv4 or IPv6). + +## Installation ## + +We recommend installing this package with [Composer](https://getcomposer.org/). + +### Download Composer ### + +To download Composer, run in the root directory of your project: + +```bash +curl -sS https://getcomposer.org/installer | php +``` + +You should now have the file `composer.phar` in your project directory. + +### Install Dependencies ### + +Run in your project root: + +``` +php composer.phar require maxmind-db/reader:~1.0 +``` + +You should now have the files `composer.json` and `composer.lock` as well as +the directory `vendor` in your project directory. If you use a version control +system, `composer.json` should be added to it. + +### Require Autoloader ### + +After installing the dependencies, you need to require the Composer autoloader +from your code: + +```php +require 'vendor/autoload.php'; +``` + +## Usage ## + +## Example ## + +```php +get($ipAddress)); + +$reader->close(); +``` + +## Optional PHP C Extension ## + +MaxMind provides an optional C extension that is a drop-in replacement for +`MaxMind\Db\Reader`. In order to use this extension, you must install the +Reader API as described above and install the extension as described below. If +you are using an autoloader, no changes to your code should be necessary. + +### Installing Extension ### + +First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as +described in its [README.md +file](https://github.com/maxmind/libmaxminddb/blob/master/README.md#installing-from-a-tarball). +After successfully installing libmaxmindb, run the following commands from the +top-level directory of this distribution: + +``` +cd ext +phpize +./configure +make +make test +sudo make install +``` + +You then must load your extension. The recommend method is to add the +following to your `php.ini` file: + +``` +extension=maxminddb.so +``` + +Note: You may need to install the PHP development package on your OS such as +php5-dev for Debian-based systems or php-devel for RedHat/Fedora-based ones. + +## 128-bit Integer Support ## + +The MaxMind DB format includes 128-bit unsigned integer as a type. Although +no MaxMind-distributed database currently makes use of this type, both the +pure PHP reader and the C extension support this type. The pure PHP reader +requires gmp or bcmath to read databases with 128-bit unsigned integers. + +The integer is currently returned as a hexadecimal string (prefixed with "0x") +by the C extension and a decimal string (no prefix) by the pure PHP reader. +Any change to make the reader implementations always return either a +hexadecimal or decimal representation of the integer will NOT be considered a +breaking change. + +## Support ## + +Please report all issues with this code using the [GitHub issue tracker] +(https://github.com/maxmind/MaxMind-DB-Reader-php/issues). + +If you are having an issue with a MaxMind service that is not specific to the +client API, please see [our support page](https://www.maxmind.com/en/support). + +## Requirements ## + +This library requires PHP 5.4 or greater. The pure PHP reader included with +this library works and is tested with HHVM. + +The GMP or BCMath extension may be required to read some databases +using the pure PHP API. + +## Contributing ## + +Patches and pull requests are encouraged. All code should follow the PSR-1 and +PSR-2 style guidelines. Please include unit tests whenever possible. + +## Versioning ## + +The MaxMind DB Reader PHP API uses [Semantic Versioning](https://semver.org/). + +## Copyright and License ## + +This software is Copyright (c) 2014-2017 by MaxMind, Inc. + +This is free software, licensed under the Apache License, Version 2.0. diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/composer.json b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/composer.json new file mode 100644 index 00000000..9d767ee7 --- /dev/null +++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/composer.json @@ -0,0 +1,34 @@ +{ + "name": "maxmind-db/reader", + "description": "MaxMind DB Reader API", + "keywords": ["database", "geoip", "geoip2", "geolocation", "maxmind"], + "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", + "type": "library", + "license": "Apache-2.0", + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "http://www.maxmind.com/" + } + ], + "require": { + "php": ">=5.4" + }, + "suggest": { + "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "2.*", + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "1.0.*", + "squizlabs/php_codesniffer": "3.*" + }, + "autoload": { + "psr-4": { + "MaxMind\\Db\\": "src/MaxMind/Db" + } + } +} diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/ext/config.m4 b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/ext/config.m4 new file mode 100644 index 00000000..a08bb2c4 --- /dev/null +++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/ext/config.m4 @@ -0,0 +1,19 @@ +PHP_ARG_WITH(maxminddb, + [Whether to enable the MaxMind DB Reader extension], + [ --with-maxminddb Enable MaxMind DB Reader extension support]) + +PHP_ARG_ENABLE(maxminddb-debug, for MaxMind DB debug support, + [ --enable-maxminddb-debug Enable enable MaxMind DB deubg support], no, no) + +if test $PHP_MAXMINDDB != "no"; then + PHP_CHECK_LIBRARY(maxminddb, MMDB_open) + + if test $PHP_MAXMINDDB_DEBUG != "no"; then + CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror" + fi + + PHP_ADD_LIBRARY(maxminddb, 1, MAXMINDDB_SHARED_LIBADD) + PHP_SUBST(MAXMINDDB_SHARED_LIBADD) + + PHP_NEW_EXTENSION(maxminddb, maxminddb.c, $ext_shared) +fi diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/ext/maxminddb.c b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/ext/maxminddb.c new file mode 100644 index 00000000..92df16a0 --- /dev/null +++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/ext/maxminddb.c @@ -0,0 +1,564 @@ +/* MaxMind, Inc., licenses this file to you 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. + */ + +#include "php_maxminddb.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#includeaddress in the MaxMind DB.
+ *
+ * @param string $ipAddress
+ * the IP address to look up
+ *
+ * @throws \BadMethodCallException if this method is called on a closed database
+ * @throws \InvalidArgumentException if something other than a single IP address is passed to the method
+ * @throws InvalidDatabaseException
+ * if the database is invalid or there is an error reading
+ * from it
+ *
+ * @return array the record for the IP address
+ */
+ public function get($ipAddress)
+ {
+ if (func_num_args() !== 1) {
+ throw new \InvalidArgumentException(
+ 'Method takes exactly one argument.'
+ );
+ }
+
+ if (!is_resource($this->fileHandle)) {
+ throw new \BadMethodCallException(
+ 'Attempt to read from a closed MaxMind DB.'
+ );
+ }
+
+ if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
+ throw new \InvalidArgumentException(
+ "The value \"$ipAddress\" is not a valid IP address."
+ );
+ }
+
+ if ($this->metadata->ipVersion === 4 && strrpos($ipAddress, ':')) {
+ throw new \InvalidArgumentException(
+ "Error looking up $ipAddress. You attempted to look up an"
+ . ' IPv6 address in an IPv4-only database.'
+ );
+ }
+ $pointer = $this->findAddressInTree($ipAddress);
+ if ($pointer === 0) {
+ return null;
+ }
+
+ return $this->resolveDataPointer($pointer);
+ }
+
+ private function findAddressInTree($ipAddress)
+ {
+ // XXX - could simplify. Done as a byte array to ease porting
+ $rawAddress = array_merge(unpack('C*', inet_pton($ipAddress)));
+
+ $bitCount = count($rawAddress) * 8;
+
+ // The first node of the tree is always node 0, at the beginning of the
+ // value
+ $node = $this->startNode($bitCount);
+
+ for ($i = 0; $i < $bitCount; $i++) {
+ if ($node >= $this->metadata->nodeCount) {
+ break;
+ }
+ $tempBit = 0xFF & $rawAddress[$i >> 3];
+ $bit = 1 & ($tempBit >> 7 - ($i % 8));
+
+ $node = $this->readNode($node, $bit);
+ }
+ if ($node === $this->metadata->nodeCount) {
+ // Record is empty
+ return 0;
+ } elseif ($node > $this->metadata->nodeCount) {
+ // Record is a data pointer
+ return $node;
+ }
+ throw new InvalidDatabaseException('Something bad happened');
+ }
+
+ private function startNode($length)
+ {
+ // Check if we are looking up an IPv4 address in an IPv6 tree. If this
+ // is the case, we can skip over the first 96 nodes.
+ if ($this->metadata->ipVersion === 6 && $length === 32) {
+ return $this->ipV4StartNode();
+ }
+ // The first node of the tree is always node 0, at the beginning of the
+ // value
+ return 0;
+ }
+
+ private function ipV4StartNode()
+ {
+ // This is a defensive check. There is no reason to call this when you
+ // have an IPv4 tree.
+ if ($this->metadata->ipVersion === 4) {
+ return 0;
+ }
+
+ if ($this->ipV4Start) {
+ return $this->ipV4Start;
+ }
+ $node = 0;
+
+ for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; $i++) {
+ $node = $this->readNode($node, 0);
+ }
+ $this->ipV4Start = $node;
+
+ return $node;
+ }
+
+ private function readNode($nodeNumber, $index)
+ {
+ $baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
+
+ // XXX - probably could condense this.
+ switch ($this->metadata->recordSize) {
+ case 24:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
+ list(, $node) = unpack('N', "\x00" . $bytes);
+
+ return $node;
+ case 28:
+ $middleByte = Util::read($this->fileHandle, $baseOffset + 3, 1);
+ list(, $middle) = unpack('C', $middleByte);
+ if ($index === 0) {
+ $middle = (0xF0 & $middle) >> 4;
+ } else {
+ $middle = 0x0F & $middle;
+ }
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 3);
+ list(, $node) = unpack('N', chr($middle) . $bytes);
+
+ return $node;
+ case 32:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
+ list(, $node) = unpack('N', $bytes);
+
+ return $node;
+ default:
+ throw new InvalidDatabaseException(
+ 'Unknown record size: '
+ . $this->metadata->recordSize
+ );
+ }
+ }
+
+ private function resolveDataPointer($pointer)
+ {
+ $resolved = $pointer - $this->metadata->nodeCount
+ + $this->metadata->searchTreeSize;
+ if ($resolved > $this->fileSize) {
+ throw new InvalidDatabaseException(
+ "The MaxMind DB file's search tree is corrupt"
+ );
+ }
+
+ list($data) = $this->decoder->decode($resolved);
+
+ return $data;
+ }
+
+ /*
+ * This is an extremely naive but reasonably readable implementation. There
+ * are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
+ * an issue, but I suspect it won't be.
+ */
+ private function findMetadataStart($filename)
+ {
+ $handle = $this->fileHandle;
+ $fstat = fstat($handle);
+ $fileSize = $fstat['size'];
+ $marker = self::$METADATA_START_MARKER;
+ $markerLength = self::$METADATA_START_MARKER_LENGTH;
+ $metadataMaxLengthExcludingMarker
+ = min(self::$METADATA_MAX_SIZE, $fileSize) - $markerLength;
+
+ for ($i = 0; $i <= $metadataMaxLengthExcludingMarker; $i++) {
+ for ($j = 0; $j < $markerLength; $j++) {
+ fseek($handle, $fileSize - $i - $j - 1);
+ $matchBit = fgetc($handle);
+ if ($matchBit !== $marker[$markerLength - $j - 1]) {
+ continue 2;
+ }
+ }
+
+ return $fileSize - $i;
+ }
+ throw new InvalidDatabaseException(
+ "Error opening database file ($filename). " .
+ 'Is this a valid MaxMind DB file?'
+ );
+ }
+
+ /**
+ * @throws \InvalidArgumentException if arguments are passed to the method
+ * @throws \BadMethodCallException if the database has been closed
+ *
+ * @return Metadata object for the database
+ */
+ public function metadata()
+ {
+ if (func_num_args()) {
+ throw new \InvalidArgumentException(
+ 'Method takes no arguments.'
+ );
+ }
+
+ // Not technically required, but this makes it consistent with
+ // C extension and it allows us to change our implementation later.
+ if (!is_resource($this->fileHandle)) {
+ throw new \BadMethodCallException(
+ 'Attempt to read from a closed MaxMind DB.'
+ );
+ }
+
+ return $this->metadata;
+ }
+
+ /**
+ * Closes the MaxMind DB and returns resources to the system.
+ *
+ * @throws \Exception
+ * if an I/O error occurs
+ */
+ public function close()
+ {
+ if (!is_resource($this->fileHandle)) {
+ throw new \BadMethodCallException(
+ 'Attempt to close a closed MaxMind DB.'
+ );
+ }
+ fclose($this->fileHandle);
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
new file mode 100644
index 00000000..40ae27e0
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
@@ -0,0 +1,311 @@
+ 'extended',
+ 1 => 'pointer',
+ 2 => 'utf8_string',
+ 3 => 'double',
+ 4 => 'bytes',
+ 5 => 'uint16',
+ 6 => 'uint32',
+ 7 => 'map',
+ 8 => 'int32',
+ 9 => 'uint64',
+ 10 => 'uint128',
+ 11 => 'array',
+ 12 => 'container',
+ 13 => 'end_marker',
+ 14 => 'boolean',
+ 15 => 'float',
+ ];
+
+ public function __construct(
+ $fileStream,
+ $pointerBase = 0,
+ $pointerTestHack = false
+ ) {
+ $this->fileStream = $fileStream;
+ $this->pointerBase = $pointerBase;
+ $this->pointerTestHack = $pointerTestHack;
+
+ $this->switchByteOrder = $this->isPlatformLittleEndian();
+ }
+
+ public function decode($offset)
+ {
+ list(, $ctrlByte) = unpack(
+ 'C',
+ Util::read($this->fileStream, $offset, 1)
+ );
+ $offset++;
+
+ $type = $this->types[$ctrlByte >> 5];
+
+ // Pointers are a special case, we don't read the next $size bytes, we
+ // use the size to determine the length of the pointer and then follow
+ // it.
+ if ($type === 'pointer') {
+ list($pointer, $offset) = $this->decodePointer($ctrlByte, $offset);
+
+ // for unit testing
+ if ($this->pointerTestHack) {
+ return [$pointer];
+ }
+
+ list($result) = $this->decode($pointer);
+
+ return [$result, $offset];
+ }
+
+ if ($type === 'extended') {
+ list(, $nextByte) = unpack(
+ 'C',
+ Util::read($this->fileStream, $offset, 1)
+ );
+
+ $typeNum = $nextByte + 7;
+
+ if ($typeNum < 8) {
+ throw new InvalidDatabaseException(
+ 'Something went horribly wrong in the decoder. An extended type '
+ . 'resolved to a type number < 8 ('
+ . $this->types[$typeNum]
+ . ')'
+ );
+ }
+
+ $type = $this->types[$typeNum];
+ $offset++;
+ }
+
+ list($size, $offset) = $this->sizeFromCtrlByte($ctrlByte, $offset);
+
+ return $this->decodeByType($type, $offset, $size);
+ }
+
+ private function decodeByType($type, $offset, $size)
+ {
+ switch ($type) {
+ case 'map':
+ return $this->decodeMap($size, $offset);
+ case 'array':
+ return $this->decodeArray($size, $offset);
+ case 'boolean':
+ return [$this->decodeBoolean($size), $offset];
+ }
+
+ $newOffset = $offset + $size;
+ $bytes = Util::read($this->fileStream, $offset, $size);
+ switch ($type) {
+ case 'utf8_string':
+ return [$this->decodeString($bytes), $newOffset];
+ case 'double':
+ $this->verifySize(8, $size);
+
+ return [$this->decodeDouble($bytes), $newOffset];
+ case 'float':
+ $this->verifySize(4, $size);
+
+ return [$this->decodeFloat($bytes), $newOffset];
+ case 'bytes':
+ return [$bytes, $newOffset];
+ case 'uint16':
+ case 'uint32':
+ return [$this->decodeUint($bytes), $newOffset];
+ case 'int32':
+ return [$this->decodeInt32($bytes), $newOffset];
+ case 'uint64':
+ case 'uint128':
+ return [$this->decodeBigUint($bytes, $size), $newOffset];
+ default:
+ throw new InvalidDatabaseException(
+ 'Unknown or unexpected type: ' . $type
+ );
+ }
+ }
+
+ private function verifySize($expected, $actual)
+ {
+ if ($expected !== $actual) {
+ throw new InvalidDatabaseException(
+ "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
+ );
+ }
+ }
+
+ private function decodeArray($size, $offset)
+ {
+ $array = [];
+
+ for ($i = 0; $i < $size; $i++) {
+ list($value, $offset) = $this->decode($offset);
+ array_push($array, $value);
+ }
+
+ return [$array, $offset];
+ }
+
+ private function decodeBoolean($size)
+ {
+ return $size === 0 ? false : true;
+ }
+
+ private function decodeDouble($bits)
+ {
+ // XXX - Assumes IEEE 754 double on platform
+ list(, $double) = unpack('d', $this->maybeSwitchByteOrder($bits));
+
+ return $double;
+ }
+
+ private function decodeFloat($bits)
+ {
+ // XXX - Assumes IEEE 754 floats on platform
+ list(, $float) = unpack('f', $this->maybeSwitchByteOrder($bits));
+
+ return $float;
+ }
+
+ private function decodeInt32($bytes)
+ {
+ $bytes = $this->zeroPadLeft($bytes, 4);
+ list(, $int) = unpack('l', $this->maybeSwitchByteOrder($bytes));
+
+ return $int;
+ }
+
+ private function decodeMap($size, $offset)
+ {
+ $map = [];
+
+ for ($i = 0; $i < $size; $i++) {
+ list($key, $offset) = $this->decode($offset);
+ list($value, $offset) = $this->decode($offset);
+ $map[$key] = $value;
+ }
+
+ return [$map, $offset];
+ }
+
+ private $pointerValueOffset = [
+ 1 => 0,
+ 2 => 2048,
+ 3 => 526336,
+ 4 => 0,
+ ];
+
+ private function decodePointer($ctrlByte, $offset)
+ {
+ $pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
+
+ $buffer = Util::read($this->fileStream, $offset, $pointerSize);
+ $offset = $offset + $pointerSize;
+
+ $packed = $pointerSize === 4
+ ? $buffer
+ : (pack('C', $ctrlByte & 0x7)) . $buffer;
+
+ $unpacked = $this->decodeUint($packed);
+ $pointer = $unpacked + $this->pointerBase
+ + $this->pointerValueOffset[$pointerSize];
+
+ return [$pointer, $offset];
+ }
+
+ private function decodeUint($bytes)
+ {
+ list(, $int) = unpack('N', $this->zeroPadLeft($bytes, 4));
+
+ return $int;
+ }
+
+ private function decodeBigUint($bytes, $byteLength)
+ {
+ $maxUintBytes = log(PHP_INT_MAX, 2) / 8;
+
+ if ($byteLength === 0) {
+ return 0;
+ }
+
+ $numberOfLongs = ceil($byteLength / 4);
+ $paddedLength = $numberOfLongs * 4;
+ $paddedBytes = $this->zeroPadLeft($bytes, $paddedLength);
+ $unpacked = array_merge(unpack("N$numberOfLongs", $paddedBytes));
+
+ $integer = 0;
+
+ // 2^32
+ $twoTo32 = '4294967296';
+
+ foreach ($unpacked as $part) {
+ // We only use gmp or bcmath if the final value is too big
+ if ($byteLength <= $maxUintBytes) {
+ $integer = ($integer << 32) + $part;
+ } elseif (extension_loaded('gmp')) {
+ $integer = gmp_strval(gmp_add(gmp_mul($integer, $twoTo32), $part));
+ } elseif (extension_loaded('bcmath')) {
+ $integer = bcadd(bcmul($integer, $twoTo32), $part);
+ } else {
+ throw new \RuntimeException(
+ 'The gmp or bcmath extension must be installed to read this database.'
+ );
+ }
+ }
+
+ return $integer;
+ }
+
+ private function decodeString($bytes)
+ {
+ // XXX - NOOP. As far as I know, the end user has to explicitly set the
+ // encoding in PHP. Strings are just bytes.
+ return $bytes;
+ }
+
+ private function sizeFromCtrlByte($ctrlByte, $offset)
+ {
+ $size = $ctrlByte & 0x1f;
+ $bytesToRead = $size < 29 ? 0 : $size - 28;
+ $bytes = Util::read($this->fileStream, $offset, $bytesToRead);
+ $decoded = $this->decodeUint($bytes);
+
+ if ($size === 29) {
+ $size = 29 + $decoded;
+ } elseif ($size === 30) {
+ $size = 285 + $decoded;
+ } elseif ($size > 30) {
+ $size = ($decoded & (0x0FFFFFFF >> (32 - (8 * $bytesToRead))))
+ + 65821;
+ }
+
+ return [$size, $offset + $bytesToRead];
+ }
+
+ private function zeroPadLeft($content, $desiredLength)
+ {
+ return str_pad($content, $desiredLength, "\x00", STR_PAD_LEFT);
+ }
+
+ private function maybeSwitchByteOrder($bytes)
+ {
+ return $this->switchByteOrder ? strrev($bytes) : $bytes;
+ }
+
+ private function isPlatformLittleEndian()
+ {
+ $testint = 0x00FF;
+ $packed = pack('S', $testint);
+
+ return $testint === current(unpack('v', $packed));
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
new file mode 100644
index 00000000..d2a9a775
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
@@ -0,0 +1,10 @@
+binaryFormatMajorVersion =
+ $metadata['binary_format_major_version'];
+ $this->binaryFormatMinorVersion =
+ $metadata['binary_format_minor_version'];
+ $this->buildEpoch = $metadata['build_epoch'];
+ $this->databaseType = $metadata['database_type'];
+ $this->languages = $metadata['languages'];
+ $this->description = $metadata['description'];
+ $this->ipVersion = $metadata['ip_version'];
+ $this->nodeCount = $metadata['node_count'];
+ $this->recordSize = $metadata['record_size'];
+ $this->nodeByteSize = $this->recordSize / 4;
+ $this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
+ }
+
+ public function __get($var)
+ {
+ return $this->$var;
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
new file mode 100644
index 00000000..87ebbf13
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
@@ -0,0 +1,26 @@
+=5.4",
+ "composer/ca-bundle": "^1.0.3",
+ "ext-curl": "*",
+ "ext-json": "*"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "2.*",
+ "phpunit/phpunit": "4.*",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Exception\\": "src/Exception",
+ "MaxMind\\WebService\\": "src/WebService"
+ }
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/AuthenticationException.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/AuthenticationException.php
new file mode 100644
index 00000000..ba423627
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/AuthenticationException.php
@@ -0,0 +1,10 @@
+uri = $uri;
+ parent::__construct($message, $httpStatus, $previous);
+ }
+
+ public function getUri()
+ {
+ return $this->uri;
+ }
+
+ public function getStatusCode()
+ {
+ return $this->getCode();
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/InsufficientFundsException.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/InsufficientFundsException.php
new file mode 100644
index 00000000..fe159a2a
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/InsufficientFundsException.php
@@ -0,0 +1,10 @@
+error = $error;
+ parent::__construct($message, $httpStatus, $uri, $previous);
+ }
+
+ public function getErrorCode()
+ {
+ return $this->error;
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php
new file mode 100644
index 00000000..31608f71
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php
@@ -0,0 +1,7 @@
+userId = $userId;
+ $this->licenseKey = $licenseKey;
+
+ $this->httpRequestFactory = isset($options['httpRequestFactory'])
+ ? $options['httpRequestFactory']
+ : new RequestFactory();
+
+ if (isset($options['host'])) {
+ $this->host = $options['host'];
+ }
+ if (isset($options['userAgent'])) {
+ $this->userAgentPrefix = $options['userAgent'] . ' ';
+ }
+
+ $this->caBundle = isset($options['caBundle']) ?
+ $this->caBundle = $options['caBundle'] : $this->getCaBundle();
+
+ if (isset($options['connectTimeout'])) {
+ $this->connectTimeout = $options['connectTimeout'];
+ }
+ if (isset($options['timeout'])) {
+ $this->timeout = $options['timeout'];
+ }
+
+ if (isset($options['proxy'])) {
+ $this->proxy = $options['proxy'];
+ }
+ }
+
+ /**
+ * @param string $service name of the service querying
+ * @param string $path the URI path to use
+ * @param array $input the data to be posted as JSON
+ *
+ * @throws InvalidInputException when the request has missing or invalid
+ * data
+ * @throws AuthenticationException when there is an issue authenticating the
+ * request
+ * @throws InsufficientFundsException when your account is out of funds
+ * @throws InvalidRequestException when the request is invalid for some
+ * other reason, e.g., invalid JSON in the POST.
+ * @throws HttpException when an unexpected HTTP error occurs
+ * @throws WebServiceException when some other error occurs. This also
+ * serves as the base class for the above exceptions.
+ *
+ * @return array The decoded content of a successful response
+ */
+ public function post($service, $path, $input)
+ {
+ $body = json_encode($input);
+ if ($body === false) {
+ throw new InvalidInputException(
+ 'Error encoding input as JSON: '
+ . $this->jsonErrorDescription()
+ );
+ }
+
+ $request = $this->createRequest(
+ $path,
+ ['Content-Type: application/json']
+ );
+
+ list($statusCode, $contentType, $body) = $request->post($body);
+
+ return $this->handleResponse(
+ $statusCode,
+ $contentType,
+ $body,
+ $service,
+ $path
+ );
+ }
+
+ public function get($service, $path)
+ {
+ $request = $this->createRequest($path);
+
+ list($statusCode, $contentType, $body) = $request->get();
+
+ return $this->handleResponse(
+ $statusCode,
+ $contentType,
+ $body,
+ $service,
+ $path
+ );
+ }
+
+ private function userAgent()
+ {
+ $curlVersion = curl_version();
+
+ return $this->userAgentPrefix . 'MaxMind-WS-API/' . self::VERSION . ' PHP/' . PHP_VERSION .
+ ' curl/' . $curlVersion['version'];
+ }
+
+ private function createRequest($path, $headers = [])
+ {
+ array_push(
+ $headers,
+ 'Authorization: Basic '
+ . base64_encode($this->userId . ':' . $this->licenseKey),
+ 'Accept: application/json'
+ );
+
+ return $this->httpRequestFactory->request(
+ $this->urlFor($path),
+ [
+ 'caBundle' => $this->caBundle,
+ 'connectTimeout' => $this->connectTimeout,
+ 'headers' => $headers,
+ 'proxy' => $this->proxy,
+ 'timeout' => $this->timeout,
+ 'userAgent' => $this->userAgent(),
+ ]
+ );
+ }
+
+ /**
+ * @param int $statusCode the HTTP status code of the response
+ * @param string $contentType the Content-Type of the response
+ * @param string $body the response body
+ * @param string $service the name of the service
+ * @param string $path the path used in the request
+ *
+ * @throws AuthenticationException when there is an issue authenticating the
+ * request
+ * @throws InsufficientFundsException when your account is out of funds
+ * @throws InvalidRequestException when the request is invalid for some
+ * other reason, e.g., invalid JSON in the POST.
+ * @throws HttpException when an unexpected HTTP error occurs
+ * @throws WebServiceException when some other error occurs. This also
+ * serves as the base class for the above exceptions
+ *
+ * @return array The decoded content of a successful response
+ */
+ private function handleResponse(
+ $statusCode,
+ $contentType,
+ $body,
+ $service,
+ $path
+ ) {
+ if ($statusCode >= 400 && $statusCode <= 499) {
+ $this->handle4xx($statusCode, $contentType, $body, $service, $path);
+ } elseif ($statusCode >= 500) {
+ $this->handle5xx($statusCode, $service, $path);
+ } elseif ($statusCode !== 200) {
+ $this->handleUnexpectedStatus($statusCode, $service, $path);
+ }
+
+ return $this->handleSuccess($body, $service);
+ }
+
+ /**
+ * @return string describing the JSON error
+ */
+ private function jsonErrorDescription()
+ {
+ $errno = json_last_error();
+ switch ($errno) {
+ case JSON_ERROR_DEPTH:
+ return 'The maximum stack depth has been exceeded.';
+ case JSON_ERROR_STATE_MISMATCH:
+ return 'Invalid or malformed JSON.';
+ case JSON_ERROR_CTRL_CHAR:
+ return 'Control character error.';
+ case JSON_ERROR_SYNTAX:
+ return 'Syntax error.';
+ case JSON_ERROR_UTF8:
+ return 'Malformed UTF-8 characters.';
+ default:
+ return "Other JSON error ($errno).";
+ }
+ }
+
+ /**
+ * @param string $path the path to use in the URL
+ *
+ * @return string the constructed URL
+ */
+ private function urlFor($path)
+ {
+ return 'https://' . $this->host . $path;
+ }
+
+ /**
+ * @param int $statusCode the HTTP status code
+ * @param string $contentType the response content-type
+ * @param string $body the response body
+ * @param string $service the service name
+ * @param string $path the path used in the request
+ *
+ * @throws AuthenticationException
+ * @throws HttpException
+ * @throws InsufficientFundsException
+ * @throws InvalidRequestException
+ */
+ private function handle4xx(
+ $statusCode,
+ $contentType,
+ $body,
+ $service,
+ $path
+ ) {
+ if (strlen($body) === 0) {
+ throw new HttpException(
+ "Received a $statusCode error for $service with no body",
+ $statusCode,
+ $this->urlFor($path)
+ );
+ }
+ if (!strstr($contentType, 'json')) {
+ throw new HttpException(
+ "Received a $statusCode error for $service with " .
+ 'the following body: ' . $body,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ }
+
+ $message = json_decode($body, true);
+ if ($message === null) {
+ throw new HttpException(
+ "Received a $statusCode error for $service but could " .
+ 'not decode the response as JSON: '
+ . $this->jsonErrorDescription() . ' Body: ' . $body,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ }
+
+ if (!isset($message['code']) || !isset($message['error'])) {
+ throw new HttpException(
+ 'Error response contains JSON but it does not ' .
+ 'specify code or error keys: ' . $body,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ }
+
+ $this->handleWebServiceError(
+ $message['error'],
+ $message['code'],
+ $statusCode,
+ $path
+ );
+ }
+
+ /**
+ * @param string $message the error message from the web service
+ * @param string $code the error code from the web service
+ * @param int $statusCode the HTTP status code
+ * @param string $path the path used in the request
+ *
+ * @throws AuthenticationException
+ * @throws InvalidRequestException
+ * @throws InsufficientFundsException
+ */
+ private function handleWebServiceError(
+ $message,
+ $code,
+ $statusCode,
+ $path
+ ) {
+ switch ($code) {
+ case 'IP_ADDRESS_NOT_FOUND':
+ case 'IP_ADDRESS_RESERVED':
+ throw new IpAddressNotFoundException(
+ $message,
+ $code,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ case 'AUTHORIZATION_INVALID':
+ case 'LICENSE_KEY_REQUIRED':
+ case 'USER_ID_REQUIRED':
+ case 'USER_ID_UNKNOWN':
+ throw new AuthenticationException(
+ $message,
+ $code,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ case 'OUT_OF_QUERIES':
+ case 'INSUFFICIENT_FUNDS':
+ throw new InsufficientFundsException(
+ $message,
+ $code,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ case 'PERMISSION_REQUIRED':
+ throw new PermissionRequiredException(
+ $message,
+ $code,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ default:
+ throw new InvalidRequestException(
+ $message,
+ $code,
+ $statusCode,
+ $this->urlFor($path)
+ );
+ }
+ }
+
+ /**
+ * @param int $statusCode the HTTP status code
+ * @param string $service the service name
+ * @param string $path the URI path used in the request
+ *
+ * @throws HttpException
+ */
+ private function handle5xx($statusCode, $service, $path)
+ {
+ throw new HttpException(
+ "Received a server error ($statusCode) for $service",
+ $statusCode,
+ $this->urlFor($path)
+ );
+ }
+
+ /**
+ * @param int $statusCode the HTTP status code
+ * @param string $service the service name
+ * @param string $path the URI path used in the request
+ *
+ * @throws HttpException
+ */
+ private function handleUnexpectedStatus($statusCode, $service, $path)
+ {
+ throw new HttpException(
+ 'Received an unexpected HTTP status ' .
+ "($statusCode) for $service",
+ $statusCode,
+ $this->urlFor($path)
+ );
+ }
+
+ /**
+ * @param string $body the successful request body
+ * @param string $service the service name
+ *
+ * @throws WebServiceException if the request body cannot be decoded as
+ * JSON
+ *
+ * @return array the decoded request body
+ */
+ private function handleSuccess($body, $service)
+ {
+ if (strlen($body) === 0) {
+ throw new WebServiceException(
+ "Received a 200 response for $service but did not " .
+ 'receive a HTTP body.'
+ );
+ }
+
+ $decodedContent = json_decode($body, true);
+ if ($decodedContent === null) {
+ throw new WebServiceException(
+ "Received a 200 response for $service but could " .
+ 'not decode the response as JSON: '
+ . $this->jsonErrorDescription() . ' Body: ' . $body
+ );
+ }
+
+ return $decodedContent;
+ }
+
+ private function getCaBundle()
+ {
+ $curlVersion = curl_version();
+
+ // On OS X, when the SSL version is "SecureTransport", the system's
+ // keychain will be used.
+ if ($curlVersion['ssl_version'] === 'SecureTransport') {
+ return;
+ }
+ $cert = CaBundle::getSystemCaRootBundlePath();
+
+ // Check if the cert is inside a phar. If so, we need to copy the cert
+ // to a temp file so that curl can see it.
+ if (substr($cert, 0, 7) === 'phar://') {
+ $tempDir = sys_get_temp_dir();
+ $newCert = tempnam($tempDir, 'geoip2-');
+ if ($newCert === false) {
+ throw new \RuntimeException(
+ "Unable to create temporary file in $tempDir"
+ );
+ }
+ if (!copy($cert, $newCert)) {
+ throw new \RuntimeException(
+ "Could not copy $cert to $newCert: "
+ . var_export(error_get_last(), true)
+ );
+ }
+
+ // We use a shutdown function rather than the destructor as the
+ // destructor isn't called on a fatal error such as an uncaught
+ // exception.
+ register_shutdown_function(
+ function () use ($newCert) {
+ unlink($newCert);
+ }
+ );
+ $cert = $newCert;
+ }
+ if (!file_exists($cert)) {
+ throw new \RuntimeException("CA cert does not exist at $cert");
+ }
+
+ return $cert;
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php
new file mode 100644
index 00000000..e44e408a
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php
@@ -0,0 +1,110 @@
+url = $url;
+ $this->options = $options;
+ }
+
+ /**
+ * @param $body
+ *
+ * @return array
+ */
+ public function post($body)
+ {
+ $curl = $this->createCurl();
+
+ curl_setopt($curl, CURLOPT_POST, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
+
+ return $this->execute($curl);
+ }
+
+ public function get()
+ {
+ $curl = $this->createCurl();
+
+ curl_setopt($curl, CURLOPT_HTTPGET, true);
+
+ return $this->execute($curl);
+ }
+
+ /**
+ * @return resource
+ */
+ private function createCurl()
+ {
+ $curl = curl_init($this->url);
+
+ if (!empty($this->options['caBundle'])) {
+ $opts[CURLOPT_CAINFO] = $this->options['caBundle'];
+ }
+ $opts[CURLOPT_SSL_VERIFYHOST] = 2;
+ $opts[CURLOPT_FOLLOWLOCATION] = false;
+ $opts[CURLOPT_SSL_VERIFYPEER] = true;
+ $opts[CURLOPT_RETURNTRANSFER] = true;
+
+ $opts[CURLOPT_HTTPHEADER] = $this->options['headers'];
+ $opts[CURLOPT_USERAGENT] = $this->options['userAgent'];
+ $opts[CURLOPT_PROXY] = $this->options['proxy'];
+
+ // The defined()s are here as the *_MS opts are not available on older
+ // cURL versions
+ $connectTimeout = $this->options['connectTimeout'];
+ if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
+ $opts[CURLOPT_CONNECTTIMEOUT_MS] = ceil($connectTimeout * 1000);
+ } else {
+ $opts[CURLOPT_CONNECTTIMEOUT] = ceil($connectTimeout);
+ }
+
+ $timeout = $this->options['timeout'];
+ if (defined('CURLOPT_TIMEOUT_MS')) {
+ $opts[CURLOPT_TIMEOUT_MS] = ceil($timeout * 1000);
+ } else {
+ $opts[CURLOPT_TIMEOUT] = ceil($timeout);
+ }
+
+ curl_setopt_array($curl, $opts);
+
+ return $curl;
+ }
+
+ private function execute($curl)
+ {
+ $body = curl_exec($curl);
+ if ($errno = curl_errno($curl)) {
+ $errorMessage = curl_error($curl);
+
+ throw new HttpException(
+ "cURL error ({$errno}): {$errorMessage}",
+ 0,
+ $this->url
+ );
+ }
+
+ $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ $contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
+ curl_close($curl);
+
+ return [$statusCode, $contentType, $body];
+ }
+}
diff --git a/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/WebService/Http/Request.php b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/WebService/Http/Request.php
new file mode 100644
index 00000000..27bdd58e
--- /dev/null
+++ b/wp/wp-content/ip-geo-api/maxmind/vendor/maxmind/web-service-common/src/WebService/Http/Request.php
@@ -0,0 +1,29 @@
+ 'form',
+ ) );
+
+ return (bool) apply_filters( 'wpcf7_autop_or_not', WPCF7_AUTOP, $options );
}
diff --git a/wp/wp-content/plugins/contact-form-7/includes/mail.php b/wp/wp-content/plugins/contact-form-7/includes/mail.php
index 70cfc2fb..4d68fc95 100644
--- a/wp/wp-content/plugins/contact-form-7/includes/mail.php
+++ b/wp/wp-content/plugins/contact-form-7/includes/mail.php
@@ -6,7 +6,7 @@ add_filter( 'wpcf7_mail_html_body', 'wpcf7_mail_html_body_autop', 10, 1 );
* Filter callback that applies auto-p to HTML email message body.
*/
function wpcf7_mail_html_body_autop( $body ) {
- if ( wpcf7_autop_or_not() ) {
+ if ( wpcf7_autop_or_not( array( 'for' => 'mail' ) ) ) {
$body = wpcf7_autop( $body );
}
diff --git a/wp/wp-content/plugins/contact-form-7/includes/submission.php b/wp/wp-content/plugins/contact-form-7/includes/submission.php
index 9036b703..39d89645 100644
--- a/wp/wp-content/plugins/contact-form-7/includes/submission.php
+++ b/wp/wp-content/plugins/contact-form-7/includes/submission.php
@@ -68,6 +68,14 @@ class WPCF7_Submission {
}
+ /**
+ * Destructor.
+ */
+ public function __destruct() {
+ $this->remove_uploaded_files();
+ }
+
+
/**
* The main logic of submission.
*/
@@ -124,8 +132,6 @@ class WPCF7_Submission {
do_action( 'wpcf7_mail_failed', $contact_form );
}
}
-
- $this->remove_uploaded_files();
};
wpcf7_switch_locale( $this->contact_form->locale(), $callback );
diff --git a/wp/wp-content/plugins/contact-form-7/license.txt b/wp/wp-content/plugins/contact-form-7/license.txt
index 7ded71ac..daf093c5 100644
--- a/wp/wp-content/plugins/contact-form-7/license.txt
+++ b/wp/wp-content/plugins/contact-form-7/license.txt
@@ -1,4 +1,4 @@
-Contact Form 7 WordPress Plugin, 2007-2023 Takayuki Miyoshi
+Contact Form 7 WordPress Plugin, 2007-2024 Takayuki Miyoshi
Contact Form 7 is distributed under the terms of the GNU GPL
This program is free software; you can redistribute it and/or modify
diff --git a/wp/wp-content/plugins/contact-form-7/modules/sendinblue/contact-form-properties.php b/wp/wp-content/plugins/contact-form-7/modules/sendinblue/contact-form-properties.php
index 668456ff..2926659d 100644
--- a/wp/wp-content/plugins/contact-form-7/modules/sendinblue/contact-form-properties.php
+++ b/wp/wp-content/plugins/contact-form-7/modules/sendinblue/contact-form-properties.php
@@ -102,7 +102,7 @@ function wpcf7_sendinblue_editor_panels( $panels ) {
)
);
- $lists = $service->get_lists();
+ $lists = wpcf7_sendinblue_get_lists();
$templates = $service->get_templates();
?>
@@ -301,3 +301,39 @@ function wpcf7_sendinblue_editor_panels( $panels ) {
return $panels;
}
+
+
+/**
+ * Retrieves contact lists from Brevo's database.
+ */
+function wpcf7_sendinblue_get_lists() {
+ static $lists = array();
+
+ $service = WPCF7_Sendinblue::get_instance();
+
+ if ( ! empty( $lists ) or ! $service->is_active() ) {
+ return $lists;
+ }
+
+ $limit = 50;
+ $offset = 0;
+
+ while ( count( $lists ) < $limit * 10 ) {
+ $lists_next = (array) $service->get_lists( array(
+ 'limit' => $limit,
+ 'offset' => $offset,
+ ) );
+
+ if ( ! empty( $lists_next ) ) {
+ $lists = array_merge( $lists, $lists_next );
+ }
+
+ if ( count( $lists_next ) < $limit ) {
+ break;
+ }
+
+ $offset += $limit;
+ }
+
+ return $lists;
+}
diff --git a/wp/wp-content/plugins/contact-form-7/modules/sendinblue/service.php b/wp/wp-content/plugins/contact-form-7/modules/sendinblue/service.php
index 305287cc..752dc1e7 100644
--- a/wp/wp-content/plugins/contact-form-7/modules/sendinblue/service.php
+++ b/wp/wp-content/plugins/contact-form-7/modules/sendinblue/service.php
@@ -252,12 +252,14 @@ trait WPCF7_Sendinblue_API {
}
- public function get_lists() {
+ public function get_lists( $options = '' ) {
+ $options = wp_parse_args( $options, array(
+ 'limit' => 50,
+ 'offset' => 0,
+ ) );
+
$endpoint = add_query_arg(
- array(
- 'limit' => 50,
- 'offset' => 0,
- ),
+ $options,
'https://api.sendinblue.com/v3/contacts/lists'
);
diff --git a/wp/wp-content/plugins/contact-form-7/readme.txt b/wp/wp-content/plugins/contact-form-7/readme.txt
index e8190e81..ea80793d 100644
--- a/wp/wp-content/plugins/contact-form-7/readme.txt
+++ b/wp/wp-content/plugins/contact-form-7/readme.txt
@@ -5,7 +5,7 @@ Tags: contact, form, contact form, feedback, email, ajax, captcha, akismet, mult
Requires at least: 6.2
Requires PHP: 7.4
Tested up to: 6.4
-Stable tag: 5.8.5
+Stable tag: 5.8.6
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -78,6 +78,10 @@ Do you have questions or issues with Contact Form 7? Use these support channels
For more information, see [Releases](https://contactform7.com/category/releases/).
+= 5.8.6 =
+
+[https://contactform7.com/contact-form-7-586/](https://contactform7.com/contact-form-7-586/)
+
= 5.8.5 =
[https://contactform7.com/contact-form-7-585/](https://contactform7.com/contact-form-7-585/)
diff --git a/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php b/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php
index ff60a500..1f85730b 100644
--- a/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php
+++ b/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php
@@ -7,12 +7,12 @@
* Author URI: https://ideasilo.wordpress.com/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
- * Version: 5.8.5
+ * Version: 5.8.6
* Requires at least: 6.2
* Requires PHP: 7.4
*/
-define( 'WPCF7_VERSION', '5.8.5' );
+define( 'WPCF7_VERSION', '5.8.6' );
define( 'WPCF7_REQUIRED_WP_VERSION', '6.2' );
diff --git a/wp/wp-content/plugins/ip-geo-block/LICENSE.txt b/wp/wp-content/plugins/ip-geo-block/LICENSE.txt
new file mode 100644
index 00000000..f288702d
--- /dev/null
+++ b/wp/wp-content/plugins/ip-geo-block/LICENSE.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. '; + if ( 'updated' === $type ) + echo '', IP_Geo_Block_Util::kses( $msg ), ''; + else + echo 'IP Geo Block: ', IP_Geo_Block_Util::kses( $msg ); + echo '
%s. It seems to have failed downloading ZIP file from WordPress-IP-Geo-API. Try to deactivate IP Geo Block once and activate it again, or install ip-geo-api with write permission according to this instruction.', 'ip-geo-block' ),
+ apply_filters( 'ip-geo-block-api-dir', $settings['api_dir'] ? $settings['api_dir'] : basename( WP_CONTENT_DIR ) )
+ ) );
+ }
+
+ else {
+ $providers = IP_Geo_Block_Provider::get_valid_providers( $settings, FALSE, FALSE, TRUE );
+ if ( empty( $providers ) ) {
+ $this->add_admin_notice( 'error', sprintf(
+ __( 'You should select at least one API at Geolocation API settings. Otherwise you\'ll be blocked after the cache expires.', 'ip-geo-block' ),
+ esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0, 'sec' => 4 ), $network ) ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-4'
+ ) );
+ }
+
+ else {
+ $providers = IP_Geo_Block_Provider::get_addons( $settings['providers'] );
+ if ( empty( $providers ) ) {
+ $this->add_admin_notice( 'error', sprintf(
+ __( 'You should select at least one API for local database at Geolocation API settings. Otherwise access to the external API may slow down the site.', 'ip-geo-block' ),
+ esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0, 'sec' => 4 ), $network ) ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-4'
+ ) );
+ }
+ }
+ }
+
+ // Check consistency of matching rule
+ if ( -1 === (int)$settings['matching_rule'] ) {
+ if ( FALSE !== $updating ) {
+ self::add_admin_notice( 'notice-warning', sprintf(
+ __( 'Now downloading geolocation databases in background. After a little while, please check your country code and “Matching rule” at Validation rules and behavior.', 'ip-geo-block' ),
+ esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME ), $network ) )
+ ) );
+ }
+ else {
+ self::add_admin_notice( 'error', sprintf(
+ __( 'The “Matching rule” is not set properly. Please confirm it at Validation rules and behavior.', 'ip-geo-block' ),
+ esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME ), $network ) )
+ ) );
+ }
+ }
+
+ // Check to finish updating matching rule
+ elseif ( 'done' === $updating ) {
+ delete_transient( IP_Geo_Block::CRON_NAME );
+ self::add_admin_notice( 'updated ', __( 'Local database and matching rule have been updated.', 'ip-geo-block' ) );
+ }
+
+ // Check self blocking (skip during updating)
+ if ( FALSE === $updating && 1 === (int)$settings['validation']['login'] ) {
+ $instance = IP_Geo_Block::get_instance();
+ $validate = $instance->validate_ip( 'login', $settings, TRUE, FALSE ); // skip authentication check
+
+ switch( $validate['result'] ) {
+ case 'limited':
+ self::add_admin_notice( 'error',
+ __( 'Once you logout, you will be unable to login again because the number of login attempts reaches the limit.', 'ip-geo-block' ) . ' ' .
+ sprintf(
+ __( 'Please remove your IP address in “%1$sStatistics in IP address cache%2$s” on “%3$sStatistics%4$s” tab to prevent locking yourself out.', 'ip-geo-block' ),
+ '', '',
+ '', ''
+ )
+ );
+ break;
+
+ case 'blocked':
+ case 'extra':
+ self::add_admin_notice( 'error',
+ ( $settings['matching_rule'] ?
+ __( 'Once you logout, you will be unable to login again because your country code or IP address is in the blacklist.', 'ip-geo-block' ) :
+ __( 'Once you logout, you will be unable to login again because your country code or IP address is not in the whitelist.', 'ip-geo-block' )
+ ) . ' ' .
+ ( 'ZZ' !== $validate['code'] ?
+ sprintf(
+ __( 'Please check your “%sValidation rules and behavior%s”.', 'ip-geo-block' ),
+ '', ''
+ ) :
+ sprintf(
+ __( 'Please confirm your local geolocation database files exist at “%sLocal database settings%s” section, or remove your IP address in cache at “%sStatistics in cache%s” section.', 'ip-geo-block' ),
+ '', '',
+ '', ''
+ )
+ )
+ );
+ break;
+ }
+ }
+
+ // Check consistency of emergency login link
+ if ( isset( $settings['login_link'] ) && $settings['login_link']['link'] && ! IP_Geo_Block_Util::verify_link( $settings['login_link']['link'], $settings['login_link']['hash'] ) ) {
+ self::add_admin_notice( 'error',
+ sprintf(
+ __( 'Emergency login link is outdated. Please delete it once and generate again at “%sPlugin settings%s” section. Also do not forget to update favorites / bookmarks in your browser.', 'ip-geo-block' ),
+ '', ''
+ )
+ );
+ }
+
+ // Check activation of IP Geo Allow
+ if ( $settings['validation']['timing'] && is_plugin_active( 'ip-geo-allow/index.php' ) ) {
+ self::add_admin_notice( 'error',
+ __( '“mu-plugins” (ip-geo-block-mu.php) at “Validation timing” is imcompatible with IP Geo Allow. Please select “init” action hook.', 'ip-geo-block' )
+ );
+ }
+ }
+
+ /**
+ * Setup menu and option page for this plugin
+ *
+ */
+ public function setup_admin_page() {
+ $settings = IP_Geo_Block::get_option();
+
+ // Register the administration menu.
+ $this->add_plugin_admin_menu( $settings );
+
+ // Avoid multiple validation.
+ if ( 'GET' === $_SERVER['REQUEST_METHOD'] )
+ $this->diagnose_admin_screen( $settings );
+
+ // Register settings page only if it is needed.
+ if ( ( isset( $_GET ['page' ] ) && IP_Geo_Block::PLUGIN_NAME === $_GET ['page' ] ) ||
+ ( isset( $_POST['option_page'] ) && IP_Geo_Block::PLUGIN_NAME === $_POST['option_page'] ) ) {
+ $this->register_settings_tab();
+ }
+
+ // Add an action link pointing to the options page. @since 2.7
+ else {
+ add_filter( 'plugin_row_meta', array( $this, 'add_plugin_meta_links' ), 10, 2 );
+ add_filter( 'plugin_action_links_' . IP_GEO_BLOCK_BASE, array( $this, 'add_action_links' ), 10, 1 );
+ }
+
+ // Register scripts for admin.
+ add_action( 'admin_enqueue_scripts', array( 'IP_Geo_Block', 'enqueue_nonce' ), 0 );
+
+ // Show admin notices at the place where it should be. @since 2.5.0
+ add_action( 'admin_notices', array( $this, 'show_admin_notices' ) );
+ add_action( 'network_admin_notices', array( $this, 'show_admin_notices' ) );
+ }
+
+ /**
+ * Get cookie that indicates open/close section
+ *
+ */
+ public function get_cookie() {
+ static $cookie = array();
+
+ if ( empty( $cookie ) && ! empty( $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) ) {
+ foreach ( explode( '&', $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) as $i => $v ) {
+ list( $i, $v ) = explode( '=', $v );
+ $cookie[ $i ] = str_split( $v );
+ }
+ }
+
+ return $cookie;
+ }
+
+ /**
+ * Prints out all settings sections added to a particular settings page
+ *
+ * wp-admin/includes/template.php @since 2.7.0
+ */
+ private function do_settings_sections( $page, $tab ) {
+ global $wp_settings_sections, $wp_settings_fields;
+
+ // target section to be opened
+ $target = isset( $_GET['sec'] ) ? (int)$_GET['sec'] : -1;
+
+ if ( isset( $wp_settings_sections[ $page ] ) ) {
+ $index = 0; // index of fieldset
+ $cookie = $this->get_cookie();
+
+ foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
+ // TRUE if open ('o') or FALSE if close ('x')
+ $stat = empty( $cookie[ $tab ][ $index ] ) || 'x' !== $cookie[ $tab ][ $index ] || $index === $target;
+
+ echo "\n", '\n";
+ ++$index;
+ }
+ }
+ }
+
+ /**
+ * Render the settings page for this plugin.
+ *
+ */
+ public function display_plugin_admin_page() {
+ $tab = $this->admin_tab;
+ $tabs = array(
+ 5 => __( 'Sites list', 'ip-geo-block' ),
+ 0 => __( 'Settings', 'ip-geo-block' ),
+ 1 => __( 'Statistics', 'ip-geo-block' ),
+ 4 => __( 'Logs', 'ip-geo-block' ),
+ 2 => __( 'Search', 'ip-geo-block' ),
+ 3 => __( 'Attribution', 'ip-geo-block' ),
+ );
+
+ $settings = IP_Geo_Block::get_option();
+ $cookie = $this->get_cookie();
+ $title = esc_html( get_admin_page_title() );
+
+ // Target page that depends on the network multisite or not.
+ if ( 'options-general.php' === $GLOBALS['pagenow'] ) {
+ $action = 'options.php';
+ unset( $tabs[5] ); // Sites list
+ if ( $this->is_network_admin ) {
+ $title .= ' ';
+ }
+ }
+
+ // '/wp-admin/network/admin.php'
+ else {
+ // `edit.php` is an action handler for Multisite administration dashboard.
+ // `edit.php` ==> do action `network_admin_edit_ip-geo-block` ==> `validate_network_settings()`
+ $action = 'edit.php?action=' . IP_Geo_Block::PLUGIN_NAME;
+ if ( $this->is_network_admin ) {
+ unset( $tabs[1], $tabs[4], $tabs[2], $tabs[3] ); // Statistics, Logs, Search, Attribution
+ $title .= ' ';
+ }
+ }
+
+?>
+', implode( '
', $tab ), "
', __( 'Thanks for providing these great services for free.', 'ip-geo-block' ), "
\n";
+ echo __( '(Most browsers will redirect you to each site without referrer when you click the link.)', 'ip-geo-block' ), "
', $desc, "
\n"; + + if ( 'select' === $args['type'] ) + break; + + echo "%s. Please check the permission.', 'ip-geo-block' ), '' . $file . ''
+ ) );
+ }
+
+ // Force to finish update matching rule
+ delete_transient( IP_Geo_Block::CRON_NAME );
+
+ // start to update databases immediately
+ do_action( IP_Geo_Block::PLUGIN_NAME . '-settings-updated', $options, TRUE );
+
+ return $options;
+ }
+
+ /**
+ * Validate settings and configure some features for network multisite.
+ *
+ * @see https://vedovini.net/2015/10/using-the-wordpress-settings-api-with-network-admin-pages/
+ */
+ public function validate_network_settings() {
+ // Must check that the user has the required capability
+ $this->check_admin_post( FALSE );
+
+ // The list of registered options (IP_Geo_Block::OPTION_NAME).
+ global $new_whitelist_options;
+ $options = $new_whitelist_options[ IP_Geo_Block::PLUGIN_NAME ];
+
+ // Go through the posted data and save the targetted options.
+ foreach ( $options as $option ) {
+ if ( isset( $_POST[ $option ] ) ) {
+ $this->update_multisite_settings( $_POST[ $option ] );
+ }
+ }
+
+ // Register a settings error to be displayed to the user
+ self::add_admin_notice( 'updated', __( 'Settings saved.' ) );
+
+ // Redirect in order to back to the settings page.
+ wp_redirect( esc_url_raw(
+ add_query_arg(
+ array( 'page' => IP_Geo_Block::PLUGIN_NAME ),
+ $this->dashboard_url( ! empty( $_POST[ $option ]['network_wide'] ) )
+ )
+ ) );
+
+ exit;
+ }
+
+ /**
+ * Update option in all blogs.
+ *
+ * @note: This function triggers `validate_settings()` on register_setting() in wp-include/option.php.
+ */
+ public function update_multisite_settings( $settings ) {
+ global $wpdb;
+ $blog_ids = $wpdb->get_col( "SELECT `blog_id` FROM `$wpdb->blogs`" );
+ $ret = TRUE;
+
+ foreach ( $blog_ids as $id ) {
+ switch_to_blog( $id );
+ $map = IP_Geo_Block::get_option( FALSE );
+ $settings['api_key']['GoogleMap'] = $map['api_key']['GoogleMap'];
+ $ret &= IP_Geo_Block::update_option( $settings, FALSE );
+ restore_current_blog();
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Analyze entries in "Validation logs"
+ *
+ * @param array $logs An array including each entry where:
+ * Array (
+ * [0 DB row number] => 154
+ * [1 Target ] => comment
+ * [2 Time ] => 1534580897
+ * [3 IP address ] => 102.177.147.***
+ * [4 Country code ] => ZA
+ * [5 Result ] => blocked
+ * [6 AS number ] => AS328239
+ * [7 Request ] => POST[80]:/wp-comments-post.php
+ * [8 User agent ] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) ...
+ * [9 HTTP headers ] => HTTP_ORIGIN=http://localhost,HTTP_X_FORWARDED_FOR=102.177.147.***
+ * [10 $_POST data ] => comment=Hello.,author,email,url,comment_post_ID,comment_parent
+ * )
+ * And put a mark at "Target"
+ * ¹¹: Passed in Whitelist
+ * ¹²: Passed in Blacklist
+ * ¹³: Passed not in list
+ * ²¹: Blocked in Whitelist
+ * ²²: Blocked in Blacklist
+ * ²³: Blocked not in list
+ */
+ public function filter_logs( $logs ) {
+ $settings = IP_Geo_Block::get_option();
+
+ // White/Black list for back-end
+ $white_backend = $settings['white_list'];
+ $black_backend = $settings['black_list'];
+
+ // White/Black list for front-end
+ if ( $settings['public']['matching_rule'] < 0 ) {
+ // Follow "Validation rule settings"
+ $white_frontend = $white_backend;
+ $black_frontend = $black_backend;
+ } else {
+ // Whitelist or Blacklist for "Public facing pages"
+ $white_frontend = $settings['public']['white_list'];
+ $black_frontend = $settings['public']['black_list'];
+ }
+
+ foreach ( $logs as $key => $log ) {
+ // Passed or Blocked
+ $mark = IP_Geo_Block::is_passed( $log[5] ) ? '¹' : '²';
+
+ // Whitelisted, Blacklisted or N/A
+ if ( 'public' === $log[1] ) {
+ $mark .= IP_Geo_Block::is_listed( $log[4], $white_frontend ) ? '¹' : (
+ IP_Geo_Block::is_listed( $log[4], $black_frontend ) ? '²' : '³' );
+ } else {
+ $mark .= IP_Geo_Block::is_listed( $log[4], $white_backend ) ? '¹' : (
+ IP_Geo_Block::is_listed( $log[4], $black_backend ) ? '²' : '³' );
+ }
+
+ // Put a mark at "Target"
+ $logs[ $key ][1] .= $mark;
+ }
+
+ return $logs;
+ }
+
+ /**
+ * Register UI "Preset filters" at "Search in logs"
+ *
+ * @param array $filters An empty array by default.
+ * @return array $filters The array of paired with 'title' and 'value'.
+ */
+ public function preset_filters( $filters = array() ) {
+ return array(
+ array( 'title' => '' . __( 'Passed in Whitelist', 'ip-geo-block' ), 'value' => '¹¹' ),
+ array( 'title' => '' . __( 'Passed in Blacklist', 'ip-geo-block' ), 'value' => '¹²' ),
+ array( 'title' => '' . __( 'Passed not in List', 'ip-geo-block' ), 'value' => '¹³' ),
+ array( 'title' => '' . __( 'Blocked in Whitelist', 'ip-geo-block' ), 'value' => '²¹' ),
+ array( 'title' => '' . __( 'Blocked in Blacklist', 'ip-geo-block' ), 'value' => '²²' ),
+ array( 'title' => '' . __( 'Blocked not in List', 'ip-geo-block' ), 'value' => '²³' ),
+ );
+ }
+
+ /**
+ * Ajax callback function
+ *
+ * @link https://codex.wordpress.org/AJAX_in_Plugins
+ * @link https://codex.wordpress.org/Function_Reference/check_ajax_referer
+ * @link https://core.trac.wordpress.org/browser/trunk/wp-admin/admin-ajax.php
+ */
+ public function admin_ajax_callback() {
+ require_once IP_GEO_BLOCK_PATH . 'admin/includes/class-admin-ajax.php';
+
+ // Check request origin, nonce, capability.
+ $this->check_admin_post( TRUE );
+
+ // `$which` and `$cmd` should be restricted by whitelist in each function
+ $settings = IP_Geo_Block::get_option();
+ $which = isset( $_POST['which'] ) ? $_POST['which'] : NULL;
+ $cmd = isset( $_POST['cmd' ] ) ? $_POST['cmd' ] : NULL;
+
+ switch ( $cmd ) {
+ case 'download':
+ $res = IP_Geo_Block::get_instance();
+ $res = $res->exec_update_db();
+ break;
+
+ case 'search': // Get geolocation by IP
+ $res = array();
+ foreach ( (array)$which as $cmd ) {
+ $res[ $cmd ] = IP_Geo_Block_Admin_Ajax::search_ip( $cmd );
+ }
+ break;
+
+ case 'scan-code': // Fetch providers to get country code
+ $res = IP_Geo_Block_Admin_Ajax::scan_country( $which );
+ break;
+
+ case 'clear-statistics': // Set default values
+ IP_Geo_Block_Logs::clear_stat();
+ $res = array(
+ 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
+ 'tab' => 'tab=1'
+ );
+ break;
+
+ case 'clear-cache': // Delete cache of IP address
+ IP_Geo_Block_API_Cache::clear_cache();
+ $res = array(
+ 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
+ 'tab' => 'tab=1'
+ );
+ break;
+
+ case 'clear-logs': // Delete logs in MySQL DB
+ IP_Geo_Block_Logs::clear_logs( $which );
+ $res = array(
+ 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
+ 'tab' => 'tab=4'
+ );
+ break;
+
+ case 'export-logs':// Export logs from MySQL DB
+ IP_Geo_Block_Admin_Ajax::export_logs( $which );
+ break;
+
+ case 'restore-logs': // Get logs from MySQL DB
+ has_filter( $cmd = IP_Geo_Block::PLUGIN_NAME . '-logs' ) or add_filter( $cmd, array( $this, 'filter_logs' ) );
+ $res = IP_Geo_Block_Admin_Ajax::restore_logs( $which );
+ break;
+
+ case 'live-start': // Restore live log
+ has_filter( $cmd = IP_Geo_Block::PLUGIN_NAME . '-logs' ) or add_filter( $cmd, array( $this, 'filter_logs' ) );
+ if ( is_wp_error( $res = IP_Geo_Block_Admin_Ajax::restore_live_log( $which, $settings ) ) )
+ $res = array( 'error' => $res->get_error_message() );
+ break;
+
+ case 'live-pause': // Pause live log
+ if ( ! is_wp_error( $res = IP_Geo_Block_Admin_Ajax::catch_live_log() ) )
+ $res = array( 'data' => array() );
+ else
+ $res = array( 'error' => $res->get_error_message() );
+ break;
+
+ case 'live-stop': // Stop live log
+ if ( ! is_wp_error( $res = IP_Geo_Block_Admin_Ajax::release_live_log() ) )
+ $res = array( 'data' => array() );
+ else
+ $res = array( 'error' => $res->get_error_message() );
+ break;
+
+ case 'reset-live': // Reset data source of live log
+ $res = IP_Geo_Block_Admin_Ajax::reset_live_log();
+ break;
+
+ case 'validate': // Validate settings
+ IP_Geo_Block_Admin_Ajax::validate_settings( $this );
+ break;
+
+ case 'import-default': // Import initial settings
+ $res = IP_Geo_Block_Admin_Ajax::settings_to_json( IP_Geo_Block::get_default() );
+ break;
+
+ case 'import-preferred': // Import preference
+ $res = IP_Geo_Block_Admin_Ajax::preferred_to_json();
+ break;
+
+ case 'gmap-error': // Reset Google Maps API key
+ if ( $settings['api_key']['GoogleMap'] === 'default' ) {
+ $settings['api_key']['GoogleMap'] = NULL;
+ IP_Geo_Block::update_option( $settings );
+ $res = array(
+ 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
+ 'tab' => 'tab=2'
+ );
+ }
+ break;
+
+ case 'generate-link': // Generate new link
+ $res = array( 'link' => IP_Geo_Block_Util::generate_link( $this ) );
+ break;
+
+ case 'delete-link': // Delete existing link
+ IP_Geo_Block_Util::delete_link( $this );
+ break;
+
+ case 'show-info': // Show system and debug information
+ $res = IP_Geo_Block_Admin_Ajax::get_wp_info();
+ break;
+
+ case 'get-actions': // Get all the ajax/post actions
+ $res = IP_Geo_Block_Util::get_registered_actions( TRUE );
+ break;
+
+ case 'export-cache': // Restore cache from database and format for DataTables
+ IP_Geo_Block_Admin_Ajax::export_cache( $settings['anonymize'] );
+ break;
+
+ case 'restore-cache': // Restore cache from database and format for DataTables
+ $res = IP_Geo_Block_Admin_Ajax::restore_cache( $settings['anonymize'] );
+ break;
+
+ case 'bulk-action-remove': // Delete specified IP addresses from cache
+ $res = IP_Geo_Block_Logs::delete_cache_entry( $which['IP'] );
+ break;
+
+ case 'bulk-action-ip-erase':
+ $res = IP_Geo_Block_Logs::delete_logs_entry( $which['IP'] );
+ break;
+
+ case 'bulk-action-ip-white':
+ case 'bulk-action-ip-black':
+ case 'bulk-action-as-white':
+ case 'bulk-action-as-black':
+ // Bulk actions for registration of settings
+ $src = ( FALSE !== strpos( $cmd, '-ip-' ) ? 'IP' : 'AS' );
+ $dst = ( FALSE !== strpos( $cmd, '-white' ) ? 'white_list' : 'black_list' );
+
+ if ( empty( $which[ $src ] ) ) {
+ $res = array( 'error' => sprintf( __( 'An error occurred while executing the ajax command `%s`.', 'ip-geo-block' ), $cmd ) );
+ break;
+ }
+
+ foreach ( array_unique( (array)$which[ $src ] ) as $val ) {
+ // replace anonymized IP address with CIDR (IPv4:256, IPv6:4096)
+ $val = preg_replace(
+ array( '/\.\*\*\*$/', '/:\w*\*\*\*$/', '/(::.*)::\/116$/' ),
+ array( '.0/24', '::/116', '$1/116' ),
+ trim( $val )
+ );
+ if ( ( filter_var( preg_replace( '/\/\d+$/', '', $val ), FILTER_VALIDATE_IP ) || preg_match( '/^AS\d+$/', $val ) ) &&
+ ( FALSE === strpos( $settings['extra_ips'][ $dst ], $val ) ) ) {
+ $settings['extra_ips'][ $dst ] .= "\n" . $val;
+ }
+ }
+
+ if ( $this->is_network_admin && $settings['network_wide'] )
+ $this->update_multisite_settings( $settings );
+ else
+ IP_Geo_Block::update_option( $settings );
+
+ $res = array( 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME );
+ break;
+
+ case 'restore-network': // Restore blocked per target in logs
+ $res = IP_Geo_Block_Admin_Ajax::restore_network( $which, (int)$_POST['offset'], (int)$_POST['length'], FALSE );
+ break;
+
+ case 'find-admin':
+ case 'find-plugins':
+ case 'find-themes':
+ // Get slug in blocked requests for exceptions
+ $res = IP_Geo_Block_Admin_Ajax::find_exceptions( $cmd );
+ break;
+
+ case 'diag-tables': // Check database tables
+ IP_Geo_Block_Logs::diag_tables() or IP_Geo_Block_Logs::create_tables();
+ $res = array( 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME );
+ break;
+ }
+
+ if ( isset( $res ) ) // wp_send_json_{success,error}() @since 3.5.0
+ wp_send_json( $res ); // @since 3.5.0
+
+ die(); // End of ajax
+ }
+
+}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.css
new file mode 100644
index 00000000..61110679
--- /dev/null
+++ b/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.css
@@ -0,0 +1,79 @@
+/*! IP Geo Block admin icons
+ * This package includes the following icon font.
+ * IcoMoon - Free / Designer: Keyamoon / License: GPL / CC BY 4.0
+ * Zondicons / Designer: Steve Schoger / License: CC BY 4.0
+ * Material Icons / Designer: Google / License: Apache License 2.0
+ */
+@font-face {
+ font-family: 'icomoon';
+ src: url('fonts/icomoon.eot?jihakz');
+ src: url('fonts/icomoon.eot?jihakz#iefix') format('embedded-opentype'),
+ url('fonts/icomoon.ttf?jihakz') format('truetype'),
+ url('fonts/icomoon.woff?jihakz') format('woff'),
+ url('fonts/icomoon.svg?jihakz#icomoon') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+[class^="ip-geo-block-icon-"], [class*=" ip-geo-block-icon-"] {
+ /* use !important to prevent issues with browser extensions that change fonts */
+ font-family: 'icomoon' !important;
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+
+ /* Better Font Rendering =========== */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.ip-geo-block-icon-calc {
+ margin-top: 0.2em !important;
+}
+.ip-geo-block-icon-calc:before {
+ content: "\e901";
+}
+.ip-geo-block-icon-vpn_lock:before {
+ content: "\e62f";
+}
+.ip-geo-block-icon-play:before {
+ content: "\ea1c";
+}
+.ip-geo-block-icon-pause:before {
+ content: "\ea1d";
+}
+.ip-geo-block-icon-stop:before {
+ content: "\ea1e";
+}
+.ip-geo-block-icon-warning:before {
+ content: "\e900";
+}
+.ip-geo-block-icon-happy:before {
+ content: "\e9df";
+}
+.ip-geo-block-icon-grin2:before {
+ content: "\e9ea";
+}
+.ip-geo-block-icon-cool:before {
+ content: "\e9eb";
+}
+.ip-geo-block-icon-confused:before {
+ content: "\e9f5";
+}
+.ip-geo-block-icon-confused2:before {
+ content: "\e9f6";
+}
+.ip-geo-block-icon-crying:before {
+ content: "\ea01";
+}
+
+/* Dashicons is the official icon font of the WordPress admin as of 3.8+. */
+#toplevel_page_ip-geo-block .dashicons-admin-generic:before {
+ font-family: 'icomoon';
+ content: "\e62f";
+ font-size: 18px;
+ margin-left: 2px;
+}
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.min.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.min.css
new file mode 100644
index 00000000..6c9419fe
--- /dev/null
+++ b/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.min.css
@@ -0,0 +1,7 @@
+/*! IP Geo Block admin icons
+ * This package includes the following icon font.
+ * IcoMoon - Free / Designer: Keyamoon / License: GPL / CC BY 4.0
+ * Zondicons / Designer: Steve Schoger / License: CC BY 4.0
+ * Material Icons / Designer: Google / License: Apache License 2.0
+ */
+@font-face{font-family:icomoon;src:url(fonts/icomoon.eot?jihakz);src:url(fonts/icomoon.eot?jihakz#iefix) format('embedded-opentype'),url(fonts/icomoon.ttf?jihakz) format('truetype'),url(fonts/icomoon.woff?jihakz) format('woff'),url(fonts/icomoon.svg?jihakz#icomoon) format('svg');font-weight:400;font-style:normal}[class*=" ip-geo-block-icon-"],[class^=ip-geo-block-icon-]{font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ip-geo-block-icon-calc{margin-top:.2em!important}.ip-geo-block-icon-calc:before{content:"\e901"}.ip-geo-block-icon-vpn_lock:before{content:"\e62f"}.ip-geo-block-icon-play:before{content:"\ea1c"}.ip-geo-block-icon-pause:before{content:"\ea1d"}.ip-geo-block-icon-stop:before{content:"\ea1e"}.ip-geo-block-icon-warning:before{content:"\e900"}.ip-geo-block-icon-happy:before{content:"\e9df"}.ip-geo-block-icon-grin2:before{content:"\e9ea"}.ip-geo-block-icon-cool:before{content:"\e9eb"}.ip-geo-block-icon-confused:before{content:"\e9f5"}.ip-geo-block-icon-confused2:before{content:"\e9f6"}.ip-geo-block-icon-crying:before{content:"\ea01"}#toplevel_page_ip-geo-block .dashicons-admin-generic:before{font-family:icomoon;content:"\e62f";font-size:18px;margin-left:2px}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin.css
new file mode 100644
index 00000000..cf7a61d7
--- /dev/null
+++ b/wp/wp-content/plugins/ip-geo-block/admin/css/admin.css
@@ -0,0 +1,1015 @@
+/*!
+ * Project: WordPress IP Geo Block
+ * Copyright (c) 2013-2019 tokkonopapa (tokkonopapa@yahoo.com)
+ * This software is released under the MIT License.
+ */
+dfn {
+ cursor: help;
+ border-bottom: 1px dotted #888;
+}
+
+/* style legend and fieldset as panel */
+fieldset, legend {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+fieldset {
+ min-width: 0;
+}
+legend {
+ display: block;
+ line-height: inherit;
+ width: 100%;
+}
+label {
+ display: inline-block;
+ max-width: 100%;
+}
+.panel {
+ border-color: #888;
+ border: 1px solid #e5e5e5;
+ -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.04);
+ -moz-box-shadow: 0 1px 1px rgba(0,0,0,.04);
+ box-shadow: 0 1px 1px rgba(0,0,0,.04);
+ background: #f5f5f5;
+}
+.panel-heading {
+ float: left !important;
+ background: #fff;
+}
+.panel-default > .panel-heading {
+ border-color: inherit;
+}
+.panel-body {
+ width: 100%;
+ padding: 0 1em;
+ display: inline-block;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.panel-body:before,
+.panel-body:after {
+ content: " ";
+ display: table;
+}
+.panel-body:after {
+ clear: both;
+}
+.ip-geo-block-navi-link {
+ text-align: left;
+}
+.ip-geo-block-help-link {
+ float: right;
+ font-size: 90%;
+ font-weight: normal;
+}
+.ip-geo-block-help-link a {
+ box-shadow: none;
+}
+
+/* style legend and fieldset */
+fieldset label {
+ vertical-align: text-middle;
+}
+fieldset input[type="checkbox"] {
+ margin: 1px 2px 0;
+}
+fieldset.ip-geo-block-field {
+/* padding: 0 10px;*/
+ margin: 1em 0;
+}
+fieldset.ip-geo-block-field h2,
+fieldset.ip-geo-block-field h3 {
+ padding: 0;
+ margin: 0;
+ font-size: 14px !important;
+}
+fieldset.ip-geo-block-field h4 {
+ margin: 0.75em 0 0.5em 0;
+}
+fieldset.ip-geo-block-field legend.panel-heading {
+ padding: 10px;
+}
+
+fieldset.ip-geo-block-field .ip-geo-block-dropup,
+fieldset.ip-geo-block-field .ip-geo-block-dropdown {
+ cursor: pointer;
+ position: relative;
+ padding-left: 1em;
+}
+fieldset.ip-geo-block-field .ip-geo-block-dropup:before,
+fieldset.ip-geo-block-field .ip-geo-block-dropdown:before {
+ content: '';
+ height: 0;
+ width: 0;
+ border: 0.4em solid transparent;
+ position: absolute;
+}
+fieldset.ip-geo-block-field .ip-geo-block-dropup:before {
+ border-left: 0.4em solid #555;
+ left: 2px;
+ top: 18%;
+}
+fieldset.ip-geo-block-field .ip-geo-block-dropdown:before {
+ border-top: 0.4em solid #555;
+ left: -2px;
+ top: 38%;
+}
+fieldset.ip-geo-block-field .form-table .ip-geo-block-dropup,
+fieldset.ip-geo-block-field .form-table .ip-geo-block-dropdown {
+ margin-top: 0.75em;
+}
+fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before {
+ top: 0.25em;
+}
+fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before {
+ top: 0.5em;
+}
+fieldset.ip-geo-block-field table.form-table {
+ margin: 0 0 0.5em;
+ width: 100%;
+}
+
+/* Text */
+textarea.regular-text {
+ width: 25em;
+}
+fieldset.ip-geo-block-field input.regular-text,
+fieldset.ip-geo-block-field textarea.regular-text {
+ font-size: 95%;
+}
+
+/* Checkbox / Radio */
+p.ip-geo-block-navi-link input[type="checkbox"],
+fieldset.ip-geo-block-field input[type="checkbox"],
+fieldset.ip-geo-block-field input[type="radio"] {
+ margin-right: 0.4em;
+}
+
+/* Plugins/Themes area, Geolocation API settings */
+input[id*="ip_geo_block_settings_rewrite_"] + label {
+ margin-left: 0.25em;
+}
+input[id*="ip_geo_block_settings_providers"] + label {
+ min-width: 7em;
+}
+
+/* Folding */
+.ip-geo-block-settings-folding {
+ margin: 0.5em 0;
+}
+.ip-geo-block-settings-folding ul {
+ margin-bottom: 0;
+}
+.ip-geo-block-settings-folding li {
+ margin: 0.5em 0;
+}
+.folding-disable {
+ pointer-events: none;
+ opacity: 0.5;
+}
+.folding-inactive {
+ opacity: 0.5;
+ font-style:oblique !important;
+}
+
+/* Etc */
+.ip-geo-block-float li {
+ display: inline-block;
+ width: 18em;
+ margin-top: 0;
+}
+.ip-geo-block-checked {
+ list-style-type: disc;
+}
+.ip-geo-block-ip-addr {
+ display: inline-block;
+ padding-top: 5px;
+}
+.ip-geo-block-hide {
+ display: none;
+}
+.ip-geo-block-sup {
+ margin-left: 0.2em;
+ display: inline-block;
+}
+.ip-geo-block-note {
+ margin-top: 1em;
+ list-style: disc inside;
+}
+.ip-geo-block-note li {
+ text-indent: -1em;
+ padding-left: 1em;
+}
+.ip-geo-block-border {
+ border-top: inherit;
+}
+.ip-geo-block-notice {
+ color: #dd3d36;
+}
+.ip-geo-block-title {
+ width: 100px;
+ display: inline-block;
+}
+.ip-geo-block-result {
+ color: #2786C2;
+ display: inline-block;
+}
+.ip-geo-block-primary {
+ color: #fff !important;;
+ background: #00838f !important;
+ border-color: #00707a !important;
+ text-shadow: none; /* for WordPress 3.7.21 */
+}
+.ip-geo-block-primary:hover {
+ background-color: #00919e !important;
+ border-color: #00525a !important;
+}
+ul#ip-geo-block-logs-preset {
+ margin: 0.25em 0;
+ max-width: 600px;
+}
+ul#ip-geo-block-logs-preset li {
+ float: left;
+ line-height: 1.5em;
+ margin-right: 1em;
+ min-width: 160px;
+}
+
+/* Loading image */
+.ip-geo-block-loading,
+#ip-geo-block-live-loading {
+ height: 16px;
+ width: 16px;
+ background-size: 16px 16px;
+ background-position: center center;
+ background-repeat: no-repeat;
+ margin-left: 1em;
+ margin-top: 0.2em;
+ display: inline-block;
+ vertical-align: top;
+}
+.ip-geo-block-loading {
+ background-image: url(data:image/gif;base64,R0lGODlhEAAQAPYCAKqqqsbGxlZWVsrKyvr6+ubm5tDQ0K6urmZmZmJiYuzs7IaGhvT09JycnLq6us7Ozurq6o6OjtbW1tra2vDw8CgoKCYmJvz8/NLS0kJCQlJSUqysrPLy8vb29pqamra2tm5ubujo6Kampvj4+IiIiMjIyEhISNzc3OLi4rKysj4+PlBQULi4uJKSkmRkZODg4KKiou7u7iQkJB4eHlpaWhISErCwsHh4eMDAwDIyMi4uLqSkpIKCgr6+vt7e3n5+fggICJCQkAwMDEpKSmBgYHZ2dhgYGBYWFnx8fF5eXk5OTiIiIjAwMIyMjISEhDQ0NJaWltTU1AQEBBwcHGpqaoqKiuTk5CoqKlhYWAoKCtjY2Hp6ehAQEJ6ensLCwkxMTJSUlCwsLAYGBnR0dDg4OFxcXLy8vKCgoA4ODsTExMzMzDw8PERERDY2NqioqHJycrS0tGhoaBQUFEZGRjo6OkBAQICAgHBwcFRUVCAgIGxsbP///wAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgACACwAAAAAEAAQAEAHjIACgoOEhYJsbTGGghcPGIJRbFNNhgQKCheDDkllDQYMHSc4MAcvhTB0aFliggQjmYNEFQ6LAh0+VoIwbFW1GGamhCgfUE5NbgMKtQYLc0a1gjsyR3E2IYwMFASDYDJvtRRWFIJ1TMq1ElqCICpetQoBEoInVCsAhhI2XhyEPUgIIG7waALlwAloCAMBACH5BAkKAAIALAEAAQAOAA4AAAeDgAKCEmBYYRVKJAaCjAcrVzIzRjVoTw2MKRk5Ww4KECkuWTWCE0Rrl4yCTow7bAupsBcCW19psKkjBEQaFLeMHBwINBy+ggoxVQkPxSMFMXBUMMUQPhRWVUU9tyFRLwQCA048cCcjIyFaJQYxjA8NEVBnAClmahCwEANwbjYBJwyMAgEAIfkECQoABQAsAQABAA4ADgAAB4OABYInO29DbC5QUYKMZiBfbCptTBUmIow4LgJBaTExZkVLFTAFKD8JB4yMQUZrBixUXaqqVFwkUG8Ys4wpQiZOWwy7ghBiRk08HcOqblUTy4wlLWbLBCMFCgBdurMjFMoFE24ADxAXFwwKITEEjD5mH2YBDxI+IdeqHCcGAxgv7IwCAQAh+QQJCgAAACwBAAEADgAOAAAHhYAAglYfTVQJSCITgowDVSAISQJKJgkpjA8LWyIGHBQBJCoZBwAQDU44jIxdTxoSAxEfqqpbFWApUCezjA5LWCJdI7uCClNXGyLCwxBHFl4HBcMAKVxfEx8Y0glZCxwlOCjDUkwPACElAygMghftAB6MClpRJygQFB0EuyMKBQUKDPQxCgQAIfkECQoAAAAsAQABAA4ADgAAB4SAAIIKahstTQ0OVoKMJzYeLVU8W29OXowvBztePh0dUTtxVD0AHDgHEoyMKWVvPj4sBqqqLUoiGDgQs4wBJmNqARe7gjEqXxgPwsMxbWw+UQzDAGY6LjEnusNjFmAEBVbRs00zc1EAHRAKHYw2CHIyO4wEHAwjgmJCZDC7F8psC7IEBQIAIfkECQoARwAsAQABAA4ADgAAB4OAR4IMPgMfNg4PCoKMEA84LCkAMB47GIwxBiUTEAQjKD0REQ9HBD4YIYyMATwtBRQnqaqMG0UOEC8ds4wYIEEQBbuMHC4gMYvCRxw0CAwcF8kBGj8EHdDCJCYiRxfXsw0qCROqRDYQECw3ORkpqjpAQjVGMxYrB7MPC0MyFQItEowCAQAh+QQJCgACACwBAAEADgAOAAAHgIACghcUVhIYEigMgowjEC8nUQ8BOGkojAQxITEdAhcxEh9wPoIMFCOMjBMAKTEXHaipjGldDxcEsqkvUAe5sh1NLb6pHTxNbGK9vlE3DU5ZLsNnIA4GbTVVuQcJdpdnS0Z3LAoxXhF4LjiMMBl5FjptKiZ6ZrJRLUkqbCAwJ4yBACH5BAUKAAEALAEAAQAOAA4AAAd/gAGCARcjHDExHASDjAQdHAoFLy8Ugw2MgiMKWhIKAQ9MYpiCEA8YHQtZCaOCJ14vX2g2rAEKZgMyNRC0BCksFUa7rCMANgIzH7QvZw4tMmO0DlAPUV9hHqNeVTC7G2tkTmkUHA8iSFUGgzZlGSYaNC4gTWqYEzA3SQhVH1aDgQA7);
+}
+
+/* Google Map infomation window */
+#ip-geo-block-map {
+ height: 400px;
+ margin: 1em auto;
+}
+#ip-geo-block-apis div.nav-tab-wrapper {
+ padding-top: 0;
+ margin-bottom: 1em;
+}
+#ip-geo-block-geoinfo {
+ white-space: normal;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+#ip-geo-block-geoinfo ul {
+ margin-top: 0;
+ margin-left: 1em;
+}
+.gm-style-iw {
+ width: 18em;
+ height: auto !important;
+ height: 100%;
+ min-height: 100%:
+}
+.gm-style-iw ul {
+ margin: 0.1em;
+}
+.gm-style-iw li {
+ margin: 0.2em;
+}
+
+/* SVG in google chart */
+svg a {
+ cursor: pointer;
+}
+svg a:hover > text {
+ fill: #0096dd;
+}
+svg a > text {
+ fill: #0073aa;
+ text-decoration: underline;
+}
+
+/* table */
+table.ip-geo-block-statistics-table {
+ float: right;
+}
+table.ip-geo-block-statistics-table th,
+table.ip-geo-block-statistics-table td {
+ width: 12em;
+ margin: 0;
+ padding: 0.2em;
+ text-align: right;
+ line-height: 1.5em;
+ word-wrap: break-word;
+}
+table.ip-geo-block-statistics-table tr:nth-child(even) {
+ background-color: #eee;
+}
+table.ip-geo-block-statistics-table tr:nth-child(odd) {
+}
+table.ip-geo-block-table {
+ margin: 1em 0;
+ width: 100%;
+ white-space: normal;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+table.ip-geo-block-table td:first-child {
+ min-width: 4.3em;
+ max-width: 5.0em;
+}
+
+/* Whois */
+@media screen and (max-width:782px) {
+ #ip-geo-block-whois .panel-body {
+ padding: 0 0.5em;
+ }
+}
+
+/* Scan the country code */
+#ip-geo-block-scan-code {
+ vertical-align: middle;
+}
+#ip-geo-block-code-list {
+ display: none;
+ margin-bottom: 0;
+}
+
+/* Google Chart */
+#ip-geo-block-chart-countries {
+ height: 200px;
+}
+#ip-geo-block-chart-daily {
+ height: 240px;
+}
+#ip_geo_block_settings_validation_mimetype + label {
+ padding-top: 0.25em;
+}
+#ip_geo_block_settings_validation_mimetype + label + ul {
+ margin-top: 0.7em;
+}
+#ip_geo_block_settings_create_user {
+ margin-bottom: 0.5em;
+}
+#ip-geo-block-toggle-sections,
+#ip-geo-block-back-to-top a {
+ box-shadow: none;
+}
+#ip-geo-block-wp-info textarea {
+ margin-top: 0.5em;
+ overflow: auto;
+ width: 100%;
+ word-wrap: normal;
+ word-break: normal;
+ white-space: pre;
+}
+#ip-geo-block-back-to-top {
+ margin:0;
+ text-align:right;
+}
+#ip-geo-block-open-new,
+#ip-geo-block-live-update {
+ margin-left: 1em;
+}
+
+/* Top menu link */
+.ip-geo-block-menu-link {
+ font-size: 13px !important;
+}
+
+/* Icons */
+dfn ~ .ip-geo-block-icon {
+ margin-left: 0.4em;
+}
+.ip-geo-block-icon {
+ position: relative;
+ cursor: pointer;
+ outline: none;
+ box-shadow: none;
+ text-decoration: none;
+ background-color: transparent;
+}
+.ip-geo-block-icon:active {
+ top: 1px;
+}
+.ip-geo-block-icon span {
+ height: 16px;
+ width: 16px;
+ margin: 0;
+ border: none;
+ display: inline-block;
+ vertical-align: middle;
+ background-size: 16px 16px;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.ip-geo-block-icon-cycle span {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAh1BMVEUAda2otLp+rsSHprWHr8IBd7EpfKRGhaNajqeUqrRymKuKoq5yo7prlKgAcqoVe6w8gqQmgq5Tj6wIdqsVdKIshrEMea1Uhp+Anqw0hawDdq4gfKhljqE7hqoLdKYbgbM4jLQygKUGeK8CdawQd6gVeKcad6NKkrSerrZAj7UAc6sAc6rc3NySrVGQAAAALXRSTlP//////////////////////////////////////////////////////////wCl7wv9AAACOklEQVR4Ae2W15rzKgxF9xTZzhTX9B7S/gN6/9ebYqzzGZsw/S7LV3FZgCSIwD/kQ8FVcBU8xatZUczy8luC/ABNOn0DSHEsvyZ4PgLatNCYR3efFxyhTQ8g+qQgJxgv2JefERzJXATRh4LHOUwAHD4S7OGEztRJaN86hAUxtaNWDUf/bRdDBbQMWVDAO8jn89WUhag1MeyCAh6hHofyrliLgZKggDMYgzF3eVAwFq0uCZq5KY0TezjIHDDzC0qqmkwe2ctGDOQVLMkgu+F3/rGXwb4xIPcJ6P3JgkM8wFjmfcFAWfeKQywaAz33BJVuHsUcAt09gVbuLDThAJkdR687ggLmf4gDJLIGV7BydtB8yn3u+fbtuj/LS7G9wZAd1AKK+yxJ1x+aBmibTtgCcEHGHsh0wdbOgNLek4L7lI5BigY8nWuZUQ3qGEXes9JzOKGJztPaGtLslu3lIXJirdxCWkASHGDTMqg7V1DKPplygDG61YJukLHjEErGSXqCSos6xNSOgzP3BDmsQBcchNwkoV8oiNnPA78zIefUgCdJeGIfE7LmFWXsFTCFdzTJ/RlfEMRiSGnFXXbkC7AIeqcKDu4ynseozeouKJiSEYBDwkJyIC1nRUjgblkNWp/e/1vXc2gjoAoLksYgjrrFMi0oDgjEEIDij1scBXMJSH6DAj6RNl7o8MkuLak8Co15/Pk+MRmT0xilQJV/sdWNKg2kTaeroudvNNsDjmejYjSL+e6v2/2r4Cp4BXNajr0H7hRfAAAAAElFTkSuQmCC);
+}
+.ip-geo-block-icon-lock span {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3Ny3y9Zzq8dRmb7M1dlXnsIFdK0AcawAcqwphrYAcKvZ29wAb6oJd680jrqlw9MBcqxmo8MUfbJLl75eoMI7kbzX2ttqp8VSmL1YnL8NeK+Tu89DlL1ImMEOebBNmL4OkqMoAAAAAXRSTlMAQObYZgAAAPlJREFUeAG9kAWyhTAQBIPOsCzufv9TPnf4Ll0CSbpmxXwNy3Yc23rz2fV8kPA99433AIQIiGDTCD0lojiOQPXCDSFJIbF16CMWItkQMkF+inZzSLYhFKLl+a9UKTZaqJTZJYtarZuo40chrv9CqJTN+behVi+Cm7RdDgRld6AMgLxrE/dxBz0BEjwBEmD/uIsWPAOAF9A+CE56ufSryr8oqfOYcBbQJ8YkES7COkFOYzTypqCDOTDo2wljaEw4vp1APYyWKd8WMBozylvCpcvmXeHQ5fCegHia4s1FgZcIVeVFeFx1M4MvYG4eBHdYWufC+addBtf8E3vdjBNhWnVQqAAAAABJRU5ErkJggg==);
+}
+.ip-geo-block-icon-unlock span {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC);
+}
+.ip-geo-block-icon-find span {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NzS19rD0NWHtMpGk7kYfbAGda0Req+WtcTT1temwM4AcasAcqwAc6wAcKydvMt1pr8Ab6pqpcLX2doggrKoxdNYm7yzw8u/y9HO1tkKdq4th7Td3t6DrcLL0taxyNPGe/YhAAAAAXRSTlMAQObYZgAAARVJREFUeAGtkkeiwyAMRP2xDfxoRjElvd3/lOkNUlZ5u0GPruan/Bnz96Xadr21rvP/7+ujXsAjom78rj4ApCoERIipqfGB1H7wPmYhw1DXjZI6nOel1oJhVAmdUP0tTEDkVC4AYvqIbaDOCqFV6vwRF0tIeYoo6J/X7ICuPAJl9ZynwiIfB5DXxZlRChulbh8xZci0EHZK3TziJFDL504rEOZ+iR5cVj82DoS7XtSshLJpKqaB0Dg3ZjcsQWKaKiF1gVQlITwh/bw2pgKeEeURhE29yKSzUFF03p1V7Wqj2Y7GfrY9X/NirJsPxKsxfBLSSs5GmH8yjAWPSNd8Yoez4f4/G1nIsksqFtGK1i9e39o0P+EAqaoRLlQ+r94AAAAASUVORK5CYII=);
+}
+span.ip-geo-block-icon-alert,
+.ip-geo-block-icon-alert span {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAkFBMVEXc3Nzc2trWl5DHRDTFOyvOgXfc1tXCLBrEMiHEMyLNcmfaxMLDMSDDLx7bu7jRiYHDLhzDMB/LX1PaxsTDLh3YtrHMY1bWmpPJVknSjYXUkYnZuLTMZVnENCPWlI3QhXzENiXXrqrDLRzXsa3Oal7Pe3Hc2NjVn5nNbmPayMbbwb7ay8rUj4fc09Lbw8Db0dDBbRUDAAAAAXRSTlMAQObYZgAAAPVJREFUeAG9ktXWwyAQBonC12brFvff5f2frr4nBredK2DnTFS8Gst2XM8XZmypIGeWcT4PFABaGIXlClfWG1NiC4Ubu705oKRcY32wTAHl2MdTYEqEK8hIiHgHSnSJeaogMyEWO4BijZCvwII2MS9UJ2BXTh+hQidoEttboBOwq3WBnkCNpQlA2iyAhol2hRu71n97p4fw0Z9/ugoPHCfFA+o/iLfCkyBglRJdICBas7uuey+R56fF14wNanj+/QjwY3aX23cBFn6EiHmHNT/ICYxystv/wJy4UHWGlN2cuPB72tFqAq3dP/Hk3zs0E5LZVryGC/hqGNnUa0SVAAAAAElFTkSuQmCC);
+ vertical-align: bottom;
+}
+
+table.form-table th .ip-geo-block-cycle span {
+ vertical-align: text-bottom;
+}
+
+/* Option list */
+.ip-geo-block-list {
+ margin-top: 0;
+ margin-bottom: 0.7em;
+}
+@media screen and (min-width:782px) {
+ ul.ip-geo-block-list .code {
+ width: 15em;
+ }
+}
+
+/* Exceptions */
+.ip-geo-block-list-exceptions label {
+ display: inline-block;
+}
+.ip-geo-block-list-exceptions dfn {
+ border: none;
+}
+.ip-geo-block-list-exceptions span.dashicons {
+ font-size: 14px;
+}
+.ip-geo-block-list-exceptions a.ip-geo-block-icon {
+ margin-left: 0.3em;
+ outline: none;
+ box-shadow: none;
+ text-decoration: none;
+ background-color: transparent;
+}
+
+/* Description */
+.form-table td p.ip-geo-block-desc,
+.form-table td p.ip-geo-block-find-desc {
+ color: #666;
+ font-size: 13px !important;
+ margin: 4px 0 0.5em 0.5em;
+}
+.ip-geo-block-find-desc {
+ display: none;
+}
+
+/* Action for admin post */
+.ip-geo-block-admin-post {
+ color: #c43322;
+ margin-left: 0.25em;
+}
+.ip-geo-block-warn {
+ color: #c43322;
+ font-weight: bold;
+}
+
+/* Badly-behaved bots and crawlers */
+input#ip_geo_block_settings_behavior_view,
+input#ip_geo_block_settings_behavior_time {
+ width: 3.5em;
+}
+
+/* Statistics */
+.ip-geo-block-top-list {
+ display: inline-table;
+ list-style-position: outside;
+ margin: 0 2em 0.5em 1.75em;
+}
+.ip-geo-block-top-list h4 {
+ margin: 1em 0;
+}
+.ip-geo-block-top-list li code {
+ background: none;
+}
+
+/* Embeded data for network site list */
+.ip-geo-block-network {
+ margin-bottom: 1em;
+}
+
+/*------------------------------------------------------------
+ * multi column for Site List
+ * https://caniuse.com/#search=flexbox
+ *------------------------------------------------------------*/
+.ip-geo-block-container {
+ margin: 0 auto;
+ padding: 0 1em;
+ position: relative;
+ width: 100%;
+}
+.ip-geo-block-row {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ align-items: stretch; /* baseline */
+ padding: 0;
+ width: 100%;
+}
+.ip-geo-block-row .ip-geo-block-column {
+ display: block;
+ flex: 1 1 auto;
+ align-self: flex-start;
+ margin-left: 0;
+ max-width: 100%;
+ width: 100%;
+}
+.ip-geo-block-row .ip-geo-block-column.column-20 {
+ flex: 0 0 20%;
+ max-width: 20%;
+}
+.ip-geo-block-row .ip-geo-block-column.column-25 {
+ flex: 0 0 25%;
+ max-width: 25%;
+}
+.ip-geo-block-row .ip-geo-block-column.column-33 {
+ flex: 0 0 33.3333%;
+ max-width: 33.3333%;
+}
+.ip-geo-block-row .ip-geo-block-column.column-50 {
+ flex: 0 0 50%;
+ max-width: 50%;
+}
+@media (min-width: 40rem) {
+ .ip-geo-block-row {
+ flex-direction: row;
+ margin-left: -2em;
+ width: calc(100% + 2em);
+ }
+ .ip-geo-block-row .ip-geo-block-column {
+ margin-bottom: inherit;
+ padding: 0 1em;
+ }
+}
+
+/*------------------------------------------------------------
+ * Customizing based on jquery.dataTables.css
+ *------------------------------------------------------------*/
+table.ip-geo-block-dataTable {
+ clear: none !important;
+}
+table.ip-geo-block-dataTable th,
+table.ip-geo-block-dataTable td {
+ text-align: right;
+}
+table.ip-geo-block-dataTable th:nth-child(n+2),
+table.ip-geo-block-dataTable td:nth-child(n+2) {
+ padding-left: 0 !important;
+}
+table.ip-geo-block-dataTable th {
+ white-space: nowrap;
+}
+table.ip-geo-block-dataTable > thead > tr {
+ line-height: 1.8em;
+}
+table.ip-geo-block-dataTable > tbody > tr {
+ cursor: pointer;
+}
+table.ip-geo-block-dataTable > thead > tr > th,
+table.ip-geo-block-dataTable > thead > tr > td,
+table.ip-geo-block-dataTable.no-footer {
+ border-bottom: 1px solid #ddd;
+}
+table.ip-geo-block-dataTable thead th,
+table.ip-geo-block-dataTable thead td {
+ padding: 10px 16px;
+}
+/* country code */
+#ip-geo-block-statistics-cache td:nth-child(3),
+#ip-geo-block-validation-logs td:nth-child(4) {
+ min-width: 1.6em;
+}
+
+/* Scroll bar */
+div[class*="ip-geo-block"] .dataTables_wrapper.no-footer .dataTables_scrollBody {
+ border-bottom: 1px solid #ddd;
+}
+
+/* Size of column */
+table.ip-geo-block-dataTable.nowrap td,
+table.ip-geo-block-dataTable > tbody > tr > td span {
+ white-space: normal !important;
+ word-wrap: break-word !important;
+ word-break: break-all !important;
+}
+table.ip-geo-block-dataTable > tbody > tr > td span {
+ display: inline-block;
+}
+
+/* Checkbox */
+.ip-geo-block-settings-folding input[type="checkbox"] {
+ margin-right: 0.5em;
+}
+table.ip-geo-block-dataTable input[type="checkbox"] {
+ margin: 0;
+ max-height: 16px;
+ max-width: 16px;
+ vertical-align: middle;
+}
+table.ip-geo-block-dataTable > thead > tr > th:first-child,
+table.ip-geo-block-dataTable > tbody > tr > td:first-child {
+ padding: 8px 4px 8px 1.4em;
+ text-align: left;
+}
+
+/* No data available in table */
+table.ip-geo-block-dataTable > tbody > tr > td.dataTables_empty,
+table.collapsed > tbody > tr > td.dataTables_empty:first-child::before {
+ border: none;
+ text-align: center;
+}
+
+/* Checkbox column */
+table.ip-geo-block-dataTable thead > tr > th:first-child.sorting_asc {
+ background-image: none !important;
+}
+table.ip-geo-block-dataTable.display tbody tr.even > .sorting_1,
+table.ip-geo-block-dataTable.display tbody tr.odd > .sorting_1,
+table.ip-geo-block-dataTable.display tbody tr:hover > .sorting_1 {
+ background-color: inherit !important;
+}
+
+/* Collapsed */
+table.ip-geo-block-dataTable.collapsed > tbody > tr > td:first-child {
+ padding: 8px 4px 8px 8px !important;
+}
+table.collapsed > tbody > tr > td:first-child::before,
+table.collapsed > tbody > tr.parent > td:first-child::before {
+ content: '';
+ height: 0;
+ width: 0;
+ display: inline-block;
+ border-radius: 0;
+ border: 5px solid transparent;
+ box-shadow: none;
+ position: relative;
+ background-color: transparent;
+}
+table.collapsed > tbody > tr > td:first-child::before {
+ border-left: 5px solid #555;
+ top: 1px;
+ left: -2px;
+}
+table.collapsed > tbody > tr.parent > td:first-child::before {
+ border-top: 5px solid #555;
+ top: 4px;
+ left: -4px;
+}
+table.collapsed > tbody > tr.child > td:first-child::before {
+ border: none;
+}
+table.collapsed > tbody > tr.child > td.child > ul li {
+ border: none;
+ padding: 0;
+ margin: 0;
+ line-height: 1.8em;
+}
+table.collapsed > tbody > tr.child > td.child > ul li span.dtr-title,
+table.collapsed > tbody > tr.child > td.child > ul li span.dtr-data {
+ font-size: 13px !important;
+ display: block;
+ white-space: normal;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+table.collapsed > tbody > tr.child > td.child > ul li span.dtr-data {
+ margin-left: 1.25em;
+ margin-right: 0.3em;
+}
+
+/* Length menu */
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length {
+ padding-top: 0.15em;
+ margin: 0.5em 0 0 0.3em;
+ position: relative;
+ display: inline-block;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length:after {
+ content: '';
+ width: 6px;
+ height: 6px;
+ border: 0px;
+ border-bottom: solid 2px #999;
+ border-right: solid 2px #999;
+ -ms-transform: rotate(45deg);
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+ position: absolute;
+ top: 50%;
+ right: 10px;
+ margin-top: -4px;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length select {
+ padding-top: 0;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ font-size: 13px !important;
+ line-height: 1.4em;
+ width: 100%;
+ height: 2.05em !important;
+ background: transparent;
+ position: relative;
+ z-index: 1;
+ padding: 0.125em 1.5em 0.125em 0.25em;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ box-shadow: none;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length select::-ms-expand {
+ display: none;
+}
+
+/* Pagenation */
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate {
+ float: none;
+ text-align: center;
+ margin-bottom: 1em;
+ margin-top: 0 !important;
+}
+@media screen and (min-width:640px) {
+ div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length {
+ margin: 0.5em 0 0 0.6em;
+ }
+ div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate {
+ position: relative;
+ left: -2.25em;
+ }
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate span.ellipsis,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button:active,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active {
+ min-width: 2em;
+ background: inherit;
+ border-color: #ddd;
+ border-radius: 0;
+ border-image: none;
+ border-style: solid;
+ border-width: 1px 1px 1px 0;
+ box-shadow: none;
+ margin: 0.5em 0 0 0;
+ padding: 0.25em 0;
+ display: inline-block;
+ text-decoration: none;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate > a.paginate_button:first-child,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:hover > a.paginate_button:first-child,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:active > a.paginate_button:first-child {
+ border-left-width: 1px;
+ border-bottom-left-radius: 4px;
+ border-top-left-radius: 4px;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate > a.paginate_button:last-child,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:hover > a.paginate_button:last-child,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:active > a.paginate_button:last-child {
+ border-bottom-right-radius: 4px;
+ border-top-right-radius: 4px;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button {
+ color: #0073aa !important;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover {
+ color: #0096dd !important;
+ background-color: #fff;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate span.ellipsis,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active {
+ cursor: default;
+ color: #999 !important;
+ background-color: transparent;
+}
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,
+div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active {
+ cursor: default;
+ color: #444 !important;
+ background-color: #fff !important;
+}
+
+/* Alignment of table */
+#ip-geo-block-1 #ip-geo-block-section-2 .panel-body,
+#ip-geo-block-4 #ip-geo-block-section-0 .panel-body {
+ padding: 0;
+}
+#ip-geo-block-1 #ip-geo-block-section-2 table.form-table,
+#ip-geo-block-4 #ip-geo-block-section-0 table.form-table {
+ margin-left: 1em;
+ max-width: 95%;
+}
+
+/* Select target / Period to extract */
+#ip-geo-block-select-target,
+#ip-geo-block-select-layout,
+#ip-geo-block-select-duration {
+ margin: 0;
+}
+#ip-geo-block-select-target li,
+#ip-geo-block-select-layout li,
+#ip-geo-block-select-duration li {
+ float: left;
+ margin-right: 1.5em;
+}
+#ip-geo-block-select-target li label,
+#ip-geo-block-select-duration li label {
+ cursor: pointer;
+}
+
+/* Filter */
+#ip_geo_block_settings_search_filter {
+ width: 16em;
+ padding-top: 3px;
+}
+
+/* Transition for new row */
+table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-passed {
+ background-color: #edf6ff !important;
+}
+table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-blocked {
+ background-color: #ffefef !important;
+}
+.ip-geo-block-new-passed {
+ animation: ip-geo-block-flash-passed 1s ease-out 0s 1 normal both running;
+}
+.ip-geo-block-new-blocked {
+ animation: ip-geo-block-flash-blocked 1s ease-out 0s 1 normal both running;
+}
+@keyframes ip-geo-block-flash-passed {
+ 0% { background-color: #ffd700; }
+ 100% { background-color: #edf6ff; }
+}
+@keyframes ip-geo-block-flash-blocked {
+ 0% { background-color: #ffd700; }
+ 100% { background-color: #ffefef; }
+}
+
+/* Mark.js */
+mark {
+ padding: 0;
+ background: #ffd700; // Gold
+}
+
+/* Live update log */
+#ip-geo-block-live-log {
+ margin: 0;
+}
+#ip-geo-block-live-log li {
+ float: left;
+ margin-right: 3em;
+}
+#ip-geo-block-live-log li:last-child {
+ margin-right: 0;
+}
+#ip-geo-block-live-log li input[type=radio] {
+ visibility: hidden;
+ position: absolute;
+}
+#ip-geo-block-live-log li input[type=radio] + label {
+ display:inline-block;
+ margin:-2px;
+ padding: 4px 12px;
+ margin-bottom: 0;
+ font-size: 14px;
+ line-height: 20px;
+ color: #333;
+ text-align: center;
+ text-shadow: 0 1px 1px rgba(255,255,255,0.75);
+ vertical-align: middle;
+ cursor: pointer;
+ background-color: #f5f5f5;
+ background-image: -moz-linear-gradient(top,#fff,#e6e6e6);
+ background-image: -webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));
+ background-image: -webkit-linear-gradient(top,#fff,#e6e6e6);
+ background-image: -o-linear-gradient(top,#fff,#e6e6e6);
+ background-image: linear-gradient(to bottom,#fff,#e6e6e6);
+ background-repeat: repeat-x;
+ border: 1px solid #ccc;
+ border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+ border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
+ border-bottom-color: #b3b3b3;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
+}
+#ip-geo-block-live-log li input[type=radio]:checked + label {
+ background-image: none;
+ outline: 0;
+ -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
+ box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
+ background-color: #e0e0e0;
+}
+
+/*----------------------------------------------------------------------
+ * Timer animation based on https://codepen.io/paulobrien/pen/joptI
+ *----------------------------------------------------------------------*/
+.ip-geo-block-live-timer {
+ height: 1em;
+ width: 1em;
+ margin: 0;
+ position: relative;
+ top: 0;
+ left: 0;
+}
+.ip-geo-block-live-timer:before {
+ content: "";
+ display: block;
+ height: 1em;
+ width: 1em;
+ background: #0073aa;
+ border-radius: 50%;
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.ip-geo-block-live-timer:after {
+ display: none
+}
+.ip-geo-block-live-timer > div {
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ clip: rect(0, 1em, 1em, .5em);
+}
+.ip-geo-block-live-timer > div:before {
+ content: " ";
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ border-radius: .5em;
+ clip: rect(0, .5em, 1em, 0);
+ background-color: #f1f1f1;
+ transform: rotate(0deg);
+}
+.ip-geo-block-live-timer > div:first-child:before {
+ animation: 30s spin-timer linear forwards;
+}
+.ip-geo-block-live-timer > div:last-child {
+ transform: rotate(180deg);
+}
+.ip-geo-block-live-timer > div:last-child:before {
+ /* older webkit seems buggy with zero so use 0.00001 if you notice something strange */
+ transform: rotate(0deg);
+ animation: 30s spin-timer linear 30s forwards;
+}
+@keyframes spin-timer {
+ 0% {transform: rotate( 0deg);}
+ 100% {transform: rotate(180deg);}
+}
+
+/* sub items in settings */
+.ip-geo-block-subitem {
+ margin-left: 1.7em
+}
+.ip-geo-block-subitem:before {
+ content: "\00bb"; /* » */
+ position: absolute;
+ left: 2em;
+}
+.ip-geo-block-subitem dfn {
+ vertical-align: middle;
+}
+.ip-geo-block-subitem-parent th,
+.ip-geo-block-subitem-parent td {
+ padding-top: 0;
+}
+
+/* placeholder */
+:placeholder-shown { color: #888; }
+::-webkit-input-placeholder { color: #888; } /* Google Chrome, Safari, Opera 15+, Android, iOS */
+:-moz-placeholder { color: #888; opacity: 1; } /* Firefox 18- */
+::-moz-placeholder { color: #888; opacity: 1; } /* Firefox 19+ */
+:-ms-input-placeholder { color: #888; } /* IE 10+ */
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin.min.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin.min.css
new file mode 100644
index 00000000..50795951
--- /dev/null
+++ b/wp/wp-content/plugins/ip-geo-block/admin/css/admin.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Project: WordPress IP Geo Block
+ * Copyright (c) 2013-2019 tokkonopapa (tokkonopapa@yahoo.com)
+ * This software is released under the MIT License.
+ */
+dfn{cursor:help;border-bottom:1px dotted #888}fieldset,legend{padding:0;margin:0;border:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}fieldset{min-width:0}legend{display:block;line-height:inherit;width:100%}label{display:inline-block;max-width:100%}.panel{border-color:#888;border:1px solid #e5e5e5;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.04);-moz-box-shadow:0 1px 1px rgba(0,0,0,.04);box-shadow:0 1px 1px rgba(0,0,0,.04);background:#f5f5f5}.panel-heading{float:left!important;background:#fff}.panel-default>.panel-heading{border-color:inherit}.panel-body{width:100%;padding:0 1em;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.panel-body:after,.panel-body:before{content:" ";display:table}.panel-body:after{clear:both}.ip-geo-block-navi-link{text-align:left}.ip-geo-block-help-link{float:right;font-size:90%;font-weight:400}.ip-geo-block-help-link a{box-shadow:none}fieldset label{vertical-align:text-middle}fieldset input[type=checkbox]{margin:1px 2px 0}fieldset.ip-geo-block-field{margin:1em 0}fieldset.ip-geo-block-field h2,fieldset.ip-geo-block-field h3{padding:0;margin:0;font-size:14px!important}fieldset.ip-geo-block-field h4{margin:.75em 0 .5em 0}fieldset.ip-geo-block-field legend.panel-heading{padding:10px}fieldset.ip-geo-block-field .ip-geo-block-dropdown,fieldset.ip-geo-block-field .ip-geo-block-dropup{cursor:pointer;position:relative;padding-left:1em}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before,fieldset.ip-geo-block-field .ip-geo-block-dropup:before{content:'';height:0;width:0;border:.4em solid transparent;position:absolute}fieldset.ip-geo-block-field .ip-geo-block-dropup:before{border-left:.4em solid #555;left:2px;top:18%}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before{border-top:.4em solid #555;left:-2px;top:38%}fieldset.ip-geo-block-field .form-table .ip-geo-block-dropdown,fieldset.ip-geo-block-field .form-table .ip-geo-block-dropup{margin-top:.75em}fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before{top:.25em}fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before{top:.5em}fieldset.ip-geo-block-field table.form-table{margin:0 0 .5em;width:100%}textarea.regular-text{width:25em}fieldset.ip-geo-block-field input.regular-text,fieldset.ip-geo-block-field textarea.regular-text{font-size:95%}fieldset.ip-geo-block-field input[type=checkbox],fieldset.ip-geo-block-field input[type=radio],p.ip-geo-block-navi-link input[type=checkbox]{margin-right:.4em}input[id*=ip_geo_block_settings_rewrite_]+label{margin-left:.25em}input[id*=ip_geo_block_settings_providers]+label{min-width:7em}.ip-geo-block-settings-folding{margin:.5em 0}.ip-geo-block-settings-folding ul{margin-bottom:0}.ip-geo-block-settings-folding li{margin:.5em 0}.folding-disable{pointer-events:none;opacity:.5}.folding-inactive{opacity:.5;font-style:oblique!important}.ip-geo-block-float li{display:inline-block;width:18em;margin-top:0}.ip-geo-block-checked{list-style-type:disc}.ip-geo-block-ip-addr{display:inline-block;padding-top:5px}.ip-geo-block-hide{display:none}.ip-geo-block-sup{margin-left:.2em;display:inline-block}.ip-geo-block-note{margin-top:1em;list-style:disc inside}.ip-geo-block-note li{text-indent:-1em;padding-left:1em}.ip-geo-block-border{border-top:inherit}.ip-geo-block-notice{color:#dd3d36}.ip-geo-block-title{width:100px;display:inline-block}.ip-geo-block-result{color:#2786c2;display:inline-block}.ip-geo-block-primary{color:#fff!important;background:#00838f!important;border-color:#00707a!important;text-shadow:none}.ip-geo-block-primary:hover{background-color:#00919e!important;border-color:#00525a!important}ul#ip-geo-block-logs-preset{margin:.25em 0;max-width:600px}ul#ip-geo-block-logs-preset li{float:left;line-height:1.5em;margin-right:1em;min-width:160px}#ip-geo-block-live-loading,.ip-geo-block-loading{height:16px;width:16px;background-size:16px 16px;background-position:center center;background-repeat:no-repeat;margin-left:1em;margin-top:.2em;display:inline-block;vertical-align:top}.ip-geo-block-loading{background-image:url(data:image/gif;base64,R0lGODlhEAAQAPYCAKqqqsbGxlZWVsrKyvr6+ubm5tDQ0K6urmZmZmJiYuzs7IaGhvT09JycnLq6us7Ozurq6o6OjtbW1tra2vDw8CgoKCYmJvz8/NLS0kJCQlJSUqysrPLy8vb29pqamra2tm5ubujo6Kampvj4+IiIiMjIyEhISNzc3OLi4rKysj4+PlBQULi4uJKSkmRkZODg4KKiou7u7iQkJB4eHlpaWhISErCwsHh4eMDAwDIyMi4uLqSkpIKCgr6+vt7e3n5+fggICJCQkAwMDEpKSmBgYHZ2dhgYGBYWFnx8fF5eXk5OTiIiIjAwMIyMjISEhDQ0NJaWltTU1AQEBBwcHGpqaoqKiuTk5CoqKlhYWAoKCtjY2Hp6ehAQEJ6ensLCwkxMTJSUlCwsLAYGBnR0dDg4OFxcXLy8vKCgoA4ODsTExMzMzDw8PERERDY2NqioqHJycrS0tGhoaBQUFEZGRjo6OkBAQICAgHBwcFRUVCAgIGxsbP///wAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgACACwAAAAAEAAQAEAHjIACgoOEhYJsbTGGghcPGIJRbFNNhgQKCheDDkllDQYMHSc4MAcvhTB0aFliggQjmYNEFQ6LAh0+VoIwbFW1GGamhCgfUE5NbgMKtQYLc0a1gjsyR3E2IYwMFASDYDJvtRRWFIJ1TMq1ElqCICpetQoBEoInVCsAhhI2XhyEPUgIIG7waALlwAloCAMBACH5BAkKAAIALAEAAQAOAA4AAAeDgAKCEmBYYRVKJAaCjAcrVzIzRjVoTw2MKRk5Ww4KECkuWTWCE0Rrl4yCTow7bAupsBcCW19psKkjBEQaFLeMHBwINBy+ggoxVQkPxSMFMXBUMMUQPhRWVUU9tyFRLwQCA048cCcjIyFaJQYxjA8NEVBnAClmahCwEANwbjYBJwyMAgEAIfkECQoABQAsAQABAA4ADgAAB4OABYInO29DbC5QUYKMZiBfbCptTBUmIow4LgJBaTExZkVLFTAFKD8JB4yMQUZrBixUXaqqVFwkUG8Ys4wpQiZOWwy7ghBiRk08HcOqblUTy4wlLWbLBCMFCgBdurMjFMoFE24ADxAXFwwKITEEjD5mH2YBDxI+IdeqHCcGAxgv7IwCAQAh+QQJCgAAACwBAAEADgAOAAAHhYAAglYfTVQJSCITgowDVSAISQJKJgkpjA8LWyIGHBQBJCoZBwAQDU44jIxdTxoSAxEfqqpbFWApUCezjA5LWCJdI7uCClNXGyLCwxBHFl4HBcMAKVxfEx8Y0glZCxwlOCjDUkwPACElAygMghftAB6MClpRJygQFB0EuyMKBQUKDPQxCgQAIfkECQoAAAAsAQABAA4ADgAAB4SAAIIKahstTQ0OVoKMJzYeLVU8W29OXowvBztePh0dUTtxVD0AHDgHEoyMKWVvPj4sBqqqLUoiGDgQs4wBJmNqARe7gjEqXxgPwsMxbWw+UQzDAGY6LjEnusNjFmAEBVbRs00zc1EAHRAKHYw2CHIyO4wEHAwjgmJCZDC7F8psC7IEBQIAIfkECQoARwAsAQABAA4ADgAAB4OAR4IMPgMfNg4PCoKMEA84LCkAMB47GIwxBiUTEAQjKD0REQ9HBD4YIYyMATwtBRQnqaqMG0UOEC8ds4wYIEEQBbuMHC4gMYvCRxw0CAwcF8kBGj8EHdDCJCYiRxfXsw0qCROqRDYQECw3ORkpqjpAQjVGMxYrB7MPC0MyFQItEowCAQAh+QQJCgACACwBAAEADgAOAAAHgIACghcUVhIYEigMgowjEC8nUQ8BOGkojAQxITEdAhcxEh9wPoIMFCOMjBMAKTEXHaipjGldDxcEsqkvUAe5sh1NLb6pHTxNbGK9vlE3DU5ZLsNnIA4GbTVVuQcJdpdnS0Z3LAoxXhF4LjiMMBl5FjptKiZ6ZrJRLUkqbCAwJ4yBACH5BAUKAAEALAEAAQAOAA4AAAd/gAGCARcjHDExHASDjAQdHAoFLy8Ugw2MgiMKWhIKAQ9MYpiCEA8YHQtZCaOCJ14vX2g2rAEKZgMyNRC0BCksFUa7rCMANgIzH7QvZw4tMmO0DlAPUV9hHqNeVTC7G2tkTmkUHA8iSFUGgzZlGSYaNC4gTWqYEzA3SQhVH1aDgQA7)}#ip-geo-block-map{height:400px;margin:1em auto}#ip-geo-block-apis div.nav-tab-wrapper{padding-top:0;margin-bottom:1em}#ip-geo-block-geoinfo{white-space:normal;word-wrap:break-word;word-break:break-all}#ip-geo-block-geoinfo ul{margin-top:0;margin-left:1em}.gm-style-iw{width:18em;height:auto!important;height:100%;min-height:100%:}.gm-style-iw ul{margin:.1em}.gm-style-iw li{margin:.2em}svg a{cursor:pointer}svg a:hover>text{fill:#0096dd}svg a>text{fill:#0073aa;text-decoration:underline}table.ip-geo-block-statistics-table{float:right}table.ip-geo-block-statistics-table td,table.ip-geo-block-statistics-table th{width:12em;margin:0;padding:.2em;text-align:right;line-height:1.5em;word-wrap:break-word}table.ip-geo-block-statistics-table tr:nth-child(even){background-color:#eee}table.ip-geo-block-table{margin:1em 0;width:100%;white-space:normal;word-wrap:break-word;word-break:break-all}table.ip-geo-block-table td:first-child{min-width:4.3em;max-width:5em}@media screen and (max-width:782px){#ip-geo-block-whois .panel-body{padding:0 .5em}}#ip-geo-block-scan-code{vertical-align:middle}#ip-geo-block-code-list{display:none;margin-bottom:0}#ip-geo-block-chart-countries{height:200px}#ip-geo-block-chart-daily{height:240px}#ip_geo_block_settings_validation_mimetype+label{padding-top:.25em}#ip_geo_block_settings_validation_mimetype+label+ul{margin-top:.7em}#ip_geo_block_settings_create_user{margin-bottom:.5em}#ip-geo-block-back-to-top a,#ip-geo-block-toggle-sections{box-shadow:none}#ip-geo-block-wp-info textarea{margin-top:.5em;overflow:auto;width:100%;word-wrap:normal;word-break:normal;white-space:pre}#ip-geo-block-back-to-top{margin:0;text-align:right}#ip-geo-block-live-update,#ip-geo-block-open-new{margin-left:1em}.ip-geo-block-menu-link{font-size:13px!important}dfn~.ip-geo-block-icon{margin-left:.4em}.ip-geo-block-icon{position:relative;cursor:pointer;outline:0;box-shadow:none;text-decoration:none;background-color:transparent}.ip-geo-block-icon:active{top:1px}.ip-geo-block-icon span{height:16px;width:16px;margin:0;border:none;display:inline-block;vertical-align:middle;background-size:16px 16px;background-position:center center;background-repeat:no-repeat}.ip-geo-block-icon-cycle span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAh1BMVEUAda2otLp+rsSHprWHr8IBd7EpfKRGhaNajqeUqrRymKuKoq5yo7prlKgAcqoVe6w8gqQmgq5Tj6wIdqsVdKIshrEMea1Uhp+Anqw0hawDdq4gfKhljqE7hqoLdKYbgbM4jLQygKUGeK8CdawQd6gVeKcad6NKkrSerrZAj7UAc6sAc6rc3NySrVGQAAAALXRSTlP//////////////////////////////////////////////////////////wCl7wv9AAACOklEQVR4Ae2W15rzKgxF9xTZzhTX9B7S/gN6/9ebYqzzGZsw/S7LV3FZgCSIwD/kQ8FVcBU8xatZUczy8luC/ABNOn0DSHEsvyZ4PgLatNCYR3efFxyhTQ8g+qQgJxgv2JefERzJXATRh4LHOUwAHD4S7OGEztRJaN86hAUxtaNWDUf/bRdDBbQMWVDAO8jn89WUhag1MeyCAh6hHofyrliLgZKggDMYgzF3eVAwFq0uCZq5KY0TezjIHDDzC0qqmkwe2ctGDOQVLMkgu+F3/rGXwb4xIPcJ6P3JgkM8wFjmfcFAWfeKQywaAz33BJVuHsUcAt09gVbuLDThAJkdR687ggLmf4gDJLIGV7BydtB8yn3u+fbtuj/LS7G9wZAd1AKK+yxJ1x+aBmibTtgCcEHGHsh0wdbOgNLek4L7lI5BigY8nWuZUQ3qGEXes9JzOKGJztPaGtLslu3lIXJirdxCWkASHGDTMqg7V1DKPplygDG61YJukLHjEErGSXqCSos6xNSOgzP3BDmsQBcchNwkoV8oiNnPA78zIefUgCdJeGIfE7LmFWXsFTCFdzTJ/RlfEMRiSGnFXXbkC7AIeqcKDu4ynseozeouKJiSEYBDwkJyIC1nRUjgblkNWp/e/1vXc2gjoAoLksYgjrrFMi0oDgjEEIDij1scBXMJSH6DAj6RNl7o8MkuLak8Co15/Pk+MRmT0xilQJV/sdWNKg2kTaeroudvNNsDjmejYjSL+e6v2/2r4Cp4BXNajr0H7hRfAAAAAElFTkSuQmCC)}.ip-geo-block-icon-lock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3Ny3y9Zzq8dRmb7M1dlXnsIFdK0AcawAcqwphrYAcKvZ29wAb6oJd680jrqlw9MBcqxmo8MUfbJLl75eoMI7kbzX2ttqp8VSmL1YnL8NeK+Tu89DlL1ImMEOebBNmL4OkqMoAAAAAXRSTlMAQObYZgAAAPlJREFUeAG9kAWyhTAQBIPOsCzufv9TPnf4Ll0CSbpmxXwNy3Yc23rz2fV8kPA99433AIQIiGDTCD0lojiOQPXCDSFJIbF16CMWItkQMkF+inZzSLYhFKLl+a9UKTZaqJTZJYtarZuo40chrv9CqJTN+behVi+Cm7RdDgRld6AMgLxrE/dxBz0BEjwBEmD/uIsWPAOAF9A+CE56ufSryr8oqfOYcBbQJ8YkES7COkFOYzTypqCDOTDo2wljaEw4vp1APYyWKd8WMBozylvCpcvmXeHQ5fCegHia4s1FgZcIVeVFeFx1M4MvYG4eBHdYWufC+addBtf8E3vdjBNhWnVQqAAAAABJRU5ErkJggg==)}.ip-geo-block-icon-unlock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC)}.ip-geo-block-icon-find span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NzS19rD0NWHtMpGk7kYfbAGda0Req+WtcTT1temwM4AcasAcqwAc6wAcKydvMt1pr8Ab6pqpcLX2doggrKoxdNYm7yzw8u/y9HO1tkKdq4th7Td3t6DrcLL0taxyNPGe/YhAAAAAXRSTlMAQObYZgAAARVJREFUeAGtkkeiwyAMRP2xDfxoRjElvd3/lOkNUlZ5u0GPruan/Bnz96Xadr21rvP/7+ujXsAjom78rj4ApCoERIipqfGB1H7wPmYhw1DXjZI6nOel1oJhVAmdUP0tTEDkVC4AYvqIbaDOCqFV6vwRF0tIeYoo6J/X7ICuPAJl9ZynwiIfB5DXxZlRChulbh8xZci0EHZK3TziJFDL504rEOZ+iR5cVj82DoS7XtSshLJpKqaB0Dg3ZjcsQWKaKiF1gVQlITwh/bw2pgKeEeURhE29yKSzUFF03p1V7Wqj2Y7GfrY9X/NirJsPxKsxfBLSSs5GmH8yjAWPSNd8Yoez4f4/G1nIsksqFtGK1i9e39o0P+EAqaoRLlQ+r94AAAAASUVORK5CYII=)}.ip-geo-block-icon-alert span,span.ip-geo-block-icon-alert{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAkFBMVEXc3Nzc2trWl5DHRDTFOyvOgXfc1tXCLBrEMiHEMyLNcmfaxMLDMSDDLx7bu7jRiYHDLhzDMB/LX1PaxsTDLh3YtrHMY1bWmpPJVknSjYXUkYnZuLTMZVnENCPWlI3QhXzENiXXrqrDLRzXsa3Oal7Pe3Hc2NjVn5nNbmPayMbbwb7ay8rUj4fc09Lbw8Db0dDBbRUDAAAAAXRSTlMAQObYZgAAAPVJREFUeAG9ktXWwyAQBonC12brFvff5f2frr4nBredK2DnTFS8Gst2XM8XZmypIGeWcT4PFABaGIXlClfWG1NiC4Ubu705oKRcY32wTAHl2MdTYEqEK8hIiHgHSnSJeaogMyEWO4BijZCvwII2MS9UJ2BXTh+hQidoEttboBOwq3WBnkCNpQlA2iyAhol2hRu71n97p4fw0Z9/ugoPHCfFA+o/iLfCkyBglRJdICBas7uuey+R56fF14wNanj+/QjwY3aX23cBFn6EiHmHNT/ICYxystv/wJy4UHWGlN2cuPB72tFqAq3dP/Hk3zs0E5LZVryGC/hqGNnUa0SVAAAAAElFTkSuQmCC);vertical-align:bottom}table.form-table th .ip-geo-block-cycle span{vertical-align:text-bottom}.ip-geo-block-list{margin-top:0;margin-bottom:.7em}@media screen and (min-width:782px){ul.ip-geo-block-list .code{width:15em}}.ip-geo-block-list-exceptions label{display:inline-block}.ip-geo-block-list-exceptions dfn{border:none}.ip-geo-block-list-exceptions span.dashicons{font-size:14px}.ip-geo-block-list-exceptions a.ip-geo-block-icon{margin-left:.3em;outline:0;box-shadow:none;text-decoration:none;background-color:transparent}.form-table td p.ip-geo-block-desc,.form-table td p.ip-geo-block-find-desc{color:#666;font-size:13px!important;margin:4px 0 .5em .5em}.ip-geo-block-find-desc{display:none}.ip-geo-block-admin-post{color:#c43322;margin-left:.25em}.ip-geo-block-warn{color:#c43322;font-weight:700}input#ip_geo_block_settings_behavior_time,input#ip_geo_block_settings_behavior_view{width:3.5em}.ip-geo-block-top-list{display:inline-table;list-style-position:outside;margin:0 2em .5em 1.75em}.ip-geo-block-top-list h4{margin:1em 0}.ip-geo-block-top-list li code{background:0 0}.ip-geo-block-network{margin-bottom:1em}.ip-geo-block-container{margin:0 auto;padding:0 1em;position:relative;width:100%}.ip-geo-block-row{display:flex;flex-direction:column;align-items:flex-start;align-items:stretch;padding:0;width:100%}.ip-geo-block-row .ip-geo-block-column{display:block;flex:1 1 auto;align-self:flex-start;margin-left:0;max-width:100%;width:100%}.ip-geo-block-row .ip-geo-block-column.column-20{flex:0 0 20%;max-width:20%}.ip-geo-block-row .ip-geo-block-column.column-25{flex:0 0 25%;max-width:25%}.ip-geo-block-row .ip-geo-block-column.column-33{flex:0 0 33.3333%;max-width:33.3333%}.ip-geo-block-row .ip-geo-block-column.column-50{flex:0 0 50%;max-width:50%}@media (min-width:40rem){.ip-geo-block-row{flex-direction:row;margin-left:-2em;width:calc(100% + 2em)}.ip-geo-block-row .ip-geo-block-column{margin-bottom:inherit;padding:0 1em}}table.ip-geo-block-dataTable{clear:none!important}table.ip-geo-block-dataTable td,table.ip-geo-block-dataTable th{text-align:right}table.ip-geo-block-dataTable td:nth-child(n+2),table.ip-geo-block-dataTable th:nth-child(n+2){padding-left:0!important}table.ip-geo-block-dataTable th{white-space:nowrap}table.ip-geo-block-dataTable>thead>tr{line-height:1.8em}table.ip-geo-block-dataTable>tbody>tr{cursor:pointer}table.ip-geo-block-dataTable.no-footer,table.ip-geo-block-dataTable>thead>tr>td,table.ip-geo-block-dataTable>thead>tr>th{border-bottom:1px solid #ddd}table.ip-geo-block-dataTable thead td,table.ip-geo-block-dataTable thead th{padding:10px 16px}#ip-geo-block-statistics-cache td:nth-child(3),#ip-geo-block-validation-logs td:nth-child(4){min-width:1.6em}div[class*=ip-geo-block] .dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #ddd}table.ip-geo-block-dataTable.nowrap td,table.ip-geo-block-dataTable>tbody>tr>td span{white-space:normal!important;word-wrap:break-word!important;word-break:break-all!important}table.ip-geo-block-dataTable>tbody>tr>td span{display:inline-block}.ip-geo-block-settings-folding input[type=checkbox]{margin-right:.5em}table.ip-geo-block-dataTable input[type=checkbox]{margin:0;max-height:16px;max-width:16px;vertical-align:middle}table.ip-geo-block-dataTable>tbody>tr>td:first-child,table.ip-geo-block-dataTable>thead>tr>th:first-child{padding:8px 4px 8px 1.4em;text-align:left}table.collapsed>tbody>tr>td.dataTables_empty:first-child::before,table.ip-geo-block-dataTable>tbody>tr>td.dataTables_empty{border:none;text-align:center}table.ip-geo-block-dataTable thead>tr>th:first-child.sorting_asc{background-image:none!important}table.ip-geo-block-dataTable.display tbody tr.even>.sorting_1,table.ip-geo-block-dataTable.display tbody tr.odd>.sorting_1,table.ip-geo-block-dataTable.display tbody tr:hover>.sorting_1{background-color:inherit!important}table.ip-geo-block-dataTable.collapsed>tbody>tr>td:first-child{padding:8px 4px 8px 8px!important}table.collapsed>tbody>tr.parent>td:first-child::before,table.collapsed>tbody>tr>td:first-child::before{content:'';height:0;width:0;display:inline-block;border-radius:0;border:5px solid transparent;box-shadow:none;position:relative;background-color:transparent}table.collapsed>tbody>tr>td:first-child::before{border-left:5px solid #555;top:1px;left:-2px}table.collapsed>tbody>tr.parent>td:first-child::before{border-top:5px solid #555;top:4px;left:-4px}table.collapsed>tbody>tr.child>td:first-child::before{border:none}table.collapsed>tbody>tr.child>td.child>ul li{border:none;padding:0;margin:0;line-height:1.8em}table.collapsed>tbody>tr.child>td.child>ul li span.dtr-data,table.collapsed>tbody>tr.child>td.child>ul li span.dtr-title{font-size:13px!important;display:block;white-space:normal;word-wrap:break-word;word-break:break-all}table.collapsed>tbody>tr.child>td.child>ul li span.dtr-data{margin-left:1.25em;margin-right:.3em}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length{padding-top:.15em;margin:.5em 0 0 .3em;position:relative;display:inline-block}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length:after{content:'';width:6px;height:6px;border:0;border-bottom:solid 2px #999;border-right:solid 2px #999;-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg);position:absolute;top:50%;right:10px;margin-top:-4px}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length select{padding-top:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-size:13px!important;line-height:1.4em;width:100%;height:2.05em!important;background:0 0;position:relative;z-index:1;padding:.125em 1.5em .125em .25em;border:1px solid #ddd;border-radius:4px;box-shadow:none}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length select::-ms-expand{display:none}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate{float:none;text-align:center;margin-bottom:1em;margin-top:0!important}@media screen and (min-width:640px){div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length{margin:.5em 0 0 .6em}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate{position:relative;left:-2.25em}}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate span.ellipsis{min-width:2em;background:inherit;border-color:#ddd;border-radius:0;border-image:none;border-style:solid;border-width:1px 1px 1px 0;box-shadow:none;margin:.5em 0 0 0;padding:.25em 0;display:inline-block;text-decoration:none}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:active>a.paginate_button:first-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:hover>a.paginate_button:first-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate>a.paginate_button:first-child{border-left-width:1px;border-bottom-left-radius:4px;border-top-left-radius:4px}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:active>a.paginate_button:last-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:hover>a.paginate_button:last-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate>a.paginate_button:last-child{border-bottom-right-radius:4px;border-top-right-radius:4px}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button{color:#0073aa!important}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover{color:#0096dd!important;background-color:#fff}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate span.ellipsis{cursor:default;color:#999!important;background-color:transparent}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover{cursor:default;color:#444!important;background-color:#fff!important}#ip-geo-block-1 #ip-geo-block-section-2 .panel-body,#ip-geo-block-4 #ip-geo-block-section-0 .panel-body{padding:0}#ip-geo-block-1 #ip-geo-block-section-2 table.form-table,#ip-geo-block-4 #ip-geo-block-section-0 table.form-table{margin-left:1em;max-width:95%}#ip-geo-block-select-duration,#ip-geo-block-select-layout,#ip-geo-block-select-target{margin:0}#ip-geo-block-select-duration li,#ip-geo-block-select-layout li,#ip-geo-block-select-target li{float:left;margin-right:1.5em}#ip-geo-block-select-duration li label,#ip-geo-block-select-target li label{cursor:pointer}#ip_geo_block_settings_search_filter{width:16em;padding-top:3px}table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-passed{background-color:#edf6ff!important}table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-blocked{background-color:#ffefef!important}.ip-geo-block-new-passed{animation:ip-geo-block-flash-passed 1s ease-out 0s 1 normal both running}.ip-geo-block-new-blocked{animation:ip-geo-block-flash-blocked 1s ease-out 0s 1 normal both running}@keyframes ip-geo-block-flash-passed{0%{background-color:gold}100%{background-color:#edf6ff}}@keyframes ip-geo-block-flash-blocked{0%{background-color:gold}100%{background-color:#ffefef}}mark{padding:0;background:gold}// Gold #ip-geo-block-live-log{margin:0}#ip-geo-block-live-log li{float:left;margin-right:3em}#ip-geo-block-live-log li:last-child{margin-right:0}#ip-geo-block-live-log li input[type=radio]{visibility:hidden;position:absolute}#ip-geo-block-live-log li input[type=radio]+label{display:inline-block;margin:-2px;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);border-bottom-color:#b3b3b3;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}#ip-geo-block-live-log li input[type=radio]:checked+label{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);background-color:#e0e0e0}.ip-geo-block-live-timer{height:1em;width:1em;margin:0;position:relative;top:0;left:0}.ip-geo-block-live-timer:before{content:"";display:block;height:1em;width:1em;background:#0073aa;border-radius:50%;position:absolute;top:0;left:0}.ip-geo-block-live-timer:after{display:none}.ip-geo-block-live-timer>div{position:absolute;width:1em;height:1em;clip:rect(0,1em,1em,.5em)}.ip-geo-block-live-timer>div:before{content:" ";position:absolute;width:1em;height:1em;border-radius:.5em;clip:rect(0,.5em,1em,0);background-color:#f1f1f1;transform:rotate(0)}.ip-geo-block-live-timer>div:first-child:before{animation:30s spin-timer linear forwards}.ip-geo-block-live-timer>div:last-child{transform:rotate(180deg)}.ip-geo-block-live-timer>div:last-child:before{transform:rotate(0);animation:30s spin-timer linear 30s forwards}@keyframes spin-timer{0%{transform:rotate(0)}100%{transform:rotate(180deg)}}.ip-geo-block-subitem{margin-left:1.7em}.ip-geo-block-subitem:before{content:"\00bb";position:absolute;left:2em}.ip-geo-block-subitem dfn{vertical-align:middle}.ip-geo-block-subitem-parent td,.ip-geo-block-subitem-parent th{padding-top:0}:placeholder-shown{color:#888}::-webkit-input-placeholder{color:#888}:-moz-placeholder{color:#888;opacity:1}::-moz-placeholder{color:#888;opacity:1}:-ms-input-placeholder{color:#888}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/cidr.min.css b/wp/wp-content/plugins/ip-geo-block/admin/css/cidr.min.css
new file mode 100644
index 00000000..09539b5c
--- /dev/null
+++ b/wp/wp-content/plugins/ip-geo-block/admin/css/cidr.min.css
@@ -0,0 +1 @@
+*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:8xp;font-size:14px;line-height:1.4}.container{margin:0;padding:0}.clr:after,.col:after,.container:after,.row:after{content:"";display:table;clear:both}.row{padding-bottom:0}.col{display:block;float:left;width:100%}.span_2{width:8.33333333333%}.span_11{width:45.8333333333%}.span_24{width:100%}fieldset{border:none;margin:0;padding:.5rem}textarea{width:100%;height:4.5rem;resize:horizontal;border:1px solid #ccc;font-size:12px;font-family:Consolas,Monaco,monospace}legend input[type=button]{margin-left:.5rem;vertical-align:middle}#j,#i{display:-ms-flexbox;display:-webkit-box;display:-webkit-flex;display:flex;justify-content:center;align-items:center}#j{padding:0 .5rem}ul#h{padding:1.5rem 0 0;list-style:none}ul#h li{width:100%;margin:.1rem 0;display:inline-block}ul#h li input{padding:0}#g{height:3em;text-align:center;border:1px solid #ccc;padding:.5rem;font-size:12px;font-family:Consolas,Monaco,monospace}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/fonts/icomoon.eot b/wp/wp-content/plugins/ip-geo-block/admin/css/fonts/icomoon.eot
new file mode 100644
index 0000000000000000000000000000000000000000..ae697d386406c8c68cb2091c84ee3b4caeda3562
GIT binary patch
literal 3988
zcmbtXU2Gd!6+YMF8OL_x*dE)HIF9j*xaze#&YwbBLB!?I9Wk?cv?CfTp)J=5v**V4brh|Va@cqU_e#vhsTOl#(v z%yaSt`6&59`7uR|qD(PE@tKmVEKokF{7`v4D>KWUwJz(IUMaoC^m?<`+3cijI(vEc zshs#6P0o^>##~YEsNBW5jlDbf*7RQ5`($31JYC+3yfgXT^GD~um4Bf?TwpC&UvO2G zrFvYoRn1oSQBPCvD~u`}TsXh*`=a=w+M?A(7yD%Nd9=^gVs3H2;unjLm2@c4maHnd z*jL{7@xD9z3Hw#_o8Rwb{~rCV{Wq7gO8b_+RC;_s*8!#h8wa9+B?Dg?_+432+1RoV z2Jr@!4O%ehhjK~zW97RlqANyLyjgLjvY>Ki<+p>o4R#FPJ|uj|h#{+nTpg+&I%{a- zu(V;15Bp+x+u{1*o2vL#L#kF(U4E$Wp_d;zJtAYo)DcG?PI|cE;oXn4eZ=s{M&sbAKm^~=f@^JcH;5;$Co@oJyHF{_9weMIpxXI6Z=ejW0GLfm`Qsl zizm;T{QFZwpV~a7!<30rPCeb{>D5!irdp>Sd#2Yji=O2?tABRibF$~=J$GxGZrbP5 z#nb0ZZzc}?@{<{w#5uwd=N_6wg|c=c7?tA}38 zdu`344vVHQy0KWl_^Ty-mTXv>xOC1k-m-Daepo(a`L5R$udiCscE$7+f2=gEY<#2q zjh(CHt5&_){>_=IS*snZ&%HI`tpk5o|9#V%lr>A%#;u+HHhSCf_K)w3dgti6e(Scs zt9W OyMABhz76~3`!^j>9@u;^`{2iidLP>MrTWWH50@PN z;>ds_2agUu`qi-!#~Q!VeRcM0!`HulGwz$4-%dQvJwENbi0|fn-~Rih|LFdYwT+pL zADvL2*mJVt Bn>iliSr8bvV{+|B(_RD3LzrSLz3LF J6o2mN4AYC^l4%!{zaVf(0Q|OCqdn zvE9T7L~$rKi^Jmbc|lyZPzJ yH2TPGh> z@w?8dxOn1Mtt}&N>AI&9)h|`*3b!w_XSO;t_$2+?yHj?2={R+%C~5Zcr{8;d=iz_; z{`&e)j-0+cq-NaIIV(1Ndh~}Y@;*ar>z{dL<;Gpd&RmT|EEbfOL(0VGaWhB}I!mHB zP=c}X(Ol`I7h`Y %Z;t1XrYhP2s ztdj1|1D6NKJ>K#7qGh{!p0>}bxLn@vbmgoH=hwssJA=<4SkZwt!L1RF@{taiQ8g^^ zh+yJd2e2K2jX)OQi2f4}5mKQFnA&2eCOO0dh^W-kQq%*0AjGGl$hs0VG~nC9ycn}0 zR86(>z@w>dE*@}tN&@fN2(^b`rKAMLJ?Z&p^kjtz%Pxm-012ADK?qh0UH5x@kqqI_ zjAe->SrWNO?D|d^s6gz+RCC!Dvpo8v7qgpT%m^2cf+;WDDOd&Yst47vxgJ!acRg5? zTL+cOYSvAZK?FUU*n!-!<-!+ZQqU-)8Nb`R^1>)sdw~Gzyf04*13GUCz=Vj`Eis $2{(pe4OO#ZG{aQtsSpL<1{L@+f}|gm=A3Ya%k{~hDTdeU=X?Y z6Ub=R$7=FPm+O4#l~$9@z1SV1(dkNEpK)~K1bEHAoYpzCw7VRUcrDCYiAxTvQg*A^ z;8Uo`=8CzuP zHNYC5&Rtuf$y}
-8)ts3J{n(R_|@1^|*%0cEDOK|y6iV-$h;NINZIj)^R z>;Qb&&%qy1^i+UIF2#Z<$Y@K4-2%iRxMc))&8RWyOUjGNA$1<(^G#|zUhIL;oP+mX zBg!wTaJL*$QDiMK-Er^FEkzs?xX8X={*S8?uox(D_dnkqL$?%eP*h~|*&2krt?r#j zOa^+9)txu4vRiw9mB+h)3)ib0{2Ra^EQK#(gXIKlZ>+Jx&IuVGyz1;4OHue)7zPeI zZxUW6!lP+4o}|Hj072p1eGKC oPb@xO}Z42v7m+^=r`>R0}K6X5@f9e;wf&uh#(`TaAm;T0=FiF9#P3r}d^9{1!{B ziqm6EW8B?_$-`!;@unNJ2E2RhW3QS9s|9e_MlCPA3y$9s@HTIl%QAflQ#`Q@ykSBr z9_Q?38L%w5?%Og#wYlCTqD^?*$JNF9T-L$w9zvuBo796%MC9KP8hA-E0Myb#d@T1M zEtDs9I)B@ La_OKQW1AEK>QKpX=O%)i%s-SL|MQ79DhlmUUi#Rl<;h_aP zx97r~Mu$O!s4X5GGY slJsCegLSRi7KabUa(u>JX#DAg}Z*|Y? zVD0*Teixkg^MhgVe?=Q=Afvt0S;ad+pdAQRVW3G2?Y#qlIe3s0H#sl0!vLD|DR zqISayHM#Ko5I<~N*zDR2-`^cLUb^P Wc!->AWwHKYd0TAcPzP Y=)!HkCK$=U231X{2~oTgP@Nq&5v<}={o$mV#5d6m7{_io(VQCqambK- Y16@Zf7?Q8!JB-NJ(KYBs*Ff|C0Zg4MIsgCw literal 0 HcmV?d00001 diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/favicon.ico b/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6eeaa2a0d393190ce748107222d9a026f992e4a7 GIT binary patch literal 894 zcmZQzU<5(|0R|u`!H~hsz#zuJz@P!dKp_SNAO?xUfG{@$0|>*we Y}F;x;`B~@Mg`jC-vo5%k$%{OoKy1zkdA+(K2o3 zEDKGQQ~gcX+N!Tt Ej1|9e2tL(rheJva*5dKY#gZsIRxM zB;!h7 5Wi?9l5?>z>S-`t`=OAFp5C?(007k>qM(bnVuyja#;c*qL9N z(Q%=@`f7d2?T&^wySIHjy#MKh?rZrO7i!Bt-@f(!@WDrwB`uD&)%Eqcd3o(gVV7ri zp6ji@(BF7(+uE0x&)(R!?s#YIg_7JW1=-KHZv1@s(DS xD9<^am-%+f#!uU}z9=j>5*%b{WE2`20#tutPWS1# zz4s39d~xOMwaqJzOl{rMU%#oo=xj&xyY1WF&71o?Hs-LOkA D^4SRbV?yXz(e#efNwKXpT1J^s+yE;1`KXoe5&f?1A$ tYso}un=1c3AzCL>B&D=RpqN3i1hL&lnclP!D`u*G0#bsJv!oAH) z-rc|T`^Wdkrw?7(xb)_p%`Y#WdAn`Pvz+W#0Rbo6-Ha3zp1gPgjDkZ)k6Gz!@9D0( zG^hL4?)Be4zWep#`{$>RUhUoaq@wgyfd9*oU{6tz+SXQhl3284sj;T&{L=I*bGxt4 z@4vfX%A<*$FN^a&MMa! gnPb zQo)$K!&zxT#Nl4)@@eaKRKFIxD0MA=SMcSM^3P$9Oy*ctFW>q)FZA%;zI(f$pBG-3 zcra-}mPXX3M|zCB?fv&MbDT3) >ro_ literal 0 HcmV?d00001 diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_both.png b/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_both.png new file mode 100644 index 0000000000000000000000000000000000000000..c4fbedfe341e57233f21936454bb4465217f6167 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRx!3HE}ruUu)Qs$m6jv*C{$vcXl^SRDQWBb$o zkkRmgz16bSjQ Ds1IQRZncrTx`1JHH`Pgg&ebxsLQ05eBP761SM literal 0 HcmV?d00001 diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_desc_disabled.png b/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_desc_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..498436626ea8e73fa160d8ffd341307486b78840 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRx!3HE}ruUu)Qo5cljv*C{$vcXl^SRD=#nvNb zkaeKmX~r}*0kf7D1_zeTT*qdxAbZ(r#xMRJ3?ZK_j;`e2{tKv)!PC{xWt~$(697L- BAHx6u literal 0 HcmV?d00001 diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/LICENSE b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/LICENSE new file mode 100644 index 00000000..605df390 --- /dev/null +++ b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016–2017 Julian Motz + +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/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.js b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.js new file mode 100644 index 00000000..4abce0bd --- /dev/null +++ b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.js @@ -0,0 +1,1255 @@ +/*! Responsive 2.1.1 + * 2014-2016 SpryMedia Ltd - datatables.net/license + */ + +/** + * @summary Responsive + * @description Responsive tables plug-in for DataTables + * @version 2.1.1 + * @file dataTables.responsive.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright 2014-2016 SpryMedia Ltd. + * + * This source file is free software, available under the following license: + * MIT license - https://datatables.net/license/mit + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + * + * For details please refer to: https://www.datatables.net + */ +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net')(root, $).$; + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +/** + * Responsive is a plug-in for the DataTables library that makes use of + * DataTables' ability to change the visibility of columns, changing the + * visibility of columns so the displayed columns fit into the table container. + * The end result is that complex tables will be dynamically adjusted to fit + * into the viewport, be it on a desktop, tablet or mobile browser. + * + * Responsive for DataTables has two modes of operation, which can used + * individually or combined: + * + * * Class name based control - columns assigned class names that match the + * breakpoint logic can be shown / hidden as required for each breakpoint. + * * Automatic control - columns are automatically hidden when there is no + * room left to display them. Columns removed from the right. + * + * In additional to column visibility control, Responsive also has built into + * options to use DataTables' child row display to show / hide the information + * from the table that has been hidden. There are also two modes of operation + * for this child row display: + * + * * Inline - when the control element that the user can use to show / hide + * child rows is displayed inside the first column of the table. + * * Column - where a whole column is dedicated to be the show / hide control. + * + * Initialisation of Responsive is performed by: + * + * * Adding the class `responsive` or `dt-responsive` to the table. In this case + * Responsive will automatically be initialised with the default configuration + * options when the DataTable is created. + * * Using the `responsive` option in the DataTables configuration options. This + * can also be used to specify the configuration options, or simply set to + * `true` to use the defaults. + * + * @class + * @param {object} settings DataTables settings object for the host table + * @param {object} [opts] Configuration options + * @requires jQuery 1.7+ + * @requires DataTables 1.10.3+ + * + * @example + * $('#example').DataTable( { + * responsive: true + * } ); + * } ); + */ +var Responsive = function ( settings, opts ) { + // Sanity check that we are using DataTables 1.10 or newer + if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) { + throw 'DataTables Responsive requires DataTables 1.10.3 or newer'; + } + + this.s = { + dt: new DataTable.Api( settings ), + columns: [], + current: [] + }; + + // Check if responsive has already been initialised on this table + if ( this.s.dt.settings()[0].responsive ) { + return; + } + + // details is an object, but for simplicity the user can give it as a string + // or a boolean + if ( opts && typeof opts.details === 'string' ) { + opts.details = { type: opts.details }; + } + else if ( opts && opts.details === false ) { + opts.details = { type: false }; + } + else if ( opts && opts.details === true ) { + opts.details = { type: 'inline' }; + } + + this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); + settings.responsive = this; + this._constructor(); +}; + +$.extend( Responsive.prototype, { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Constructor + */ + + /** + * Initialise the Responsive instance + * + * @private + */ + _constructor: function () + { + var that = this; + var dt = this.s.dt; + var dtPrivateSettings = dt.settings()[0]; + var oldWindowWidth = $(window).width(); + + dt.settings()[0]._responsive = this; + + // Use DataTables' throttle function to avoid processor thrashing on + // resize + $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { + // iOS has a bug whereby resize can fire when only scrolling + // See: https://stackoverflow.com/questions/8898412 + var width = $(window).width(); + + if ( width !== oldWindowWidth ) { + that._resize(); + oldWindowWidth = width; + } + } ) ); + + // DataTables doesn't currently trigger an event when a row is added, so + // we need to hook into its private API to enforce the hidden rows when + // new data is added + dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { + if ( $.inArray( false, that.s.current ) !== -1 ) { + $('>td, >th', tr).each( function ( i ) { + var idx = dt.column.index( 'toData', i ); + + if ( that.s.current[idx] === false ) { + $(this).css('display', 'none'); + } + } ); + } + } ); + + // Destroy event handler + dt.on( 'destroy.dtr', function () { + dt.off( '.dtr' ); + $( dt.table().body() ).off( '.dtr' ); + $(window).off( 'resize.dtr orientationchange.dtr' ); + + // Restore the columns that we've hidden + $.each( that.s.current, function ( i, val ) { + if ( val === false ) { + that._setColumnVis( i, true ); + } + } ); + } ); + + // Reorder the breakpoints array here in case they have been added out + // of order + this.c.breakpoints.sort( function (a, b) { + return a.width < b.width ? 1 : + a.width > b.width ? -1 : 0; + } ); + + this._classLogic(); + this._resizeAuto(); + + // Details handler + var details = this.c.details; + + if ( details.type !== false ) { + that._detailsInit(); + + // DataTables will trigger this event on every column it shows and + // hides individually + dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) { + that._classLogic(); + that._resizeAuto(); + that._resize(); + } ); + + // Redraw the details box on each draw which will happen if the data + // has changed. This is used until DataTables implements a native + // `updated` event for rows + dt.on( 'draw.dtr', function () { + that._redrawChildren(); + } ); + + $(dt.table().node()).addClass( 'dtr-'+details.type ); + } + + dt.on( 'column-reorder.dtr', function (e, settings, details) { + that._classLogic(); + that._resizeAuto(); + that._resize(); + } ); + + // Change in column sizes means we need to calc + dt.on( 'column-sizing.dtr', function () { + that._resizeAuto(); + that._resize(); + }); + + // On Ajax reload we want to reopen any child rows which are displayed + // by responsive + dt.on( 'preXhr.dtr', function () { + var rowIds = []; + dt.rows().every( function () { + if ( this.child.isShown() ) { + rowIds.push( this.id(true) ); + } + } ); + + dt.one( 'draw.dtr', function () { + dt.rows( rowIds ).every( function () { + that._detailsDisplay( this, false ); + } ); + } ); + }); + + dt.on( 'init.dtr', function (e, settings, details) { + that._resizeAuto(); + that._resize(); + + // If columns were hidden, then DataTables needs to adjust the + // column sizing + if ( $.inArray( false, that.s.current ) ) { + dt.columns.adjust(); + } + } ); + + // First pass - draw the table for the current viewport size + this._resize(); + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Private methods + */ + + /** + * Calculate the visibility for the columns in a table for a given + * breakpoint. The result is pre-determined based on the class logic if + * class names are used to control all columns, but the width of the table + * is also used if there are columns which are to be automatically shown + * and hidden. + * + * @param {string} breakpoint Breakpoint name to use for the calculation + * @return {array} Array of boolean values initiating the visibility of each + * column. + * @private + */ + _columnsVisiblity: function ( breakpoint ) + { + var dt = this.s.dt; + var columns = this.s.columns; + var i, ien; + + // Create an array that defines the column ordering based first on the + // column's priority, and secondly the column index. This allows the + // columns to be removed from the right if the priority matches + var order = columns + .map( function ( col, idx ) { + return { + columnIdx: idx, + priority: col.priority + }; + } ) + .sort( function ( a, b ) { + if ( a.priority !== b.priority ) { + return a.priority - b.priority; + } + return a.columnIdx - b.columnIdx; + } ); + + // Class logic - determine which columns are in this breakpoint based + // on the classes. If no class control (i.e. `auto`) then `-` is used + // to indicate this to the rest of the function + var display = $.map( columns, function ( col ) { + return col.auto && col.minWidth === null ? + false : + col.auto === true ? + '-' : + $.inArray( breakpoint, col.includeIn ) !== -1; + } ); + + // Auto column control - first pass: how much width is taken by the + // ones that must be included from the non-auto columns + var requiredWidth = 0; + for ( i=0, ien=display.length ; i = size ) { + add( colIdx, breakpoints[i].name ); + } + } + } + else if ( operator === 'not-' ) { + // Add all but this breakpoint + for ( i=0, ien=breakpoints.length ; i =0 ; i-- ) { + if ( width <= breakpoints[i].width ) { + breakpoint = breakpoints[i].name; + break; + } + } + + // Show the columns for that break point + var columnsVis = this._columnsVisiblity( breakpoint ); + this.s.current = columnsVis; + + // Set the class before the column visibility is changed so event + // listeners know what the state is. Need to determine if there are + // any columns that are not visible but can be shown + var collapsedClass = false; + for ( i=0, ien=columns.length ; i ') + .append( footerCells ) + .appendTo( clonedFooter ); + } + + $(' ') + .append( headerCells ) + .appendTo( clonedHeader ); + + // In the inline case extra padding is applied to the first column to + // give space for the show / hide icon. We need to use this in the + // calculation + if ( this.c.details.type === 'inline' ) { + $(clonedTable).addClass( 'dtr-inline collapsed' ); + } + + // It is unsafe to insert elements with the same name into the DOM + // multiple times. For example, cloning and inserting a checked radio + // clears the chcecked state of the original radio. + $( clonedTable ).find( '[name]' ).removeAttr( 'name' ); + + var inserted = $('') + .css( { + width: 1, + height: 1, + overflow: 'hidden' + } ) + .append( clonedTable ); + + inserted.insertBefore( dt.table().node() ); + + // The cloned header now contains the smallest that each column can be + headerCells.each( function (i) { + var idx = dt.column.index( 'fromVisible', i ); + columns[ idx ].minWidth = this.offsetWidth || 0; + } ); + + inserted.remove(); + }, + + /** + * Set a column's visibility. + * + * We don't use DataTables' column visibility controls in order to ensure + * that column visibility can Responsive can no-exist. Since only IE8+ is + * supported (and all evergreen browsers of course) the control of the + * display attribute works well. + * + * @param {integer} col Column index + * @param {boolean} showHide Show or hide (true or false) + * @private + */ + _setColumnVis: function ( col, showHide ) + { + var dt = this.s.dt; + var display = showHide ? '' : 'none'; // empty string will remove the attr + + $( dt.column( col ).header() ).css( 'display', display ); + $( dt.column( col ).footer() ).css( 'display', display ); + dt.column( col ).nodes().to$().css( 'display', display ); + }, + + + /** + * Update the cell tab indexes for keyboard accessibility. This is called on + * every table draw - that is potentially inefficient, but also the least + * complex option given that column visibility can change on the fly. Its a + * shame user-focus was removed from CSS 3 UI, as it would have solved this + * issue with a single CSS statement. + * + * @private + */ + _tabIndexes: function () + { + var dt = this.s.dt; + var cells = dt.cells( { page: 'current' } ).nodes().to$(); + var ctx = dt.settings()[0]; + var target = this.c.details.target; + + cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' ); + + var selector = typeof target === 'number' ? + ':eq('+target+')' : + target; + + // This is a bit of a hack - we need to limit the selected nodes to just + // those of this table + if ( selector === 'td:first-child, th:first-child' ) { + selector = '>td:first-child, >th:first-child'; + } + + $( selector, dt.rows( { page: 'current' } ).nodes() ) + .attr( 'tabIndex', ctx.iTabIndex ) + .data( 'dtr-keyboard', 1 ); + } +} ); + + +/** + * List of default breakpoints. Each item in the array is an object with two + * properties: + * + * * `name` - the breakpoint name. + * * `width` - the breakpoint width + * + * @name Responsive.breakpoints + * @static + */ +Responsive.breakpoints = [ + { name: 'desktop', width: Infinity }, + { name: 'tablet-l', width: 1024 }, + { name: 'tablet-p', width: 768 }, + { name: 'mobile-l', width: 480 }, + { name: 'mobile-p', width: 320 } +]; + + +/** + * Display methods - functions which define how the hidden data should be shown + * in the table. + * + * @namespace + * @name Responsive.defaults + * @static + */ +Responsive.display = { + childRow: function ( row, update, render ) { + if ( update ) { + if ( $(row.node()).hasClass('parent') ) { + row.child( render(), 'child' ).show(); + + return true; + } + } + else { + if ( ! row.child.isShown() ) { + row.child( render(), 'child' ).show(); + $( row.node() ).addClass( 'parent' ); + + return true; + } + else { + row.child( false ); + $( row.node() ).removeClass( 'parent' ); + + return false; + } + } + }, + + childRowImmediate: function ( row, update, render ) { + if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) { + // User interaction and the row is show, or nothing to show + row.child( false ); + $( row.node() ).removeClass( 'parent' ); + + return false; + } + else { + // Display + row.child( render(), 'child' ).show(); + $( row.node() ).addClass( 'parent' ); + + return true; + } + }, + + // This is a wrapper so the modal options for Bootstrap and jQuery UI can + // have options passed into them. This specific one doesn't need to be a + // function but it is for consistency in the `modal` name + modal: function ( options ) { + return function ( row, update, render ) { + if ( ! update ) { + // Show a modal + var close = function () { + modal.remove(); // will tidy events for us + $(document).off( 'keypress.dtr' ); + }; + + var modal = $('') + .append( $('') + .append( $('') + .append( render() ) + ) + .append( $(' ×' ) + .click( function () { + close(); + } ) + ) + ) + .append( $('') + .click( function () { + close(); + } ) + ) + .appendTo( 'body' ); + + $(document).on( 'keyup.dtr', function (e) { + if ( e.keyCode === 27 ) { + e.stopPropagation(); + + close(); + } + } ); + } + else { + $('div.dtr-modal-content') + .empty() + .append( render() ); + } + + if ( options && options.header ) { + $('div.dtr-modal-content').prepend( + ''+options.header( row )+'
' + ); + } + }; + } +}; + + +/** + * Display methods - functions which define how the hidden data should be shown + * in the table. + * + * @namespace + * @name Responsive.defaults + * @static + */ +Responsive.renderer = { + listHidden: function () { + return function ( api, rowIdx, columns ) { + var data = $.map( columns, function ( col ) { + return col.hidden ? + '- '+ + ''+ + col.title+ + ' '+ + ''+ + col.data+ + ''+ + '
' : + ''; + } ).join(''); + + return data ? + $('').append( data ) : + false; + } + }, + + tableAll: function ( options ) { + options = $.extend( { + tableClass: '' + }, options ); + + return function ( api, rowIdx, columns ) { + var data = $.map( columns, function ( col ) { + return '
'+ + ' '; + } ).join(''); + + return $(''+col.title+':'+' '+ + ''+col.data+' '+ + '').append( data ); + } + } +}; + +/** + * Responsive default settings for initialisation + * + * @namespace + * @name Responsive.defaults + * @static + */ +Responsive.defaults = { + /** + * List of breakpoints for the instance. Note that this means that each + * instance can have its own breakpoints. Additionally, the breakpoints + * cannot be changed once an instance has been creased. + * + * @type {Array} + * @default Takes the value of `Responsive.breakpoints` + */ + breakpoints: Responsive.breakpoints, + + /** + * Enable / disable auto hiding calculations. It can help to increase + * performance slightly if you disable this option, but all columns would + * need to have breakpoint classes assigned to them + * + * @type {Boolean} + * @default `true` + */ + auto: true, + + /** + * Details control. If given as a string value, the `type` property of the + * default object is set to that value, and the defaults used for the rest + * of the object - this is for ease of implementation. + * + * The object consists of the following properties: + * + * * `display` - A function that is used to show and hide the hidden details + * * `renderer` - function that is called for display of the child row data. + * The default function will show the data from the hidden columns + * * `target` - Used as the selector for what objects to attach the child + * open / close to + * * `type` - `false` to disable the details display, `inline` or `column` + * for the two control types + * + * @type {Object|string} + */ + details: { + display: Responsive.display.childRow, + + renderer: Responsive.renderer.listHidden(), + + target: 0, + + type: 'inline' + }, + + /** + * Orthogonal data request option. This is used to define the data type + * requested when Responsive gets the data to show in the child row. + * + * @type {String} + */ + orthogonal: 'display' +}; + + +/* + * API + */ +var Api = $.fn.dataTable.Api; + +// Doesn't do anything - work around for a bug in DT... Not documented +Api.register( 'responsive()', function () { + return this; +} ); + +Api.register( 'responsive.index()', function ( li ) { + li = $(li); + + return { + column: li.data('dtr-index'), + row: li.parent().data('dtr-index') + }; +} ); + +Api.register( 'responsive.rebuild()', function () { + return this.iterator( 'table', function ( ctx ) { + if ( ctx._responsive ) { + ctx._responsive._classLogic(); + } + } ); +} ); + +Api.register( 'responsive.recalc()', function () { + return this.iterator( 'table', function ( ctx ) { + if ( ctx._responsive ) { + ctx._responsive._resizeAuto(); + ctx._responsive._resize(); + } + } ); +} ); + +Api.register( 'responsive.hasHidden()', function () { + var ctx = this.context[0]; + + return ctx._responsive ? + $.inArray( false, ctx._responsive.s.current ) !== -1 : + false; +} ); + + +/** + * Version information + * + * @name Responsive.version + * @static + */ +Responsive.version = '2.1.1'; + + +$.fn.dataTable.Responsive = Responsive; +$.fn.DataTable.Responsive = Responsive; + +// Attach a listener to the document which listens for DataTables initialisation +// events so we can automatically initialise +$(document).on( 'preInit.dt.dtr', function (e, settings, json) { + if ( e.namespace !== 'dt' ) { + return; + } + + if ( $(settings.nTable).hasClass( 'responsive' ) || + $(settings.nTable).hasClass( 'dt-responsive' ) || + settings.oInit.responsive || + DataTable.defaults.responsive + ) { + var init = settings.oInit.responsive; + + if ( init !== false ) { + new Responsive( settings, $.isPlainObject( init ) ? init : {} ); + } + } +} ); + + +return Responsive; +})); diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.min.js b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.min.js new file mode 100644 index 00000000..2bbfabbb --- /dev/null +++ b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.min.js @@ -0,0 +1,26 @@ +/*! + Responsive 2.1.1 + 2014-2016 SpryMedia Ltd - datatables.net/license +*/ +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return c(l,window,document)}):"object"===typeof exports?module.exports=function(l,k){l||(l=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(l,k).$;return c(k,l,l.document)}:c(jQuery,window,document)})(function(c,l,k,p){var m=c.fn.dataTable,j=function(b,a){if(!m.versionCheck||!m.versionCheck("1.10.3"))throw"DataTables Responsive requires DataTables 1.10.3 or newer";this.s={dt:new m.Api(b),columns:[], +current:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details?a.details={type:a.details}:a&&!1===a.details?a.details={type:!1}:a&&!0===a.details&&(a.details={type:"inline"}),this.c=c.extend(!0,{},j.defaults,m.defaults.responsive,a),b.responsive=this,this._constructor())};c.extend(j.prototype,{_constructor:function(){var b=this,a=this.s.dt,d=a.settings()[0],e=c(l).width();a.settings()[0]._responsive=this;c(l).on("resize.dtr orientationchange.dtr",m.util.throttle(function(){var a= +c(l).width();a!==e&&(b._resize(),e=a)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,b.s.current)&&c(">td, >th",e).each(function(e){e=a.column.index("toData",e);!1===b.s.current[e]&&c(this).css("display","none")})});a.on("destroy.dtr",function(){a.off(".dtr");c(a.table().body()).off(".dtr");c(l).off("resize.dtr orientationchange.dtr");c.each(b.s.current,function(a,e){!1===e&&b._setColumnVis(a,!0)})});this.c.breakpoints.sort(function(a,b){return a.width
+b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(b._detailsInit(),a.on("column-visibility.dtr",function(){b._classLogic();b._resizeAuto();b._resize()}),a.on("draw.dtr",function(){b._redrawChildren()}),c(a.table().node()).addClass("dtr-"+d.type));a.on("column-reorder.dtr",function(){b._classLogic();b._resizeAuto();b._resize()});a.on("column-sizing.dtr",function(){b._resizeAuto();b._resize()});a.on("preXhr.dtr",function(){var e=[];a.rows().every(function(){this.child.isShown()&& +e.push(this.id(true))});a.one("draw.dtr",function(){a.rows(e).every(function(){b._detailsDisplay(this,false)})})});a.on("init.dtr",function(){b._resizeAuto();b._resize();c.inArray(false,b.s.current)&&a.columns.adjust()});this._resize()},_columnsVisiblity:function(b){var a=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),h=c.map(d,function(a){return a.auto&& +null===a.minWidth?!1:!0===a.auto?"-":-1!==c.inArray(b,a.includeIn)}),n=0;e=0;for(f=h.length;e a-d[i].minWidth?(n=!0,h[i]=!1):h[i]=!0,a-=d[i].minWidth)}g=!1;e=0;for(f=d.length;e =g&&f(c,a[d].name)}else{if("not-"===i){d=0;for(i=a.length;d").append(h).appendTo(f)}c(" ").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");c(d).find("[name]").removeAttr("name");d=c("").css({width:1,height:1,overflow:"hidden"}).append(d);d.insertBefore(b.table().node());g.each(function(c){c=b.column.index("fromVisible",c);a[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(b, +a){var d=this.s.dt,e=a?"":"none";c(d.column(b).header()).css("display",e);c(d.column(b).footer()).css("display",e);d.column(b).nodes().to$().css("display",e)},_tabIndexes:function(){var b=this.s.dt,a=b.cells({page:"current"}).nodes().to$(),d=b.settings()[0],e=this.c.details.target;a.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");a="number"===typeof e?":eq("+e+")":e;"td:first-child, th:first-child"===a&&(a=">td:first-child, >th:first-child");c(a,b.rows({page:"current"}).nodes()).attr("tabIndex", +d.iTabIndex).data("dtr-keyboard",1)}});j.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];j.display={childRow:function(b,a,d){if(a){if(c(b.node()).hasClass("parent"))return b.child(d(),"child").show(),!0}else{if(b.child.isShown())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0}},childRowImmediate:function(b,a,d){if(!a&& +b.child.isShown()||!b.responsive.hasHidden())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0},modal:function(b){return function(a,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('').append(c('').append(c('').append(e())).append(c(' ×').click(function(){f()}))).append(c('').click(function(){f()})).appendTo("body"); +c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}b&&b.header&&c("div.dtr-modal-content").prepend(""+b.header(a)+"
")}}};j.renderer={listHidden:function(){return function(b,a,d){return(b=c.map(d,function(a){return a.hidden?'- '+a.title+' '+a.data+"
":""}).join(""))?c('').append(b): +!1}},tableAll:function(b){b=c.extend({tableClass:""},b);return function(a,d,e){a=c.map(e,function(a){return'
"}).join("");return c(' '+a.title+": "+a.data+" ').append(a)}}};j.defaults={breakpoints:j.breakpoints,auto:!0,details:{display:j.display.childRow,renderer:j.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var o=c.fn.dataTable.Api; +o.register("responsive()",function(){return this});o.register("responsive.index()",function(b){b=c(b);return{column:b.data("dtr-index"),row:b.parent().data("dtr-index")}});o.register("responsive.rebuild()",function(){return this.iterator("table",function(b){b._responsive&&b._responsive._classLogic()})});o.register("responsive.recalc()",function(){return this.iterator("table",function(b){b._responsive&&(b._responsive._resizeAuto(),b._responsive._resize())})});o.register("responsive.hasHidden()",function(){var b= +this.context[0];return b._responsive?-1!==c.inArray(!1,b._responsive.s.current):!1});j.version="2.1.1";c.fn.dataTable.Responsive=j;c.fn.DataTable.Responsive=j;c(k).on("preInit.dt.dtr",function(b,a){if("dt"===b.namespace&&(c(a.nTable).hasClass("responsive")||c(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||m.defaults.responsive)){var d=a.oInit.responsive;!1!==d&&new j(a,c.isPlainObject(d)?d:{})}});return j}); diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/datatables-all.js b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/datatables-all.js new file mode 100644 index 00000000..378deb62 --- /dev/null +++ b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/datatables-all.js @@ -0,0 +1,17649 @@ +/*! DataTables 1.10.16 + * 2008-2017 SpryMedia Ltd - datatables.net/license + */ + +/** + * @summary DataTables + * @description Paginate, search and order HTML tables + * @version 1.10.16 + * @file jquery.dataTables.js + * @author SpryMedia Ltd + * @contact www.datatables.net + * @copyright Copyright 2008-2017 SpryMedia Ltd. + * + * This source file is free software, available under the following license: + * MIT license - https://datatables.net/license + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + * + * For details please refer to: https://www.datatables.net + */ + +/*jslint evil: true, undef: true, browser: true */ +/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ + +(function( factory ) { + "use strict"; + + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +} +(function( $, window, document, undefined ) { + "use strict"; + + /** + * DataTables is a plug-in for the jQuery Javascript library. It is a highly + * flexible tool, based upon the foundations of progressive enhancement, + * which will add advanced interaction controls to any HTML table. For a + * full list of features please refer to + * [DataTables.net](href="https://datatables.net). + * + * Note that the `DataTable` object is not a global variable but is aliased + * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may + * be accessed. + * + * @class + * @param {object} [init={}] Configuration object for DataTables. Options + * are defined by {@link DataTable.defaults} + * @requires jQuery 1.7+ + * + * @example + * // Basic initialisation + * $(document).ready( function { + * $('#example').dataTable(); + * } ); + * + * @example + * // Initialisation with configuration options - in this case, disable + * // pagination and sorting. + * $(document).ready( function { + * $('#example').dataTable( { + * "paginate": false, + * "sort": false + * } ); + * } ); + */ + var DataTable = function ( options ) + { + /** + * Perform a jQuery selector action on the table's TR elements (from the tbody) and + * return the resulting jQuery object. + * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on + * @param {object} [oOpts] Optional parameters for modifying the rows to be included + * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter + * criterion ("applied") or all TR elements (i.e. no filter). + * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. + * Can be either 'current', whereby the current sorting of the table is used, or + * 'original' whereby the original order the data was read into the table is used. + * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page + * ("current") or not ("all"). If 'current' is given, then order is assumed to be + * 'current' and filter is 'applied', regardless of what they might be given as. + * @returns {object} jQuery object, filtered by the given selector. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Highlight every second row + * oTable.$('tr:odd').css('backgroundColor', 'blue'); + * } ); + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Filter to rows with 'Webkit' in them, add a background colour and then + * // remove the filter, thus highlighting the 'Webkit' rows only. + * oTable.fnFilter('Webkit'); + * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); + * oTable.fnFilter(''); + * } ); + */ + this.$ = function ( sSelector, oOpts ) + { + return this.api(true).$( sSelector, oOpts ); + }; + + + /** + * Almost identical to $ in operation, but in this case returns the data for the matched + * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes + * rather than any descendants, so the data can be obtained for the row/cell. If matching + * rows are found, the data returned is the original data array/object that was used to + * create the row (or a generated array if from a DOM source). + * + * This method is often useful in-combination with $ where both functions are given the + * same parameters and the array indexes will match identically. + * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on + * @param {object} [oOpts] Optional parameters for modifying the rows to be included + * @param {string} [oOpts.filter=none] Select elements that meet the current filter + * criterion ("applied") or all elements (i.e. no filter). + * @param {string} [oOpts.order=current] Order of the data in the processed array. + * Can be either 'current', whereby the current sorting of the table is used, or + * 'original' whereby the original order the data was read into the table is used. + * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page + * ("current") or not ("all"). If 'current' is given, then order is assumed to be + * 'current' and filter is 'applied', regardless of what they might be given as. + * @returns {array} Data for the matched elements. If any elements, as a result of the + * selector, were not TR, TD or TH elements in the DataTable, they will have a null + * entry in the array. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Get the data from the first row in the table + * var data = oTable._('tr:first'); + * + * // Do something useful with the data + * alert( "First cell is: "+data[0] ); + * } ); + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Filter to 'Webkit' and get all data for + * oTable.fnFilter('Webkit'); + * var data = oTable._('tr', {"search": "applied"}); + * + * // Do something with the data + * alert( data.length+" rows matched the search" ); + * } ); + */ + this._ = function ( sSelector, oOpts ) + { + return this.api(true).rows( sSelector, oOpts ).data(); + }; + + + /** + * Create a DataTables Api instance, with the currently selected tables for + * the Api's context. + * @param {boolean} [traditional=false] Set the API instance's context to be + * only the table referred to by the `DataTable.ext.iApiIndex` option, as was + * used in the API presented by DataTables 1.9- (i.e. the traditional mode), + * or if all tables captured in the jQuery object should be used. + * @return {DataTables.Api} + */ + this.api = function ( traditional ) + { + return traditional ? + new _Api( + _fnSettingsFromNode( this[ _ext.iApiIndex ] ) + ) : + new _Api( this ); + }; + + + /** + * Add a single new row or multiple rows of data to the table. Please note + * that this is suitable for client-side processing only - if you are using + * server-side processing (i.e. "bServerSide": true), then to add data, you + * must add it to the data source, i.e. the server-side, through an Ajax call. + * @param {array|object} data The data to be added to the table. This can be: + *
+ *
+ * @param {bool} [redraw=true] redraw the table or not + * @returns {array} An array of integers, representing the list of indexes in + * aoData ({@link DataTable.models.oSettings}) that have been added to + * the table. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * // Global var for counter + * var giCount = 2; + * + * $(document).ready(function() { + * $('#example').dataTable(); + * } ); + * + * function fnClickAddRow() { + * $('#example').dataTable().fnAddData( [ + * giCount+".1", + * giCount+".2", + * giCount+".3", + * giCount+".4" ] + * ); + * + * giCount++; + * } + */ + this.fnAddData = function( data, redraw ) + { + var api = this.api( true ); + + /* Check if we want to add multiple rows or not */ + var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ? + api.rows.add( data ) : + api.row.add( data ); + + if ( redraw === undefined || redraw ) { + api.draw(); + } + + return rows.flatten().toArray(); + }; + + + /** + * This function will make DataTables recalculate the column sizes, based on the data + * contained in the table and the sizes applied to the columns (in the DOM, CSS or + * through the sWidth parameter). This can be useful when the width of the table's + * parent element changes (for example a window resize). + * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false + * } ); + * + * $(window).on('resize', function () { + * oTable.fnAdjustColumnSizing(); + * } ); + * } ); + */ + this.fnAdjustColumnSizing = function ( bRedraw ) + { + var api = this.api( true ).columns.adjust(); + var settings = api.settings()[0]; + var scroll = settings.oScroll; + + if ( bRedraw === undefined || bRedraw ) { + api.draw( false ); + } + else if ( scroll.sX !== "" || scroll.sY !== "" ) { + /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ + _fnScrollDraw( settings ); + } + }; + + + /** + * Quickly and simply clear a table + * @param {bool} [bRedraw=true] redraw the table or not + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) + * oTable.fnClearTable(); + * } ); + */ + this.fnClearTable = function( bRedraw ) + { + var api = this.api( true ).clear(); + + if ( bRedraw === undefined || bRedraw ) { + api.draw(); + } + }; + + + /** + * The exact opposite of 'opening' a row, this function will close any rows which + * are currently 'open'. + * @param {node} nTr the table row to 'close' + * @returns {int} 0 on success, or 1 if failed (can't find the row) + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable; + * + * // 'open' an information row when a row is clicked on + * $('#example tbody tr').click( function () { + * if ( oTable.fnIsOpen(this) ) { + * oTable.fnClose( this ); + * } else { + * oTable.fnOpen( this, "Temporary row opened", "info_row" ); + * } + * } ); + * + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnClose = function( nTr ) + { + this.api( true ).row( nTr ).child.hide(); + }; + + + /** + * Remove a row for the table + * @param {mixed} target The index of the row from aoData to be deleted, or + * the TR element you want to delete + * @param {function|null} [callBack] Callback function + * @param {bool} [redraw=true] Redraw the table or not + * @returns {array} The row that was deleted + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Immediately remove the first row + * oTable.fnDeleteRow( 0 ); + * } ); + */ + this.fnDeleteRow = function( target, callback, redraw ) + { + var api = this.api( true ); + var rows = api.rows( target ); + var settings = rows.settings()[0]; + var data = settings.aoData[ rows[0][0] ]; + + rows.remove(); + + if ( callback ) { + callback.call( this, settings, data ); + } + + if ( redraw === undefined || redraw ) { + api.draw(); + } + + return data; + }; + + + /** + * Restore the table to it's original state in the DOM by removing all of DataTables + * enhancements, alterations to the DOM structure of the table and event listeners. + * @param {boolean} [remove=false] Completely remove the table from the DOM + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * // This example is fairly pointless in reality, but shows how fnDestroy can be used + * var oTable = $('#example').dataTable(); + * oTable.fnDestroy(); + * } ); + */ + this.fnDestroy = function ( remove ) + { + this.api( true ).destroy( remove ); + }; + + + /** + * Redraw the table + * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) + * oTable.fnDraw(); + * } ); + */ + this.fnDraw = function( complete ) + { + // Note that this isn't an exact match to the old call to _fnDraw - it takes + // into account the new data, but can hold position. + this.api( true ).draw( complete ); + }; + + + /** + * Filter the input based on data + * @param {string} sInput String to filter the table on + * @param {int|null} [iColumn] Column to limit filtering to + * @param {bool} [bRegex=false] Treat as regular expression or not + * @param {bool} [bSmart=true] Perform smart filtering or not + * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) + * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Sometime later - filter... + * oTable.fnFilter( 'test string' ); + * } ); + */ + this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) + { + var api = this.api( true ); + + if ( iColumn === null || iColumn === undefined ) { + api.search( sInput, bRegex, bSmart, bCaseInsensitive ); + } + else { + api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); + } + + api.draw(); + }; + + + /** + * Get the data for the whole table, an individual row or an individual cell based on the + * provided parameters. + * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as + * a TR node then the data source for the whole row will be returned. If given as a + * TD/TH cell node then iCol will be automatically calculated and the data for the + * cell returned. If given as an integer, then this is treated as the aoData internal + * data index for the row (see fnGetPosition) and the data for that row used. + * @param {int} [col] Optional column index that you want the data of. + * @returns {array|object|string} If mRow is undefined, then the data for all rows is + * returned. If mRow is defined, just data for that row, and is iCol is + * defined, only data for the designated cell is returned. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * // Row data + * $(document).ready(function() { + * oTable = $('#example').dataTable(); + * + * oTable.$('tr').click( function () { + * var data = oTable.fnGetData( this ); + * // ... do something with the array / object of data for the row + * } ); + * } ); + * + * @example + * // Individual cell data + * $(document).ready(function() { + * oTable = $('#example').dataTable(); + * + * oTable.$('td').click( function () { + * var sData = oTable.fnGetData( this ); + * alert( 'The cell clicked on had the value of '+sData ); + * } ); + * } ); + */ + this.fnGetData = function( src, col ) + { + var api = this.api( true ); + + if ( src !== undefined ) { + var type = src.nodeName ? src.nodeName.toLowerCase() : ''; + + return col !== undefined || type == 'td' || type == 'th' ? + api.cell( src, col ).data() : + api.row( src ).data() || null; + } + + return api.data().toArray(); + }; + + + /** + * Get an array of the TR nodes that are used in the table's body. Note that you will + * typically want to use the '$' API method in preference to this as it is more + * flexible. + * @param {int} [iRow] Optional row index for the TR element you want + * @returns {array|node} If iRow is undefined, returns an array of all TR elements + * in the table's body, or iRow is defined, just the TR element requested. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Get the nodes from the table + * var nNodes = oTable.fnGetNodes( ); + * } ); + */ + this.fnGetNodes = function( iRow ) + { + var api = this.api( true ); + + return iRow !== undefined ? + api.row( iRow ).node() : + api.rows().nodes().flatten().toArray(); + }; + + + /** + * Get the array indexes of a particular cell from it's DOM element + * and column index including hidden columns + * @param {node} node this can either be a TR, TD or TH in the table's body + * @returns {int} If nNode is given as a TR, then a single index is returned, or + * if given as a cell, an array of [row index, column index (visible), + * column index (all)] is given. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * $('#example tbody td').click( function () { + * // Get the position of the current data from the node + * var aPos = oTable.fnGetPosition( this ); + * + * // Get the data array for this row + * var aData = oTable.fnGetData( aPos[0] ); + * + * // Update the data array and return the value + * aData[ aPos[1] ] = 'clicked'; + * this.innerHTML = 'clicked'; + * } ); + * + * // Init DataTables + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnGetPosition = function( node ) + { + var api = this.api( true ); + var nodeName = node.nodeName.toUpperCase(); + + if ( nodeName == 'TR' ) { + return api.row( node ).index(); + } + else if ( nodeName == 'TD' || nodeName == 'TH' ) { + var cell = api.cell( node ).index(); + + return [ + cell.row, + cell.columnVisible, + cell.column + ]; + } + return null; + }; + + + /** + * Check to see if a row is 'open' or not. + * @param {node} nTr the table row to check + * @returns {boolean} true if the row is currently open, false otherwise + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable; + * + * // 'open' an information row when a row is clicked on + * $('#example tbody tr').click( function () { + * if ( oTable.fnIsOpen(this) ) { + * oTable.fnClose( this ); + * } else { + * oTable.fnOpen( this, "Temporary row opened", "info_row" ); + * } + * } ); + * + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnIsOpen = function( nTr ) + { + return this.api( true ).row( nTr ).child.isShown(); + }; + + + /** + * This function will place a new row directly after a row which is currently + * on display on the page, with the HTML contents that is passed into the + * function. This can be used, for example, to ask for confirmation that a + * particular record should be deleted. + * @param {node} nTr The table row to 'open' + * @param {string|node|jQuery} mHtml The HTML to put into the row + * @param {string} sClass Class to give the new TD cell + * @returns {node} The row opened. Note that if the table row passed in as the + * first parameter, is not found in the table, this method will silently + * return. + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable; + * + * // 'open' an information row when a row is clicked on + * $('#example tbody tr').click( function () { + * if ( oTable.fnIsOpen(this) ) { + * oTable.fnClose( this ); + * } else { + * oTable.fnOpen( this, "Temporary row opened", "info_row" ); + * } + * } ); + * + * oTable = $('#example').dataTable(); + * } ); + */ + this.fnOpen = function( nTr, mHtml, sClass ) + { + return this.api( true ) + .row( nTr ) + .child( mHtml, sClass ) + .show() + .child()[0]; + }; + + + /** + * Change the pagination - provides the internal logic for pagination in a simple API + * function. With this function you can have a DataTables table go to the next, + * previous, first or last pages. + * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" + * or page number to jump to (integer), note that page 0 is the first page. + * @param {bool} [bRedraw=true] Redraw the table or not + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * oTable.fnPageChange( 'next' ); + * } ); + */ + this.fnPageChange = function ( mAction, bRedraw ) + { + var api = this.api( true ).page( mAction ); + + if ( bRedraw === undefined || bRedraw ) { + api.draw(false); + } + }; + + + /** + * Show a particular column + * @param {int} iCol The column whose display should be changed + * @param {bool} bShow Show (true) or hide (false) the column + * @param {bool} [bRedraw=true] Redraw the table or not + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Hide the second column after initialisation + * oTable.fnSetColumnVis( 1, false ); + * } ); + */ + this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) + { + var api = this.api( true ).column( iCol ).visible( bShow ); + + if ( bRedraw === undefined || bRedraw ) { + api.columns.adjust().draw(); + } + }; + + + /** + * Get the settings for a particular table for external manipulation + * @returns {object} DataTables settings object. See + * {@link DataTable.models.oSettings} + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * var oSettings = oTable.fnSettings(); + * + * // Show an example parameter from the settings + * alert( oSettings._iDisplayStart ); + * } ); + */ + this.fnSettings = function() + { + return _fnSettingsFromNode( this[_ext.iApiIndex] ); + }; + + + /** + * Sort the table by a particular column + * @param {int} iCol the data index to sort on. Note that this will not match the + * 'display index' if you have hidden data entries + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Sort immediately with columns 0 and 1 + * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); + * } ); + */ + this.fnSort = function( aaSort ) + { + this.api( true ).order( aaSort ).draw(); + }; + + + /** + * Attach a sort listener to an element for a given column + * @param {node} nNode the element to attach the sort listener to + * @param {int} iColumn the column that a click on this node will sort on + * @param {function} [fnCallback] callback function when sort is run + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Sort on column 1, when 'sorter' is clicked on + * oTable.fnSortListener( document.getElementById('sorter'), 1 ); + * } ); + */ + this.fnSortListener = function( nNode, iColumn, fnCallback ) + { + this.api( true ).order.listener( nNode, iColumn, fnCallback ); + }; + + + /** + * Update a table cell or row - this method will accept either a single value to + * update the cell with, an array of values with one element for each column or + * an object in the same format as the original data source. The function is + * self-referencing in order to make the multi column updates easier. + * @param {object|array|string} mData Data to update the cell/row with + * @param {node|int} mRow TR element you want to update or the aoData index + * @param {int} [iColumn] The column to update, give as null or undefined to + * update a whole row. + * @param {bool} [bRedraw=true] Redraw the table or not + * @param {bool} [bAction=true] Perform pre-draw actions or not + * @returns {int} 0 on success, 1 on error + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell + * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row + * } ); + */ + this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) + { + var api = this.api( true ); + + if ( iColumn === undefined || iColumn === null ) { + api.row( mRow ).data( mData ); + } + else { + api.cell( mRow, iColumn ).data( mData ); + } + + if ( bAction === undefined || bAction ) { + api.columns.adjust(); + } + + if ( bRedraw === undefined || bRedraw ) { + api.draw(); + } + return 0; + }; + + + /** + * Provide a common method for plug-ins to check the version of DataTables being used, in order + * to ensure compatibility. + * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the + * formats "X" and "X.Y" are also acceptable. + * @returns {boolean} true if this version of DataTables is greater or equal to the required + * version, or false if this version of DataTales is not suitable + * @method + * @dtopt API + * @deprecated Since v1.10 + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * alert( oTable.fnVersionCheck( '1.9.0' ) ); + * } ); + */ + this.fnVersionCheck = _ext.fnVersionCheck; + + + var _that = this; + var emptyInit = options === undefined; + var len = this.length; + + if ( emptyInit ) { + options = {}; + } + + this.oApi = this.internal = _ext.internal; + + // Extend with old style plug-in API methods + for ( var fn in DataTable.ext.internal ) { + if ( fn ) { + this[fn] = _fnExternApiFunc(fn); + } + } + + this.each(function() { + // For each initialisation we want to give it a clean initialisation + // object that can be bashed around + var o = {}; + var oInit = len > 1 ? // optimisation for single table case + _fnExtend( o, options, true ) : + options; + + /*global oInit,_that,emptyInit*/ + var i=0, iLen, j, jLen, k, kLen; + var sId = this.getAttribute( 'id' ); + var bInitHandedOff = false; + var defaults = DataTable.defaults; + var $this = $(this); + + + /* Sanity check */ + if ( this.nodeName.toLowerCase() != 'table' ) + { + _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); + return; + } + + /* Backwards compatibility for the defaults */ + _fnCompatOpts( defaults ); + _fnCompatCols( defaults.column ); + + /* Convert the camel-case defaults to Hungarian */ + _fnCamelToHungarian( defaults, defaults, true ); + _fnCamelToHungarian( defaults.column, defaults.column, true ); + + /* Setting up the initialisation object */ + _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) ); + + + + /* Check to see if we are re-initialising a table */ + var allSettings = DataTable.settings; + for ( i=0, iLen=allSettings.length ; i- 1D array of data - add a single row with the data provided
+ *- 2D array of arrays - add multiple rows in a single call
+ *- object - data object when using mData
+ *- array of objects - multiple data objects when using mData
+ *').appendTo($this); + } + oSettings.nTHead = thead[0]; + + var tbody = $this.children('tbody'); + if ( tbody.length === 0 ) { + tbody = $('').appendTo($this); + } + oSettings.nTBody = tbody[0]; + + var tfoot = $this.children('tfoot'); + if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { + // If we are a scrolling table, and no footer has been given, then we need to create + // a tfoot element for the caption element to be appended to + tfoot = $('').appendTo($this); + } + + if ( tfoot.length === 0 || tfoot.children().length === 0 ) { + $this.addClass( oClasses.sNoFooter ); + } + else if ( tfoot.length > 0 ) { + oSettings.nTFoot = tfoot[0]; + _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); + } + + /* Check if there is data passing into the constructor */ + if ( oInit.aaData ) { + for ( i=0 ; i /g; + + // This is not strict ISO8601 - Date.parse() is quite lax, although + // implementations differ between browsers. + var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; + + // Escape regular expression special characters + var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); + + // https://en.wikipedia.org/wiki/Foreign_exchange_market + // - \u20BD - Russian ruble. + // - \u20a9 - South Korean Won + // - \u20BA - Turkish Lira + // - \u20B9 - Indian Rupee + // - R - Brazil (R$) and South Africa + // - fr - Swiss Franc + // - kr - Swedish krona, Norwegian krone and Danish krone + // - \u2009 is thin space and \u202F is narrow no-break space, both used in many + // standards as thousands separators. + var _re_formatted_numeric = /[',$ツ」竄ャツ・%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; + + + var _empty = function ( d ) { + return !d || d === true || d === '-' ? true : false; + }; + + + var _intVal = function ( s ) { + var integer = parseInt( s, 10 ); + return !isNaN(integer) && isFinite(s) ? integer : null; + }; + + // Convert from a formatted number with characters other than `.` as the + // decimal place, to a Javascript number + var _numToDecimal = function ( num, decimalPoint ) { + // Cache created regular expressions for speed as this function is called often + if ( ! _re_dic[ decimalPoint ] ) { + _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); + } + return typeof num === 'string' && decimalPoint !== '.' ? + num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : + num; + }; + + + var _isNumber = function ( d, decimalPoint, formatted ) { + var strType = typeof d === 'string'; + + // If empty return immediately so there must be a number if it is a + // formatted string (this stops the string "k", or "kr", etc being detected + // as a formatted number for currency + if ( _empty( d ) ) { + return true; + } + + if ( decimalPoint && strType ) { + d = _numToDecimal( d, decimalPoint ); + } + + if ( formatted && strType ) { + d = d.replace( _re_formatted_numeric, '' ); + } + + return !isNaN( parseFloat(d) ) && isFinite( d ); + }; + + + // A string without HTML in it can be considered to be HTML still + var _isHtml = function ( d ) { + return _empty( d ) || typeof d === 'string'; + }; + + + var _htmlNumeric = function ( d, decimalPoint, formatted ) { + if ( _empty( d ) ) { + return true; + } + + var html = _isHtml( d ); + return ! html ? + null : + _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? + true : + null; + }; + + + var _pluck = function ( a, prop, prop2 ) { + var out = []; + var i=0, ien=a.length; + + // Could have the test in the loop for slightly smaller code, but speed + // is essential here + if ( prop2 !== undefined ) { + for ( ; i ') + .css( { + position: 'fixed', + top: 0, + left: $(window).scrollLeft()*-1, // allow for scrolling + height: 1, + width: 1, + overflow: 'hidden' + } ) + .append( + $('') + .css( { + position: 'absolute', + top: 1, + left: 1, + width: 100, + overflow: 'scroll' + } ) + .append( + $('') + .css( { + width: '100%', + height: 10 + } ) + ) + ) + .appendTo( 'body' ); + + var outer = n.children(); + var inner = outer.children(); + + // Numbers below, in order, are: + // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth + // + // IE6 XP: 100 100 100 83 + // IE7 Vista: 100 100 100 83 + // IE 8+ Windows: 83 83 100 83 + // Evergreen Windows: 83 83 100 83 + // Evergreen Mac with scrollbars: 85 85 100 85 + // Evergreen Mac without scrollbars: 100 100 100 100 + + // Get scrollbar width + browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; + + // IE6/7 will oversize a width 100% element inside a scrolling element, to + // include the width of the scrollbar, while other browsers ensure the inner + // element is contained without forcing scrolling + browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; + + // In rtl text layout, some browsers (most, but not all) will place the + // scrollbar on the left, rather than the right. + browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; + + // IE8- don't provide height and width for getBoundingClientRect + browser.bBounding = n[0].getBoundingClientRect().width ? true : false; + + n.remove(); + } + + $.extend( settings.oBrowser, DataTable.__browser ); + settings.oScroll.iBarWidth = DataTable.__browser.barWidth; + } + + + /** + * Array.prototype reduce[Right] method, used for browsers which don't support + * JS 1.6. Done this way to reduce code size, since we iterate either way + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnReduce ( that, fn, init, start, end, inc ) + { + var + i = start, + value, + isSet = false; + + if ( init !== undefined ) { + value = init; + isSet = true; + } + + while ( i !== end ) { + if ( ! that.hasOwnProperty(i) ) { + continue; + } + + value = isSet ? + fn( value, that[i], i, that ) : + that[i]; + + isSet = true; + i += inc; + } + + return value; + } + + /** + * Add a column to the list used for the table with default values + * @param {object} oSettings dataTables settings object + * @param {node} nTh The th element for this column + * @memberof DataTable#oApi + */ + function _fnAddColumn( oSettings, nTh ) + { + // Add column to aoColumns array + var oDefaults = DataTable.defaults.column; + var iCol = oSettings.aoColumns.length; + var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { + "nTh": nTh ? nTh : document.createElement('th'), + "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', + "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], + "mData": oDefaults.mData ? oDefaults.mData : iCol, + idx: iCol + } ); + oSettings.aoColumns.push( oCol ); + + // Add search object for column specific search. Note that the `searchCols[ iCol ]` + // passed into extend can be undefined. This allows the user to give a default + // with only some of the parameters defined, and also not give a default + var searchCols = oSettings.aoPreSearchCols; + searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); + + // Use the default column options function to initialise classes etc + _fnColumnOptions( oSettings, iCol, $(nTh).data() ); + } + + + /** + * Apply options for a column + * @param {object} oSettings dataTables settings object + * @param {int} iCol column index to consider + * @param {object} oOptions object with sType, bVisible and bSearchable etc + * @memberof DataTable#oApi + */ + function _fnColumnOptions( oSettings, iCol, oOptions ) + { + var oCol = oSettings.aoColumns[ iCol ]; + var oClasses = oSettings.oClasses; + var th = $(oCol.nTh); + + // Try to get width information from the DOM. We can't get it from CSS + // as we'd need to parse the CSS stylesheet. `width` option can override + if ( ! oCol.sWidthOrig ) { + // Width attribute + oCol.sWidthOrig = th.attr('width') || null; + + // Style attribute + var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); + if ( t ) { + oCol.sWidthOrig = t[1]; + } + } + + /* User specified column options */ + if ( oOptions !== undefined && oOptions !== null ) + { + // Backwards compatibility + _fnCompatCols( oOptions ); + + // Map camel case parameters to their Hungarian counterparts + _fnCamelToHungarian( DataTable.defaults.column, oOptions ); + + /* Backwards compatibility for mDataProp */ + if ( oOptions.mDataProp !== undefined && !oOptions.mData ) + { + oOptions.mData = oOptions.mDataProp; + } + + if ( oOptions.sType ) + { + oCol._sManualType = oOptions.sType; + } + + // `class` is a reserved word in Javascript, so we need to provide + // the ability to use a valid name for the camel case input + if ( oOptions.className && ! oOptions.sClass ) + { + oOptions.sClass = oOptions.className; + } + if ( oOptions.sClass ) { + th.addClass( oOptions.sClass ); + } + + $.extend( oCol, oOptions ); + _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); + + /* iDataSort to be applied (backwards compatibility), but aDataSort will take + * priority if defined + */ + if ( oOptions.iDataSort !== undefined ) + { + oCol.aDataSort = [ oOptions.iDataSort ]; + } + _fnMap( oCol, oOptions, "aDataSort" ); + } + + /* Cache the data get and set functions for speed */ + var mDataSrc = oCol.mData; + var mData = _fnGetObjectDataFn( mDataSrc ); + var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; + + var attrTest = function( src ) { + return typeof src === 'string' && src.indexOf('@') !== -1; + }; + oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( + attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) + ); + oCol._setter = null; + + oCol.fnGetData = function (rowData, type, meta) { + var innerData = mData( rowData, type, undefined, meta ); + + return mRender && type ? + mRender( innerData, type, rowData, meta ) : + innerData; + }; + oCol.fnSetData = function ( rowData, val, meta ) { + return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); + }; + + // Indicate if DataTables should read DOM data as an object or array + // Used in _fnGetRowElements + if ( typeof mDataSrc !== 'number' ) { + oSettings._rowReadObject = true; + } + + /* Feature sorting overrides column specific when off */ + if ( !oSettings.oFeatures.bSort ) + { + oCol.bSortable = false; + th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called + } + + /* Check that the class assignment is correct for sorting */ + var bAsc = $.inArray('asc', oCol.asSorting) !== -1; + var bDesc = $.inArray('desc', oCol.asSorting) !== -1; + if ( !oCol.bSortable || (!bAsc && !bDesc) ) + { + oCol.sSortingClass = oClasses.sSortableNone; + oCol.sSortingClassJUI = ""; + } + else if ( bAsc && !bDesc ) + { + oCol.sSortingClass = oClasses.sSortableAsc; + oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; + } + else if ( !bAsc && bDesc ) + { + oCol.sSortingClass = oClasses.sSortableDesc; + oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; + } + else + { + oCol.sSortingClass = oClasses.sSortable; + oCol.sSortingClassJUI = oClasses.sSortJUI; + } + } + + + /** + * Adjust the table column widths for new data. Note: you would probably want to + * do a redraw after calling this function! + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnAdjustColumnSizing ( settings ) + { + /* Not interested in doing column width calculation if auto-width is disabled */ + if ( settings.oFeatures.bAutoWidth !== false ) + { + var columns = settings.aoColumns; + + _fnCalculateColumnWidths( settings ); + for ( var i=0 , iLen=columns.length ; i =0 ; i-- ) + { + def = aoColDefs[i]; + + /* Each definition can target multiple columns, as it is an array */ + var aTargets = def.targets !== undefined ? + def.targets : + def.aTargets; + + if ( ! $.isArray( aTargets ) ) + { + aTargets = [ aTargets ]; + } + + for ( j=0, jLen=aTargets.length ; j = 0 ) + { + /* Add columns that we don't yet know about */ + while( columns.length <= aTargets[j] ) + { + _fnAddColumn( oSettings ); + } + + /* Integer, basic index */ + fn( aTargets[j], def ); + } + else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) + { + /* Negative integer, right to left column counting */ + fn( columns.length+aTargets[j], def ); + } + else if ( typeof aTargets[j] === 'string' ) + { + /* Class name matching on TH element */ + for ( k=0, kLen=columns.length ; k =0 if successful (index of new aoData entry), -1 if failed + * @memberof DataTable#oApi + */ + function _fnAddData ( oSettings, aDataIn, nTr, anTds ) + { + /* Create the object for storing information about this new row */ + var iRow = oSettings.aoData.length; + var oData = $.extend( true, {}, DataTable.models.oRow, { + src: nTr ? 'dom' : 'data', + idx: iRow + } ); + + oData._aData = aDataIn; + oSettings.aoData.push( oData ); + + /* Create the cells */ + var nTd, sThisType; + var columns = oSettings.aoColumns; + + // Invalidate the column types as the new data needs to be revalidated + for ( var i=0, iLen=columns.length ; i iTarget ) + { + a[i]--; + } + } + + if ( iTargetIndex != -1 && splice === undefined ) + { + a.splice( iTargetIndex, 1 ); + } + } + + + /** + * Mark cached data as invalid such that a re-read of the data will occur when + * the cached data is next requested. Also update from the data source object. + * + * @param {object} settings DataTables settings object + * @param {int} rowIdx Row index to invalidate + * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' + * or 'data' + * @param {int} [colIdx] Column index to invalidate. If undefined the whole + * row will be invalidated + * @memberof DataTable#oApi + * + * @todo For the modularisation of v1.11 this will need to become a callback, so + * the sort and filter methods can subscribe to it. That will required + * initialisation options for sorting, which is why it is not already baked in + */ + function _fnInvalidate( settings, rowIdx, src, colIdx ) + { + var row = settings.aoData[ rowIdx ]; + var i, ien; + var cellWrite = function ( cell, col ) { + // This is very frustrating, but in IE if you just write directly + // to innerHTML, and elements that are overwritten are GC'ed, + // even if there is a reference to them elsewhere + while ( cell.childNodes.length ) { + cell.removeChild( cell.firstChild ); + } + + cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); + }; + + // Are we reading last data from DOM or the data object? + if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { + // Read the data from the DOM + row._aData = _fnGetRowElements( + settings, row, colIdx, colIdx === undefined ? undefined : row._aData + ) + .data; + } + else { + // Reading from data object, update the DOM + var cells = row.anCells; + + if ( cells ) { + if ( colIdx !== undefined ) { + cellWrite( cells[colIdx], colIdx ); + } + else { + for ( i=0, ien=cells.length ; i ').appendTo( thead ); + } + + for ( i=0, ien=columns.length ; i tr').attr('role', 'row'); + + /* Deal with the footer - add classes if required */ + $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); + $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); + + // Cache the footer cells. Note that we only take the cells from the first + // row in the footer. If there is more than one row the user wants to + // interact with, they need to use the table().foot() method. Note also this + // allows cells to be used for multiple columns using colspan + if ( tfoot !== null ) { + var cells = oSettings.aoFooter[0]; + + for ( i=0, ien=cells.length ; i =0 ; j-- ) + { + if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) + { + aoLocal[i].splice( j, 1 ); + } + } + + /* Prep the applied array - it needs an element for each row */ + aApplied.push( [] ); + } + + for ( i=0, iLen=aoLocal.length ; i = oSettings.fnRecordsDisplay() ? + 0 : + iInitDisplayStart; + + oSettings.iInitDisplayStart = -1; + } + + var iDisplayStart = oSettings._iDisplayStart; + var iDisplayEnd = oSettings.fnDisplayEnd(); + + /* Server-side processing draw intercept */ + if ( oSettings.bDeferLoading ) + { + oSettings.bDeferLoading = false; + oSettings.iDraw++; + _fnProcessingDisplay( oSettings, false ); + } + else if ( !bServerSide ) + { + oSettings.iDraw++; + } + else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) + { + return; + } + + if ( aiDisplay.length !== 0 ) + { + var iStart = bServerSide ? 0 : iDisplayStart; + var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; + + for ( var j=iStart ; j ', { 'class': iStripes ? asStripeClasses[0] : '' } ) + .append( $(' ', { + 'valign': 'top', + 'colSpan': _fnVisbleColumns( oSettings ), + 'class': oSettings.oClasses.sRowEmpty + } ).html( sZero ) )[0]; + } + + /* Header and footer callbacks */ + _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], + _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); + + _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], + _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); + + var body = $(oSettings.nTBody); + + body.children().detach(); + body.append( $(anRows) ); + + /* Call all required callback functions for the end of a draw */ + _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); + + /* Draw is complete, sorting and filtering must be as well */ + oSettings.bSorted = false; + oSettings.bFiltered = false; + oSettings.bDrawing = false; + } + + + /** + * Redraw the table - taking account of the various features which are enabled + * @param {object} oSettings dataTables settings object + * @param {boolean} [holdPosition] Keep the current paging position. By default + * the paging is reset to the first page + * @memberof DataTable#oApi + */ + function _fnReDraw( settings, holdPosition ) + { + var + features = settings.oFeatures, + sort = features.bSort, + filter = features.bFilter; + + if ( sort ) { + _fnSort( settings ); + } + + if ( filter ) { + _fnFilterComplete( settings, settings.oPreviousSearch ); + } + else { + // No filtering, so we want to just use the display master + settings.aiDisplay = settings.aiDisplayMaster.slice(); + } + + if ( holdPosition !== true ) { + settings._iDisplayStart = 0; + } + + // Let any modules know about the draw hold position state (used by + // scrolling internally) + settings._drawHold = holdPosition; + + _fnDraw( settings ); + + settings._drawHold = false; + } + + + /** + * Add the options to the page HTML for the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnAddOptionsHtml ( oSettings ) + { + var classes = oSettings.oClasses; + var table = $(oSettings.nTable); + var holding = $('').insertBefore( table ); // Holding element for speed + var features = oSettings.oFeatures; + + // All DataTables are wrapped in a div + var insert = $('', { + id: oSettings.sTableId+'_wrapper', + 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) + } ); + + oSettings.nHolding = holding[0]; + oSettings.nTableWrapper = insert[0]; + oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; + + /* Loop over the user set positioning and place the elements as needed */ + var aDom = oSettings.sDom.split(''); + var featureNode, cOption, nNewNode, cNext, sAttr, j; + for ( var i=0 ; i ')[0]; + + /* Check to see if we should append an id and/or a class name to the container */ + cNext = aDom[i+1]; + if ( cNext == "'" || cNext == '"' ) + { + sAttr = ""; + j = 2; + while ( aDom[i+j] != cNext ) + { + sAttr += aDom[i+j]; + j++; + } + + /* Replace jQuery UI constants @todo depreciated */ + if ( sAttr == "H" ) + { + sAttr = classes.sJUIHeader; + } + else if ( sAttr == "F" ) + { + sAttr = classes.sJUIFooter; + } + + /* The attribute can be in the format of "#id.class", "#id" or "class" This logic + * breaks the string into parts and applies them as needed + */ + if ( sAttr.indexOf('.') != -1 ) + { + var aSplit = sAttr.split('.'); + nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); + nNewNode.className = aSplit[1]; + } + else if ( sAttr.charAt(0) == "#" ) + { + nNewNode.id = sAttr.substr(1, sAttr.length-1); + } + else + { + nNewNode.className = sAttr; + } + + i += j; /* Move along the position array */ + } + + insert.append( nNewNode ); + insert = $(nNewNode); + } + else if ( cOption == '>' ) + { + /* End container div */ + insert = insert.parent(); + } + // @todo Move options into their own plugins? + else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) + { + /* Length */ + featureNode = _fnFeatureHtmlLength( oSettings ); + } + else if ( cOption == 'f' && features.bFilter ) + { + /* Filter */ + featureNode = _fnFeatureHtmlFilter( oSettings ); + } + else if ( cOption == 'r' && features.bProcessing ) + { + /* pRocessing */ + featureNode = _fnFeatureHtmlProcessing( oSettings ); + } + else if ( cOption == 't' ) + { + /* Table */ + featureNode = _fnFeatureHtmlTable( oSettings ); + } + else if ( cOption == 'i' && features.bInfo ) + { + /* Info */ + featureNode = _fnFeatureHtmlInfo( oSettings ); + } + else if ( cOption == 'p' && features.bPaginate ) + { + /* Pagination */ + featureNode = _fnFeatureHtmlPaginate( oSettings ); + } + else if ( DataTable.ext.feature.length !== 0 ) + { + /* Plug-in features */ + var aoFeatures = DataTable.ext.feature; + for ( var k=0, kLen=aoFeatures.length ; k '; + + var str = language.sSearch; + str = str.match(/_INPUT_/) ? + str.replace('_INPUT_', input) : + str+input; + + var filter = $('', { + 'id': ! features.f ? tableId+'_filter' : null, + 'class': classes.sFilter + } ) + .append( $('' ).append( str ) ); + + var searchFn = function() { + /* Update all other filter input elements for the new display */ + var n = features.f; + var val = !this.value ? "" : this.value; // mental IE8 fix :-( + + /* Now do the filter */ + if ( val != previousSearch.sSearch ) { + _fnFilterComplete( settings, { + "sSearch": val, + "bRegex": previousSearch.bRegex, + "bSmart": previousSearch.bSmart , + "bCaseInsensitive": previousSearch.bCaseInsensitive + } ); + + // Need to redraw, without resorting + settings._iDisplayStart = 0; + _fnDraw( settings ); + } + }; + + var searchDelay = settings.searchDelay !== null ? + settings.searchDelay : + _fnDataSource( settings ) === 'ssp' ? + 400 : + 0; + + var jqFilter = $('input', filter) + .val( previousSearch.sSearch ) + .attr( 'placeholder', language.sSearchPlaceholder ) + .on( + 'keyup.DT search.DT input.DT paste.DT cut.DT', + searchDelay ? + _fnThrottle( searchFn, searchDelay ) : + searchFn + ) + .on( 'keypress.DT', function(e) { + /* Prevent form submission */ + if ( e.keyCode == 13 ) { + return false; + } + } ) + .attr('aria-controls', tableId); + + // Update the input elements whenever the table is filtered + $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { + if ( settings === s ) { + // IE9 throws an 'unknown error' if document.activeElement is used + // inside an iframe or frame... + try { + if ( jqFilter[0] !== document.activeElement ) { + jqFilter.val( previousSearch.sSearch ); + } + } + catch ( e ) {} + } + } ); + + return filter[0]; + } + + + /** + * Filter the table using both the global filter and column based filtering + * @param {object} oSettings dataTables settings object + * @param {object} oSearch search information + * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) + * @memberof DataTable#oApi + */ + function _fnFilterComplete ( oSettings, oInput, iForce ) + { + var oPrevSearch = oSettings.oPreviousSearch; + var aoPrevSearch = oSettings.aoPreSearchCols; + var fnSaveFilter = function ( oFilter ) { + /* Save the filtering values */ + oPrevSearch.sSearch = oFilter.sSearch; + oPrevSearch.bRegex = oFilter.bRegex; + oPrevSearch.bSmart = oFilter.bSmart; + oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; + }; + var fnRegex = function ( o ) { + // Backwards compatibility with the bEscapeRegex option + return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; + }; + + // Resolve any column types that are unknown due to addition or invalidation + // @todo As per sort - can this be moved into an event handler? + _fnColumnTypes( oSettings ); + + /* In server-side processing all filtering is done by the server, so no point hanging around here */ + if ( _fnDataSource( oSettings ) != 'ssp' ) + { + /* Global filter */ + _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); + fnSaveFilter( oInput ); + + /* Now do the individual column filter */ + for ( var i=0 ; i input.length || + input.indexOf(prevSearch) !== 0 || + settings.bSorted // On resort, the display master needs to be + // re-filtered since indexes will have changed + ) { + settings.aiDisplay = displayMaster.slice(); + } + + // Search the display array + display = settings.aiDisplay; + + for ( i=0 ; i ')[0]; + var __filter_div_textContent = __filter_div.textContent !== undefined; + + // Update the filtering data for each row if needed (by invalidation or first run) + function _fnFilterData ( settings ) + { + var columns = settings.aoColumns; + var column; + var i, j, ien, jen, filterData, cellData, row; + var fomatters = DataTable.ext.type.search; + var wasInvalidated = false; + + for ( i=0, ien=settings.aoData.length ; i ', { + 'class': settings.oClasses.sInfo, + 'id': ! nodes ? tid+'_info' : null + } ); + + if ( ! nodes ) { + // Update display on each draw + settings.aoDrawCallback.push( { + "fn": _fnUpdateInfo, + "sName": "information" + } ); + + n + .attr( 'role', 'status' ) + .attr( 'aria-live', 'polite' ); + + // Table is described by our info div + $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); + } + + return n[0]; + } + + + /** + * Update the information elements in the display + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnUpdateInfo ( settings ) + { + /* Show information about the table */ + var nodes = settings.aanFeatures.i; + if ( nodes.length === 0 ) { + return; + } + + var + lang = settings.oLanguage, + start = settings._iDisplayStart+1, + end = settings.fnDisplayEnd(), + max = settings.fnRecordsTotal(), + total = settings.fnRecordsDisplay(), + out = total ? + lang.sInfo : + lang.sInfoEmpty; + + if ( total !== max ) { + /* Record set after filtering */ + out += ' ' + lang.sInfoFiltered; + } + + // Convert the macros + out += lang.sInfoPostFix; + out = _fnInfoMacros( settings, out ); + + var callback = lang.fnInfoCallback; + if ( callback !== null ) { + out = callback.call( settings.oInstance, + settings, start, end, max, total, out + ); + } + + $(nodes).html( out ); + } + + + function _fnInfoMacros ( settings, str ) + { + // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only + // internally + var + formatter = settings.fnFormatNumber, + start = settings._iDisplayStart+1, + len = settings._iDisplayLength, + vis = settings.fnRecordsDisplay(), + all = len === -1; + + return str. + replace(/_START_/g, formatter.call( settings, start ) ). + replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). + replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). + replace(/_TOTAL_/g, formatter.call( settings, vis ) ). + replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). + replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); + } + + + + /** + * Draw the table for the first time, adding all required features + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnInitialise ( settings ) + { + var i, iLen, iAjaxStart=settings.iInitDisplayStart; + var columns = settings.aoColumns, column; + var features = settings.oFeatures; + var deferLoading = settings.bDeferLoading; // value modified by the draw + + /* Ensure that the table data is fully initialised */ + if ( ! settings.bInitialised ) { + setTimeout( function(){ _fnInitialise( settings ); }, 200 ); + return; + } + + /* Show the display HTML options */ + _fnAddOptionsHtml( settings ); + + /* Build and draw the header / footer for the table */ + _fnBuildHead( settings ); + _fnDrawHead( settings, settings.aoHeader ); + _fnDrawHead( settings, settings.aoFooter ); + + /* Okay to show that something is going on now */ + _fnProcessingDisplay( settings, true ); + + /* Calculate sizes for columns */ + if ( features.bAutoWidth ) { + _fnCalculateColumnWidths( settings ); + } + + for ( i=0, iLen=columns.length ; i ', { + 'name': tableId+'_length', + 'aria-controls': tableId, + 'class': classes.sLengthSelect + } ); + + for ( var i=0, ien=lengths.length ; i ').addClass( classes.sLength ); + if ( ! settings.aanFeatures.l ) { + div[0].id = tableId+'_length'; + } + + div.children().append( + settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) + ); + + // Can't use `select` variable as user might provide their own and the + // reference is broken by the use of outerHTML + $('select', div) + .val( settings._iDisplayLength ) + .on( 'change.DT', function(e) { + _fnLengthChange( settings, $(this).val() ); + _fnDraw( settings ); + } ); + + // Update node value whenever anything changes the table's length + $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { + if ( settings === s ) { + $('select', div).val( len ); + } + } ); + + return div[0]; + } + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Note that most of the paging logic is done in + * DataTable.ext.pager + */ + + /** + * Generate the node required for default pagination + * @param {object} oSettings dataTables settings object + * @returns {node} Pagination feature node + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlPaginate ( settings ) + { + var + type = settings.sPaginationType, + plugin = DataTable.ext.pager[ type ], + modern = typeof plugin === 'function', + redraw = function( settings ) { + _fnDraw( settings ); + }, + node = $('').addClass( settings.oClasses.sPaging + type )[0], + features = settings.aanFeatures; + + if ( ! modern ) { + plugin.fnInit( settings, node, redraw ); + } + + /* Add a draw callback for the pagination on first instance, to update the paging display */ + if ( ! features.p ) + { + node.id = settings.sTableId+'_paginate'; + + settings.aoDrawCallback.push( { + "fn": function( settings ) { + if ( modern ) { + var + start = settings._iDisplayStart, + len = settings._iDisplayLength, + visRecords = settings.fnRecordsDisplay(), + all = len === -1, + page = all ? 0 : Math.ceil( start / len ), + pages = all ? 1 : Math.ceil( visRecords / len ), + buttons = plugin(page, pages), + i, ien; + + for ( i=0, ien=features.p.length ; i records ) + { + start = 0; + } + } + else if ( action == "first" ) + { + start = 0; + } + else if ( action == "previous" ) + { + start = len >= 0 ? + start - len : + 0; + + if ( start < 0 ) + { + start = 0; + } + } + else if ( action == "next" ) + { + if ( start + len < records ) + { + start += len; + } + } + else if ( action == "last" ) + { + start = Math.floor( (records-1) / len) * len; + } + else + { + _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); + } + + var changed = settings._iDisplayStart !== start; + settings._iDisplayStart = start; + + if ( changed ) { + _fnCallbackFire( settings, null, 'page', [settings] ); + + if ( redraw ) { + _fnDraw( settings ); + } + } + + return changed; + } + + + + /** + * Generate the node required for the processing node + * @param {object} settings dataTables settings object + * @returns {node} Processing element + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlProcessing ( settings ) + { + return $('', { + 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, + 'class': settings.oClasses.sProcessing + } ) + .html( settings.oLanguage.sProcessing ) + .insertBefore( settings.nTable )[0]; + } + + + /** + * Display or hide the processing indicator + * @param {object} settings dataTables settings object + * @param {bool} show Show the processing indicator (true) or not (false) + * @memberof DataTable#oApi + */ + function _fnProcessingDisplay ( settings, show ) + { + if ( settings.oFeatures.bProcessing ) { + $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); + } + + _fnCallbackFire( settings, null, 'processing', [settings, show] ); + } + + /** + * Add any control elements for the table - specifically scrolling + * @param {object} settings dataTables settings object + * @returns {node} Node to add to the DOM + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlTable ( settings ) + { + var table = $(settings.nTable); + + // Add the ARIA grid role to the table + table.attr( 'role', 'grid' ); + + // Scrolling from here on in + var scroll = settings.oScroll; + + if ( scroll.sX === '' && scroll.sY === '' ) { + return settings.nTable; + } + + var scrollX = scroll.sX; + var scrollY = scroll.sY; + var classes = settings.oClasses; + var caption = table.children('caption'); + var captionSide = caption.length ? caption[0]._captionSide : null; + var headerClone = $( table[0].cloneNode(false) ); + var footerClone = $( table[0].cloneNode(false) ); + var footer = table.children('tfoot'); + var _div = ''; + var size = function ( s ) { + return !s ? null : _fnStringToCss( s ); + }; + + if ( ! footer.length ) { + footer = null; + } + + /* + * The HTML structure that we want to generate in this function is: + * div - scroller + * div - scroll head + * div - scroll head inner + * table - scroll head table + * thead - thead + * div - scroll body + * table - table (master table) + * thead - thead clone for sizing + * tbody - tbody + * div - scroll foot + * div - scroll foot inner + * table - scroll foot table + * tfoot - tfoot + */ + var scroller = $( _div, { 'class': classes.sScrollWrapper } ) + .append( + $(_div, { 'class': classes.sScrollHead } ) + .css( { + overflow: 'hidden', + position: 'relative', + border: 0, + width: scrollX ? size(scrollX) : '100%' + } ) + .append( + $(_div, { 'class': classes.sScrollHeadInner } ) + .css( { + 'box-sizing': 'content-box', + width: scroll.sXInner || '100%' + } ) + .append( + headerClone + .removeAttr('id') + .css( 'margin-left', 0 ) + .append( captionSide === 'top' ? caption : null ) + .append( + table.children('thead') + ) + ) + ) + ) + .append( + $(_div, { 'class': classes.sScrollBody } ) + .css( { + position: 'relative', + overflow: 'auto', + width: size( scrollX ) + } ) + .append( table ) + ); + + if ( footer ) { + scroller.append( + $(_div, { 'class': classes.sScrollFoot } ) + .css( { + overflow: 'hidden', + border: 0, + width: scrollX ? size(scrollX) : '100%' + } ) + .append( + $(_div, { 'class': classes.sScrollFootInner } ) + .append( + footerClone + .removeAttr('id') + .css( 'margin-left', 0 ) + .append( captionSide === 'bottom' ? caption : null ) + .append( + table.children('tfoot') + ) + ) + ) + ); + } + + var children = scroller.children(); + var scrollHead = children[0]; + var scrollBody = children[1]; + var scrollFoot = footer ? children[2] : null; + + // When the body is scrolled, then we also want to scroll the headers + if ( scrollX ) { + $(scrollBody).on( 'scroll.DT', function (e) { + var scrollLeft = this.scrollLeft; + + scrollHead.scrollLeft = scrollLeft; + + if ( footer ) { + scrollFoot.scrollLeft = scrollLeft; + } + } ); + } + + $(scrollBody).css( + scrollY && scroll.bCollapse ? 'max-height' : 'height', + scrollY + ); + + settings.nScrollHead = scrollHead; + settings.nScrollBody = scrollBody; + settings.nScrollFoot = scrollFoot; + + // On redraw - align columns + settings.aoDrawCallback.push( { + "fn": _fnScrollDraw, + "sName": "scrolling" + } ); + + return scroller[0]; + } + + + + /** + * Update the header, footer and body tables for resizing - i.e. column + * alignment. + * + * Welcome to the most horrible function DataTables. The process that this + * function follows is basically: + * 1. Re-create the table inside the scrolling div + * 2. Take live measurements from the DOM + * 3. Apply the measurements to align the columns + * 4. Clean up + * + * @param {object} settings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnScrollDraw ( settings ) + { + // Given that this is such a monster function, a lot of variables are use + // to try and keep the minimised size as small as possible + var + scroll = settings.oScroll, + scrollX = scroll.sX, + scrollXInner = scroll.sXInner, + scrollY = scroll.sY, + barWidth = scroll.iBarWidth, + divHeader = $(settings.nScrollHead), + divHeaderStyle = divHeader[0].style, + divHeaderInner = divHeader.children('div'), + divHeaderInnerStyle = divHeaderInner[0].style, + divHeaderTable = divHeaderInner.children('table'), + divBodyEl = settings.nScrollBody, + divBody = $(divBodyEl), + divBodyStyle = divBodyEl.style, + divFooter = $(settings.nScrollFoot), + divFooterInner = divFooter.children('div'), + divFooterTable = divFooterInner.children('table'), + header = $(settings.nTHead), + table = $(settings.nTable), + tableEl = table[0], + tableStyle = tableEl.style, + footer = settings.nTFoot ? $(settings.nTFoot) : null, + browser = settings.oBrowser, + ie67 = browser.bScrollOversize, + dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), + headerTrgEls, footerTrgEls, + headerSrcEls, footerSrcEls, + headerCopy, footerCopy, + headerWidths=[], footerWidths=[], + headerContent=[], footerContent=[], + idx, correction, sanityWidth, + zeroOut = function(nSizer) { + var style = nSizer.style; + style.paddingTop = "0"; + style.paddingBottom = "0"; + style.borderTopWidth = "0"; + style.borderBottomWidth = "0"; + style.height = 0; + }; + + // If the scrollbar visibility has changed from the last draw, we need to + // adjust the column sizes as the table width will have changed to account + // for the scrollbar + var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; + + if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { + settings.scrollBarVis = scrollBarVis; + _fnAdjustColumnSizing( settings ); + return; // adjust column sizing will call this function again + } + else { + settings.scrollBarVis = scrollBarVis; + } + + /* + * 1. Re-create the table inside the scrolling div + */ + + // Remove the old minimised thead and tfoot elements in the inner table + table.children('thead, tfoot').remove(); + + if ( footer ) { + footerCopy = footer.clone().prependTo( table ); + footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized + footerSrcEls = footerCopy.find('tr'); + } + + // Clone the current header and footer elements and then place it into the inner table + headerCopy = header.clone().prependTo( table ); + headerTrgEls = header.find('tr'); // original header is in its own table + headerSrcEls = headerCopy.find('tr'); + headerCopy.find('th, td').removeAttr('tabindex'); + + + /* + * 2. Take live measurements from the DOM - do not alter the DOM itself! + */ + + // Remove old sizing and apply the calculated column widths + // Get the unique column headers in the newly created (cloned) header. We want to apply the + // calculated sizes to this header + if ( ! scrollX ) + { + divBodyStyle.width = '100%'; + divHeader[0].style.width = '100%'; + } + + $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { + idx = _fnVisibleToColumnIndex( settings, i ); + el.style.width = settings.aoColumns[idx].sWidth; + } ); + + if ( footer ) { + _fnApplyToChildren( function(n) { + n.style.width = ""; + }, footerSrcEls ); + } + + // Size the table as a whole + sanityWidth = table.outerWidth(); + if ( scrollX === "" ) { + // No x scrolling + tableStyle.width = "100%"; + + // IE7 will make the width of the table when 100% include the scrollbar + // - which is shouldn't. When there is a scrollbar we need to take this + // into account. + if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || + divBody.css('overflow-y') == "scroll") + ) { + tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); + } + + // Recalculate the sanity width + sanityWidth = table.outerWidth(); + } + else if ( scrollXInner !== "" ) { + // legacy x scroll inner has been given - use it + tableStyle.width = _fnStringToCss(scrollXInner); + + // Recalculate the sanity width + sanityWidth = table.outerWidth(); + } + + // Hidden header should have zero height, so remove padding and borders. Then + // set the width based on the real headers + + // Apply all styles in one pass + _fnApplyToChildren( zeroOut, headerSrcEls ); + + // Read all widths in next pass + _fnApplyToChildren( function(nSizer) { + headerContent.push( nSizer.innerHTML ); + headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); + }, headerSrcEls ); + + // Apply all widths in final pass + _fnApplyToChildren( function(nToSize, i) { + // Only apply widths to the DataTables detected header cells - this + // prevents complex headers from having contradictory sizes applied + if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { + nToSize.style.width = headerWidths[i]; + } + }, headerTrgEls ); + + $(headerSrcEls).height(0); + + /* Same again with the footer if we have one */ + if ( footer ) + { + _fnApplyToChildren( zeroOut, footerSrcEls ); + + _fnApplyToChildren( function(nSizer) { + footerContent.push( nSizer.innerHTML ); + footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); + }, footerSrcEls ); + + _fnApplyToChildren( function(nToSize, i) { + nToSize.style.width = footerWidths[i]; + }, footerTrgEls ); + + $(footerSrcEls).height(0); + } + + + /* + * 3. Apply the measurements + */ + + // "Hide" the header and footer that we used for the sizing. We need to keep + // the content of the cell so that the width applied to the header and body + // both match, but we want to hide it completely. We want to also fix their + // width to what they currently are + _fnApplyToChildren( function(nSizer, i) { + nSizer.innerHTML = ''; + nSizer.style.width = headerWidths[i]; + }, headerSrcEls ); + + if ( footer ) + { + _fnApplyToChildren( function(nSizer, i) { + nSizer.innerHTML = ''; + nSizer.style.width = footerWidths[i]; + }, footerSrcEls ); + } + + // Sanity check that the table is of a sensible width. If not then we are going to get + // misalignment - try to prevent this by not allowing the table to shrink below its min width + if ( table.outerWidth() < sanityWidth ) + { + // The min width depends upon if we have a vertical scrollbar visible or not */ + correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || + divBody.css('overflow-y') == "scroll")) ? + sanityWidth+barWidth : + sanityWidth; + + // IE6/7 are a law unto themselves... + if ( ie67 && (divBodyEl.scrollHeight > + divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") + ) { + tableStyle.width = _fnStringToCss( correction-barWidth ); + } + + // And give the user a warning that we've stopped the table getting too small + if ( scrollX === "" || scrollXInner !== "" ) { + _fnLog( settings, 1, 'Possible column misalignment', 6 ); + } + } + else + { + correction = '100%'; + } + + // Apply to the container elements + divBodyStyle.width = _fnStringToCss( correction ); + divHeaderStyle.width = _fnStringToCss( correction ); + + if ( footer ) { + settings.nScrollFoot.style.width = _fnStringToCss( correction ); + } + + + /* + * 4. Clean up + */ + if ( ! scrollY ) { + /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting + * the scrollbar height from the visible display, rather than adding it on. We need to + * set the height in order to sort this. Don't want to do it in any other browsers. + */ + if ( ie67 ) { + divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); + } + } + + /* Finally set the width's of the header and footer tables */ + var iOuterWidth = table.outerWidth(); + divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); + divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); + + // Figure out if there are scrollbar present - if so then we need a the header and footer to + // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) + var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; + var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); + divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; + + if ( footer ) { + divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); + divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); + divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; + } + + // Correct DOM ordering for colgroup - comes before the thead + table.children('colgroup').insertBefore( table.children('thead') ); + + /* Adjust the position of the header in case we loose the y-scrollbar */ + divBody.scroll(); + + // If sorting or filtering has occurred, jump the scrolling back to the top + // only if we aren't holding the position + if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { + divBodyEl.scrollTop = 0; + } + } + + + + /** + * Apply a given function to the display child nodes of an element array (typically + * TD children of TR rows + * @param {function} fn Method to apply to the objects + * @param array {nodes} an1 List of elements to look through for display children + * @param array {nodes} an2 Another list (identical structure to the first) - optional + * @memberof DataTable#oApi + */ + function _fnApplyToChildren( fn, an1, an2 ) + { + var index=0, i=0, iLen=an1.length; + var nNode1, nNode2; + + while ( i < iLen ) { + nNode1 = an1[i].firstChild; + nNode2 = an2 ? an2[i].firstChild : null; + + while ( nNode1 ) { + if ( nNode1.nodeType === 1 ) { + if ( an2 ) { + fn( nNode1, nNode2, index ); + } + else { + fn( nNode1, index ); + } + + index++; + } + + nNode1 = nNode1.nextSibling; + nNode2 = an2 ? nNode2.nextSibling : null; + } + + i++; + } + } + + + + var __re_html_remove = /<.*?>/g; + + + /** + * Calculate the width of columns for the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnCalculateColumnWidths ( oSettings ) + { + var + table = oSettings.nTable, + columns = oSettings.aoColumns, + scroll = oSettings.oScroll, + scrollY = scroll.sY, + scrollX = scroll.sX, + scrollXInner = scroll.sXInner, + columnCount = columns.length, + visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), + headerCells = $('th', oSettings.nTHead), + tableWidthAttr = table.getAttribute('width'), // from DOM element + tableContainer = table.parentNode, + userInputs = false, + i, column, columnIdx, width, outerWidth, + browser = oSettings.oBrowser, + ie67 = browser.bScrollOversize; + + var styleWidth = table.style.width; + if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { + tableWidthAttr = styleWidth; + } + + /* Convert any user input sizes into pixel sizes */ + for ( i=0 ; i ').appendTo( tmpTable.find('tbody') ); + + // Clone the table header and footer - we can't use the header / footer + // from the cloned table, since if scrolling is active, the table's + // real header and footer are contained in different table tags + tmpTable.find('thead, tfoot').remove(); + tmpTable + .append( $(oSettings.nTHead).clone() ) + .append( $(oSettings.nTFoot).clone() ); + + // Remove any assigned widths from the footer (from scrolling) + tmpTable.find('tfoot th, tfoot td').css('width', ''); + + // Apply custom sizing to the cloned header + headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); + + for ( i=0 ; i ').css( { + width: column.sWidthOrig, + margin: 0, + padding: 0, + border: 0, + height: 1 + } ) ); + } + } + + // Find the widest cell for each column and put it into the table + if ( oSettings.aoData.length ) { + for ( i=0 ; i ').css( scrollX || scrollY ? + { + position: 'absolute', + top: 0, + left: 0, + height: 1, + right: 0, + overflow: 'hidden' + } : + {} + ) + .append( tmpTable ) + .appendTo( tableContainer ); + + // When scrolling (X or Y) we want to set the width of the table as + // appropriate. However, when not scrolling leave the table width as it + // is. This results in slightly different, but I think correct behaviour + if ( scrollX && scrollXInner ) { + tmpTable.width( scrollXInner ); + } + else if ( scrollX ) { + tmpTable.css( 'width', 'auto' ); + tmpTable.removeAttr('width'); + + // If there is no width attribute or style, then allow the table to + // collapse + if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { + tmpTable.width( tableContainer.clientWidth ); + } + } + else if ( scrollY ) { + tmpTable.width( tableContainer.clientWidth ); + } + else if ( tableWidthAttr ) { + tmpTable.width( tableWidthAttr ); + } + + // Get the width of each column in the constructed table - we need to + // know the inner width (so it can be assigned to the other table's + // cells) and the outer width so we can calculate the full width of the + // table. This is safe since DataTables requires a unique cell for each + // column, but if ever a header can span multiple columns, this will + // need to be modified. + var total = 0; + for ( i=0 ; i ') + .css( 'width', _fnStringToCss( width ) ) + .appendTo( parent || document.body ); + + var val = n[0].offsetWidth; + n.remove(); + + return val; + } + + + /** + * Get the widest node + * @param {object} settings dataTables settings object + * @param {int} colIdx column of interest + * @returns {node} widest table node + * @memberof DataTable#oApi + */ + function _fnGetWidestNode( settings, colIdx ) + { + var idx = _fnGetMaxLenString( settings, colIdx ); + if ( idx < 0 ) { + return null; + } + + var data = settings.aoData[ idx ]; + return ! data.nTr ? // Might not have been created when deferred rendering + $(' ').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : + data.anCells[ colIdx ]; + } + + + /** + * Get the maximum strlen for each data column + * @param {object} settings dataTables settings object + * @param {int} colIdx column of interest + * @returns {string} max string length for each column + * @memberof DataTable#oApi + */ + function _fnGetMaxLenString( settings, colIdx ) + { + var s, max=-1, maxIdx = -1; + + for ( var i=0, ien=settings.aoData.length ; i max ) { + max = s.length; + maxIdx = i; + } + } + + return maxIdx; + } + + + /** + * Append a CSS unit (only if required) to a string + * @param {string} value to css-ify + * @returns {string} value with css unit + * @memberof DataTable#oApi + */ + function _fnStringToCss( s ) + { + if ( s === null ) { + return '0px'; + } + + if ( typeof s == 'number' ) { + return s < 0 ? + '0px' : + s+'px'; + } + + // Check it has a unit character already + return s.match(/\d$/) ? + s+'px' : + s; + } + + + + function _fnSortFlatten ( settings ) + { + var + i, iLen, k, kLen, + aSort = [], + aiOrig = [], + aoColumns = settings.aoColumns, + aDataSort, iCol, sType, srcCol, + fixed = settings.aaSortingFixed, + fixedObj = $.isPlainObject( fixed ), + nestedSort = [], + add = function ( a ) { + if ( a.length && ! $.isArray( a[0] ) ) { + // 1D array + nestedSort.push( a ); + } + else { + // 2D array + $.merge( nestedSort, a ); + } + }; + + // Build the sort array, with pre-fix and post-fix options if they have been + // specified + if ( $.isArray( fixed ) ) { + add( fixed ); + } + + if ( fixedObj && fixed.pre ) { + add( fixed.pre ); + } + + add( settings.aaSorting ); + + if (fixedObj && fixed.post ) { + add( fixed.post ); + } + + for ( i=0 ; i y ? 1 : 0; + if ( test !== 0 ) { + return sort.dir === 'asc' ? test : -test; + } + } + + x = aiOrig[a]; + y = aiOrig[b]; + return x y ? 1 : 0; + } ); + } + else { + // Depreciated - remove in 1.11 (providing a plug-in option) + // Not all sort types have formatting methods, so we have to call their sorting + // methods. + displayMaster.sort( function ( a, b ) { + var + x, y, k, l, test, sort, fn, + len=aSort.length, + dataA = aoData[a]._aSortData, + dataB = aoData[b]._aSortData; + + for ( k=0 ; k y ? 1 : 0; + } ); + } + } + + /* Tell the draw function that we have sorted the data */ + oSettings.bSorted = true; + } + + + function _fnSortAria ( settings ) + { + var label; + var nextSort; + var columns = settings.aoColumns; + var aSort = _fnSortFlatten( settings ); + var oAria = settings.oLanguage.oAria; + + // ARIA attributes - need to loop all columns, to update all (removing old + // attributes as needed) + for ( var i=0, iLen=columns.length ; i /g, "" ); + var th = col.nTh; + + // IE7 is throwing an error when setting these properties with jQuery's + // attr() and removeAttr() methods... + th.removeAttribute('aria-sort'); + + /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ + if ( col.bSortable ) { + if ( aSort.length > 0 && aSort[0].col == i ) { + th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); + nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; + } + else { + nextSort = asSorting[0]; + } + + label = sTitle + ( nextSort === "asc" ? + oAria.sSortAscending : + oAria.sSortDescending + ); + } + else { + label = sTitle; + } + + th.setAttribute('aria-label', label); + } + } + + + /** + * Function to run on user sort request + * @param {object} settings dataTables settings object + * @param {node} attachTo node to attach the handler to + * @param {int} colIdx column sorting index + * @param {boolean} [append=false] Append the requested sort to the existing + * sort if true (i.e. multi-column sort) + * @param {function} [callback] callback function + * @memberof DataTable#oApi + */ + function _fnSortListener ( settings, colIdx, append, callback ) + { + var col = settings.aoColumns[ colIdx ]; + var sorting = settings.aaSorting; + var asSorting = col.asSorting; + var nextSortIdx; + var next = function ( a, overflow ) { + var idx = a._idx; + if ( idx === undefined ) { + idx = $.inArray( a[1], asSorting ); + } + + return idx+1 < asSorting.length ? + idx+1 : + overflow ? + null : + 0; + }; + + // Convert to 2D array if needed + if ( typeof sorting[0] === 'number' ) { + sorting = settings.aaSorting = [ sorting ]; + } + + // If appending the sort then we are multi-column sorting + if ( append && settings.oFeatures.bSortMulti ) { + // Are we already doing some kind of sort on this column? + var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); + + if ( sortIdx !== -1 ) { + // Yes, modify the sort + nextSortIdx = next( sorting[sortIdx], true ); + + if ( nextSortIdx === null && sorting.length === 1 ) { + nextSortIdx = 0; // can't remove sorting completely + } + + if ( nextSortIdx === null ) { + sorting.splice( sortIdx, 1 ); + } + else { + sorting[sortIdx][1] = asSorting[ nextSortIdx ]; + sorting[sortIdx]._idx = nextSortIdx; + } + } + else { + // No sort on this column yet + sorting.push( [ colIdx, asSorting[0], 0 ] ); + sorting[sorting.length-1]._idx = 0; + } + } + else if ( sorting.length && sorting[0][0] == colIdx ) { + // Single column - already sorting on this column, modify the sort + nextSortIdx = next( sorting[0] ); + + sorting.length = 1; + sorting[0][1] = asSorting[ nextSortIdx ]; + sorting[0]._idx = nextSortIdx; + } + else { + // Single column - sort only on this column + sorting.length = 0; + sorting.push( [ colIdx, asSorting[0] ] ); + sorting[0]._idx = 0; + } + + // Run the sort by calling a full redraw + _fnReDraw( settings ); + + // callback used for async user interaction + if ( typeof callback == 'function' ) { + callback( settings ); + } + } + + + /** + * Attach a sort handler (click) to a node + * @param {object} settings dataTables settings object + * @param {node} attachTo node to attach the handler to + * @param {int} colIdx column sorting index + * @param {function} [callback] callback function + * @memberof DataTable#oApi + */ + function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) + { + var col = settings.aoColumns[ colIdx ]; + + _fnBindAction( attachTo, {}, function (e) { + /* If the column is not sortable - don't to anything */ + if ( col.bSortable === false ) { + return; + } + + // If processing is enabled use a timeout to allow the processing + // display to be shown - otherwise to it synchronously + if ( settings.oFeatures.bProcessing ) { + _fnProcessingDisplay( settings, true ); + + setTimeout( function() { + _fnSortListener( settings, colIdx, e.shiftKey, callback ); + + // In server-side processing, the draw callback will remove the + // processing display + if ( _fnDataSource( settings ) !== 'ssp' ) { + _fnProcessingDisplay( settings, false ); + } + }, 0 ); + } + else { + _fnSortListener( settings, colIdx, e.shiftKey, callback ); + } + } ); + } + + + /** + * Set the sorting classes on table's body, Note: it is safe to call this function + * when bSort and bSortClasses are false + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnSortingClasses( settings ) + { + var oldSort = settings.aLastSort; + var sortClass = settings.oClasses.sSortColumn; + var sort = _fnSortFlatten( settings ); + var features = settings.oFeatures; + var i, ien, colIdx; + + if ( features.bSort && features.bSortClasses ) { + // Remove old sorting classes + for ( i=0, ien=oldSort.length ; i 0 && s.time < +new Date() - (duration*1000) ) { + callback(); + return; + } + + // Number of columns have changed - all bets are off, no restore of settings + if ( s.columns && columns.length !== s.columns.length ) { + callback(); + return; + } + + // Store the saved state so it might be accessed at any time + settings.oLoadedState = $.extend( true, {}, s ); + + // Restore key features - todo - for 1.11 this needs to be done by + // subscribed events + if ( s.start !== undefined ) { + settings._iDisplayStart = s.start; + settings.iInitDisplayStart = s.start; + } + if ( s.length !== undefined ) { + settings._iDisplayLength = s.length; + } + + // Order + if ( s.order !== undefined ) { + settings.aaSorting = []; + $.each( s.order, function ( i, col ) { + settings.aaSorting.push( col[0] >= columns.length ? + [ 0, col[1] ] : + col + ); + } ); + } + + // Search + if ( s.search !== undefined ) { + $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); + } + + // Columns + // + if ( s.columns ) { + for ( i=0, ien=s.columns.length ; i = end ) + { + start = end - len; + } + + // Keep the start record on the current page + start -= (start % len); + + if ( len === -1 || start < 0 ) + { + start = 0; + } + + settings._iDisplayStart = start; + } + + + function _fnRenderer( settings, type ) + { + var renderer = settings.renderer; + var host = DataTable.ext.renderer[type]; + + if ( $.isPlainObject( renderer ) && renderer[type] ) { + // Specific renderer for this type. If available use it, otherwise use + // the default. + return host[renderer[type]] || host._; + } + else if ( typeof renderer === 'string' ) { + // Common renderer - if there is one available for this type use it, + // otherwise use the default + return host[renderer] || host._; + } + + // Use the default + return host._; + } + + + /** + * Detect the data source being used for the table. Used to simplify the code + * a little (ajax) and to make it compress a little smaller. + * + * @param {object} settings dataTables settings object + * @returns {string} Data source + * @memberof DataTable#oApi + */ + function _fnDataSource ( settings ) + { + if ( settings.oFeatures.bServerSide ) { + return 'ssp'; + } + else if ( settings.ajax || settings.sAjaxSource ) { + return 'ajax'; + } + return 'dom'; + } + + + + + /** + * Computed structure of the DataTables API, defined by the options passed to + * `DataTable.Api.register()` when building the API. + * + * The structure is built in order to speed creation and extension of the Api + * objects since the extensions are effectively pre-parsed. + * + * The array is an array of objects with the following structure, where this + * base array represents the Api prototype base: + * + * [ + * { + * name: 'data' -- string - Property name + * val: function () {}, -- function - Api method (or undefined if just an object + * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result + * propExt: [ ... ] -- array - Array of Api object definitions to extend the property + * }, + * { + * name: 'row' + * val: {}, + * methodExt: [ ... ], + * propExt: [ + * { + * name: 'data' + * val: function () {}, + * methodExt: [ ... ], + * propExt: [ ... ] + * }, + * ... + * ] + * } + * ] + * + * @type {Array} + * @ignore + */ + var __apiStruct = []; + + + /** + * `Array.prototype` reference. + * + * @type object + * @ignore + */ + var __arrayProto = Array.prototype; + + + /** + * Abstraction for `context` parameter of the `Api` constructor to allow it to + * take several different forms for ease of use. + * + * Each of the input parameter types will be converted to a DataTables settings + * object where possible. + * + * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one + * of: + * + * * `string` - jQuery selector. Any DataTables' matching the given selector + * with be found and used. + * * `node` - `TABLE` node which has already been formed into a DataTable. + * * `jQuery` - A jQuery object of `TABLE` nodes. + * * `object` - DataTables settings object + * * `DataTables.Api` - API instance + * @return {array|null} Matching DataTables settings objects. `null` or + * `undefined` is returned if no matching DataTable is found. + * @ignore + */ + var _toSettings = function ( mixed ) + { + var idx, jq; + var settings = DataTable.settings; + var tables = $.map( settings, function (el, i) { + return el.nTable; + } ); + + if ( ! mixed ) { + return []; + } + else if ( mixed.nTable && mixed.oApi ) { + // DataTables settings object + return [ mixed ]; + } + else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { + // Table node + idx = $.inArray( mixed, tables ); + return idx !== -1 ? [ settings[idx] ] : null; + } + else if ( mixed && typeof mixed.settings === 'function' ) { + return mixed.settings().toArray(); + } + else if ( typeof mixed === 'string' ) { + // jQuery selector + jq = $(mixed); + } + else if ( mixed instanceof $ ) { + // jQuery object (also DataTables instance) + jq = mixed; + } + + if ( jq ) { + return jq.map( function(i) { + idx = $.inArray( this, tables ); + return idx !== -1 ? settings[idx] : null; + } ).toArray(); + } + }; + + + /** + * DataTables API class - used to control and interface with one or more + * DataTables enhanced tables. + * + * The API class is heavily based on jQuery, presenting a chainable interface + * that you can use to interact with tables. Each instance of the API class has + * a "context" - i.e. the tables that it will operate on. This could be a single + * table, all tables on a page or a sub-set thereof. + * + * Additionally the API is designed to allow you to easily work with the data in + * the tables, retrieving and manipulating it as required. This is done by + * presenting the API class as an array like interface. The contents of the + * array depend upon the actions requested by each method (for example + * `rows().nodes()` will return an array of nodes, while `rows().data()` will + * return an array of objects or arrays depending upon your table's + * configuration). The API object has a number of array like methods (`push`, + * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, + * `unique` etc) to assist your working with the data held in a table. + * + * Most methods (those which return an Api instance) are chainable, which means + * the return from a method call also has all of the methods available that the + * top level object had. For example, these two calls are equivalent: + * + * // Not chained + * api.row.add( {...} ); + * api.draw(); + * + * // Chained + * api.row.add( {...} ).draw(); + * + * @class DataTable.Api + * @param {array|object|string|jQuery} context DataTable identifier. This is + * used to define which DataTables enhanced tables this API will operate on. + * Can be one of: + * + * * `string` - jQuery selector. Any DataTables' matching the given selector + * with be found and used. + * * `node` - `TABLE` node which has already been formed into a DataTable. + * * `jQuery` - A jQuery object of `TABLE` nodes. + * * `object` - DataTables settings object + * @param {array} [data] Data to initialise the Api instance with. + * + * @example + * // Direct initialisation during DataTables construction + * var api = $('#example').DataTable(); + * + * @example + * // Initialisation using a DataTables jQuery object + * var api = $('#example').dataTable().api(); + * + * @example + * // Initialisation as a constructor + * var api = new $.fn.DataTable.Api( 'table.dataTable' ); + */ + _Api = function ( context, data ) + { + if ( ! (this instanceof _Api) ) { + return new _Api( context, data ); + } + + var settings = []; + var ctxSettings = function ( o ) { + var a = _toSettings( o ); + if ( a ) { + settings = settings.concat( a ); + } + }; + + if ( $.isArray( context ) ) { + for ( var i=0, ien=context.length ; i idx ? + new _Api( ctx[idx], this[idx] ) : + null; + }, + + + filter: function ( fn ) + { + var a = []; + + if ( __arrayProto.filter ) { + a = __arrayProto.filter.call( this, fn, this ); + } + else { + // Compatibility for browsers without EMCA-252-5 (JS 1.6) + for ( var i=0, ien=this.length ; i 0 ) { + return ctx[0].json; + } + + // else return undefined; + } ); + + + /** + * Get the data submitted in the last Ajax request + */ + _api_register( 'ajax.params()', function () { + var ctx = this.context; + + if ( ctx.length > 0 ) { + return ctx[0].oAjaxData; + } + + // else return undefined; + } ); + + + /** + * Reload tables from the Ajax data source. Note that this function will + * automatically re-draw the table when the remote data has been loaded. + * + * @param {boolean} [reset=true] Reset (default) or hold the current paging + * position. A full re-sort and re-filter is performed when this method is + * called, which is why the pagination reset is the default action. + * @returns {DataTables.Api} this + */ + _api_register( 'ajax.reload()', function ( callback, resetPaging ) { + return this.iterator( 'table', function (settings) { + __reload( settings, resetPaging===false, callback ); + } ); + } ); + + + /** + * Get the current Ajax URL. Note that this returns the URL from the first + * table in the current context. + * + * @return {string} Current Ajax source URL + *//** + * Set the Ajax URL. Note that this will set the URL for all tables in the + * current context. + * + * @param {string} url URL to set. + * @returns {DataTables.Api} this + */ + _api_register( 'ajax.url()', function ( url ) { + var ctx = this.context; + + if ( url === undefined ) { + // get + if ( ctx.length === 0 ) { + return undefined; + } + ctx = ctx[0]; + + return ctx.ajax ? + $.isPlainObject( ctx.ajax ) ? + ctx.ajax.url : + ctx.ajax : + ctx.sAjaxSource; + } + + // set + return this.iterator( 'table', function ( settings ) { + if ( $.isPlainObject( settings.ajax ) ) { + settings.ajax.url = url; + } + else { + settings.ajax = url; + } + // No need to consider sAjaxSource here since DataTables gives priority + // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any + // value of `sAjaxSource` redundant. + } ); + } ); + + + /** + * Load data from the newly set Ajax URL. Note that this method is only + * available when `ajax.url()` is used to set a URL. Additionally, this method + * has the same effect as calling `ajax.reload()` but is provided for + * convenience when setting a new URL. Like `ajax.reload()` it will + * automatically redraw the table once the remote data has been loaded. + * + * @returns {DataTables.Api} this + */ + _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { + // Same as a reload, but makes sense to present it for easy access after a + // url change + return this.iterator( 'table', function ( ctx ) { + __reload( ctx, resetPaging===false, callback ); + } ); + } ); + + + + + var _selector_run = function ( type, selector, selectFn, settings, opts ) + { + var + out = [], res, + a, i, ien, j, jen, + selectorType = typeof selector; + + // Can't just check for isArray here, as an API or jQuery instance might be + // given with their array like look + if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { + selector = [ selector ]; + } + + for ( i=0, ien=selector.length ; i 0 ) { + // Assign the first element to the first item in the instance + // and truncate the instance and context + inst[0] = inst[i]; + inst[0].length = 1; + inst.length = 1; + inst.context = [ inst.context[i] ]; + + return inst; + } + } + + // Not found - return an empty instance + inst.length = 0; + return inst; + }; + + + var _selector_row_indexes = function ( settings, opts ) + { + var + i, ien, tmp, a=[], + displayFiltered = settings.aiDisplay, + displayMaster = settings.aiDisplayMaster; + + var + search = opts.search, // none, applied, removed + order = opts.order, // applied, current, index (original - compatibility with 1.9) + page = opts.page; // all, current + + if ( _fnDataSource( settings ) == 'ssp' ) { + // In server-side processing mode, most options are irrelevant since + // rows not shown don't exist and the index order is the applied order + // Removed is a special case - for consistency just return an empty + // array + return search === 'removed' ? + [] : + _range( 0, displayMaster.length ); + } + else if ( page == 'current' ) { + // Current page implies that order=current and fitler=applied, since it is + // fairly senseless otherwise, regardless of what order and search actually + // are + for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i = 0 && search == 'applied') ) + { + a.push( i ); + } + } + } + } + + return a; + }; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Rows + * + * {} - no selector - use all available rows + * {integer} - row aoData index + * {node} - TR node + * {string} - jQuery selector to apply to the TR elements + * {array} - jQuery array of nodes, or simply an array of TR nodes + * + */ + + + var __row_selector = function ( settings, selector, opts ) + { + var rows; + var run = function ( sel ) { + var selInt = _intVal( sel ); + var i, ien; + + // Short cut - selector is a number and no options provided (default is + // all records, so no need to check if the index is in there, since it + // must be - dev error if the index doesn't exist). + if ( selInt !== null && ! opts ) { + return [ selInt ]; + } + + if ( ! rows ) { + rows = _selector_row_indexes( settings, opts ); + } + + if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { + // Selector - integer + return [ selInt ]; + } + else if ( sel === null || sel === undefined || sel === '' ) { + // Selector - none + return rows; + } + + // Selector - function + if ( typeof sel === 'function' ) { + return $.map( rows, function (idx) { + var row = settings.aoData[ idx ]; + return sel( idx, row._aData, row.nTr ) ? idx : null; + } ); + } + + // Get nodes in the order from the `rows` array with null values removed + var nodes = _removeEmpty( + _pluck_order( settings.aoData, rows, 'nTr' ) + ); + + // Selector - node + if ( sel.nodeName ) { + if ( sel._DT_RowIndex !== undefined ) { + return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup + } + else if ( sel._DT_CellIndex ) { + return [ sel._DT_CellIndex.row ]; + } + else { + var host = $(sel).closest('*[data-dt-row]'); + return host.length ? + [ host.data('dt-row') ] : + []; + } + } + + // ID selector. Want to always be able to select rows by id, regardless + // of if the tr element has been created or not, so can't rely upon + // jQuery here - hence a custom implementation. This does not match + // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, + // but to select it using a CSS selector engine (like Sizzle or + // querySelect) it would need to need to be escaped for some characters. + // DataTables simplifies this for row selectors since you can select + // only a row. A # indicates an id any anything that follows is the id - + // unescaped. + if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { + // get row index from id + var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; + if ( rowObj !== undefined ) { + return [ rowObj.idx ]; + } + + // need to fall through to jQuery in case there is DOM id that + // matches + } + + // Selector - jQuery selector string, array of nodes or jQuery object/ + // As jQuery's .filter() allows jQuery objects to be passed in filter, + // it also allows arrays, so this will cope with all three options + return $(nodes) + .filter( sel ) + .map( function () { + return this._DT_RowIndex; + } ) + .toArray(); + }; + + return _selector_run( 'row', selector, run, settings, opts ); + }; + + + _api_register( 'rows()', function ( selector, opts ) { + // argument shifting + if ( selector === undefined ) { + selector = ''; + } + else if ( $.isPlainObject( selector ) ) { + opts = selector; + selector = ''; + } + + opts = _selector_opts( opts ); + + var inst = this.iterator( 'table', function ( settings ) { + return __row_selector( settings, selector, opts ); + }, 1 ); + + // Want argument shifting here and in __row_selector? + inst.selector.rows = selector; + inst.selector.opts = opts; + + return inst; + } ); + + _api_register( 'rows().nodes()', function () { + return this.iterator( 'row', function ( settings, row ) { + return settings.aoData[ row ].nTr || undefined; + }, 1 ); + } ); + + _api_register( 'rows().data()', function () { + return this.iterator( true, 'rows', function ( settings, rows ) { + return _pluck_order( settings.aoData, rows, '_aData' ); + }, 1 ); + } ); + + _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { + return this.iterator( 'row', function ( settings, row ) { + var r = settings.aoData[ row ]; + return type === 'search' ? r._aFilterData : r._aSortData; + }, 1 ); + } ); + + _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { + return this.iterator( 'row', function ( settings, row ) { + _fnInvalidate( settings, row, src ); + } ); + } ); + + _api_registerPlural( 'rows().indexes()', 'row().index()', function () { + return this.iterator( 'row', function ( settings, row ) { + return row; + }, 1 ); + } ); + + _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { + var a = []; + var context = this.context; + + // `iterator` will drop undefined values, but in this case we want them + for ( var i=0, ien=context.length ; i 0 ) { + settings._iRecordsDisplay--; + } + + // Check for an 'overflow' they case for displaying the table + _fnLengthOverflow( settings ); + + // Remove the row's ID reference if there is one + var id = settings.rowIdFn( rowData._aData ); + if ( id !== undefined ) { + delete settings.aIds[ id ]; + } + } ); + + this.iterator( 'table', function ( settings ) { + for ( var i=0, ien=settings.aoData.length ; i ').addClass( k ); + $('td', created) + .addClass( k ) + .html( r ) + [0].colSpan = _fnVisbleColumns( ctx ); + + rows.push( created[0] ); + } + }; + + addRow( data, klass ); + + if ( row._details ) { + row._details.detach(); + } + + row._details = $(rows); + + // If the children were already shown, that state should be retained + if ( row._detailsShow ) { + row._details.insertAfter( row.nTr ); + } + }; + + + var __details_remove = function ( api, idx ) + { + var ctx = api.context; + + if ( ctx.length ) { + var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; + + if ( row && row._details ) { + row._details.remove(); + + row._detailsShow = undefined; + row._details = undefined; + } + } + }; + + + var __details_display = function ( api, show ) { + var ctx = api.context; + + if ( ctx.length && api.length ) { + var row = ctx[0].aoData[ api[0] ]; + + if ( row._details ) { + row._detailsShow = show; + + if ( show ) { + row._details.insertAfter( row.nTr ); + } + else { + row._details.detach(); + } + + __details_events( ctx[0] ); + } + } + }; + + + var __details_events = function ( settings ) + { + var api = new _Api( settings ); + var namespace = '.dt.DT_details'; + var drawEvent = 'draw'+namespace; + var colvisEvent = 'column-visibility'+namespace; + var destroyEvent = 'destroy'+namespace; + var data = settings.aoData; + + api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); + + if ( _pluck( data, '_details' ).length > 0 ) { + // On each draw, insert the required elements into the document + api.on( drawEvent, function ( e, ctx ) { + if ( settings !== ctx ) { + return; + } + + api.rows( {page:'current'} ).eq(0).each( function (idx) { + // Internal data grab + var row = data[ idx ]; + + if ( row._detailsShow ) { + row._details.insertAfter( row.nTr ); + } + } ); + } ); + + // Column visibility change - update the colspan + api.on( colvisEvent, function ( e, ctx, idx, vis ) { + if ( settings !== ctx ) { + return; + } + + // Update the colspan for the details rows (note, only if it already has + // a colspan) + var row, visible = _fnVisbleColumns( ctx ); + + for ( var i=0, ien=data.length ; i =0 count from left, <0 count from right) + * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) + * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) + * "{string}:name" - column name + * "{string}" - jQuery selector on column header nodes + * + */ + + // can be an array of these items, comma separated list, or an array of comma + // separated lists + + var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; + + + // r1 and r2 are redundant - but it means that the parameters match for the + // iterator callback in columns().data() + var __columnData = function ( settings, column, r1, r2, rows ) { + var a = []; + for ( var row=0, ien=rows.length ; row = 0 ? + selInt : // Count from left + columns.length + selInt // Count from right (+ because its a negative value) + ]; + } + + // Selector = function + if ( typeof s === 'function' ) { + var rows = _selector_row_indexes( settings, opts ); + + return $.map( columns, function (col, idx) { + return s( + idx, + __columnData( settings, idx, 0, 0, rows ), + nodes[ idx ] + ) ? idx : null; + } ); + } + + // jQuery or string selector + var match = typeof s === 'string' ? + s.match( __re_column_selector ) : + ''; + + if ( match ) { + switch( match[2] ) { + case 'visIdx': + case 'visible': + var idx = parseInt( match[1], 10 ); + // Visible index given, convert to column index + if ( idx < 0 ) { + // Counting from the right + var visColumns = $.map( columns, function (col,i) { + return col.bVisible ? i : null; + } ); + return [ visColumns[ visColumns.length + idx ] ]; + } + // Counting from the left + return [ _fnVisibleToColumnIndex( settings, idx ) ]; + + case 'name': + // match by name. `names` is column index complete and in order + return $.map( names, function (name, i) { + return name === match[1] ? i : null; + } ); + + default: + return []; + } + } + + // Cell in the table body + if ( s.nodeName && s._DT_CellIndex ) { + return [ s._DT_CellIndex.column ]; + } + + // jQuery selector on the TH elements for the columns + var jqResult = $( nodes ) + .filter( s ) + .map( function () { + return $.inArray( this, nodes ); // `nodes` is column index complete and in order + } ) + .toArray(); + + if ( jqResult.length || ! s.nodeName ) { + return jqResult; + } + + // Otherwise a node which might have a `dt-column` data attribute, or be + // a child or such an element + var host = $(s).closest('*[data-dt-column]'); + return host.length ? + [ host.data('dt-column') ] : + []; + }; + + return _selector_run( 'column', selector, run, settings, opts ); + }; + + + var __setColumnVis = function ( settings, column, vis ) { + var + cols = settings.aoColumns, + col = cols[ column ], + data = settings.aoData, + row, cells, i, ien, tr; + + // Get + if ( vis === undefined ) { + return col.bVisible; + } + + // Set + // No change + if ( col.bVisible === vis ) { + return; + } + + if ( vis ) { + // Insert column + // Need to decide if we should use appendChild or insertBefore + var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); + + for ( i=0, ien=data.length ; i iThat; + } + + return true; + }; + + + /** + * Check if a `