From ccdc963935a71eecf37bdb626a01ca0afd7f3673 Mon Sep 17 00:00:00 2001 From: polytan02 Date: Thu, 22 Dec 2016 00:51:06 +0000 Subject: [PATCH] Use of release 1.0.1 instead of master git --- sources/CHANGELOG | 8 +- sources/{lib => }/JSON_renderer.php | 3 +- sources/{lib => }/OPDS_renderer.php | 4 +- sources/README.md | 8 +- sources/about.html | 46 +- sources/{lib/Author.php => author.php} | 7 +- sources/base.php | 1181 ++++++- sources/book.php | 661 ++++ sources/build.xml | 54 - sources/checkconfig.php | 115 +- sources/composer-dl.sh | 18 - sources/composer.json | 74 - sources/composer.lock | 2517 --------------- sources/config.php | 9 +- sources/config_default.php | 61 +- sources/config_local.php.example | 9 +- sources/cops-1.0.1.zip | Bin 0 -> 954968 bytes sources/customcolumn.php | 1180 +++++++ sources/{lib/Data.php => data.php} | 7 +- sources/epubfs.php | 164 +- sources/epubreader.php | 148 +- sources/feed.php | 36 +- sources/fetch.php | 86 +- sources/getJSON.php | 8 +- sources/index.php | 72 +- sources/lang/Localization_de.json | 2 +- sources/lang/Localization_pl.json | 8 +- sources/{lib/Language.php => language.php} | 5 +- sources/lib/Base.php | 213 -- sources/lib/Book.php | 651 ---- sources/lib/CustomColumn.php | 109 - sources/lib/CustomColumnType.php | 314 -- sources/lib/CustomColumnTypeBool.php | 94 - sources/lib/CustomColumnTypeComment.php | 70 - sources/lib/CustomColumnTypeDate.php | 87 - sources/lib/CustomColumnTypeEnumeration.php | 102 - sources/lib/CustomColumnTypeFloat.php | 78 - sources/lib/CustomColumnTypeInteger.php | 78 - sources/lib/CustomColumnTypeRating.php | 110 - sources/lib/CustomColumnTypeSeries.php | 102 - sources/lib/CustomColumnTypeText.php | 105 - sources/lib/Entry.php | 78 - sources/lib/EntryBook.php | 47 - sources/lib/Link.php | 41 - sources/lib/LinkFacet.php | 16 - sources/lib/LinkNavigation.php | 21 - sources/lib/Page.php | 180 -- sources/lib/PageAbout.php | 15 - sources/lib/PageAllAuthors.php | 22 - sources/lib/PageAllAuthorsLetter.php | 17 - sources/lib/PageAllBooks.php | 22 - sources/lib/PageAllBooksLetter.php | 22 - sources/lib/PageAllCustoms.php | 20 - sources/lib/PageAllLanguages.php | 17 - sources/lib/PageAllPublishers.php | 17 - sources/lib/PageAllRating.php | 17 - sources/lib/PageAllSeries.php | 17 - sources/lib/PageAllTags.php | 17 - sources/lib/PageAuthorDetail.php | 18 - sources/lib/PageBookDetail.php | 16 - sources/lib/PageCustomDetail.php | 19 - sources/lib/PageCustomize.php | 100 - sources/lib/PageLanguageDetail.php | 18 - sources/lib/PagePublisherDetail.php | 18 - sources/lib/PageQueryResult.php | 163 - sources/lib/PageRatingDetail.php | 18 - sources/lib/PageRecentBooks.php | 17 - sources/lib/PageSerieDetail.php | 18 - sources/lib/PageTagDetail.php | 18 - sources/login.html | 195 +- sources/phpunit.xml.dist | 30 - sources/{lib/Publisher.php => publisher.php} | 5 +- sources/{lib/Rating.php => rating.php} | 5 +- .../jquery.magnific-popup.min.js | 4 + .../Magnific-Popup/magnific-popup.css | 363 +++ sources/resources/PHPMailer/LICENSE | 504 +++ sources/resources/PHPMailer/README.md | 134 + .../resources/PHPMailer/class.phpmailer.php | 2810 +++++++++++++++++ sources/resources/PHPMailer/class.pop3.php | 418 +++ sources/resources/PHPMailer/class.smtp.php | 1088 +++++++ sources/resources/bootstrap/LICENSE | 21 + sources/resources/bootstrap/README.md | 134 + .../dist/css/bootstrap-theme.min.css | 5 + .../bootstrap/dist/css/bootstrap.min.css | 5 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 ++ .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../bootstrap/dist/js/bootstrap.min.js | 7 + sources/resources/doT-php/doT.php | 101 + sources/resources/doT/doT.min.js | 8 + .../epub-loader/BaseExport.class.php | 209 -- .../epub-loader/BookExport.class.php | 143 - .../resources/epub-loader/BookInfos.class.php | 74 - .../epub-loader/CalibreDbLoader.class.php | 420 --- .../resources/epub-loader/CsvExport.class.php | 77 - sources/resources/epub-loader/README | 17 - .../resources/epub-loader/ZipFile.class.php | 119 - sources/resources/epub-loader/app/.gitignore | 1 - .../epub-loader/app/action_csv_export.php | 31 - .../epub-loader/app/action_db_load.php | 30 - .../resources/epub-loader/app/cops-feed.php | 27 - .../app/epub-loader-config.php.example | 60 - sources/resources/epub-loader/app/footer.php | 47 - sources/resources/epub-loader/app/header.php | 88 - sources/resources/epub-loader/app/index.php | 151 - .../resources/epub-loader/metadata_sqlite.sql | 549 ---- sources/resources/jQuery/jquery-1.11.1.min.js | 4 + .../resources/jquery-cookie/jquery.cookies.js | 2 + .../jquery.sortElements.js | 69 + sources/resources/lru/lru.js | 249 ++ sources/resources/normalize/normalize.css | 425 +++ .../php-epub-meta/LICENSE_php-epub-meta | 22 + sources/resources/php-epub-meta/epub.php | 890 ++++++ sources/resources/php-epub-meta/tbszip.php | 1007 ++++++ .../typeahead/typeahead.bundle.min.js | 7 + sources/sendtomail.php | 5 +- sources/{lib/Serie.php => serie.php} | 7 +- sources/styles/cops-monocle.js | 12 - sources/{lib/Tag.php => tag.php} | 7 +- sources/templates/bootstrap/bookdetail.html | 148 +- sources/templates/bootstrap/file.html | 300 +- sources/templates/bootstrap/header.html | 58 +- sources/templates/bootstrap/main.html | 134 +- sources/templates/bootstrap/page.html | 6 +- sources/templates/default/bookdetail.html | 132 +- sources/templates/default/file.html | 86 +- sources/templates/default/footer.html | 28 +- sources/templates/default/header.html | 100 +- sources/templates/default/main.html | 100 +- sources/templates/default/page.html | 8 +- .../test/BaseWithCustomColumns/metadata.db | Bin 1190912 -> 0 bytes sources/test/BaseWithOneBook/metadata.db | Bin 117760 -> 0 bytes ...entures in Wonderland - Lewis Carroll.epub | Bin 1597594 -> 0 bytes .../cover.jpg | Bin 200128 -> 0 bytes .../metadata.opf | 32 - sources/test/BaseWithSomeBooks/metadata.db | Bin 195584 -> 0 bytes sources/test/EpubFsTest.php | 106 - sources/test/OPDSTest.php | 253 -- sources/test/OPDSValidator.jar | Bin 17700 -> 0 bytes sources/test/Sauce.php | 234 -- sources/test/baseTest.php | 205 -- sources/test/bookTest.php | 603 ---- sources/test/config_local.php.sauce | 17 - sources/test/config_test.php | 11 - sources/test/coverage-checker.php | 43 - sources/test/customColumnsTest.php | 1102 ------- sources/test/jing.jar | Bin 708436 -> 0 bytes sources/test/jsonTest.php | 72 - sources/test/mailTest.php | 67 - sources/test/opds-relax-ng/atom.rng | 598 ---- .../test/opds-relax-ng/opds_catalog_1_1.rng | 599 ---- .../opds-relax-ng/opensearchdescription.rng | 416 --- sources/test/pageMultidatabaseTest.php | 77 - sources/test/pageTest.php | 964 ------ sources/test/prepareSauceTest.sh | 38 - sources/test/res/atom.rnc | 338 -- sources/test/res/opds_v1.0.rnc | 131 - sources/test/res/opds_v1.1.rnc | 151 - sources/tools/export_file.txt | 71 - sources/tools/updateLang.pl | 118 - sources/transliteration.php | 13 +- sources/util.js | 30 +- sources/web.config | 38 +- 165 files changed, 12599 insertions(+), 15315 deletions(-) rename sources/{lib => }/JSON_renderer.php (99%) rename sources/{lib => }/OPDS_renderer.php (99%) rename sources/{lib/Author.php => author.php} (97%) create mode 100644 sources/book.php delete mode 100644 sources/build.xml delete mode 100755 sources/composer-dl.sh delete mode 100644 sources/composer.json delete mode 100644 sources/composer.lock create mode 100644 sources/cops-1.0.1.zip create mode 100644 sources/customcolumn.php rename sources/{lib/Data.php => data.php} (98%) rename sources/{lib/Language.php => language.php} (97%) delete mode 100644 sources/lib/Base.php delete mode 100644 sources/lib/Book.php delete mode 100644 sources/lib/CustomColumn.php delete mode 100644 sources/lib/CustomColumnType.php delete mode 100644 sources/lib/CustomColumnTypeBool.php delete mode 100644 sources/lib/CustomColumnTypeComment.php delete mode 100644 sources/lib/CustomColumnTypeDate.php delete mode 100644 sources/lib/CustomColumnTypeEnumeration.php delete mode 100644 sources/lib/CustomColumnTypeFloat.php delete mode 100644 sources/lib/CustomColumnTypeInteger.php delete mode 100644 sources/lib/CustomColumnTypeRating.php delete mode 100644 sources/lib/CustomColumnTypeSeries.php delete mode 100644 sources/lib/CustomColumnTypeText.php delete mode 100644 sources/lib/Entry.php delete mode 100644 sources/lib/EntryBook.php delete mode 100644 sources/lib/Link.php delete mode 100644 sources/lib/LinkFacet.php delete mode 100644 sources/lib/LinkNavigation.php delete mode 100644 sources/lib/Page.php delete mode 100644 sources/lib/PageAbout.php delete mode 100644 sources/lib/PageAllAuthors.php delete mode 100644 sources/lib/PageAllAuthorsLetter.php delete mode 100644 sources/lib/PageAllBooks.php delete mode 100644 sources/lib/PageAllBooksLetter.php delete mode 100644 sources/lib/PageAllCustoms.php delete mode 100644 sources/lib/PageAllLanguages.php delete mode 100644 sources/lib/PageAllPublishers.php delete mode 100644 sources/lib/PageAllRating.php delete mode 100644 sources/lib/PageAllSeries.php delete mode 100644 sources/lib/PageAllTags.php delete mode 100644 sources/lib/PageAuthorDetail.php delete mode 100644 sources/lib/PageBookDetail.php delete mode 100644 sources/lib/PageCustomDetail.php delete mode 100644 sources/lib/PageCustomize.php delete mode 100644 sources/lib/PageLanguageDetail.php delete mode 100644 sources/lib/PagePublisherDetail.php delete mode 100644 sources/lib/PageQueryResult.php delete mode 100644 sources/lib/PageRatingDetail.php delete mode 100644 sources/lib/PageRecentBooks.php delete mode 100644 sources/lib/PageSerieDetail.php delete mode 100644 sources/lib/PageTagDetail.php delete mode 100644 sources/phpunit.xml.dist rename sources/{lib/Publisher.php => publisher.php} (97%) rename sources/{lib/Rating.php => rating.php} (97%) create mode 100644 sources/resources/Magnific-Popup/jquery.magnific-popup.min.js create mode 100644 sources/resources/Magnific-Popup/magnific-popup.css create mode 100644 sources/resources/PHPMailer/LICENSE create mode 100644 sources/resources/PHPMailer/README.md create mode 100644 sources/resources/PHPMailer/class.phpmailer.php create mode 100644 sources/resources/PHPMailer/class.pop3.php create mode 100644 sources/resources/PHPMailer/class.smtp.php create mode 100644 sources/resources/bootstrap/LICENSE create mode 100644 sources/resources/bootstrap/README.md create mode 100644 sources/resources/bootstrap/dist/css/bootstrap-theme.min.css create mode 100644 sources/resources/bootstrap/dist/css/bootstrap.min.css create mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.eot create mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.svg create mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf create mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.woff create mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 create mode 100644 sources/resources/bootstrap/dist/js/bootstrap.min.js create mode 100644 sources/resources/doT-php/doT.php create mode 100644 sources/resources/doT/doT.min.js delete mode 100644 sources/resources/epub-loader/BaseExport.class.php delete mode 100644 sources/resources/epub-loader/BookExport.class.php delete mode 100644 sources/resources/epub-loader/BookInfos.class.php delete mode 100644 sources/resources/epub-loader/CalibreDbLoader.class.php delete mode 100644 sources/resources/epub-loader/CsvExport.class.php delete mode 100644 sources/resources/epub-loader/README delete mode 100644 sources/resources/epub-loader/ZipFile.class.php delete mode 100644 sources/resources/epub-loader/app/.gitignore delete mode 100644 sources/resources/epub-loader/app/action_csv_export.php delete mode 100644 sources/resources/epub-loader/app/action_db_load.php delete mode 100644 sources/resources/epub-loader/app/cops-feed.php delete mode 100644 sources/resources/epub-loader/app/epub-loader-config.php.example delete mode 100644 sources/resources/epub-loader/app/footer.php delete mode 100644 sources/resources/epub-loader/app/header.php delete mode 100644 sources/resources/epub-loader/app/index.php delete mode 100644 sources/resources/epub-loader/metadata_sqlite.sql create mode 100644 sources/resources/jQuery/jquery-1.11.1.min.js create mode 100644 sources/resources/jquery-cookie/jquery.cookies.js create mode 100644 sources/resources/jquery-sortelements/jquery.sortElements.js create mode 100644 sources/resources/lru/lru.js create mode 100644 sources/resources/normalize/normalize.css create mode 100644 sources/resources/php-epub-meta/LICENSE_php-epub-meta create mode 100644 sources/resources/php-epub-meta/epub.php create mode 100644 sources/resources/php-epub-meta/tbszip.php create mode 100644 sources/resources/typeahead/typeahead.bundle.min.js rename sources/{lib/Serie.php => serie.php} (95%) rename sources/{lib/Tag.php => tag.php} (95%) delete mode 100644 sources/test/BaseWithCustomColumns/metadata.db delete mode 100644 sources/test/BaseWithOneBook/metadata.db delete mode 100644 sources/test/BaseWithSomeBooks/Lewis Carroll/Alice's Adventures in Wonderland (17)/Alice's Adventures in Wonderland - Lewis Carroll.epub delete mode 100644 sources/test/BaseWithSomeBooks/Lewis Carroll/Alice's Adventures in Wonderland (17)/cover.jpg delete mode 100644 sources/test/BaseWithSomeBooks/Lewis Carroll/Alice's Adventures in Wonderland (17)/metadata.opf delete mode 100644 sources/test/BaseWithSomeBooks/metadata.db delete mode 100644 sources/test/EpubFsTest.php delete mode 100644 sources/test/OPDSTest.php delete mode 100644 sources/test/OPDSValidator.jar delete mode 100644 sources/test/Sauce.php delete mode 100644 sources/test/baseTest.php delete mode 100644 sources/test/bookTest.php delete mode 100644 sources/test/config_local.php.sauce delete mode 100644 sources/test/config_test.php delete mode 100644 sources/test/coverage-checker.php delete mode 100644 sources/test/customColumnsTest.php delete mode 100644 sources/test/jing.jar delete mode 100644 sources/test/jsonTest.php delete mode 100644 sources/test/mailTest.php delete mode 100644 sources/test/opds-relax-ng/atom.rng delete mode 100644 sources/test/opds-relax-ng/opds_catalog_1_1.rng delete mode 100644 sources/test/opds-relax-ng/opensearchdescription.rng delete mode 100644 sources/test/pageMultidatabaseTest.php delete mode 100644 sources/test/pageTest.php delete mode 100644 sources/test/prepareSauceTest.sh delete mode 100644 sources/test/res/atom.rnc delete mode 100644 sources/test/res/opds_v1.0.rnc delete mode 100644 sources/test/res/opds_v1.1.rnc delete mode 100644 sources/tools/export_file.txt delete mode 100644 sources/tools/updateLang.pl diff --git a/sources/CHANGELOG b/sources/CHANGELOG index 43b732c..891c85d 100644 --- a/sources/CHANGELOG +++ b/sources/CHANGELOG @@ -1,10 +1,4 @@ -1.1.0 - 201612XX - * Merged a huge PR that clean most of COPS source code. Thanks to Markus Birth for his work and his patience. - * Updated Polish tranlations. - * Fixed a bad external dependency in login.html causing problem with HTPPS. Thanks to polytan02. - * Added automatic redirection to the OPDS feed for many new Android apps (see #309). Thanks to horus68. - -1.0.1 - 20161015 +1.0.1 - 201610XX * Fixed some type of custom column showing id instead of text - Thanks to Mike Schwörer. * Fixed the redirection to the OPDS catalog for Moon+ Reader. * Fixed the mail character encoding, now in UTF-8. diff --git a/sources/lib/JSON_renderer.php b/sources/JSON_renderer.php similarity index 99% rename from sources/lib/JSON_renderer.php rename to sources/JSON_renderer.php index 4df3df5..ecca867 100644 --- a/sources/lib/JSON_renderer.php +++ b/sources/JSON_renderer.php @@ -6,7 +6,8 @@ * @author Sébastien Lucas */ -require_once dirname(__FILE__) . '/../base.php'; +require_once ("base.php"); +require_once ("book.php"); class JSONRenderer { diff --git a/sources/lib/OPDS_renderer.php b/sources/OPDS_renderer.php similarity index 99% rename from sources/lib/OPDS_renderer.php rename to sources/OPDS_renderer.php index 893e342..14d1f33 100644 --- a/sources/lib/OPDS_renderer.php +++ b/sources/OPDS_renderer.php @@ -3,10 +3,10 @@ * COPS (Calibre OPDS PHP Server) class file * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Sébastien Lucas + * @author Sbastien Lucas */ -require_once dirname(__FILE__) . '/../base.php'; +require_once ("base.php"); class OPDSRenderer { diff --git a/sources/README.md b/sources/README.md index e4661c3..526c220 100644 --- a/sources/README.md +++ b/sources/README.md @@ -6,13 +6,11 @@ See : [COPS's home](http://blog.slucas.fr/en/oss/calibre-opds-php-server) for mo Don't forget to check the [Wiki](https://github.com/seblucas/cops/wiki). -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/seblucas/cops/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/seblucas/cops/?branch=master) +[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/seblucas/cops/badges/quality-score.png?s=e1c87a92ef90b8d666cd9bd4f3612bd10db84364)](https://scrutinizer-ci.com/g/seblucas/cops/) -[![Code Coverage](https://scrutinizer-ci.com/g/seblucas/cops/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/seblucas/cops/?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/seblucas/cops/badges/coverage.png?s=1e21d8c3bf96d7b0b7cc0e54429fa897ddea1506)](https://scrutinizer-ci.com/g/seblucas/cops/) -[![Build Status / Scrutinizer](https://scrutinizer-ci.com/g/seblucas/cops/badges/build.png?b=master)](https://scrutinizer-ci.com/g/seblucas/cops/build-status/master) - -[![Build Status](https://travis-ci.org/seblucas/cops.svg?branch=master)](https://travis-ci.org/seblucas/cops) +[![Build Status](https://travis-ci.org/seblucas/cops.png)](https://travis-ci.org/seblucas/cops) [![Selenium Test Status](https://saucelabs.com/browser-matrix/seblucas.svg)](https://saucelabs.com/u/seblucas) diff --git a/sources/about.html b/sources/about.html index d794905..d3369f9 100644 --- a/sources/about.html +++ b/sources/about.html @@ -1,23 +1,23 @@ -
-

About COPS

-

Authors

-

COPS is developed and maintained by Sébastien Lucas.

- -

See full history on Github to check all authors.

- -

COPS use some external libraries, check README for the details.

-

Copyright

-

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.

- -

The complete content of license is provided in file COPYING within distribution and also available online.

-

Contact

-

For more info please visit COPS Home Page

- -

You can also check COPS's topic on MobileRead forum.

- -

DISCLAIMER : COPS is an open source software free to install everywhere. So if you have questions about any books available with any installation of COPS, please ask the owner of the website and not COPS's maintainer.

-

Thanks

-

Thanks a lot to Kovid Goyal for Calibre.

- -

And many thanks to all those who helped test COPS.

-
+
+

About COPS

+

Authors

+

COPS is developed and maintained by Sébastien Lucas.

+ +

See full history on Github to check all authors.

+ +

COPS use some external libraries, check README for the details.

+

Copyright

+

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.

+ +

The complete content of license is provided in file COPYING within distribution and also available online.

+

Contact

+

For more info please visit COPS Home Page

+ +

You can also check COPS's topic on MobileRead forum.

+ +

DISCLAIMER : COPS is an open source software free to install everywhere. So if you have questions about any books available with any installation of COPS, please ask the owner of the website and not COPS's maintainer.

+

Thanks

+

Thanks a lot to Kovid Goyal for Calibre.

+ +

And many thanks to all those who helped test COPS.

+
diff --git a/sources/lib/Author.php b/sources/author.php similarity index 97% rename from sources/lib/Author.php rename to sources/author.php index 85e2860..6149bd3 100644 --- a/sources/lib/Author.php +++ b/sources/author.php @@ -3,11 +3,12 @@ * COPS (Calibre OPDS PHP Server) class file * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Sébastien Lucas + * @author Sbastien Lucas */ -class Author extends Base -{ +require_once('base.php'); + +class Author extends Base { const ALL_AUTHORS_ID = "cops:authors"; const AUTHOR_COLUMNS = "authors.id as id, authors.name as name, authors.sort as sort, count(*) as count"; diff --git a/sources/base.php b/sources/base.php index dd6d7fd..e3cfc7d 100644 --- a/sources/base.php +++ b/sources/base.php @@ -6,21 +6,19 @@ * @author Sébastien Lucas */ -require 'config.php'; +/** @var array $config */ -define ('VERSION', '1.0.2'); -define ('DB', 'db'); +define ("VERSION", "1.0.1"); +define ("DB", "db"); date_default_timezone_set($config['default_timezone']); -function useServerSideRendering() -{ +function useServerSideRendering () { global $config; - return preg_match('/' . $config['cops_server_side_render'] . '/', $_SERVER['HTTP_USER_AGENT']); + return preg_match("/" . $config['cops_server_side_render'] . "/", $_SERVER['HTTP_USER_AGENT']); } -function serverSideRender($data) -{ +function serverSideRender ($data) { // Get the templates $theme = getCurrentTemplate (); $header = file_get_contents('templates/' . $theme . '/header.html'); @@ -31,10 +29,10 @@ function serverSideRender($data) // Generate the function for the template $template = new doT (); - $dot = $template->template ($page, array ('bookdetail' => $bookdetail, - 'header' => $header, - 'footer' => $footer, - 'main' => $main)); + $dot = $template->template ($page, array ("bookdetail" => $bookdetail, + "header" => $header, + "footer" => $footer, + "main" => $main)); // If there is a syntax error in the function created // $dot will be equal to FALSE if (!$dot) { @@ -48,103 +46,91 @@ function serverSideRender($data) return NULL; } -function getQueryString() -{ - if (isset($_SERVER['QUERY_STRING'])) { +function getQueryString () { + if ( isset($_SERVER['QUERY_STRING']) ) { return $_SERVER['QUERY_STRING']; } return ""; } -function notFound() -{ - header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found'); - header('Status: 404 Not Found'); +function notFound () { + header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); + header("Status: 404 Not Found"); $_SERVER['REDIRECT_STATUS'] = 404; } -function getURLParam($name, $default = NULL) -{ - if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != '') { +function getURLParam ($name, $default = NULL) { + if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != "") { return $_GET[$name]; } return $default; } -function getCurrentOption($option) -{ +function getCurrentOption ($option) { global $config; if (isset($_COOKIE[$option])) { - if (isset($config ['cops_' . $option]) && is_array ($config ['cops_' . $option])) { - return explode (',', $_COOKIE[$option]); + if (isset($config ["cops_" . $option]) && is_array ($config ["cops_" . $option])) { + return explode (",", $_COOKIE[$option]); } else { return $_COOKIE[$option]; } } - if (isset($config ['cops_' . $option])) { - return $config ['cops_' . $option]; + if (isset($config ["cops_" . $option])) { + return $config ["cops_" . $option]; } - return ''; + return ""; } -function getCurrentCss() -{ - return 'templates/' . getCurrentTemplate () . '/styles/style-' . getCurrentOption('style') . '.css'; +function getCurrentCss () { + return "templates/" . getCurrentTemplate () . "/styles/style-" . getCurrentOption ("style") . ".css"; } -function getCurrentTemplate() -{ - return getCurrentOption ('template'); +function getCurrentTemplate () { + return getCurrentOption ("template"); } -function getUrlWithVersion($url) -{ - return $url . '?v=' . VERSION; +function getUrlWithVersion ($url) { + return $url . "?v=" . VERSION; } -function xml2xhtml($xml) -{ - return preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', function($m) { - $xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param'); - if (in_array($m[1], $xhtml_tags)) { - return '<' . $m[1] . $m[2] . ' />'; - } else { - return '<' . $m[1] . $m[2] . '>'; - } - }, $xml); +function xml2xhtml($xml) { + return preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', create_function('$m', ' + $xhtml_tags = array("br", "hr", "input", "frame", "img", "area", "link", "col", "base", "basefont", "param"); + return in_array($m[1], $xhtml_tags) ? "<$m[1]$m[2] />" : "<$m[1]$m[2]>"; + '), $xml); } function display_xml_error($error) { - $return = ''; + $return = ""; $return .= str_repeat('-', $error->column) . "^\n"; switch ($error->level) { case LIBXML_ERR_WARNING: - $return .= 'Warning ' . $error->code . ': '; + $return .= "Warning $error->code: "; break; case LIBXML_ERR_ERROR: - $return .= 'Error ' . $error->code . ': '; + $return .= "Error $error->code: "; break; case LIBXML_ERR_FATAL: - $return .= 'Fatal Error ' . $error->code . ': '; + $return .= "Fatal Error $error->code: "; break; } $return .= trim($error->message) . - "\n Line: " . $error->line . - "\n Column: " . $error->column; + "\n Line: $error->line" . + "\n Column: $error->column"; if ($error->file) { - $return .= "\n File: " . $error->file; + $return .= "\n File: $error->file"; } return "$return\n\n--------------------------------------------\n\n"; } -function are_libxml_errors_ok() +function are_libxml_errors_ok () { $errors = libxml_get_errors(); @@ -154,8 +140,7 @@ function are_libxml_errors_ok() return true; } -function html2xhtml($html) -{ +function html2xhtml ($html) { $doc = new DOMDocument(); libxml_use_internal_errors(true); @@ -175,7 +160,7 @@ function html2xhtml($html) } */ - if (!are_libxml_errors_ok ()) $output = 'HTML code not valid.'; + if (!are_libxml_errors_ok ()) $output = "HTML code not valid."; libxml_use_internal_errors(false); return $output; @@ -185,8 +170,7 @@ function html2xhtml($html) * This method is a direct copy-paste from * http://tmont.com/blargh/2010/1/string-format-in-php */ -function str_format($format) -{ +function str_format($format) { $args = func_get_args(); $format = array_shift($args); @@ -206,8 +190,7 @@ function str_format($format) * languages id are normalized : fr-fr -> fr_FR * @return array of languages */ -function getAcceptLanguages() -{ +function getAcceptLanguages() { $langs = array(); if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { @@ -215,7 +198,7 @@ function getAcceptLanguages() $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE']; if (preg_match('/^(\w{2})-\w{2}$/', $accept, $matches)) { // Special fix for IE11 which send fr-FR and nothing else - $accept = $accept . ',' . $matches[1] . ';q=0.8'; + $accept = $accept . "," . $matches[1] . ";q=0.8"; } preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $accept, $lang_parse); @@ -224,9 +207,9 @@ function getAcceptLanguages() foreach ($lang_parse[1] as $lang) { // Format the language code (not standard among browsers) if (strlen($lang) == 5) { - $lang = str_replace('-', '_', $lang); - $splitted = preg_split('/_/', $lang); - $lang = $splitted[0] . '_' . strtoupper($splitted[1]); + $lang = str_replace("-", "_", $lang); + $splitted = preg_split("/_/", $lang); + $lang = $splitted[0] . "_" . strtoupper($splitted[1]); } array_push($langs, $lang); } @@ -250,11 +233,10 @@ function getAcceptLanguages() * Find the best translation file possible based on the accepted languages * @return array of language and language file */ -function getLangAndTranslationFile() -{ +function getLangAndTranslationFile() { global $config; $langs = array(); - $lang = 'en'; + $lang = "en"; if (!empty($config['cops_language'])) { $lang = $config['cops_language']; } @@ -281,15 +263,14 @@ function getLangAndTranslationFile() * This method is based on this page * http://www.mind-it.info/2010/02/22/a-simple-approach-to-localization-in-php/ */ -function localize($phrase, $count=-1, $reset=false) -{ +function localize($phrase, $count=-1, $reset=false) { global $config; if ($count == 0) - $phrase .= '.none'; + $phrase .= ".none"; if ($count == 1) - $phrase .= '.one'; + $phrase .= ".one"; if ($count > 1) - $phrase .= '.many'; + $phrase .= ".many"; /* Static keyword is used to ensure the file is loaded only once */ static $translations = NULL; @@ -300,7 +281,7 @@ function localize($phrase, $count=-1, $reset=false) if (is_null($translations)) { $lang_file_en = NULL; list ($lang, $lang_file) = getLangAndTranslationFile(); - if ($lang != 'en') { + if ($lang != "en") { $lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json'; } @@ -310,11 +291,12 @@ function localize($phrase, $count=-1, $reset=false) /* Clean the array of all unfinished translations */ foreach (array_keys ($translations) as $key) { - if (preg_match ('/^##TODO##/', $key)) { + if (preg_match ("/^##TODO##/", $key)) { unset ($translations [$key]); } } - if (!is_null($lang_file_en)) { + if ($lang_file_en) + { $lang_file_content = file_get_contents($lang_file_en); $translations_en = json_decode($lang_file_content, true); $translations = array_merge ($translations_en, $translations); @@ -326,14 +308,13 @@ function localize($phrase, $count=-1, $reset=false) return $phrase; } -function addURLParameter($urlParams, $paramName, $paramValue) -{ +function addURLParameter($urlParams, $paramName, $paramValue) { if (empty ($urlParams)) { - $urlParams = ''; + $urlParams = ""; } - $start = ''; - if (preg_match ('#^\?(.*)#', $urlParams, $matches)) { - $start = '?'; + $start = ""; + if (preg_match ("#^\?(.*)#", $urlParams, $matches)) { + $start = "?"; $urlParams = $matches[1]; } $params = array(); @@ -346,19 +327,1035 @@ function addURLParameter($urlParams, $paramName, $paramValue) return $start . http_build_query($params); } -function useNormAndUp() -{ +function useNormAndUp () { global $config; - return $config ['cops_normalized_search'] == '1'; + return $config ['cops_normalized_search'] == "1"; } -function normalizeUtf8String($s) -{ +function normalizeUtf8String( $s) { include_once 'transliteration.php'; return _transliteration_process($s); } -function normAndUp($s) -{ - return mb_strtoupper(normalizeUtf8String($s), 'UTF-8'); +function normAndUp ($s) { + return mb_strtoupper (normalizeUtf8String($s), 'UTF-8'); +} + +class Link +{ + const OPDS_THUMBNAIL_TYPE = "http://opds-spec.org/image/thumbnail"; + const OPDS_IMAGE_TYPE = "http://opds-spec.org/image"; + const OPDS_ACQUISITION_TYPE = "http://opds-spec.org/acquisition"; + const OPDS_NAVIGATION_TYPE = "application/atom+xml;profile=opds-catalog;kind=navigation"; + const OPDS_PAGING_TYPE = "application/atom+xml;profile=opds-catalog;kind=acquisition"; + + public $href; + public $type; + public $rel; + public $title; + public $facetGroup; + public $activeFacet; + + public function __construct($phref, $ptype, $prel = NULL, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) { + $this->href = $phref; + $this->type = $ptype; + $this->rel = $prel; + $this->title = $ptitle; + $this->facetGroup = $pfacetGroup; + $this->activeFacet = $pactiveFacet; + } + + public function hrefXhtml () { + return $this->href; + } + + public function getScriptName() { + $parts = explode('/', $_SERVER["SCRIPT_NAME"]); + return $parts[count($parts) - 1]; + } +} + +class LinkNavigation extends Link +{ + public function __construct($phref, $prel = NULL, $ptitle = NULL) { + parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle); + if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB)); + if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href; + if (preg_match ("/(bookdetail|getJSON).php/", parent::getScriptName())) { + $this->href = "index.php" . $this->href; + } else { + $this->href = parent::getScriptName() . $this->href; + } + } +} + +class LinkFacet extends Link +{ + public function __construct($phref, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) { + parent::__construct ($phref, Link::OPDS_PAGING_TYPE, "http://opds-spec.org/facet", $ptitle, $pfacetGroup, $pactiveFacet); + if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB)); + $this->href = parent::getScriptName() . $this->href; + } +} + +class Entry +{ + public $title; + public $id; + public $content; + public $numberOfElement; + public $contentType; + public $linkArray; + public $localUpdated; + public $className; + private static $updated = NULL; + + public static $icons = array( + Author::ALL_AUTHORS_ID => 'images/author.png', + Serie::ALL_SERIES_ID => 'images/serie.png', + Book::ALL_RECENT_BOOKS_ID => 'images/recent.png', + Tag::ALL_TAGS_ID => 'images/tag.png', + Language::ALL_LANGUAGES_ID => 'images/language.png', + CustomColumnType::ALL_CUSTOMS_ID => 'images/custom.png', + Rating::ALL_RATING_ID => 'images/rating.png', + "cops:books$" => 'images/allbook.png', + "cops:books:letter" => 'images/allbook.png', + Publisher::ALL_PUBLISHERS_ID => 'images/publisher.png' + ); + + public function getUpdatedTime () { + if (!is_null ($this->localUpdated)) { + return date (DATE_ATOM, $this->localUpdated); + } + if (is_null (self::$updated)) { + self::$updated = time(); + } + return date (DATE_ATOM, self::$updated); + } + + public function getNavLink () { + foreach ($this->linkArray as $link) { + /* @var $link LinkNavigation */ + + if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; } + + return $link->hrefXhtml (); + } + return "#"; + } + + public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pclass = "", $pcount = 0) { + global $config; + $this->title = $ptitle; + $this->id = $pid; + $this->content = $pcontent; + $this->contentType = $pcontentType; + $this->linkArray = $plinkArray; + $this->className = $pclass; + $this->numberOfElement = $pcount; + + if ($config['cops_show_icons'] == 1) + { + foreach (self::$icons as $reg => $image) + { + if (preg_match ("/" . $reg . "/", $pid)) { + array_push ($this->linkArray, new Link (getUrlWithVersion ($image), "image/png", Link::OPDS_THUMBNAIL_TYPE)); + break; + } + } + } + + if (!is_null (GetUrlParam (DB))) $this->id = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":", $this->id); + } +} + +class EntryBook extends Entry +{ + public $book; + + /** + * EntryBook constructor. + * @param string $ptitle + * @param integer $pid + * @param string $pcontent + * @param string $pcontentType + * @param array $plinkArray + * @param Book $pbook + */ + public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pbook) { + parent::__construct ($ptitle, $pid, $pcontent, $pcontentType, $plinkArray); + $this->book = $pbook; + $this->localUpdated = $pbook->timestamp; + } + + public function getCoverThumbnail () { + foreach ($this->linkArray as $link) { + /* @var $link LinkNavigation */ + + if ($link->rel == Link::OPDS_THUMBNAIL_TYPE) + return $link->hrefXhtml (); + } + return null; + } + + public function getCover () { + foreach ($this->linkArray as $link) { + /* @var $link LinkNavigation */ + + if ($link->rel == Link::OPDS_IMAGE_TYPE) + return $link->hrefXhtml (); + } + return null; + } +} + +class Page +{ + public $title; + public $subtitle = ""; + public $authorName = ""; + public $authorUri = ""; + public $authorEmail = ""; + public $idPage; + public $idGet; + public $query; + public $favicon; + public $n; + public $book; + public $totalNumber = -1; + + /* @var Entry[] */ + public $entryArray = array(); + + public static function getPage ($pageId, $id, $query, $n) + { + switch ($pageId) { + case Base::PAGE_ALL_AUTHORS : + return new PageAllAuthors ($id, $query, $n); + case Base::PAGE_AUTHORS_FIRST_LETTER : + return new PageAllAuthorsLetter ($id, $query, $n); + case Base::PAGE_AUTHOR_DETAIL : + return new PageAuthorDetail ($id, $query, $n); + case Base::PAGE_ALL_TAGS : + return new PageAllTags ($id, $query, $n); + case Base::PAGE_TAG_DETAIL : + return new PageTagDetail ($id, $query, $n); + case Base::PAGE_ALL_LANGUAGES : + return new PageAllLanguages ($id, $query, $n); + case Base::PAGE_LANGUAGE_DETAIL : + return new PageLanguageDetail ($id, $query, $n); + case Base::PAGE_ALL_CUSTOMS : + return new PageAllCustoms ($id, $query, $n); + case Base::PAGE_CUSTOM_DETAIL : + return new PageCustomDetail ($id, $query, $n); + case Base::PAGE_ALL_RATINGS : + return new PageAllRating ($id, $query, $n); + case Base::PAGE_RATING_DETAIL : + return new PageRatingDetail ($id, $query, $n); + case Base::PAGE_ALL_SERIES : + return new PageAllSeries ($id, $query, $n); + case Base::PAGE_ALL_BOOKS : + return new PageAllBooks ($id, $query, $n); + case Base::PAGE_ALL_BOOKS_LETTER: + return new PageAllBooksLetter ($id, $query, $n); + case Base::PAGE_ALL_RECENT_BOOKS : + return new PageRecentBooks ($id, $query, $n); + case Base::PAGE_SERIE_DETAIL : + return new PageSerieDetail ($id, $query, $n); + case Base::PAGE_OPENSEARCH_QUERY : + return new PageQueryResult ($id, $query, $n); + case Base::PAGE_BOOK_DETAIL : + return new PageBookDetail ($id, $query, $n); + case Base::PAGE_ALL_PUBLISHERS: + return new PageAllPublishers ($id, $query, $n); + case Base::PAGE_PUBLISHER_DETAIL : + return new PagePublisherDetail ($id, $query, $n); + case Base::PAGE_ABOUT : + return new PageAbout ($id, $query, $n); + case Base::PAGE_CUSTOMIZE : + return new PageCustomize ($id, $query, $n); + default: + $page = new Page ($id, $query, $n); + $page->idPage = "cops:catalog"; + return $page; + } + } + + public function __construct($pid, $pquery, $pn) { + global $config; + + $this->idGet = $pid; + $this->query = $pquery; + $this->n = $pn; + $this->favicon = $config['cops_icon']; + $this->authorName = empty($config['cops_author_name']) ? utf8_encode('Sébastien Lucas') : $config['cops_author_name']; + $this->authorUri = empty($config['cops_author_uri']) ? 'http://blog.slucas.fr' : $config['cops_author_uri']; + $this->authorEmail = empty($config['cops_author_email']) ? 'sebastien@slucas.fr' : $config['cops_author_email']; + } + + public function InitializeContent () + { + global $config; + $this->title = $config['cops_title_default']; + $this->subtitle = $config['cops_subtitle_default']; + if (Base::noDatabaseSelected ()) { + $i = 0; + foreach (Base::getDbNameList () as $key) { + $nBooks = Book::getBookCount ($i); + array_push ($this->entryArray, new Entry ($key, "cops:{$i}:catalog", + str_format (localize ("bookword", $nBooks), $nBooks), "text", + array ( new LinkNavigation ("?" . DB . "={$i}")), "", $nBooks)); + $i++; + Base::clearDb (); + } + } else { + if (!in_array (PageQueryResult::SCOPE_AUTHOR, getCurrentOption ('ignored_categories'))) { + array_push ($this->entryArray, Author::getCount()); + } + if (!in_array (PageQueryResult::SCOPE_SERIES, getCurrentOption ('ignored_categories'))) { + $series = Serie::getCount(); + if (!is_null ($series)) array_push ($this->entryArray, $series); + } + if (!in_array (PageQueryResult::SCOPE_PUBLISHER, getCurrentOption ('ignored_categories'))) { + $publisher = Publisher::getCount(); + if (!is_null ($publisher)) array_push ($this->entryArray, $publisher); + } + if (!in_array (PageQueryResult::SCOPE_TAG, getCurrentOption ('ignored_categories'))) { + $tags = Tag::getCount(); + if (!is_null ($tags)) array_push ($this->entryArray, $tags); + } + if (!in_array (PageQueryResult::SCOPE_RATING, getCurrentOption ('ignored_categories'))) { + $rating = Rating::getCount(); + if (!is_null ($rating)) array_push ($this->entryArray, $rating); + } + if (!in_array ("language", getCurrentOption ('ignored_categories'))) { + $languages = Language::getCount(); + if (!is_null ($languages)) array_push ($this->entryArray, $languages); + } + foreach ($config['cops_calibre_custom_column'] as $lookup) { + $customColumn = CustomColumnType::createByLookup($lookup); + if (!is_null ($customColumn) && $customColumn->isSearchable()) { + array_push ($this->entryArray, $customColumn->getCount()); + } + } + $this->entryArray = array_merge ($this->entryArray, Book::getCount()); + + if (Base::isMultipleDatabaseEnabled ()) $this->title = Base::getDbName (); + } + } + + public function isPaginated () + { + return (getCurrentOption ("max_item_per_page") != -1 && + $this->totalNumber != -1 && + $this->totalNumber > getCurrentOption ("max_item_per_page")); + } + + public function getNextLink () + { + $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ()); + if (($this->n) * getCurrentOption ("max_item_per_page") < $this->totalNumber) { + return new LinkNavigation ($currentUrl . "&n=" . ($this->n + 1), "next", localize ("paging.next.alternate")); + } + return NULL; + } + + public function getPrevLink () + { + $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ()); + if ($this->n > 1) { + return new LinkNavigation ($currentUrl . "&n=" . ($this->n - 1), "previous", localize ("paging.previous.alternate")); + } + return NULL; + } + + public function getMaxPage () + { + return ceil ($this->totalNumber / getCurrentOption ("max_item_per_page")); + } + + public function containsBook () + { + if (count ($this->entryArray) == 0) return false; + if (get_class ($this->entryArray [0]) == "EntryBook") return true; + return false; + } +} + +class PageAllAuthors extends Page +{ + public function InitializeContent () + { + $this->title = localize("authors.title"); + if (getCurrentOption ("author_split_first_letter") == 1) { + $this->entryArray = Author::getAllAuthorsByFirstLetter(); + } + else { + $this->entryArray = Author::getAllAuthors(); + } + $this->idPage = Author::ALL_AUTHORS_ID; + } +} + +class PageAllAuthorsLetter extends Page +{ + public function InitializeContent () + { + $this->idPage = Author::getEntryIdByLetter ($this->idGet); + $this->entryArray = Author::getAuthorsByStartingLetter ($this->idGet); + $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("authorword", count ($this->entryArray)), count ($this->entryArray)), $this->idGet); + } +} + +class PageAuthorDetail extends Page +{ + public function InitializeContent () + { + $author = Author::getAuthorById ($this->idGet); + $this->idPage = $author->getEntryId (); + $this->title = $author->name; + list ($this->entryArray, $this->totalNumber) = Book::getBooksByAuthor ($this->idGet, $this->n); + } +} + +class PageAllPublishers extends Page +{ + public function InitializeContent () + { + $this->title = localize("publishers.title"); + $this->entryArray = Publisher::getAllPublishers(); + $this->idPage = Publisher::ALL_PUBLISHERS_ID; + } +} + +class PagePublisherDetail extends Page +{ + public function InitializeContent () + { + $publisher = Publisher::getPublisherById ($this->idGet); + $this->title = $publisher->name; + list ($this->entryArray, $this->totalNumber) = Book::getBooksByPublisher ($this->idGet, $this->n); + $this->idPage = $publisher->getEntryId (); + } +} + +class PageAllTags extends Page +{ + public function InitializeContent () + { + $this->title = localize("tags.title"); + $this->entryArray = Tag::getAllTags(); + $this->idPage = Tag::ALL_TAGS_ID; + } +} + +class PageAllLanguages extends Page +{ + public function InitializeContent () + { + $this->title = localize("languages.title"); + $this->entryArray = Language::getAllLanguages(); + $this->idPage = Language::ALL_LANGUAGES_ID; + } +} + +class PageCustomDetail extends Page +{ + public function InitializeContent () + { + $customId = getURLParam ("custom", NULL); + $custom = CustomColumn::createCustom ($customId, $this->idGet); + $this->idPage = $custom->getEntryId (); + $this->title = $custom->value; + list ($this->entryArray, $this->totalNumber) = Book::getBooksByCustom ($custom, $this->idGet, $this->n); + } +} + +class PageAllCustoms extends Page +{ + public function InitializeContent () + { + $customId = getURLParam ("custom", NULL); + $columnType = CustomColumnType::createByCustomID($customId); + + $this->title = $columnType->getTitle(); + $this->entryArray = $columnType->getAllCustomValues(); + $this->idPage = $columnType->getAllCustomsId(); + } +} + +class PageTagDetail extends Page +{ + public function InitializeContent () + { + $tag = Tag::getTagById ($this->idGet); + $this->idPage = $tag->getEntryId (); + $this->title = $tag->name; + list ($this->entryArray, $this->totalNumber) = Book::getBooksByTag ($this->idGet, $this->n); + } +} + +class PageLanguageDetail extends Page +{ + public function InitializeContent () + { + $language = Language::getLanguageById ($this->idGet); + $this->idPage = $language->getEntryId (); + $this->title = $language->lang_code; + list ($this->entryArray, $this->totalNumber) = Book::getBooksByLanguage ($this->idGet, $this->n); + } +} + +class PageAllSeries extends Page +{ + public function InitializeContent () + { + $this->title = localize("series.title"); + $this->entryArray = Serie::getAllSeries(); + $this->idPage = Serie::ALL_SERIES_ID; + } +} + +class PageSerieDetail extends Page +{ + public function InitializeContent () + { + $serie = Serie::getSerieById ($this->idGet); + $this->title = $serie->name; + list ($this->entryArray, $this->totalNumber) = Book::getBooksBySeries ($this->idGet, $this->n); + $this->idPage = $serie->getEntryId (); + } +} + +class PageAllRating extends Page +{ + public function InitializeContent () + { + $this->title = localize("ratings.title"); + $this->entryArray = Rating::getAllRatings(); + $this->idPage = Rating::ALL_RATING_ID; + } +} + +class PageRatingDetail extends Page +{ + public function InitializeContent () + { + $rating = Rating::getRatingById ($this->idGet); + $this->idPage = $rating->getEntryId (); + $this->title =str_format (localize ("ratingword", $rating->name/2), $rating->name/2); + list ($this->entryArray, $this->totalNumber) = Book::getBooksByRating ($this->idGet, $this->n); + } +} + +class PageAllBooks extends Page +{ + public function InitializeContent () + { + $this->title = localize ("allbooks.title"); + if (getCurrentOption ("titles_split_first_letter") == 1) { + $this->entryArray = Book::getAllBooks(); + } + else { + list ($this->entryArray, $this->totalNumber) = Book::getBooks ($this->n); + } + $this->idPage = Book::ALL_BOOKS_ID; + } +} + +class PageAllBooksLetter extends Page +{ + public function InitializeContent () + { + list ($this->entryArray, $this->totalNumber) = Book::getBooksByStartingLetter ($this->idGet, $this->n); + $this->idPage = Book::getEntryIdByLetter ($this->idGet); + + $count = $this->totalNumber; + if ($count == -1) + $count = count ($this->entryArray); + + $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("bookword", $count), $count), $this->idGet); + } +} + +class PageRecentBooks extends Page +{ + public function InitializeContent () + { + $this->title = localize ("recent.title"); + $this->entryArray = Book::getAllRecentBooks (); + $this->idPage = Book::ALL_RECENT_BOOKS_ID; + } +} + +class PageQueryResult extends Page +{ + const SCOPE_TAG = "tag"; + const SCOPE_RATING = "rating"; + const SCOPE_SERIES = "series"; + const SCOPE_AUTHOR = "author"; + const SCOPE_BOOK = "book"; + const SCOPE_PUBLISHER = "publisher"; + + private function useTypeahead () { + return !is_null (getURLParam ("search")); + } + + private function searchByScope ($scope, $limit = FALSE) { + $n = $this->n; + $numberPerPage = NULL; + $queryNormedAndUp = trim($this->query); + if (useNormAndUp ()) { + $queryNormedAndUp = normAndUp ($this->query); + } + if ($limit) { + $n = 1; + $numberPerPage = 5; + } + switch ($scope) { + case self::SCOPE_BOOK : + $array = Book::getBooksByStartingLetter ('%' . $queryNormedAndUp, $n, NULL, $numberPerPage); + break; + case self::SCOPE_AUTHOR : + $array = Author::getAuthorsForSearch ('%' . $queryNormedAndUp); + break; + case self::SCOPE_SERIES : + $array = Serie::getAllSeriesByQuery ($queryNormedAndUp); + break; + case self::SCOPE_TAG : + $array = Tag::getAllTagsByQuery ($queryNormedAndUp, $n, NULL, $numberPerPage); + break; + case self::SCOPE_PUBLISHER : + $array = Publisher::getAllPublishersByQuery ($queryNormedAndUp); + break; + default: + $array = Book::getBooksByQuery ( + array ("all" => "%" . $queryNormedAndUp . "%"), $n); + } + + return $array; + } + + public function doSearchByCategory () { + $database = GetUrlParam (DB); + $out = array (); + $pagequery = Base::PAGE_OPENSEARCH_QUERY; + $dbArray = array (""); + $d = $database; + $query = $this->query; + // Special case when no databases were chosen, we search on all databases + if (Base::noDatabaseSelected ()) { + $dbArray = Base::getDbNameList (); + $d = 0; + } + foreach ($dbArray as $key) { + if (Base::noDatabaseSelected ()) { + array_push ($this->entryArray, new Entry ($key, DB . ":query:{$d}", + " ", "text", + array ( new LinkNavigation ("?" . DB . "={$d}")), "tt-header")); + Base::getDb ($d); + } + foreach (array (PageQueryResult::SCOPE_BOOK, + PageQueryResult::SCOPE_AUTHOR, + PageQueryResult::SCOPE_SERIES, + PageQueryResult::SCOPE_TAG, + PageQueryResult::SCOPE_PUBLISHER) as $key) { + if (in_array($key, getCurrentOption ('ignored_categories'))) { + continue; + } + $array = $this->searchByScope ($key, TRUE); + + $i = 0; + if (count ($array) == 2 && is_array ($array [0])) { + $total = $array [1]; + $array = $array [0]; + } else { + $total = count($array); + } + if ($total > 0) { + // Comment to help the perl i18n script + // str_format (localize("bookword", count($array)) + // str_format (localize("authorword", count($array)) + // str_format (localize("seriesword", count($array)) + // str_format (localize("tagword", count($array)) + // str_format (localize("publisherword", count($array)) + array_push ($this->entryArray, new Entry (str_format (localize ("search.result.{$key}"), $this->query), DB . ":query:{$d}:{$key}", + str_format (localize("{$key}word", $total), $total), "text", + array ( new LinkNavigation ("?page={$pagequery}&query={$query}&db={$d}&scope={$key}")), + Base::noDatabaseSelected () ? "" : "tt-header", $total)); + } + if (!Base::noDatabaseSelected () && $this->useTypeahead ()) { + foreach ($array as $entry) { + array_push ($this->entryArray, $entry); + $i++; + if ($i > 4) { break; }; + } + } + } + $d++; + if (Base::noDatabaseSelected ()) { + Base::clearDb (); + } + } + return $out; + } + + public function InitializeContent () + { + $scope = getURLParam ("scope"); + if (empty ($scope)) { + $this->title = str_format (localize ("search.result"), $this->query); + } else { + // Comment to help the perl i18n script + // str_format (localize ("search.result.author"), $this->query) + // str_format (localize ("search.result.tag"), $this->query) + // str_format (localize ("search.result.series"), $this->query) + // str_format (localize ("search.result.book"), $this->query) + // str_format (localize ("search.result.publisher"), $this->query) + $this->title = str_format (localize ("search.result.{$scope}"), $this->query); + } + + $crit = "%" . $this->query . "%"; + + // Special case when we are doing a search and no database is selected + if (Base::noDatabaseSelected () && !$this->useTypeahead ()) { + $i = 0; + foreach (Base::getDbNameList () as $key) { + Base::clearDb (); + list ($array, $totalNumber) = Book::getBooksByQuery (array ("all" => $crit), 1, $i, 1); + array_push ($this->entryArray, new Entry ($key, DB . ":query:{$i}", + str_format (localize ("bookword", $totalNumber), $totalNumber), "text", + array ( new LinkNavigation ("?" . DB . "={$i}&page=9&query=" . $this->query)), "", $totalNumber)); + $i++; + } + return; + } + if (empty ($scope)) { + $this->doSearchByCategory (); + return; + } + + $array = $this->searchByScope ($scope); + if (count ($array) == 2 && is_array ($array [0])) { + list ($this->entryArray, $this->totalNumber) = $array; + } else { + $this->entryArray = $array; + } + } +} + +class PageBookDetail extends Page +{ + public function InitializeContent () + { + $this->book = Book::getBookById ($this->idGet); + $this->title = $this->book->title; + } +} + +class PageAbout extends Page +{ + public function InitializeContent () + { + $this->title = localize ("about.title"); + } +} + +class PageCustomize extends Page +{ + private function isChecked ($key, $testedValue = 1) { + $value = getCurrentOption ($key); + if (is_array ($value)) { + if (in_array ($testedValue, $value)) { + return "checked='checked'"; + } + } else { + if ($value == $testedValue) { + return "checked='checked'"; + } + } + return ""; + } + + private function isSelected ($key, $value) { + if (getCurrentOption ($key) == $value) { + return "selected='selected'"; + } + return ""; + } + + private function getStyleList () { + $result = array (); + foreach (glob ("templates/" . getCurrentTemplate () . "/styles/style-*.css") as $filename) { + if (preg_match ('/styles\/style-(.*?)\.css/', $filename, $m)) { + array_push ($result, $m [1]); + } + } + return $result; + } + + public function InitializeContent () + { + $this->title = localize ("customize.title"); + $this->entryArray = array (); + + $ignoredBaseArray = array (PageQueryResult::SCOPE_AUTHOR, + PageQueryResult::SCOPE_TAG, + PageQueryResult::SCOPE_SERIES, + PageQueryResult::SCOPE_PUBLISHER, + PageQueryResult::SCOPE_RATING, + "language"); + + $content = ""; + array_push ($this->entryArray, new Entry ("Template", "", + "Click to switch to Bootstrap", "text", + array ())); + if (!preg_match("/(Kobo|Kindle\/3.0|EBRD1101)/", $_SERVER['HTTP_USER_AGENT'])) { + $content .= ''; + } else { + foreach ($this-> getStyleList () as $filename) { + $content .= "isChecked ("style", $filename) . " />"; + } + } + array_push ($this->entryArray, new Entry (localize ("customize.style"), "", + $content, "text", + array ())); + if (!useServerSideRendering ()) { + $content = 'isChecked ("use_fancyapps") . ' />'; + array_push ($this->entryArray, new Entry (localize ("customize.fancybox"), "", + $content, "text", + array ())); + } + $content = ''; + array_push ($this->entryArray, new Entry (localize ("customize.paging"), "", + $content, "text", + array ())); + $content = ''; + array_push ($this->entryArray, new Entry (localize ("customize.email"), "", + $content, "text", + array ())); + $content = 'isChecked ("html_tag_filter") . ' />'; + array_push ($this->entryArray, new Entry (localize ("customize.filter"), "", + $content, "text", + array ())); + $content = ""; + foreach ($ignoredBaseArray as $key) { + $keyPlural = preg_replace ('/(ss)$/', 's', $key . "s"); + $content .= 'isChecked ("ignored_categories", $key) . ' > ' . localize ("{$keyPlural}.title") . ' '; + } + + array_push ($this->entryArray, new Entry (localize ("customize.ignored"), "", + $content, "text", + array ())); + } +} + +abstract class Base +{ + const PAGE_INDEX = "index"; + const PAGE_ALL_AUTHORS = "1"; + const PAGE_AUTHORS_FIRST_LETTER = "2"; + const PAGE_AUTHOR_DETAIL = "3"; + const PAGE_ALL_BOOKS = "4"; + const PAGE_ALL_BOOKS_LETTER = "5"; + const PAGE_ALL_SERIES = "6"; + const PAGE_SERIE_DETAIL = "7"; + const PAGE_OPENSEARCH = "8"; + const PAGE_OPENSEARCH_QUERY = "9"; + const PAGE_ALL_RECENT_BOOKS = "10"; + const PAGE_ALL_TAGS = "11"; + const PAGE_TAG_DETAIL = "12"; + const PAGE_BOOK_DETAIL = "13"; + const PAGE_ALL_CUSTOMS = "14"; + const PAGE_CUSTOM_DETAIL = "15"; + const PAGE_ABOUT = "16"; + const PAGE_ALL_LANGUAGES = "17"; + const PAGE_LANGUAGE_DETAIL = "18"; + const PAGE_CUSTOMIZE = "19"; + const PAGE_ALL_PUBLISHERS = "20"; + const PAGE_PUBLISHER_DETAIL = "21"; + const PAGE_ALL_RATINGS = "22"; + const PAGE_RATING_DETAIL = "23"; + + const COMPATIBILITY_XML_ALDIKO = "aldiko"; + + private static $db = NULL; + + public static function isMultipleDatabaseEnabled () { + global $config; + return is_array ($config['calibre_directory']); + } + + public static function useAbsolutePath () { + global $config; + $path = self::getDbDirectory(); + return preg_match ('/^\//', $path) || // Linux / + preg_match ('/^\w\:/', $path); // Windows X: + } + + public static function noDatabaseSelected () { + return self::isMultipleDatabaseEnabled () && is_null (GetUrlParam (DB)); + } + + public static function getDbList () { + global $config; + if (self::isMultipleDatabaseEnabled ()) { + return $config['calibre_directory']; + } else { + return array ("" => $config['calibre_directory']); + } + } + + public static function getDbNameList () { + global $config; + if (self::isMultipleDatabaseEnabled ()) { + return array_keys ($config['calibre_directory']); + } else { + return array (""); + } + } + + public static function getDbName ($database = NULL) { + global $config; + if (self::isMultipleDatabaseEnabled ()) { + if (is_null ($database)) $database = GetUrlParam (DB, 0); + if (!is_null($database) && !preg_match('/^\d+$/', $database)) { + self::error ($database); + } + $array = array_keys ($config['calibre_directory']); + return $array[$database]; + } + return ""; + } + + public static function getDbDirectory ($database = NULL) { + global $config; + if (self::isMultipleDatabaseEnabled ()) { + if (is_null ($database)) $database = GetUrlParam (DB, 0); + if (!is_null($database) && !preg_match('/^\d+$/', $database)) { + self::error ($database); + } + $array = array_values ($config['calibre_directory']); + return $array[$database]; + } + return $config['calibre_directory']; + } + + + public static function getDbFileName ($database = NULL) { + return self::getDbDirectory ($database) .'metadata.db'; + } + + private static function error ($database) { + if (php_sapi_name() != "cli") { + header("location: checkconfig.php?err=1"); + } + throw new Exception("Database <{$database}> not found."); + } + + public static function getDb ($database = NULL) { + if (is_null (self::$db)) { + try { + if (is_readable (self::getDbFileName ($database))) { + self::$db = new PDO('sqlite:'. self::getDbFileName ($database)); + if (useNormAndUp ()) { + self::$db->sqliteCreateFunction ('normAndUp', 'normAndUp', 1); + } + } else { + self::error ($database); + } + } catch (Exception $e) { + self::error ($database); + } + } + return self::$db; + } + + public static function checkDatabaseAvailability () { + if (self::noDatabaseSelected ()) { + for ($i = 0; $i < count (self::getDbList ()); $i++) { + self::getDb ($i); + self::clearDb (); + } + } else { + self::getDb (); + } + return true; + } + + public static function clearDb () { + self::$db = NULL; + } + + public static function executeQuerySingle ($query, $database = NULL) { + return self::getDb ($database)->query($query)->fetchColumn(); + } + + public static function getCountGeneric($table, $id, $pageId, $numberOfString = NULL) { + if (!$numberOfString) { + $numberOfString = $table . ".alphabetical"; + } + $count = self::executeQuerySingle ('select count(*) from ' . $table); + if ($count == 0) return NULL; + $entry = new Entry (localize($table . ".title"), $id, + str_format (localize($numberOfString, $count), $count), "text", + array ( new LinkNavigation ("?page=".$pageId)), "", $count); + return $entry; + } + + public static function getEntryArrayWithBookNumber ($query, $columns, $params, $category) { + /* @var $result PDOStatement */ + + list (, $result) = self::executeQuery ($query, $columns, "", $params, -1); + $entryArray = array(); + while ($post = $result->fetchObject ()) + { + /* @var $instance Author|Tag|Serie|Publisher */ + + $instance = new $category ($post); + if (property_exists($post, "sort")) { + $title = $post->sort; + } else { + $title = $post->name; + } + array_push ($entryArray, new Entry ($title, $instance->getEntryId (), + str_format (localize("bookword", $post->count), $post->count), "text", + array ( new LinkNavigation ($instance->getUri ())), "", $post->count)); + } + return $entryArray; + } + + public static function executeQuery($query, $columns, $filter, $params, $n, $database = NULL, $numberPerPage = NULL) { + $totalResult = -1; + + if (useNormAndUp ()) { + $query = preg_replace("/upper/", "normAndUp", $query); + $columns = preg_replace("/upper/", "normAndUp", $columns); + } + + if (is_null ($numberPerPage)) { + $numberPerPage = getCurrentOption ("max_item_per_page"); + } + + if ($numberPerPage != -1 && $n != -1) + { + // First check total number of results + $result = self::getDb ($database)->prepare (str_format ($query, "count(*)", $filter)); + $result->execute ($params); + $totalResult = $result->fetchColumn (); + + // Next modify the query and params + $query .= " limit ?, ?"; + array_push ($params, ($n - 1) * $numberPerPage, $numberPerPage); + } + + $result = self::getDb ($database)->prepare(str_format ($query, $columns, $filter)); + $result->execute ($params); + return array ($totalResult, $result); + } + } diff --git a/sources/book.php b/sources/book.php new file mode 100644 index 0000000..a61f950 --- /dev/null +++ b/sources/book.php @@ -0,0 +1,661 @@ + + */ + +require_once('base.php'); +require_once('serie.php'); +require_once('author.php'); +require_once('rating.php'); +require_once('publisher.php'); +require_once('tag.php'); +require_once('language.php'); +require_once("customcolumn.php"); +require_once('data.php'); +require_once('resources/php-epub-meta/epub.php'); + +// Silly thing because PHP forbid string concatenation in class const +define ('SQL_BOOKS_LEFT_JOIN', "left outer join comments on comments.book = books.id + left outer join books_ratings_link on books_ratings_link.book = books.id + left outer join ratings on books_ratings_link.rating = ratings.id "); +define ('SQL_BOOKS_ALL', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " order by books.sort "); +define ('SQL_BOOKS_BY_PUBLISHER', "select {0} from books_publishers_link, books " . SQL_BOOKS_LEFT_JOIN . " + where books_publishers_link.book = books.id and publisher = ? {1} order by publisher"); +define ('SQL_BOOKS_BY_FIRST_LETTER', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " + where upper (books.sort) like ? order by books.sort"); +define ('SQL_BOOKS_BY_AUTHOR', "select {0} from books_authors_link, books " . SQL_BOOKS_LEFT_JOIN . " + left outer join books_series_link on books_series_link.book = books.id + where books_authors_link.book = books.id and author = ? {1} order by series desc, series_index asc, pubdate asc"); +define ('SQL_BOOKS_BY_SERIE', "select {0} from books_series_link, books " . SQL_BOOKS_LEFT_JOIN . " + where books_series_link.book = books.id and series = ? {1} order by series_index"); +define ('SQL_BOOKS_BY_TAG', "select {0} from books_tags_link, books " . SQL_BOOKS_LEFT_JOIN . " + where books_tags_link.book = books.id and tag = ? {1} order by sort"); +define ('SQL_BOOKS_BY_LANGUAGE', "select {0} from books_languages_link, books " . SQL_BOOKS_LEFT_JOIN . " + where books_languages_link.book = books.id and lang_code = ? {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM', "select {0} from {2}, books " . SQL_BOOKS_LEFT_JOIN . " + where {2}.book = books.id and {2}.{3} = ? {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_BOOL_TRUE', "select {0} from {2}, books " . SQL_BOOKS_LEFT_JOIN . " + where {2}.book = books.id and {2}.value = 1 {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_BOOL_FALSE', "select {0} from {2}, books " . SQL_BOOKS_LEFT_JOIN . " + where {2}.book = books.id and {2}.value = 0 {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_BOOL_NULL', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " + where books.id not in (select book from {2}) {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_RATING', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " + left join {2} on {2}.book = books.id + left join {3} on {3}.id = {2}.{4} + where {3}.value = ? order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_RATING_NULL', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " + left join {2} on {2}.book = books.id + left join {3} on {3}.id = {2}.{4} + where ((books.id not in (select {2}.book from {2})) or ({3}.value = 0)) {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_DATE', "select {0} from {2}, books " . SQL_BOOKS_LEFT_JOIN . " + where {2}.book = books.id and date({2}.value) = ? {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_DIRECT', "select {0} from {2}, books " . SQL_BOOKS_LEFT_JOIN . " + where {2}.book = books.id and {2}.value = ? {1} order by sort"); +define ('SQL_BOOKS_BY_CUSTOM_DIRECT_ID', "select {0} from {2}, books " . SQL_BOOKS_LEFT_JOIN . " + where {2}.book = books.id and {2}.id = ? {1} order by sort"); +define ('SQL_BOOKS_QUERY', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " + where ( + exists (select null from authors, books_authors_link where book = books.id and author = authors.id and authors.name like ?) or + exists (select null from tags, books_tags_link where book = books.id and tag = tags.id and tags.name like ?) or + exists (select null from series, books_series_link on book = books.id and books_series_link.series = series.id and series.name like ?) or + exists (select null from publishers, books_publishers_link where book = books.id and books_publishers_link.publisher = publishers.id and publishers.name like ?) or + title like ?) {1} order by books.sort"); +define ('SQL_BOOKS_RECENT', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " + where 1=1 {1} order by timestamp desc limit "); +define ('SQL_BOOKS_BY_RATING', "select {0} from books " . SQL_BOOKS_LEFT_JOIN . " + where books_ratings_link.book = books.id and ratings.id = ? {1} order by sort"); + +class Book extends Base { + const ALL_BOOKS_UUID = "urn:uuid"; + const ALL_BOOKS_ID = "cops:books"; + const ALL_RECENT_BOOKS_ID = "cops:recentbooks"; + const BOOK_COLUMNS = "books.id as id, books.title as title, text as comment, path, timestamp, pubdate, series_index, uuid, has_cover, ratings.rating"; + + const SQL_BOOKS_LEFT_JOIN = SQL_BOOKS_LEFT_JOIN; + const SQL_BOOKS_ALL = SQL_BOOKS_ALL; + const SQL_BOOKS_BY_PUBLISHER = SQL_BOOKS_BY_PUBLISHER; + const SQL_BOOKS_BY_FIRST_LETTER = SQL_BOOKS_BY_FIRST_LETTER; + const SQL_BOOKS_BY_AUTHOR = SQL_BOOKS_BY_AUTHOR; + const SQL_BOOKS_BY_SERIE = SQL_BOOKS_BY_SERIE; + const SQL_BOOKS_BY_TAG = SQL_BOOKS_BY_TAG; + const SQL_BOOKS_BY_LANGUAGE = SQL_BOOKS_BY_LANGUAGE; + const SQL_BOOKS_BY_CUSTOM = SQL_BOOKS_BY_CUSTOM; + const SQL_BOOKS_BY_CUSTOM_BOOL_TRUE = SQL_BOOKS_BY_CUSTOM_BOOL_TRUE; + const SQL_BOOKS_BY_CUSTOM_BOOL_FALSE = SQL_BOOKS_BY_CUSTOM_BOOL_FALSE; + const SQL_BOOKS_BY_CUSTOM_BOOL_NULL = SQL_BOOKS_BY_CUSTOM_BOOL_NULL; + const SQL_BOOKS_BY_CUSTOM_RATING = SQL_BOOKS_BY_CUSTOM_RATING; + const SQL_BOOKS_BY_CUSTOM_RATING_NULL = SQL_BOOKS_BY_CUSTOM_RATING_NULL; + const SQL_BOOKS_BY_CUSTOM_DATE = SQL_BOOKS_BY_CUSTOM_DATE; + const SQL_BOOKS_BY_CUSTOM_DIRECT = SQL_BOOKS_BY_CUSTOM_DIRECT; + const SQL_BOOKS_BY_CUSTOM_DIRECT_ID = SQL_BOOKS_BY_CUSTOM_DIRECT_ID; + const SQL_BOOKS_QUERY = SQL_BOOKS_QUERY; + const SQL_BOOKS_RECENT = SQL_BOOKS_RECENT; + const SQL_BOOKS_BY_RATING = SQL_BOOKS_BY_RATING; + + const BAD_SEARCH = "QQQQQ"; + + public $id; + public $title; + public $timestamp; + public $pubdate; + public $path; + public $uuid; + public $hasCover; + public $relativePath; + public $seriesIndex; + public $comment; + public $rating; + public $datas = NULL; + public $authors = NULL; + public $publisher = NULL; + public $serie = NULL; + public $tags = NULL; + public $languages = NULL; + public $format = array (); + + + public function __construct($line) { + $this->id = $line->id; + $this->title = $line->title; + $this->timestamp = strtotime ($line->timestamp); + $this->pubdate = $line->pubdate; + $this->path = Base::getDbDirectory () . $line->path; + $this->relativePath = $line->path; + $this->seriesIndex = $line->series_index; + $this->comment = $line->comment; + $this->uuid = $line->uuid; + $this->hasCover = $line->has_cover; + if (!file_exists ($this->getFilePath ("jpg"))) { + // double check + $this->hasCover = 0; + } + $this->rating = $line->rating; + } + + public function getEntryId () { + return self::ALL_BOOKS_UUID.":".$this->uuid; + } + + public static function getEntryIdByLetter ($startingLetter) { + return self::ALL_BOOKS_ID.":letter:".$startingLetter; + } + + public function getUri () { + return "?page=".parent::PAGE_BOOK_DETAIL."&id=$this->id"; + } + + public function getDetailUrl () { + $urlParam = $this->getUri (); + if (!is_null (GetUrlParam (DB))) $urlParam = addURLParameter ($urlParam, DB, GetUrlParam (DB)); + return 'index.php' . $urlParam; + } + + public function getTitle () { + return $this->title; + } + + /* Other class (author, series, tag, ...) initialization and accessors */ + + /** + * @return Author[] + */ + public function getAuthors () { + if (is_null ($this->authors)) { + $this->authors = Author::getAuthorByBookId ($this->id); + } + return $this->authors; + } + + public function getAuthorsName () { + return implode (", ", array_map (function ($author) { return $author->name; }, $this->getAuthors ())); + } + + public function getAuthorsSort () { + return implode (", ", array_map (function ($author) { return $author->sort; }, $this->getAuthors ())); + } + + public function getPublisher () { + if (is_null ($this->publisher)) { + $this->publisher = Publisher::getPublisherByBookId ($this->id); + } + return $this->publisher; + } + + /** + * @return Serie + */ + public function getSerie () { + if (is_null ($this->serie)) { + $this->serie = Serie::getSerieByBookId ($this->id); + } + return $this->serie; + } + + /** + * @return string + */ + public function getLanguages () { + $lang = array (); + $result = parent::getDb ()->prepare('select languages.lang_code + from books_languages_link, languages + where books_languages_link.lang_code = languages.id + and book = ? + order by item_order'); + $result->execute (array ($this->id)); + while ($post = $result->fetchObject ()) + { + array_push ($lang, Language::getLanguageString($post->lang_code)); + } + return implode (", ", $lang); + } + + /** + * @return Tag[] + */ + public function getTags () { + if (is_null ($this->tags)) { + $this->tags = array (); + + $result = parent::getDb ()->prepare('select tags.id as id, name + from books_tags_link, tags + where tag = tags.id + and book = ? + order by name'); + $result->execute (array ($this->id)); + while ($post = $result->fetchObject ()) + { + array_push ($this->tags, new Tag ($post)); + } + } + return $this->tags; + } + + public function getTagsName () { + return implode (", ", array_map (function ($tag) { return $tag->name; }, $this->getTags ())); + } + + /** + * @return Data[] + */ + public function getDatas () + { + if (is_null ($this->datas)) { + $this->datas = Data::getDataByBook ($this); + } + return $this->datas; + } + + /* End of other class (author, series, tag, ...) initialization and accessors */ + + public static function getFilterString () { + $filter = getURLParam ("tag", NULL); + if (empty ($filter)) return ""; + + $exists = true; + if (preg_match ("/^!(.*)$/", $filter, $matches)) { + $exists = false; + $filter = $matches[1]; + } + + $result = "exists (select null from books_tags_link, tags where books_tags_link.book = books.id and books_tags_link.tag = tags.id and tags.name = '" . $filter . "')"; + + if (!$exists) { + $result = "not " . $result; + } + + return "and " . $result; + } + + public function GetMostInterestingDataToSendToKindle () + { + $bestFormatForKindle = array ("EPUB", "PDF", "AZW3", "MOBI"); + $bestRank = -1; + $bestData = NULL; + foreach ($this->getDatas () as $data) { + $key = array_search ($data->format, $bestFormatForKindle); + if ($key !== false && $key > $bestRank) { + $bestRank = $key; + $bestData = $data; + } + } + return $bestData; + } + + public function getDataById ($idData) + { + $reduced = array_filter ($this->getDatas (), function ($data) use ($idData) { + return $data->id == $idData; + }); + return reset ($reduced); + } + + public function getRating () { + if (is_null ($this->rating) || $this->rating == 0) { + return ""; + } + $retour = ""; + for ($i = 0; $i < $this->rating / 2; $i++) { + $retour .= "★"; + } + for ($i = 0; $i < 5 - $this->rating / 2; $i++) { + $retour .= "☆"; + } + return $retour; + } + + public function getPubDate () { + if (empty ($this->pubdate)) { + return ""; + } + $dateY = (int) substr($this->pubdate, 0, 4); + if ($dateY > 102) { + return str_pad($dateY, 4, "0", STR_PAD_LEFT); + } + return ""; + } + + public function getComment ($withSerie = true) { + $addition = ""; + $se = $this->getSerie (); + if (!is_null ($se) && $withSerie) { + $addition = $addition . "" . localize("content.series") . "" . str_format (localize ("content.series.data"), $this->seriesIndex, htmlspecialchars ($se->name)) . "
\n"; + } + if (preg_match ("/<\/(div|p|a|span)>/", $this->comment)) + { + return $addition . html2xhtml ($this->comment); + } + else + { + return $addition . htmlspecialchars ($this->comment); + } + } + + public function getDataFormat ($format) { + $reduced = array_filter ($this->getDatas (), function ($data) use ($format) { + return $data->format == $format; + }); + return reset ($reduced); + } + + public function getFilePath ($extension, $idData = NULL, $relative = false) + { + if ($extension == "jpg") + { + $file = "cover.jpg"; + } + else + { + $data = $this->getDataById ($idData); + if (!$data) return NULL; + $file = $data->name . "." . strtolower ($data->format); + } + + if ($relative) + { + return $this->relativePath."/".$file; + } + else + { + return $this->path."/".$file; + } + } + + public function getUpdatedEpub ($idData) + { + global $config; + $data = $this->getDataById ($idData); + + try + { + $epub = new EPub ($data->getLocalPath ()); + + $epub->Title ($this->title); + $authorArray = array (); + foreach ($this->getAuthors() as $author) { + $authorArray [$author->sort] = $author->name; + } + $epub->Authors ($authorArray); + $epub->Language ($this->getLanguages ()); + $epub->Description ($this->getComment (false)); + $epub->Subjects ($this->getTagsName ()); + $epub->Cover2 ($this->getFilePath ("jpg"), "image/jpeg"); + $epub->Calibre ($this->uuid); + $se = $this->getSerie (); + if (!is_null ($se)) { + $epub->Serie ($se->name); + $epub->SerieIndex ($this->seriesIndex); + } + if ($config['cops_provide_kepub'] == "1" && preg_match("/Kobo/", $_SERVER['HTTP_USER_AGENT'])) { + $epub->updateForKepub (); + } + $epub->download ($data->getUpdatedFilenameEpub ()); + } + catch (Exception $e) + { + echo "Exception : " . $e->getMessage(); + } + } + + public function getThumbnail ($width, $height, $outputfile = NULL) { + if (is_null ($width) && is_null ($height)) { + return false; + } + + $file = $this->getFilePath ("jpg"); + // get image size + if ($size = GetImageSize($file)) { + $w = $size[0]; + $h = $size[1]; + //set new size + if (!is_null ($width)) { + $nw = $width; + if ($nw >= $w) { return false; } + $nh = ($nw*$h)/$w; + } else { + $nh = $height; + if ($nh >= $h) { return false; } + $nw = ($nh*$w)/$h; + } + } else { + return false; + } + + //draw the image + $src_img = imagecreatefromjpeg($file); + $dst_img = imagecreatetruecolor($nw,$nh); + imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $nw, $nh, $w, $h);//resizing the image + imagejpeg($dst_img,$outputfile,80); + imagedestroy($src_img); + imagedestroy($dst_img); + + return true; + } + + public function getLinkArray () + { + $linkArray = array(); + + if ($this->hasCover) + { + array_push ($linkArray, Data::getLink ($this, "jpg", "image/jpeg", Link::OPDS_IMAGE_TYPE, "cover.jpg", NULL)); + + array_push ($linkArray, Data::getLink ($this, "jpg", "image/jpeg", Link::OPDS_THUMBNAIL_TYPE, "cover.jpg", NULL)); + } + + foreach ($this->getDatas () as $data) + { + if ($data->isKnownType ()) + { + array_push ($linkArray, $data->getDataLink (Link::OPDS_ACQUISITION_TYPE, $data->format)); + } + } + + foreach ($this->getAuthors () as $author) { + /* @var $author Author */ + array_push ($linkArray, new LinkNavigation ($author->getUri (), "related", str_format (localize ("bookentry.author"), localize ("splitByLetter.book.other"), $author->name))); + } + + $serie = $this->getSerie (); + if (!is_null ($serie)) { + array_push ($linkArray, new LinkNavigation ($serie->getUri (), "related", str_format (localize ("content.series.data"), $this->seriesIndex, $serie->name))); + } + + return $linkArray; + } + + + public function getEntry () { + return new EntryBook ($this->getTitle (), $this->getEntryId (), + $this->getComment (), "text/html", + $this->getLinkArray (), $this); + } + + public static function getBookCount($database = NULL) { + return parent::executeQuerySingle ('select count(*) from books', $database); + } + + public static function getCount() { + global $config; + $nBooks = parent::executeQuerySingle ('select count(*) from books'); + $result = array(); + $entry = new Entry (localize ("allbooks.title"), + self::ALL_BOOKS_ID, + str_format (localize ("allbooks.alphabetical", $nBooks), $nBooks), "text", + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_BOOKS)), "", $nBooks); + array_push ($result, $entry); + if ($config['cops_recentbooks_limit'] > 0) { + $entry = new Entry (localize ("recent.title"), + self::ALL_RECENT_BOOKS_ID, + str_format (localize ("recent.list"), $config['cops_recentbooks_limit']), "text", + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_RECENT_BOOKS)), "", $config['cops_recentbooks_limit']); + array_push ($result, $entry); + } + return $result; + } + + public static function getBooksByAuthor($authorId, $n) { + return self::getEntryArray (self::SQL_BOOKS_BY_AUTHOR, array ($authorId), $n); + } + + public static function getBooksByRating($ratingId, $n) { + return self::getEntryArray (self::SQL_BOOKS_BY_RATING, array ($ratingId), $n); + } + + public static function getBooksByPublisher($publisherId, $n) { + return self::getEntryArray (self::SQL_BOOKS_BY_PUBLISHER, array ($publisherId), $n); + } + + public static function getBooksBySeries($serieId, $n) { + return self::getEntryArray (self::SQL_BOOKS_BY_SERIE, array ($serieId), $n); + } + + public static function getBooksByTag($tagId, $n) { + return self::getEntryArray (self::SQL_BOOKS_BY_TAG, array ($tagId), $n); + } + + public static function getBooksByLanguage($languageId, $n) { + return self::getEntryArray (self::SQL_BOOKS_BY_LANGUAGE, array ($languageId), $n); + } + + /** + * @param $customColumn CustomColumn + * @param $id integer + * @param $n integer + * @return array + */ + public static function getBooksByCustom($customColumn, $id, $n) { + list($query, $params) = $customColumn->getQuery($id); + + return self::getEntryArray ($query, $params, $n); + } + + public static function getBookById($bookId) { + $result = parent::getDb ()->prepare('select ' . self::BOOK_COLUMNS . ' +from books ' . self::SQL_BOOKS_LEFT_JOIN . ' +where books.id = ?'); + $result->execute (array ($bookId)); + while ($post = $result->fetchObject ()) + { + $book = new Book ($post); + return $book; + } + return NULL; + } + + public static function getBookByDataId($dataId) { + $result = parent::getDb ()->prepare('select ' . self::BOOK_COLUMNS . ', data.name, data.format +from data, books ' . self::SQL_BOOKS_LEFT_JOIN . ' +where data.book = books.id and data.id = ?'); + $result->execute (array ($dataId)); + while ($post = $result->fetchObject ()) + { + $book = new Book ($post); + $data = new Data ($post, $book); + $data->id = $dataId; + $book->datas = array ($data); + return $book; + } + return NULL; + } + + public static function getBooksByQuery($query, $n, $database = NULL, $numberPerPage = NULL) { + $i = 0; + $critArray = array (); + foreach (array (PageQueryResult::SCOPE_AUTHOR, + PageQueryResult::SCOPE_TAG, + PageQueryResult::SCOPE_SERIES, + PageQueryResult::SCOPE_PUBLISHER, + PageQueryResult::SCOPE_BOOK) as $key) { + if (in_array($key, getCurrentOption ('ignored_categories')) || + (!array_key_exists ($key, $query) && !array_key_exists ("all", $query))) { + $critArray [$i] = self::BAD_SEARCH; + } + else { + if (array_key_exists ($key, $query)) { + $critArray [$i] = $query [$key]; + } else { + $critArray [$i] = $query ["all"]; + } + } + $i++; + } + return self::getEntryArray (self::SQL_BOOKS_QUERY, $critArray, $n, $database, $numberPerPage); + } + + public static function getBooks($n) { + list ($entryArray, $totalNumber) = self::getEntryArray (self::SQL_BOOKS_ALL , array (), $n); + return array ($entryArray, $totalNumber); + } + + public static function getAllBooks() { + /* @var $result PDOStatement */ + + list (, $result) = parent::executeQuery ("select {0} +from books +group by substr (upper (sort), 1, 1) +order by substr (upper (sort), 1, 1)", "substr (upper (sort), 1, 1) as title, count(*) as count", self::getFilterString (), array (), -1); + + $entryArray = array(); + while ($post = $result->fetchObject ()) + { + array_push ($entryArray, new Entry ($post->title, Book::getEntryIdByLetter ($post->title), + str_format (localize("bookword", $post->count), $post->count), "text", + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_BOOKS_LETTER."&id=". rawurlencode ($post->title))), "", $post->count)); + } + return $entryArray; + } + + public static function getBooksByStartingLetter($letter, $n, $database = NULL, $numberPerPage = NULL) { + return self::getEntryArray (self::SQL_BOOKS_BY_FIRST_LETTER, array ($letter . "%"), $n, $database, $numberPerPage); + } + + public static function getEntryArray ($query, $params, $n, $database = NULL, $numberPerPage = NULL) { + /* @var $totalNumber integer */ + /* @var $result PDOStatement */ + list($totalNumber, $result) = parent::executeQuery($query, self::BOOK_COLUMNS, self::getFilterString (), $params, $n, $database, $numberPerPage); + + $entryArray = array(); + while ($post = $result->fetchObject()) + { + $book = new Book ($post); + array_push ($entryArray, $book->getEntry()); + } + return array ($entryArray, $totalNumber); + } + + public static function getAllRecentBooks() { + global $config; + list ($entryArray, ) = self::getEntryArray (self::SQL_BOOKS_RECENT . $config['cops_recentbooks_limit'], array (), -1); + return $entryArray; + } + + /** + * The values of all the specified columns + * + * @param string[] $columns + * @return CustomColumn[] + */ + public function getCustomColumnValues($columns, $asArray = false) { + $result = array(); + + foreach ($columns as $lookup) { + $col = CustomColumnType::createByLookup($lookup); + if (! is_null($col)) { + $cust = $col->getCustomByBook($this); + if (! is_null($cust)) { + if ($asArray) { + array_push($result, $cust->toArray()); + } else { + array_push($result, $cust); + } + } + } + } + + return $result; + } +} diff --git a/sources/build.xml b/sources/build.xml deleted file mode 100644 index 9cb7a2d..0000000 --- a/sources/build.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/checkconfig.php b/sources/checkconfig.php index 242a80a..4ef2a29 100644 --- a/sources/checkconfig.php +++ b/sources/checkconfig.php @@ -9,15 +9,15 @@ * */ - require_once 'config.php'; - require_once 'base.php'; + require_once ("config.php"); + require_once ("base.php"); - $err = getURLParam('err', -1); - $full = getURLParam('full'); + $err = getURLParam ("err", -1); + $full = getURLParam ("full"); $error = NULL; switch ($err) { case 1 : - $error = 'Database error'; + $error = "Database error"; break; } @@ -38,7 +38,7 @@

You've been redirected because COPS is not configured properly

@@ -53,12 +53,12 @@ = 50300) { - echo 'OK (' . PHP_VERSION . ')'; + echo "OK (" . PHP_VERSION . ")"; } else { - echo 'Please install PHP >= 5.3 (' . PHP_VERSION . ')'; + echo "Please install PHP >= 5.3 (" . PHP_VERSION . ")"; } } else { - echo 'Please install PHP >= 5.3'; + echo "Please install PHP >= 5.3"; } ?> @@ -68,9 +68,9 @@

@@ -80,9 +80,9 @@

@@ -92,9 +92,9 @@

@@ -104,9 +104,9 @@

@@ -116,9 +116,9 @@

@@ -128,9 +128,9 @@

@@ -139,10 +139,10 @@

Check if Normalizer class is properly installed and loaded

@@ -152,25 +152,25 @@

$database) { +foreach (Base::getDbList () as $name => $database) { ?>

Check if Calibre database path is not an URL

@@ -179,31 +179,31 @@ foreach (Base::getDbList() as $name => $database) {

Check if Calibre database file exists and is readable

-
  • Value of $config[\'calibre_directory\'] in config_local.php
  • -
  • Value of open_basedir in your php.ini
  • +
  • Value of \$config['calibre_directory'] in config_local.php
  • +
  • Value of open_basedir in your php.ini
  • The access rights of the Calibre Database
  • -
  • Synology users please read this
  • -'; +
  • Synology users please read this
  • +"; } ?>

    - +

    Check if Calibre database file can be opened with PHP

    @@ -213,15 +213,15 @@ Please check

    query('select count(*) FROM sqlite_master WHERE type="table" AND name in ("books", "authors", "tags", "series")')->fetchColumn(); + $db = new PDO('sqlite:'. Base::getDbFileName ($i)); + $count = $db->query("select count(*) FROM sqlite_master WHERE type='table' AND name in ('books', 'authors', 'tags', 'series')")->fetchColumn(); if ($count == 4) { - echo $name . ' OK'; + echo "{$name} OK"; } else { - echo $name . ' Not all Calibre tables were found. Are you sure you\'re using the correct database.'; + echo "{$name} Not all Calibre tables were found. Are you sure you're using the correct database."; } } catch (Exception $e) { - echo $name . ' If the file is readable, check your php configuration. Exception detail : ' . $e; + echo "{$name} If the file is readable, check your php configuration. Exception detail : " . $e; } ?>

    @@ -232,27 +232,24 @@ Please check

    prepare('select books.path || "/" || data.name || "." || lower (format) as fullpath from data join books on data.book = books.id'); - $result->execute(); - while ($post = $result->fetchObject()) + $db = new PDO('sqlite:'. Base::getDbFileName ($i)); + $result = $db->prepare("select books.path || '/' || data.name || '.' || lower (format) as fullpath from data join books on data.book = books.id"); + $result->execute (); + while ($post = $result->fetchObject ()) { - if (!is_file (Base::getDbDirectory($i) . $post->fullpath)) { - echo '

    ' . Base::getDbDirectory($i) . $post->fullpath . '

    '; + if (!is_file (Base::getDbDirectory ($i) . $post->fullpath)) { + echo "

    " . Base::getDbDirectory ($i) . $post->fullpath . "

    "; } } } catch (Exception $e) { - echo $name . ' If the file is readable, check your php configuration. Exception detail : ' . $e; + echo "{$name} If the file is readable, check your php configuration. Exception detail : " . $e; } ?>

    - + + +
    diff --git a/sources/composer-dl.sh b/sources/composer-dl.sh deleted file mode 100755 index 043f357..0000000 --- a/sources/composer-dl.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# https://getcomposer.org/ -if [ -x `which wget` ]; then - echo "wget found." - wget -q https://getcomposer.org/installer -O - | php -elif [ -x `which curl` ]; then - echo "curl found." - curl -sS https://getcomposer.org/installer | php -else - echo "Please install wget or curl to download Composer." -fi - -if [ -f "./composer.phar" ]; then - chmod a+x ./composer.phar - - # Install support for bower and NPM packages - ./composer.phar global require "fxp/composer-asset-plugin:~1.1" -fi diff --git a/sources/composer.json b/sources/composer.json deleted file mode 100644 index 6933c45..0000000 --- a/sources/composer.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "Calibre OPDS (and HTML) PHP Server", - "description": "web-based light alternative to Calibre content server / Calibre2OPDS to serve ebooks (epub, mobi, pdf, ...)", - "require": { - "ext-gd": "*", - "ext-xml": "*", - "ext-intl": "*", - "ext-json": "*", - "ext-pdo_sqlite": "*", - "ext-mbstring": "*", - "dimsemenov/magnific-popup": "~1.0", - "phpmailer/phpmailer": "~5.2", - "twbs/bootstrap": "~3.3", - "bower-asset/jQuery": "~1.11", - "bower-asset/jquery-cookie": "~1.4", - "bower-asset/normalize.css": "~3.0", - "twitter/typeahead.js": "~0.10.5", - "seblucas/dot-php": "~1.0.0", - "seblucas/php-epub-meta": "~1.0.0", - "seblucas/tbszip": "~2.16", - "simonpioli/sortelements": "dev-master", - "bower-asset/doT": "~1.0.1", - "rsms/js-lru": "dev-v2" - }, - "require-dev": { - "phpunit/phpunit": "5.4.* || 4.8.*", - "sauce/sausage": ">=0.12.0", - "phing/phing": "2.*" - }, - "autoload": { - "classmap": ["lib/", "resources/"] - }, - "repositories": [ - { - "type": "package", - "package": { - "name": "seblucas/dot-php", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/seblucas/doT-php", - "reference": "master" - }, - "autoload": { - "classmap": ["./"] - } - } - }, - { - "type": "package", - "package": { - "name": "simonpioli/sortelements", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/simonpioli/sortElements", - "reference": "master" - } - } - }, - { - "type": "package", - "package": { - "name": "rsms/js-lru", - "version": "dev-v2", - "source": { - "type": "git", - "url": "https://github.com/rsms/js-lru", - "reference": "v2" - } - } - } - ] -} diff --git a/sources/composer.lock b/sources/composer.lock deleted file mode 100644 index 0144816..0000000 --- a/sources/composer.lock +++ /dev/null @@ -1,2517 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "hash": "796be60d03ca5c5b4f2f01e3d4d4b870", - "content-hash": "5cdf7fa70c21736e02127769497e9b5b", - "packages": [ - { - "name": "bower-asset/dot", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/olado/doT.git", - "reference": "195025f06055761f6da3a900251382e788c42d0e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/olado/doT/zipball/195025f06055761f6da3a900251382e788c42d0e", - "reference": "195025f06055761f6da3a900251382e788c42d0e", - "shasum": "" - }, - "type": "bower-asset-library" - }, - { - "name": "bower-asset/jquery", - "version": "1.12.4", - "source": { - "type": "git", - "url": "https://github.com/jquery/jquery-dist.git", - "reference": "5e89585e0121e72ff47de177c5ef604f3089a53d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/5e89585e0121e72ff47de177c5ef604f3089a53d", - "reference": "5e89585e0121e72ff47de177c5ef604f3089a53d", - "shasum": "" - }, - "type": "bower-asset-library", - "extra": { - "bower-asset-main": "dist/jquery.js", - "bower-asset-ignore": [ - "package.json" - ] - }, - "license": [ - "MIT" - ], - "keywords": [ - "browser", - "javascript", - "jquery", - "library" - ] - }, - { - "name": "bower-asset/jquery-cookie", - "version": "v1.4.1", - "source": { - "type": "git", - "url": "https://github.com/carhartl/jquery-cookie.git", - "reference": "7f88a4e631aba8a8c688fd8999ce6b9bcfd50718" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/carhartl/jquery-cookie/zipball/7f88a4e631aba8a8c688fd8999ce6b9bcfd50718", - "reference": "7f88a4e631aba8a8c688fd8999ce6b9bcfd50718", - "shasum": "" - }, - "require": { - "bower-asset/jquery": ">=1.2" - }, - "type": "bower-asset-library", - "extra": { - "bower-asset-main": [ - "./jquery.cookie.js" - ], - "bower-asset-ignore": [ - "test", - ".*", - "*.json", - "*.md", - "*.txt", - "Gruntfile.js" - ] - } - }, - { - "name": "bower-asset/normalize.css", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/necolas/normalize.css.git", - "reference": "2bdda84272650aedfb45d8abe11a6d177933a803" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/necolas/normalize.css/zipball/2bdda84272650aedfb45d8abe11a6d177933a803", - "reference": "2bdda84272650aedfb45d8abe11a6d177933a803", - "shasum": "" - }, - "type": "bower-asset-library", - "extra": { - "bower-asset-main": "normalize.css", - "bower-asset-ignore": [ - "CHANGELOG.md", - "CONTRIBUTING.md", - "component.json", - "package.json", - "test.html" - ] - } - }, - { - "name": "dimsemenov/magnific-popup", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/dimsemenov/Magnific-Popup.git", - "reference": "6b7a8088783cbce01034414c1fd2d8e1889093ae" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dimsemenov/Magnific-Popup/zipball/6b7a8088783cbce01034414c1fd2d8e1889093ae", - "reference": "6b7a8088783cbce01034414c1fd2d8e1889093ae", - "shasum": "" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "description": "Light and responsive lightbox script with focus on performance.", - "homepage": "http://dimsemenov.com/plugins/magnific-popup/", - "time": "2016-02-20 09:06:30" - }, - { - "name": "phpmailer/phpmailer", - "version": "v5.2.17", - "source": { - "type": "git", - "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "208913c6042967ba404f4bfa0819bf5bef79dbec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/208913c6042967ba404f4bfa0819bf5bef79dbec", - "reference": "208913c6042967ba404f4bfa0819bf5bef79dbec", - "shasum": "" - }, - "require": { - "php": ">=5.0.0" - }, - "require-dev": { - "phpdocumentor/phpdocumentor": "*", - "phpunit/phpunit": "4.7.*" - }, - "suggest": { - "league/oauth2-google": "Needed for Google XOAUTH2 authentication" - }, - "type": "library", - "autoload": { - "classmap": [ - "class.phpmailer.php", - "class.phpmaileroauth.php", - "class.phpmaileroauthgoogle.php", - "class.smtp.php", - "class.pop3.php", - "extras/EasyPeasyICS.php", - "extras/ntlm_sasl_client.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1" - ], - "authors": [ - { - "name": "Jim Jagielski", - "email": "jimjag@gmail.com" - }, - { - "name": "Marcus Bointon", - "email": "phpmailer@synchromedia.co.uk" - }, - { - "name": "Andy Prevost", - "email": "codeworxtech@users.sourceforge.net" - }, - { - "name": "Brent R. Matzelle" - } - ], - "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "time": "2016-12-09 10:03:48" - }, - { - "name": "rsms/js-lru", - "version": "dev-v2", - "source": { - "type": "git", - "url": "https://github.com/rsms/js-lru", - "reference": "v2" - }, - "type": "library", - "time": "2016-11-16 03:30:49" - }, - { - "name": "seblucas/dot-php", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/seblucas/doT-php.git", - "reference": "0b6b351e539007eb72c0c34131204d036ce4454f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/seblucas/doT-php/zipball/0b6b351e539007eb72c0c34131204d036ce4454f", - "reference": "0b6b351e539007eb72c0c34131204d036ce4454f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "doT.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0" - ], - "authors": [ - { - "name": "Sébastien Lucas", - "email": "sebastien@slucas.fr", - "homepage": "http://www.slucas.fr/", - "role": "Developer" - } - ], - "description": "PHP rendering engine for doT.js (The fastest + concise javascript template engine for nodejs and browsers)", - "homepage": "https://github.com/seblucas/doT-php", - "keywords": [ - "Rendering", - "dot", - "engine", - "template" - ], - "time": "2016-07-03 12:29:39" - }, - { - "name": "seblucas/php-epub-meta", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/seblucas/php-epub-meta.git", - "reference": "ee222ba6f75c809dd88fa8bc5798fc7868fd915c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/seblucas/php-epub-meta/zipball/ee222ba6f75c809dd88fa8bc5798fc7868fd915c", - "reference": "ee222ba6f75c809dd88fa8bc5798fc7868fd915c", - "shasum": "" - }, - "require": { - "ext-xml": "*", - "ext-zip": "*", - "php": ">=5.3.0", - "seblucas/tbszip": "~2.16.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "autoload": { - "classmap": [ - "lib/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "authors": [ - { - "name": "Sébastien Lucas", - "email": "sebastien@slucas.fr", - "homepage": "http://www.slucas.fr/", - "role": "Developer" - }, - { - "name": "Andreas Gohr", - "email": "andi@splitbrain.org", - "homepage": "https://www.splitbrain.org/", - "role": "Developer" - } - ], - "description": "Reading and writing metadata included in the EPub ebook format", - "homepage": "https://github.com/seblucas/php-epub-meta", - "keywords": [ - "ebook", - "epub", - "metadata" - ], - "time": "2016-07-03 20:07:37" - }, - { - "name": "seblucas/tbszip", - "version": "2.16.1", - "source": { - "type": "git", - "url": "https://github.com/seblucas/tbszip.git", - "reference": "2c50bf309bb4431a24e206f164fdb4a2e6b10b7f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/seblucas/tbszip/zipball/2c50bf309bb4431a24e206f164fdb4a2e6b10b7f", - "reference": "2c50bf309bb4431a24e206f164fdb4a2e6b10b7f", - "shasum": "" - }, - "require": { - "ext-zlib": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "5.4.*" - }, - "type": "library", - "autoload": { - "classmap": [ - "tbszip.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1+" - ], - "authors": [ - { - "name": "Skrol29", - "homepage": "http://www.tinybutstrong.com/", - "role": "Developer" - }, - { - "name": "Sébastien Lucas", - "email": "sebastien@slucas.fr", - "homepage": "http://www.slucas.fr/", - "role": "Developer" - } - ], - "description": "Work with zip archives without making temporary files or needing binaries", - "homepage": "http://www.tinybutstrong.com/tools.php", - "keywords": [ - "archive", - "compression", - "zip" - ], - "time": "2016-07-03 12:26:16" - }, - { - "name": "simonpioli/sortelements", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/simonpioli/sortElements", - "reference": "master" - }, - "type": "library", - "time": "2012-04-25 11:04:51" - }, - { - "name": "twbs/bootstrap", - "version": "v3.3.7", - "source": { - "type": "git", - "url": "https://github.com/twbs/bootstrap.git", - "reference": "0b9c4a4007c44201dce9a6cc1a38407005c26c86" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twbs/bootstrap/zipball/0b9c4a4007c44201dce9a6cc1a38407005c26c86", - "reference": "0b9c4a4007c44201dce9a6cc1a38407005c26c86", - "shasum": "" - }, - "replace": { - "twitter/bootstrap": "self.version" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jacob Thornton", - "email": "jacobthornton@gmail.com" - }, - { - "name": "Mark Otto", - "email": "markdotto@gmail.com" - } - ], - "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", - "homepage": "http://getbootstrap.com", - "keywords": [ - "JS", - "css", - "framework", - "front-end", - "less", - "mobile-first", - "responsive", - "web" - ], - "time": "2016-07-25 15:51:55" - }, - { - "name": "twitter/typeahead.js", - "version": "v0.10.5", - "source": { - "type": "git", - "url": "https://github.com/twitter/typeahead.js.git", - "reference": "5f198b87d1af845da502ea9df93a5e84801ce742" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twitter/typeahead.js/zipball/5f198b87d1af845da502ea9df93a5e84801ce742", - "reference": "5f198b87d1af845da502ea9df93a5e84801ce742", - "shasum": "" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Twitter Inc.", - "homepage": "https://twitter.com/twitteross" - } - ], - "description": "fast and fully-featured autocomplete library", - "homepage": "http://twitter.github.com/typeahead.js", - "keywords": [ - "autocomplete", - "typeahead" - ], - "time": "2014-08-08 06:18:07" - } - ], - "packages-dev": [ - { - "name": "appium/php-client", - "version": "v0.2.0", - "source": { - "type": "git", - "url": "https://github.com/appium/php-client.git", - "reference": "06c68c20d389bfd50a512393b1fe750cc5044b2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/appium/php-client/zipball/06c68c20d389bfd50a512393b1fe750cc5044b2f", - "reference": "06c68c20d389bfd50a512393b1fe750cc5044b2f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "phpunit/phpunit-selenium": ">=1.3.3" - }, - "type": "appium-php", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Isaac Murchie", - "email": "isaac@saucelabs.com", - "homepage": "http://www.saucelabs.com", - "role": "Lead" - } - ], - "description": "PHP client for Selenium 3.0/Appium 1.0", - "homepage": "http://github.com/appium/appium-php", - "keywords": [ - "appium", - "phpunit", - "selenium" - ], - "time": "2016-11-09 01:09:43" - }, - { - "name": "brianium/habitat", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/brianium/habitat.git", - "reference": "d0979e3bb379cbc78ecb42b3ac171bc2b7e06d96" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/brianium/habitat/zipball/d0979e3bb379cbc78ecb42b3ac171bc2b7e06d96", - "reference": "d0979e3bb379cbc78ecb42b3ac171bc2b7e06d96", - "shasum": "" - }, - "require-dev": { - "monolog/monolog": ">=1.5.0", - "phpunit/phpunit": ">=3.7.21" - }, - "type": "library", - "autoload": { - "psr-0": { - "Habitat": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Brian", - "email": "scaturrob@gmail.com", - "homepage": "http://brianscaturro.com", - "role": "Lead" - } - ], - "description": "A dependable php environment", - "time": "2013-06-08 04:42:29" - }, - { - "name": "brianium/paratest", - "version": "0.14.0", - "source": { - "type": "git", - "url": "https://github.com/brianium/paratest.git", - "reference": "dddcfa8510da7aae9616ba1738ebf630d9e84aa4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/brianium/paratest/zipball/dddcfa8510da7aae9616ba1738ebf630d9e84aa4", - "reference": "dddcfa8510da7aae9616ba1738ebf630d9e84aa4", - "shasum": "" - }, - "require": { - "brianium/habitat": "1.0.0", - "composer/semver": "~1.2", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-simplexml": "*", - "php": ">=5.5.11", - "phpunit/php-timer": ">=1.0.4", - "phpunit/phpunit": ">=3.7.8", - "symfony/console": "~2.3|~3.0", - "symfony/process": "~2.3|~3.0" - }, - "bin": [ - "bin/paratest" - ], - "type": "library", - "autoload": { - "psr-0": { - "ParaTest": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Brian Scaturro", - "email": "scaturrob@gmail.com", - "homepage": "http://brianscaturro.com", - "role": "Lead" - } - ], - "description": "Parallel testing for PHP", - "homepage": "https://github.com/brianium/paratest", - "keywords": [ - "concurrent", - "parallel", - "phpunit", - "testing" - ], - "time": "2016-08-12 20:14:13" - }, - { - "name": "composer/semver", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "time": "2016-08-30 16:08:34" - }, - { - "name": "doctrine/instantiator", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", - "shasum": "" - }, - "require": { - "php": ">=5.3,<8.0-DEV" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2015-06-14 21:17:01" - }, - { - "name": "myclabs/deep-copy", - "version": "1.5.5", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108", - "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "doctrine/collections": "1.*", - "phpunit/phpunit": "~4.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "homepage": "https://github.com/myclabs/DeepCopy", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2016-10-31 17:19:45" - }, - { - "name": "phing/phing", - "version": "2.15.2", - "source": { - "type": "git", - "url": "https://github.com/phingofficial/phing.git", - "reference": "0999ab4e94e609dc00998e3d1b88df843054db7c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phingofficial/phing/zipball/0999ab4e94e609dc00998e3d1b88df843054db7c", - "reference": "0999ab4e94e609dc00998e3d1b88df843054db7c", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "require-dev": { - "ext-pdo_sqlite": "*", - "lastcraft/simpletest": "@dev", - "mikey179/vfsstream": "^1.6", - "pdepend/pdepend": "2.x", - "pear/archive_tar": "1.4.x", - "pear/http_request2": "dev-trunk", - "pear/net_growl": "dev-trunk", - "pear/pear-core-minimal": "1.10.1", - "pear/versioncontrol_git": "@dev", - "pear/versioncontrol_svn": "~0.5", - "phpdocumentor/phpdocumentor": "2.x", - "phploc/phploc": "~2.0.6", - "phpmd/phpmd": "~2.2", - "phpunit/phpunit": ">=3.7", - "sebastian/git": "~1.0", - "sebastian/phpcpd": "2.x", - "siad007/versioncontrol_hg": "^1.0", - "squizlabs/php_codesniffer": "~2.2", - "symfony/yaml": "~2.7" - }, - "suggest": { - "pdepend/pdepend": "PHP version of JDepend", - "pear/archive_tar": "Tar file management class", - "pear/versioncontrol_git": "A library that provides OO interface to handle Git repository", - "pear/versioncontrol_svn": "A simple OO-style interface for Subversion, the free/open-source version control system", - "phpdocumentor/phpdocumentor": "Documentation Generator for PHP", - "phploc/phploc": "A tool for quickly measuring the size of a PHP project", - "phpmd/phpmd": "PHP version of PMD tool", - "phpunit/php-code-coverage": "Library that provides collection, processing, and rendering functionality for PHP code coverage information", - "phpunit/phpunit": "The PHP Unit Testing Framework", - "sebastian/phpcpd": "Copy/Paste Detector (CPD) for PHP code", - "siad007/versioncontrol_hg": "A library for interfacing with Mercurial repositories.", - "tedivm/jshrink": "Javascript Minifier built in PHP" - }, - "bin": [ - "bin/phing" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.15.x-dev" - } - }, - "autoload": { - "classmap": [ - "classes/phing/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "classes" - ], - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Michiel Rook", - "email": "mrook@php.net" - }, - { - "name": "Phing Community", - "homepage": "https://www.phing.info/trac/wiki/Development/Contributors" - } - ], - "description": "PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.", - "homepage": "https://www.phing.info/", - "keywords": [ - "build", - "phing", - "task", - "tool" - ], - "time": "2016-10-13 09:01:45" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "1.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2015-12-27 11:43:31" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-09-30 07:12:33" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "0.2.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", - "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "time": "2016-11-25 06:54:22" - }, - { - "name": "phpspec/prophecy", - "version": "v1.6.2", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "6c52c2722f8460122f96f86346600e1077ce22cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb", - "reference": "6c52c2722f8460122f96f86346600e1077ce22cb", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0|^2.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.0", - "phpunit/phpunit": "^4.8 || ^5.6.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2016-11-21 14:58:47" - }, - { - "name": "phpunit/php-code-coverage", - "version": "4.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "903fd6318d0a90b4770a009ff73e4a4e9c437929" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/903fd6318d0a90b4770a009ff73e4a4e9c437929", - "reference": "903fd6318d0a90b4770a009ff73e4a4e9c437929", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "^1.4.2", - "sebastian/code-unit-reverse-lookup": "~1.0", - "sebastian/environment": "^1.3.2 || ^2.0", - "sebastian/version": "~1.0|~2.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "^5.4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.4.0", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2016-11-28 16:00:31" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2016-10-03 07:40:28" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21 13:50:34" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4|~5" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2016-05-12 18:03:57" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.4.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b", - "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2016-11-15 14:06:22" - }, - { - "name": "phpunit/phpunit", - "version": "5.4.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3132365e1430c091f208e120b8845d39c25f20e6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3132365e1430c091f208e120b8845d39c25f20e6", - "reference": "3132365e1430c091f208e120b8845d39c25f20e6", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "^4.0.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "^3.2", - "sebastian/comparator": "~1.1", - "sebastian/diff": "~1.2", - "sebastian/environment": "^1.3 || ^2.0", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/object-enumerator": "~1.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "~1.0|~2.0", - "symfony/yaml": "~2.1|~3.0" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2016-07-26 14:48:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "3.4.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", - "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2 || ^2.0" - }, - "conflict": { - "phpunit/phpunit": "<5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2016-12-08 20:27:08" - }, - { - "name": "phpunit/phpunit-selenium", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/giorgiosironi/phpunit-selenium.git", - "reference": "d3aa8984c31efcff7c8829b9bd9ad7ab4c94709c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/giorgiosironi/phpunit-selenium/zipball/d3aa8984c31efcff7c8829b9bd9ad7ab4c94709c", - "reference": "d3aa8984c31efcff7c8829b9bd9ad7ab4c94709c", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-dom": "*", - "php": ">=5.6", - "phpunit/phpunit": "~5.0", - "sebastian/comparator": "~1.0" - }, - "require-dev": { - "phing/phing": "2.*" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Giorgio Sironi", - "email": "info@giorgiosironi.com", - "role": "developer" - }, - { - "name": "Ivan Kurnosov", - "email": "zerkms@zerkms.com", - "role": "developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "original developer" - } - ], - "description": "Selenium Server integration for PHPUnit", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "phpunit", - "selenium", - "testing", - "xunit" - ], - "time": "2016-04-22 10:41:33" - }, - { - "name": "psr/log", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2016-10-10 12:19:37" - }, - { - "name": "sauce/sausage", - "version": "0.17.0", - "source": { - "type": "git", - "url": "https://github.com/jlipps/sausage.git", - "reference": "ce7fea6a8de0090459cf23719aec907452600aa6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jlipps/sausage/zipball/ce7fea6a8de0090459cf23719aec907452600aa6", - "reference": "ce7fea6a8de0090459cf23719aec907452600aa6", - "shasum": "" - }, - "require": { - "appium/php-client": ">=0.1.0", - "brianium/paratest": ">=0.12.1", - "php": ">=5.4.0", - "phpunit/phpunit-selenium": ">=1.4.1", - "sauce/sausage-installer": ">=0.1.0" - }, - "require-dev": { - "phpunit/phpunit": ">=4.5.1" - }, - "suggest": { - "sauce/connect": ">=3.1" - }, - "bin": [ - "bin/sauce_config" - ], - "type": "sauce-sausage", - "autoload": { - "psr-0": { - "Sauce": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Jonathan Lipps", - "email": "jlipps@saucelabs.com", - "homepage": "http://www.saucelabs.com", - "role": "Lead" - } - ], - "description": "PHP version of the Sauce Labs API", - "homepage": "http://github.com/jlipps/sausage", - "keywords": [ - "Sauce", - "SauceLabs", - "api", - "appium", - "phpunit", - "selenium", - "testing" - ], - "time": "2015-04-28 03:02:03" - }, - { - "name": "sauce/sausage-installer", - "version": "v0.1.0", - "source": { - "type": "git", - "url": "https://github.com/jlipps/sausage-installer.git", - "reference": "5435cadb3ef1cec77218814af3c121b3556a5444" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jlipps/sausage-installer/zipball/5435cadb3ef1cec77218814af3c121b3556a5444", - "reference": "5435cadb3ef1cec77218814af3c121b3556a5444", - "shasum": "" - }, - "type": "composer-installer", - "extra": { - "class": "Sauce\\Composer\\SausageInstaller" - }, - "autoload": { - "psr-0": { - "Sauce": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Jonathan Lipps", - "email": "jlipps@saucelabs.com", - "homepage": "http://www.saucelabs.com", - "role": "Lead" - } - ], - "homepage": "http://github.com/jlipps/sausage-installer", - "time": "2012-09-28 18:41:38" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", - "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2016-02-13 06:45:14" - }, - { - "name": "sebastian/comparator", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f", - "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2016-11-19 09:18:40" - }, - { - "name": "sebastian/diff", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2015-12-08 07:14:41" - }, - { - "name": "sebastian/environment", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2016-11-26 07:53:53" - }, - { - "name": "sebastian/exporter", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2016-06-17 09:04:28" - }, - { - "name": "sebastian/global-state", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2015-10-12 03:26:01" - }, - { - "name": "sebastian/object-enumerator", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", - "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", - "shasum": "" - }, - "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2016-01-28 13:25:10" - }, - { - "name": "sebastian/recursion-context", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11 19:50:13" - }, - { - "name": "sebastian/resource-operations", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "shasum": "" - }, - "require": { - "php": ">=5.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28 20:34:47" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03 07:35:21" - }, - { - "name": "symfony/console", - "version": "v3.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "d12aa9ca20f4db83ec58410978dab6afcb9d6aaa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/d12aa9ca20f4db83ec58410978dab6afcb9d6aaa", - "reference": "d12aa9ca20f4db83ec58410978dab6afcb9d6aaa", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "symfony/debug": "~2.8|~3.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/filesystem": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/filesystem": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Console Component", - "homepage": "https://symfony.com", - "time": "2016-12-11 14:34:22" - }, - { - "name": "symfony/debug", - "version": "v3.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "9f923e68d524a3095c5a2ae5fc7220c7cbc12231" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/9f923e68d524a3095c5a2ae5fc7220c7cbc12231", - "reference": "9f923e68d524a3095c5a2ae5fc7220c7cbc12231", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" - }, - "require-dev": { - "symfony/class-loader": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Debug Component", - "homepage": "https://symfony.com", - "time": "2016-11-16 22:18:16" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2016-11-14 01:06:16" - }, - { - "name": "symfony/process", - "version": "v3.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "02ea84847aad71be7e32056408bb19f3a616cdd3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/02ea84847aad71be7e32056408bb19f3a616cdd3", - "reference": "02ea84847aad71be7e32056408bb19f3a616cdd3", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com", - "time": "2016-11-24 10:40:28" - }, - { - "name": "symfony/yaml", - "version": "v3.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "a7095af4b97a0955f85c8989106c249fa649011f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/a7095af4b97a0955f85c8989106c249fa649011f", - "reference": "a7095af4b97a0955f85c8989106c249fa649011f", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "symfony/console": "~2.8|~3.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2016-12-10 10:07:06" - }, - { - "name": "webmozart/assert", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2016-11-23 20:04:58" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "simonpioli/sortelements": 20, - "rsms/js-lru": 20 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "ext-gd": "*", - "ext-xml": "*", - "ext-intl": "*", - "ext-json": "*", - "ext-pdo_sqlite": "*", - "ext-mbstring": "*" - }, - "platform-dev": [] -} diff --git a/sources/config.php b/sources/config.php index b1e487a..2990244 100644 --- a/sources/config.php +++ b/sources/config.php @@ -6,18 +6,17 @@ * @author Sébastien Lucas */ -require_once dirname(__FILE__) . '/vendor/autoload.php'; -require dirname(__FILE__) . '/config_default.php'; +require_once 'config_default.php'; if (file_exists(dirname(__FILE__) . '/config_local.php') && (php_sapi_name() !== 'cli')) { - require dirname(__FILE__) . '/config_local.php'; + require_once 'config_local.php'; } $remote_user = array_key_exists('PHP_AUTH_USER', $_SERVER) ? $_SERVER['PHP_AUTH_USER'] : ''; // Clean username, only allow a-z, A-Z, 0-9, -_ chars -$remote_user = preg_replace( '/[^a-zA-Z0-9_-]/', '', $remote_user); +$remote_user = preg_replace( "/[^a-zA-Z0-9_-]/", "", $remote_user); $user_config_file = 'config_local.' . $remote_user . '.php'; if (file_exists(dirname(__FILE__) . '/' . $user_config_file) && (php_sapi_name() !== 'cli')) { - require_once dirname(__FILE__) . '/' . $user_config_file; + require_once $user_config_file; } if(!is_null($config['cops_basic_authentication']) && diff --git a/sources/config_default.php b/sources/config_default.php index c1d8418..4b7b5f7 100644 --- a/sources/config_default.php +++ b/sources/config_default.php @@ -6,9 +6,8 @@ * @author Sébastien Lucas */ - if (!isset($config)) { + if (!isset($config)) $config = array(); - } /* * The directory containing calibre's metadata.db file, with sub-directories @@ -41,27 +40,27 @@ /* * Catalog's author name */ - $config['cops_author_name'] = 'Sébastien Lucas'; + $config['cops_author_name'] = "Sébastien Lucas"; /* * Catalog's author uri */ - $config['cops_author_uri'] = 'http://blog.slucas.fr'; + $config['cops_author_uri'] = "http://blog.slucas.fr"; /* * Catalog's author email */ - $config['cops_author_email'] = 'sebastien@slucas.fr'; + $config['cops_author_email'] = "sebastien@slucas.fr"; /* * Catalog's title */ - $config['cops_title_default'] = 'COPS'; + $config['cops_title_default'] = "COPS"; /* * Catalog's subtitle */ - $config['cops_subtitle_default'] = ''; + $config['cops_subtitle_default'] = ""; /* * Wich header to use when downloading books outside the web directory @@ -70,44 +69,44 @@ * X-Sendfile : For Lightttpd or Apache (with mod_xsendfile) * No value (default) : Let PHP handle the download */ - $config['cops_x_accel_redirect'] = ''; + $config['cops_x_accel_redirect'] = ""; /* * Height of thumbnail image for OPDS */ - $config['cops_opds_thumbnail_height'] = '164'; + $config['cops_opds_thumbnail_height'] = "164"; /* * Height of thumbnail image for HTML */ - $config['cops_html_thumbnail_height'] = '164'; + $config['cops_html_thumbnail_height'] = "164"; /* * Icon for both OPDS and HTML catalog * Note that this has to be a real icon (.ico) */ - $config['cops_icon'] = 'favicon.ico'; + $config['cops_icon'] = "favicon.ico"; /* * Show icon for authors, series, tags and books on OPDS feed * 1 : enable * 0 : disable */ - $config['cops_show_icons'] = '1'; + $config['cops_show_icons'] = "1"; /* * Default timezone * Check following link for other timezones : * http://www.php.net/manual/en/timezones.php */ - $config['default_timezone'] = 'Europe/Paris'; + $config['default_timezone'] = "Europe/Paris"; /* * Prefered format for HTML catalog * The two first will be displayed in book entries * The other only appear in book detail */ - $config['cops_prefered_format'] = array('EPUB', 'PDF', 'AZW3', 'AZW', 'MOBI', 'CBR', 'CBZ'); + $config['cops_prefered_format'] = array ("EPUB", "PDF", "AZW3", "AZW", "MOBI", "CBR", "CBZ"); /* * use URL rewriting for downloading of ebook in HTML catalog @@ -115,7 +114,7 @@ * 1 : enable * 0 : disable */ - $config['cops_use_url_rewriting'] = '0'; + $config['cops_use_url_rewriting'] = "0"; /* * generate a invalid OPDS stream to allow bad OPDS client to use search @@ -124,41 +123,41 @@ * 1 : enable support for non compliant OPDS client * 0 : always generate valid OPDS code */ - $config['cops_generate_invalid_opds_stream'] = '0'; + $config['cops_generate_invalid_opds_stream'] = "0"; /* * Max number of items per page * -1 unlimited */ - $config['cops_max_item_per_page'] = '-1'; + $config['cops_max_item_per_page'] = "-1"; /* * split authors by first letter * 1 : Yes * 0 : No */ - $config['cops_author_split_first_letter'] = '1'; + $config['cops_author_split_first_letter'] = "1"; /* * split titles by first letter * 1 : Yes * 0 : No */ - $config['cops_titles_split_first_letter'] = '1'; + $config['cops_titles_split_first_letter'] = "1"; /* * Enable the Lightboxes (for popups) * 1 : Yes (enable) * 0 : No */ - $config['cops_use_fancyapps'] = '1'; + $config['cops_use_fancyapps'] = "1"; /* * Update Epub metadata before download * 1 : Yes (enable) * 0 : No */ - $config['cops_update_epub-metadata'] = '0'; + $config['cops_update_epub-metadata'] = "0"; /* * Filter on tags to book list @@ -169,7 +168,7 @@ * * Example : array ("All" => "", "Unread" => "!Read", "Read" => "Read") */ - $config['cops_books_filter'] = array(); + $config['cops_books_filter'] = array (); /* * Custom Columns for the index page @@ -179,7 +178,7 @@ * * Note that the composite custom columns are not supported */ - $config['cops_calibre_custom_column'] = array(); + $config['cops_calibre_custom_column'] = array (); /* * Custom Columns for the list representation @@ -208,7 +207,7 @@ * 1 : Yes (enable) * 0 : No */ - $config['cops_provide_kepub'] = '0'; + $config['cops_provide_kepub'] = "0"; /* * Enable and configure Send To Kindle (or Email) feature. @@ -238,7 +237,7 @@ * 1 : Yes (enable) * 0 : No */ - $config['cops_html_tag_filter'] = '0'; + $config['cops_html_tag_filter'] = "0"; /* * Thumbnails are generated on-the-fly so it can be problematic on servers with slow CPU (Raspberry Pi, Dockstar, Piratebox, ...). @@ -247,7 +246,7 @@ * "1" : always send the full size image (Network hungry) * any url : Send a constant image as the thumbnail (you can try "images/bookcover.png") */ - $config['cops_thumbnail_handling'] = ''; + $config['cops_thumbnail_handling'] = ""; /* * Directory to keep resized thumbnails: allow to resize thumbnails only on first access, then use this cache. @@ -256,14 +255,14 @@ * "/tmp/cache/" (example) : will generate thumbnails in /tmp/cache/ * BEWARE : it has to end with a / */ - $config['cops_thumbnail_cache_directory'] = ''; + $config['cops_thumbnail_cache_directory'] = ""; /* * Contains a list of user agent for browsers not compatible with client side rendering * For now : Kindle, Sony PRS-T1, Sony PRS-T2, All Cybook devices (maybe a little extreme). * This item is used as regular expression so "." will force server side rendering for all devices */ - $config['cops_server_side_render'] = 'Kindle\/1\.0|Kindle\/2\.0|Kindle\/3\.0|EBRD1101|EBRD1201|cybook'; + $config['cops_server_side_render'] = "Kindle\/1\.0|Kindle\/2\.0|Kindle\/3\.0|EBRD1101|EBRD1201|cybook"; /* * Specify the ignored categories for the home screen and with search @@ -277,7 +276,7 @@ * - rating * - language */ - $config ['cops_ignored_categories'] = array(); + $config ['cops_ignored_categories'] = array (); /* * If you use a Sony eReader or Aldiko you can't download ebooks if your catalog @@ -287,7 +286,7 @@ * index.php or feed.php first. * BEWARE : Do not touch this if you're not using password, not using PRS-TX or not using Aldiko. */ - $config ['cops_fetch_protect'] = '0'; + $config ['cops_fetch_protect'] = "0"; /* * WARNING NOT READY FOR PRODUCTION USE @@ -295,7 +294,7 @@ * 1 : Yes (enable) * 0 : No */ - $config ['cops_normalized_search'] = '0'; + $config ['cops_normalized_search'] = "0"; /* * Enable PHP password protection (You can use if htpasswd is not possible for you) diff --git a/sources/config_local.php.example b/sources/config_local.php.example index 78a9e54..2bf34bf 100644 --- a/sources/config_local.php.example +++ b/sources/config_local.php.example @@ -1,14 +1,7 @@ ne>W!+z%)z97|t~s2f_ut7$IgHEGC5!ZULpR2uIEB z;=IFsA@9BQvP_k|5HjUsOXwF8KKITpJsv15;YcY=M<_V`rNTlcXh%r!>(n{T+li86 z(meMns>)oIu#(x3E+Ho`1a`?>3Z1X2Fz;C=ViP{RV}|Z+cgwPZxv!@4Zp~;{3RAuzqO_ zmQ+^Z$_%RIshs$Oqk>p|7}CQe1C8GZ0}#Ur>Kkgy6vBhyZiPFXO5A- zS3Ev$9KLc3jmKUDzWw%nL&F}$GZq_fpS8C^h?@uZR9IC&hrz~!j`A?!bi1jaS)cIJ zYS~MiSlvK4A#1CRcZ(6(1c!4M&GQWEEJ@H>&{<*OC*Km3+ayG$e-U{LmEFM6KI1T2`kPCKH z$=XK^XgOKe&Xsg&{ZZ*#y`41vNStE(jPaOW*2D7OB4-Np1+$T}prJI%jWr$|OUvuG zN;MwS1l$~)olX9Gm>c+;N#4$FaH`^4n%qCm(EH&KnB?#)o3UYHgm#aWenP5iCKkxd zlNC$`Z7{frX7KWy%KsnB?~(}7niMll)Jz!|D!G8m!LT*@5(4gJTujv) zhzs8tN+0>ZjdsO`s$?OhCnQXfD5LR5>0O>aG%X@Ds%Z`1cKwLG31)7VNO!*n?<{Z* zW>g{hUVFQAKR_DLH9R~&h_8q-1g;fn;vkVzkte0q-bZq#t4)rxNETUEZJbjJgnG|o zTXH>%^=d2B=sRXbQrj8ep9SR}W<+v$%X1S7CAy2HTl)u4O9KQH0000804A(MNyB|9 zl+_sk03AgD00{s907FPYPDe#dPe+wp+j1L8a($n#s8HA|aF+xDQkT)}+76PEMwpRC zv`Bfh>)2ovx(h&wjV^3o2tna@|A_tIAJ`ulf0$2ZR&`eaAZHx2J3|6px2(*QCoj$M za5NmNBXu$wKO2ueefmcIUcI(oOs;CTG^*LGjB+!TwRPi`Dsx4#el#QAitZdYR7p;fUao)CcoW|UlvUX)OcWtUW?4h{8jfZcTjhBG?_Ld;dGgJ9 zrN7#uu(~`{uW`g|aj4$33-$hXL(MtYF8^f zP5M&ka^B+TN|(4F*OpDS!GCi@`?R&vMS;7-UKje#s8!`wIFIZkT9HS~uR8ubTJuL- zXu6|V5MRXe7j{vbhDX-T215p3 zI$k*Z;p4w1#(W8BI(4PX#_G9K=RgJp;5eJNR#(Yd0+5cZf{|fs@@CO4rzLRkhQGe) z9>;>bvxb07PF2$dscr<&1{mHJIdHC60UT6Kw)WH6RkGFhCs1jlukiYO;y73 zaYolxnc<0Zw=N3@w^SO#vMe`C2;(4HLc_1j3J458f4aI-cWqI^5~dawvDtDqjh@ry zu~IEIaPC}F!+uurX?`p;O!d5SrZB*c#6yr0@}X85!%bDWFjWPAQq_!aUpDb{=cfFu zmoS7MZPRRRXw^;&n~78jq19lm>+&%y)Kv`kq`LftcW2`lqw&GkB%P4xUQ`K{R)fl{ z3Y{7C2Q}TOe>@q9Cs7|>U&svrY#PktozaJjQ}IVn#wRB)9&(6VVgtfpGTyij$ljJf zn8wsNgeLIE^=rE31Mi9Em1Zk-iU#7b++82Rl^?2W7`7&dt-xhQ!>5Pp^WR!iZH_W> zemMN_$#8tAe)w1V5WkJ_zkag>1LA(}b=koUUJy4Shxf8=$OVckWZ?M~w|DlJpHBnL znGs?(qT7V8kZ(=QgH#B%L?{B`6TyjZ>^|FvzT^e2{PAC9`_mm6N89Lp_I*wYgbMdC zEu%3XZ!2vd@`PulZd_qE>M!~Zo}jeZq8~kL0TGvPE}{5!4ej(y3<`_Qy0#(HWGhv( z3R16ECbKh}skNDUElMyXg%4fbLZ`|++HGmpYV!W-xyNG`Np5DkEt*~+(HuCIE*-%G zY*!FO{V|q%ZfgwMFxs`)GVGR2MH~sc5Lsj?V2k-cwfv*ezDNXQ=$`Iw(@}^6a$+#f z&9t4*gAp%1Xa%2;A}Up(BQ+h7|j$F>g4Ll@=tA#E9p9=;4<`=?lGY@j%n`8m# z=|)`^W|L^7hE`eVL!fyrZe2}vO_V*}!J*fiMboV6?~ae>ka;^D0+fzxGcDRo*T=N0 z^Re_Kktv%L$JTb>B6X17-noQB_ zzXW<~LPHCE@kmTA(_zvo@Q)5lPdt{6o}Z3m)R_Qum}XzCz)0&w%C~=V)!NJ-fSya( zCivxjG*)N&_GVSYAfatT^IcTN73RKy6Fl)wXSsv(&DHPJ4?44DqoaAwbqyH4Z#;N! z+h_o&-of`6s7HrbWnMBST)I`e0>-}>zTk5U?^LH0!tQv1lh_?Gt7S9QSq7|aS+HIB zSkrY*N@5aVbFaRv3K#guncOYmG*LgsYMPB4$0jHQ{V4wPLc_He#i4p@)(BznmHgm8 zS8V3wq*JRV)arqoZNSoYX7I()gPE&{;xV1&$egtL_d_e11VTf+Om_Afe6BQ`coi`D z<*L~zKs3})SgR54He56$nA)qvEwg>2YbzXgiP(C!Nf!Y4T36eZ&V5viM{E*AN?f-a zcZ(s@*73p9qt6sfKQ#3l@^JV@cmfC@ErAQkOi^%X3uI<@na+|qu;S74Cnu>4+Bs%e zXn`DxI0?G!7hq1l9lVP-9ug`5O7JbyUON*;>H};Xqjb%%v*K~EV*K-sip=;`IWO3H zJ2U>?K!st~oq@-8%@iXx9;Ruy_YEQ|=vbgX zLLloD;?QL9jrh5(>1QYe0@I~;z>`Io}Gf zF}*3a*Zlb5t&fvA2UzyWC!E~q<)QMiC7D%-EjpumeeUyliLrhFJG5r&%7Gd!6DC~9 z+L+Qi+Q-7c7+$(h2#M1v&zhUJc50h;xqSekhF(;0Y!{q2Q*(T|d5jy$5NX{~1|$|u zw#nRQQ@8#?K1kSu#(M3i3bqk5@3G>#)G#%5^s+ONN(Ro z4u6=5pE?G=VoVnG71pK6`Vwd=Z^D>k<2P-J-6avRpXaXi^7$tkswf==dsDB!7*-P8z z+iD#NpS6Sy8msA$YPeV+#7fk7+eYHE_gSv(0K+!Wlp8E&o12-f>gJ|kU+4n?pI4`^ zc?S%sfh+U#N}hjcCvq%AW_{kl-=mPZ0io?xqsy=QFsTz9s^M^W@LQoEu0qf?(`C}< z+c%@Y;o#<2ESTy5VoNFn|F2;iya3wN+B{q z$OH%O4~9b?+|Elf>zjTRZw~T>qyVEW48%Dck^?&Iw=3$~?YYh>c6?=sV#uveh<-|f z><+Y7vhxBuk1jZSMPbp$$s^_gsW$9U%a8|TdetX1^gbmGx1w1=m1yOC(6l#%_7w&f zej=vcONCFBvwOv%Hn!K2)%anXwCT8Ff=hWAYwshPS11= z!cegbe>U`C`swJ!_%u?K{Y5~|!pZ_wmq#fSaE8nJ##Ay_R>zs}3{Z+hydJ3gjx_IGS*NdssPzI?m9+Tk890El!iTKc0 zOCFdfAVg1El%7%s&?j7H`i`a^;$KOgKtvzSP)hn_XCBf`7)Ia|{_5qssr!=N=tP%W zbYv^dK+J@g$J12&!X5dnmkXTzSHu?8DenoUq#V>$f4XD#Ii7Y(E!+Ryjz?L$*S;5L;`VQzXP4*r|J2&@l-C{w@iWT&g;#(pwf zL06jjl|?|&g3UyA-2G#iH_x?S!Kc_J5ZRZoDsP!~na(iN&DXgp=|5h4qfUG$60tML zC6GZ;8F}symgT-4xn=Hs&2-vY0N4h{RzTOj++k<*As9EJv4~zv1TfQN?_MUl%r_|_ea%s^r?3)gSDe_R8|2t!l5a@OCL%-IVaS(@e>^+wwUGsN5hj{cfx1t ztCL4gUi1R|CUE27v5_OltwdP%D^R0iZ5xdLjV!cTgPg zDG}#zt7psPp|(>cb4{b2|GqnkQqD$g%DURi0Ew!*jc{kmz^u1jSVgHmEkScoCF5wEg9-2N_mKZYb%itK3zdrId z60!-@EwPYxr>@^d4mK&XqJ@@8Ol&G&ckYwMU z{nXc9J6a*2;U#(L^O*TS!98wpHBM*iz$&qYtrKPBaAt^*iRu9DS7eBK)cV z!z~j1y>?TJ_0HP5_~pO2ry#vYmes6xoSumUZ?l!efTG>7*6Gy>k(&A^^=S0yfTk-Y zy-#CX$`wP5q>cmX``aOvJuHSkf+Z zd_)t(TtjWqb1p0K2C2KSu}c%tPlSV5trXCVCHOsNsTibqyg$onf0om3lE48~#78kS1X6ru@Lh6!km&52QP{OwDip+P}zvkU3*Pp9ws zb^&fkag`hndI6u?EavT|-$*DfQi;lf4Y<6`B+pB0Y$b4)agCGil=EgdwyBRzxuELi z(l-Th+E9+)iKB52wD&s<4HSwrE>uQr9qQIc>YB2(LlUrmIB<}V;%r;W*1E3fA-YTb zw=KeQoIGQy40Ce`I%?T|bfsJP&N;nKCR;h_B&dQG5(lMHYUS2-2wPr>`@5wr^S=8= zHR;ddq#-HDzNdb`v2N43AGkkDn{fq!(e z!Du`hA1HW^c;v=Ns)48HIBf-I+^9!yLv;Vh+cov8a8a`43?3XnzHea2yZHb2_L2~ntdP0fxL3h+yuH#67|p6?x;4+a;y ziW(pWoNA=IMD%rQm+eDF2G@21}Sw!%Qr(4!+~ z!m3)Fq$_cxL>^>=A^4ifa&!Uj0Ph;I^wj`z3+F|P3#m-XKlsFf4@mOklC-SH<&e$n zRV~5gBtP6i{3pr?a4DB?Atap>hOO%riM8|pv}#WtB#?|chqt;cBSJlM6vz5kGCFB~ zC-MxOT87`qaM^$DgOpE4XE;D{^uenNqPkBxJW-jimV+Qca3fc9vRVTT~(CK`A1Axgoh0H$j7ib8gS@$TLhE`W|nXFO!n* zRz?s`AFH2XHNdgdyZmVGN@5b;w@CMe?Rx5NqTnNn`T9ynzv|F@(Nr7}kYtx^OABXp zPa;~vyI@9LST!C!ix!G6wu3C`>3AJDxf-n8>Zo1STeZApW+}zRHjpB;*WjIitW)Wv z->)$%{9=apZ%cYnDX-&|mDAJI)+QY!T9o`=i#nIQPiW9(t@ke(bN)H}yNnkNCgh+qnT?P)N+S7W6W^9cjsA#zme#{C0VtPS)*RXdn4!u2y&oj9 z?f3`zAMceZ9Z0TPy|lH2TGLIJ0lE(th0ok{ypJaJOZ@~b^o`a@`%{cyFX7&Dbz$oa zNQ!v1)^&W5ebChS*E|jdT1i6QRFki}K5Rs2Ccj_d_TIAuM_c^?4CKOPyZ4y<-T1}< zAxp6hg{tXbbH6w9+Vv=M4_M(;O@A& zJ>@i}&?g}vIvJn%B%9pCuQV1Ch_b56yKg;}CJS+WI?t?b$Zt8sLR9=mWx%Yr1-{XB`nM?iUhJL$& z5#5j?%G`x(YC$kAcy!%;vaoNA4-IV6`{C;?QNssWAsjG8-wRnjIHE2^ILEd_b0#q) z*bfS$8l`ebfA$L_6!>MkE{&n0vi8BJnrab9ic&7@df9E*E(N#58KJoZ6?rL1&$wAEx3 zRYii~If}BXR+pNsNl^5y!TDLXqafSoCnx=3I0qIwCHbAg2^sF(HPNdXmKi(WL1nnr zxSQZli|U^{6!f{pcvk@ed-+Lp{M8X%DYtBX<86#1pArX{OVD1qb{^ttHndx_;adMe zOdmH9n2}qyf|NuRqT8*dGmB7w3rr*{sV%ag#=R0gABmvOLiZ!(O*jFvz4NWQPa=%K zWCn=lZzVy?s9q5kQ9|?}8XZ$HUI5;Y+BV`>0TMLkrR2TpJoqaJ@Z-nH%lH~>0oi>v zdDM=Dvj|-DI=KzE;o0uB9J@4M$sF%9vOR<{I4{0D*}JbQhggf!^BXycfAP$JlO%HD zHP7(f(j!~i>PsGA7Sp?Mgq_>!ylcwF1;f%=cTdYobFruZ9&WYphrgy~n4G^N>)a&t z;quMp)8P|Qu+9>nMNA~&1wk|q@`EJbBMs&JX1*-=JE`Qb4$9-PrP(?#rI1hOLEQc3 zm;QNj$p$eBX>sr-pGtm5#gJ`3n{?6l1&^SptfQAq8*`yr6q&@Q>O|4~g@Dk2#4p;VW^7pvH53da3uNo<=qMMqkKbbp^SNW(@NO?2ox;DY>Z)6Q=f(#dF@3q_rYsSY z25-i|oG+Gq6VjxWRBQF#BrU%*6!NL0qyWpu z^cNurm!UeIb%iLY^8Ka&(}}#Qy0<;c=e{`hvt`>go+ej2WKc{^Za&7V1xum8B`nXxnfF1Q?}^FpVi;I4_LN|v;9!~X|RO9KQH000080LHL=L(W2%eybV) z07ymv00#g707FkuSxHVuom^XU<2JH>4(j{}lwZcK;wbUt>?Lt3RkAIQwQI|cB+tZe zOG%K$9g5Tvq&@ogr@w9h1a+C@Y-+O;n`EQW=*!m^%y-{u`sd^5Nq-!S2IKynetf#T z8(wMpcQBd^)OY*>{qxCGHY*GLA<_S63Zu_|`srLLeN}F@Rra!~_370a{qpZWCHzR= zRL1B@xvbyP%IKT2DHdr>1QIr&5&9i0{ny~u1`WwVCJ z(YrHRdX0yfu}YUqU9afNJe!-s8oemz&Ds=oqUn7-U!}!MR=nt}2Kl0_b(-hpn_2V} ziG$_wSebM^%MA%YPgllMvU*uodQF^b>vxWS7sh5Ug>YD>U+9-_=~i#crcz51)1qAC ziCyvg#5}V=o2z?TUv7!-qOMX){MED;AC@UhmFD`fnbFef&TWL)&5GI-3t8%=Nvo88 zHoTPn)>3$;JkRgn(<^K6X&ZVCi-zsc5_p$4N@5`%t!^yoMh}w6tm?9+J!|P^lauhV zILn96z;v}lwOaDdMiMM|H)*leC4E!rO;x^B=~}<7N>Fa&yHziXLIwC)P=-1+bS>YyKGja)m9(bSytHEq>J8}*3V_5=V`&4-D+WmMejJa zbb@8sgVuarnL@vjU^gcH0%@>RJtqksfuqVSO;uq#BmsAT33O6zDq5d*_(0?jb7uE+ zFFw<>hE}Lm`YI?rk#R7XVWNWqZACl72kI|=i$7yOu8|iaWK21E%g-Z}AbYb3vUoZCyQ6f+7 zOHsZBx{DGtEhv+mEuYS`#HY2H*J3*C;Vhp@VIo;p29laXi>#0*Va&3HB4vepf-p_N zrtTIIN?;r+ZNJE)5~otZa4X)Rywy`v`KGf9nY7K*nu*U%Rj0IJdSgQmvsspBb>{pK zD2qhZ!4r)onSdiF{&l&?mQY_7#SJ|$UsHJL#J_QnoNeYSoqCaztX2kQr|73T;~lfl z&`U#vc%6p)z)R-zkF+BrQUwVIex;QH%N1s%p{qTyGX8c)o#~S;8(0!lEmALfsv^xJ zI(<@!z=vItO3*uNuM8Ab;DeZ|C=C5qRw;ipuwipZOGxkQm9F3DOlz~TKkL);Gmc9V zCc9E6wN$4c&PaY_=T1$c$n>_#NT`sJ<%hX>Av5QQXE_?Xke9?KOfDHgc#QMiHP+L}JI;V8tN7A1XOAqs7I zN#0#2*w8@?mwPdWna|h{)9=>?tC-wMFxaHl(j%aQH=~@lu(1XayY9${nK!Q-tUx}d zW5tq=BrDQ9p*3Vn2r?uH3hir-rB%6T=E4RC5u7e*CkT*h&T;fOg@~4N@#r1BuxVO#lN%EJ<0rwf1?JmLzTW`H^mIBH-%oUZ zbgi!*M%TmX@L@F3HxFa_@$q>$`k3hJ;bb}R;=tjZk0#im;aZP$cAN$RcNSg0n% zACaNQ$%o-ZPsD!mDEyredNw4uL@{Ow>~mO%_5kkL?~zWP@K$E2STnEesj0Q0IHyg< zTaKQ92Ivy2*(;qG=@(NG=GzVD>D$j@(;4$ZJEvvkT_-lD&K=5nQ&y}73?>rg7zjB8 zb^!k#tBmz7H^k-zd@`K^%Ee^0bIGW40dtpVnLvQ&BW>xiXA6pD1CD8uL2NCCszQgV|LNmB!fu+ z&lVwzb~tso5Esj+tf_6rCQlKRsC!jO;VqY{YKlG4JE!cCj#(rQu`xCBqvQt4b^M8n zzwvaVNfrfw> z86UZM)8bzR(QLALQ#Ll2)ye0uFDKol-)vy$6kuo*j1e4@@ms33H0OETCgypXtw}1x zw2%B3`in6em;^Myp*tm?Ss$^0e~=z`JfUQM*nB#(rl3_2%V=+bw8A?KBHR2h0s>vp zks|O`ykm3gs5CF>bOpDyZ_`nQQ<6-F!K=eD6)x00B`H4qz)&R z8|PuL=Kzl){Dq+V)o11&G_&S>Xf?;-JEkbRstzlR_n6MJDe-LdM#FJ&E$kk3#fgih zqNg#?WY^wxgwDb11EFN%Hg~Sl8QJXty(HBjz`Zs`ltgx6O%%s}R$Mqr&)Otlo;Fr8 zh=3WFSuWvoPO@de(jH;nPUV<}gw*5kUrtS>YH$jj38tq^;mBI58ydGC27PheALJ z3N89n6lFu+1w}v?gxM%M9#0?icqtQbzc`-zoC4EQ{*rhE7WBhef$$MNIBN?QTwP;} zk6^uMyq7i~7gN|Z7#BuOp8NO(a+;IfQom;AZO11vl@{Th4!+I}yQ`lOU^^kZwkBWt znxj7h;*Cil)^SJ=njpfLDnZc^c_L1%`JigyRxw4>RzQ+Oi;OT*?JB zsu&@*xC1X+L)Hg9!vfafy*0`B6?s?GK1&L1fqgcm9f!pA zj@0ffjiPf?hY!?_(%Ez!Nrk><*TXrcxEM)IGTR9%YB#8`V~qi)3tB?MCxz}S?}b!X z0#X2O%OR5I2?+3Dm~x1(D2cnHS2)_rE#pCE!_h*@A@mDQK4n{#c}c4U1p_{R`bfVa zOiOWWN*^Xsn*f}0{k;wj)5(d05r9!t|6`zPYZaG{=rzgiDs(gm1u(Nx2%z^aG@a6l z6Nh#wPH&X?YAQ*8ec?=MLnvY72ZbFaP-R7ME=M)Pr&IPI6rep13#1mAbaK}4bm_|r zq~yuEoJaNnsT?AtcCi*aNdDzFkjNQ+PW5Y28M)*d5-SsFmxq%1HkkUl?kOga|r<#x6*NNkC-# zJ4=H-G2~A4Yno?5j%1dTcdohqCi~i&wBklhn^rJDVu!Fz93XcHsz5tS3ebf#^cWbq z4wugm5dBQ$v9=Rjtgi`2VUayk*p+w`qjwLda}EsrBmn=pGdM1P*~x!#2J>Uul@$xh27sCdtwUN)a;c=eqbJSGM~9h6pP&nnOQ%7$Y@Lc!#Do`a3(9e< zL*&FuXvVopZ8tL`d2&behLeVvX{pEs)0fp1uP#gae#{n$hX0><}D(AvHF+Kobi$e&%+lC`MJ1wA!t$3A%BS368hBe`HD| z)uv$F!aRqil!NW5vrsNHccn)`ez}JhBIb$fY$Y6Awx>hu6 z!$#&k7}ff(G~hb9W^lPfU{Cuz+-5M!#OOi8INz#6u(IPN(WC%AZeCWAZ_ixET#B6Q z4JA#{P)S5&r(6^X16>2H|F^{q&>|@WNx6pdKQ5vRevMH}2TLf?RA{gHxhHta;@ghQagcj8VL;uZBE@V|ZeiImD)8S)6dIMkV8K8U+jV}7% zvdP7>5&URaxka|)pob{A+tBgcvGL1RotXoWwWf7QhlDjh3>se6!-TdbSSu#=uOYI z(ir1}ae$43q)7TS^1N&-6 zh&w5c8+G_=Px>fzwl)r+d<*LT!Hzpa4Lb(plpiUww?^;Mly4-vCo(A_M%=9>Mh$+? z7g;y^q8jaNbEFySM<|?o$|y3p%H^`DxL?&7IB_{xTU39iL$c|dt8)OX*CdJ+x43$$ zYe{ZGMNkrDw)FpVoKtIouB8;YW8TM3M)tR!9xf%Yb2)`fG;{_K1So6&ce8lmTAqNE zC_9y&vmzvlh-3UqOLv~We}H<8K9z3sI&-syu3t^&+8BG5s7MPL46__r5uiJ#ZvF+E z60QjOF(RRK*)QCB>N6jwG3rNVQahv{me{e8MA~g)%Lo@Jeq!Aa8jpV~BNuM|37^L` z{nDXvi>Vz_FPp8KoXpfnvq%~k6hmGdu57)&irY5Pw4R}}kS((3;l#p?d_ozBD=*#|2?^j?3Q=*KXJ@h?SfiJi$+H$Yj43aNNmbWn$#lG~=K*n=IYxzWiqE5V)fDViEYO! zQ0OOB-MZ=-m+SnXo~zYK;UKHGt{bGdnk{c$bQfQxE~CNjA`X3*&rQ-`(=U~y=*KYI z1iN#@0{W9sUsV}YAD%=){6@wzy!LOnBoBdUeb47;N{m{EksS4cxehXG@j7mqkcz*d zg|f==^zENWt5(7K|2&WrrTINOn$I=?jdm{WvQZ+k@rgpL#qAb959PlJe6Rm3hs$ zdn-qdq2^b)gkhCC`y(Uif&qYHVNUcXZEu3T#WdJ>pqLclGdOqR-EOjq$JTwB$-;2m z7jiuU91`xt=mLGPFr;ERyLcHm;w8carL;Ln5qSiX!L=iXqe6WZ^+p^aopD2(hF|n= z6wP{Os&+oq=f+&kS#q|%^X^_EA+9nSsB@9_1kM|ST9v18lC)VIhipHi(H7660%{jf z`ynykA@od@m7f~uEaeZl9n*t4r~~S-xA(T8Awt+562VTBY#U}+N{{pXC&*0?b93lU zhKw%#(DUHY&!9%u!B}B${)A`Y#Q(-qsMhuGIu^VGszuYdM+_4)-T0u~3_aj`n@Kxp z7@|PvN5*dM42>j5bU>yK5Q2UOs31Sd;Jp6b&)wd6K*Ml)n>wZtG^N0Ge zKb{T;6GeP{8eVrdb<&>@+b8<-aC-ajG!4vSbN$h?{^xLXo#?@k2@QUK91kY6e?_#1 z_r&pl9u7xWcTd+m2z*HtMh{bx6YY%noIbE<{JWkyF+=p#{a{S;8%_I{!@D6ZiOJ!c z;dDex@O*J!IKO(j>(eHl#*Yt^0qQppArT>gkB5_g>i$GI!T$Et4}?g%MB~0cy5fV{ zIY?|*KR-MnYS6y#uJMBMFF;TOeLc7tTuq0c=y>T(T4wTeKXCG%Oj$s8cX~9qB7Xbh zXFVB=KMk)S2Q?l%_J<^X%t(*Npz<&h-}0e{!y_#je1Z-7+Rp(^0FC}f z(l!V)I(PMXNQ>iyb`L+{Pv}8=_|K$95Bk3UEQ8t4PCbatFuC2;3Q~$zJNuUpkijMK zGi0`i5eNiFblt!2e;iB_6_kLNcEjX}o;(h&hWHP9PO3*|eJ4^OEBfsTr%1nWM0B5y z6I+8Gx+8-PLf1xKM`-O`yF6{z-qAnk#ofaM%0`P!`eii}?pW=!zNMqM9MEh1>rX>?9$80`Elh?^CJ&B+lOsDezI;miX9ru1B}eBt{a zwpNsbNSUm$A^u2e=Q3`j3@9dWO?rhCLqLzrxpNH4YSoPe5(C499SkOQiks0@(9kUQ z5x7WYZL2Ph5`$oxyNfRBoWi z%pd`TSF?3JD+2G%w!P6*Ezu56_@C1*f9io=t9 zywOIQ4t%>2ah-(Zh9G}|Jo$S+F%Svh9f37;sD$*4a*w5^ke|vhQOa7tQ{lfdt?p&& zUoeUAE3LpJ5cL`K{3`2mUK(8>>YVpQxZT(}WkJ8~3AZ z*X+ULc<(UH=vY=I?j!^e6xIeSW2IDUnMA@r(${XySo+v_P&| z0xcVis#Rq{8q;>SI9&`&FR5*YCgnlE$@9kr(D9_AnjjH9_|Qx+&#y*`GR%A zse`V!q~QPJyQ^>SdaYUP`hzz1a4;}A)`4Jm+yhf^H>pDP$R}hM@pAKbF(W-0Tv=^5 zNb|VM)y{l-{+NgGwbNgJ@3wQdq?1J+y?yqu_4nSxFtYo4ZK^XZH@Pcik-+ED=_q8L9j#_uqiaiZ?FF2Z_MVEz zAK6kBxF~PszUHl)Q%^BPK}LHaGgSNy)KqR;JeS*Yu`P_Zam2*gHY_C5K`jGpB0wn4 z1-r$G(7z%*e~0!MPYjYdTDj0`wVPAH7>qp&B{f>?AK*scrt>eRVi)*}43gmLH)+Xq zOQu#9zb5*euv(Sn{P&Omw8(=5e_w~q{0*;9q(QE(d&KRADvRqIwG|HNPkg>y+fdOx z*zi{lgeF@R`=S&r+Nwl{8s3KgVu?_qQGPm{?`Oj8ORVDNqi{k%gJ-+q6{EVk4O1z~ z5%(n|aSCsKNYr2IUJ#)3_h%0LT^H)`-*vHH+WbFIO9KQH000080J)AsNqR(n8Q}^5 z07WbS01*HH07_F&PG53mZe(S0WpXZXXmGt+ZByeo68_Gw5H4znXG1dVec6Huv%F*n zc6mvWu(ekV4=P3{J>(HxIX2a%sig~G1C9+doBw&Bk=h+ zIwwDp<oy?+1k@v%1#(q0(P`-+J7=aJuABun2GyfjS~VT`O~{O`Z-DNj5Wkn_}~ zoV@2u4gAb~9O=#C1K{d!Y{cwK>cz|n1DBDG1!SxTDp>Y@Whx9mXHy$e_FuXJ_>R(hP>=A0Ch#>&12^%) zfXrEfD92%tupl`^HqsH0Hj&HXXYPmh)F)eR7|gu+em=hCkpX$9{f=Tb1CggEG@&p> zC7!*an1wN;?gG}3Shw457;z`#b6|c+lkGbKw%w9H?3{Te5PrNFpnw1a@*~Jf;2_Y? z`{cPwGnK*!t#%GTW0dX}feo{25xayg)%)Rx{mQ6N%862rTIdRQGkvWz_AN3vAYy5; zrtdw}((2R>)$QLXwC^O1Nbu**h9(RJ&_fg1Xiu>79v&o^fjw>h~I35rTx+IBHR3(Sk!yFjLn@Vqz%X!mo#cAcoT2Ou* zLWbH-OPO@o`&1D8U)2b|K(PFtIw4FG3~kJx?d>&` z92y4(I4qff?IQ*xeAm`i-u!Ge$y2DT3rDRh7B^QKl2B!snp0^wPb%>cb)+PJks%HomGZ5Y zTa`_rQt}dCSyh1S9Eg!}F)wX~h7l%eO3ezUl%b8v7dNI@rPqok5}nLL`kWdQ*X0L1 z3x!z_70#k|rH1sE)%A)*4qeTLJ`?H8e#Hh&o+3sU5Z>^*3RzpXe$nzqH$#@410j#J zCc0T=$6vAQCJ$RVmgpfBjfo?d(!uJt!DQ%F0%i$h6^Q#KN36Z@W@=@*uq=vAzJ@V5 zg0!%=7lbD&MU0ux+=NYW6$9Y^Pw~PDD=XZn^nX{z7x;lu%G%D-D?=EaPP1!H79qUg z1-Ag8HdOF>#c@AEhHOdSZ?< zp^jC1aV*?iC;7Ilu+&sfZrK_fbfd>Go|=HNxpqjHMNKF;-VQyVMFrrbu9` z0^upoX4`?$dpHM1ATiSpM5O63<>hS$6bQs{>*!?^J?g_%B*13K8q9!wP3rM*wmlYS zG=MRVDICw{w}vBfyH<^HShv52v23`$-emW!UGwU0 zKHw7#=ClA$^`?q$c-&0O7l6Gs5Npd(W;I_h@wdl zAymlQtW~|G`ndFlQsCdaf*aS7o=l~pO+DaGO%^%1N@&oO&xqIAEgi`1a|ipW91Wg? z*{n~>wJHwIu+A%+szT)2p}GxRE_XA$FqU95(x@Bm?&s$!iMksWP*_2*4Qrd@Ypt>F zB8oPGZ36I;}>t=YU#F| zhkGolsqLHPNt5H90s6E1qkAW%MA>wi51{YzTtXDvY;t)%Yz@d1KyKyJu%_yE@gN2R zlVxo&geQxHYwhi?eSHt%%0FuKSakK(eS#pH#kR`6MezW@FV^+5s%$&Rv&$;!4G8T6 z^K|lI{^zjU^pwHUmKh4Mm$kDrm?u;rPMw19pqm+_Om^A?5Y!+5?z8SS>O8~_OPIXu zn3CUjQZC$o?L9^Ap)$Iq)IQ*!Ojv(&gPI4Vc@n}^vIKU&qHifw>GNG%H$BTr>t+jS z)t*zj`wx^6TDM;j)Wj)oS9&uGj9V>qQ0ls^V(T^Ldv{G&K5EvX=pcx@#ZNxehevPkl|_MJtaiiD5v5O?7Y!U^VQx}5%3X9~n@ z&pr3Lz?*xRDLdH08f@#7?d}goTH~&nv#v9;hfUAjVpTGAQ-r@0 zWL9`I6B$+(pM%d*duOoA#io~_-xSbuv2q2<**yhd&h2c1dsAbIuL6Fq>B9iPTP9$D zp+*c*J%@)mYEZa%y1O!6Ai=(R)+$N8G}U0JeV0#`6v=`}iYa3>kCh&8&3_j^MsLf5 zgizFa)<4g`%J||9I;{qB*+_$mFT#vEec(gD1jFdMxEm(oF906q+HSM=K6cxu%At#> zXD5k5hnLZ@+KZ@68&3NM(X)c3IV?O!Xl*UB_o;<=J6U`g?Xy-JxWcYK-}wKlhm9I! zB!-58cLVpJzrG)q8P=hfAzjq?xqK7XUV?MOmG_!0*mUNU50H(z`0ch)b<+U^%?E9&)D$Ecp} z%s9zo+*Vl3a})ngfD%V`jOX?Ce-1p zs!OYu3wryG!>2GzAg{||c1}sdO!=RZJ`HYMg~|6m=1a(+jnj$s3NgPYjn93v`M>13 zoP2;Jt!l^DaC-+fSDVzFNrP#>t?_Z2$)&4FZv55S@GD8Oh=MvNrpy5=WA> zuysDjO12}1cS$;6Wx!*sS$4z)<>y%DL+5M)0?V9yIk4sB$=UHWv`B;(O8r}X;vaV@ z+)OI@+YVaWHllvNo= zSg-o!+V;!#ZGnk+ z&X6C;*}{_Lj(%$)Ajsr0u0L)rr0JP34U0z6Ir*&;P`>Roc?ZgKI>}R6hxGpZ!@1re ze?$em5jn((SETCi*IMu#0NY9q9;>nu+|s+gkd zEK}Q+0{i8>ZIcVlBk`JZ3*i`HN(AwngPZ{2D`^7z?4jZ-Ns&m(TKK+f??9S1*qC^f z5Qs_}*5OWy`AYH`7mZ11RHvM{@M3=$F@DwYVEsFAW62jc=fY;1Z!QO$6lb`H2nCOf zacIfHvBB~#lKFF#+tWA`oV~)&=t(RY>Z%E@(ED`f{?iuN_v3V*nm`Jm|2b3-o%WrM zLPyQeSZ9Vo@d+}`5qr7D5-m6Kha;C!eR{#d^(WL|pNBK3RLAJ=a$B51zdLY3iP$K@ zo~!OXq93qG(rAGuY&M_~kT8L7ct1$JBuI5ZdsK=kp3I6Kv>37-Ap(_$`-;m7<`zU zpPd|d18Ej#Bsi<2=y1i!SJog=5*N~eZJUbVM>3O1c~}>J1$qB_AXTGjiVK{B9n4pZ ze|`~;GxuP?*N+A-&Ue3R@NA~}hrop4c8_Q&72@KN*i!5JFuMPn0@_)r#`}SNJzv8 zG}(Au&>Zh^hlIM*{H*>avPMR3>Y76V-zwJ z-EA$l5c8nOX$9yQ%_FtTwfJVk;}qp*!<`zc;9{1{HfzV#ID<95=HSzEW>eJ;gl>?( zTgeL@EO3y9^k<7e@P-`C%uc(TbO8N_Q6f=6(_|on`hE~FgP0o?d5sYigyJ~ywxn<0 zZv}@8beHxQwjxlA`=#3uf`fwh7%^qw(kR5Bi;420zeyB+pV4;A|8vaM$w-_vtZ@w8 zW33-SXm81*?bUhz!YG*oEb%%1VA8cpw2OM}zOQiT0LJ(e%i4s0`ND#rTnBNlg$@_K zTCec8*0$-{i{coO1l6>X0S`LM6?z3OF=|4DBQ#hik!U<5FO6tayLj*BDZ%zt+t}-4 z45E~tkNHHCC5W`9C>`1uK==IPGkS0L5}3{zM}0F*QvST>l_sKKm*sRwdSoSGeeR91 zIM>&tquDsfb~31f9EGivZBmv4OX0z&Xi_4qBb7x_+J-Z1La)T27I$e)zRl}yq+}6( z#MqGM3~ytspi5pA>(rv<`LO;9qFFw;sXFgCa?le4pqX$Ek|*m;=@AqFLo0VW_-B|J zo&^4sZnOE-)j{I0Uc<-^gGEiMV`8MA7<4%7nFuS|bP!>w|k5TgG9+l_qBFGa`X0wW6 z8dYPK(CVonmtB}{_0E;#$(%uGjyqp)topl6Z0`zh8`a+-@)Gu9sNsaV7lGS)^J&Tn zY!^oHYY1@#hjE@gwEaz%cd6sGR?{ltsdY|X1`xtNjorkjBi)$9%mS@9pQy8P`W;18 zdbg`DfX@k3|D?CRX4Z?}W{Iqq%v02@O1uwvAlN=xXYRHxh|-7xaIE}g7^MStsBEBq z9Ugl$IiIyYh*P}iH|BtPMr92s?F4b~>|uh68)(*)U>9YzGOc~6m89sjTSm?Lhli4% zaZzSgbsd&pWbO~}fA!i>5tZcUpMTELe~tLm2>+MGq$DaRA}dN~Ym%$JZMP$acyoROX($RPd8uI5^Cz@`EqHLO?MSn)}?>WC!JKe z_8h}^zdN31wSMVuze?yb|JY-(!}Bz&K$SoHsk6P~nV+s`b=fsluDe^RCt@2twI--v z8q5?Me$Q-<55AXiB`~O{dG(kjRC_VZ?QB~_2CwRjd|5alwSKCHUc^MNd-g;cXDhrE ze#a*>?FTWIMc-B44qO94ot38GK|QvQCn-(*?-U*ctt!hp-#-pWX&$I)ZqEPtZ^ip$ zQQ4JevH58CUj-Kr4^8z^5m&|y{;h13m3=!^9Na5BeA^#==(f>!Wi?AK7l_pCU((=- zhkJ{wy!>lbu~UBrF20(4^zJ`P&D%?IaPZ`#OfD`zEmf@>-c8b75&jItt21;hLH zb>Vunu_xJ*r(fPS%dc!XF;L}Q3+u47x)ykUh2vF)OEFYE85*y4kf9~D(7hd-5>r1% z^^+g&;Zuxf-XiyxC_kAbXX%?Lop1z>Zc4Z#NyTb_!!cMq0#{g6;RDwmWy8~vRORaT zT{zQRm9FKsr8br<^~wbn4_!&njDt!SHVf>D`snK_HNe%;0sGX(73&kjVWhC!BbU(b z!Z5MQl?ODpnzf$NiR?CO7ossy-?5^FY_RTxU|?FlvFsMsRjaz7GG=wXBa9fNbwv2t zR+l(?WEi`ef;HGDu7vDbVkSgl4iJY;kSuHH13@ejQ01i=maH1-9yMRhWu$Vh`yfgz z*iCef&0!bS$P+gf-3)NB0WAcQQrIS@*f>T8v;#)cIKv-Y zj;J}Wb=2E1CnsrbASP5J5NgCXRKjZNIr&<&EMI)C-zp9dcjoD#xnL1HHjP8k#oU~E zixVMS-IDFR}5^J|Hh0D0eXX=d$7GcY=`kyLvEm}{z#m*+2gbWHU@(|Ye8Pli2^ zn`9IE;(pz}o)YrSUpPGQZ;zpP;W#;6dM&M{VgCF?OGJ-LFLkTq%{lk;AryAoX5llo zgAZuq5AUqL-hgx8N8$BOK9flhDmjbFXjTSM0%~1+K!qGrlpyefylZ+D`wk?>LFdAu z_;qJvdjz)c-av0&*Db~huURFQ@_@9u{xDm`G0E};s}cu!$30!^+(qw@HW4+IBV!xG z$cYu(LeRRa&yTXYlzx}#gC!PGZeKpB2whk1&H0Er1A%e_n8y-}>#PxZ&X z)$cq0;`NL7-^gTAd$37l*zyCaGf|UjHN;*U7uCjdRFBWN6_iMGj@)rlKqTINz_WBj zZ+#hbPNDC-&ax#Tfgs>x(PgwQ;APPK1MGH)O|%7tn&5FBDULbHk&L}?mJGL}LpY(; z+6*gmv)@KX2nKb5GW!&SIF;2OUdibvChZZz$SOsp&ds&!V~wK>nmD&Xd*G*|E{nfmDi0H_YL1mVq-f}LA|+LIR( z%Y-o3FqW^RD}~cEY7%?Ie43iBjnoaj3#!;g7^GF#Sjy2;9e3de_&JpR?}o-E#`Q+) zb3b!n#>#X6V!jBL`vG!|m(|T$Lz^*`)6@vb@w&eVzg7d8zSx;|0s=BU!V}yj_R`ys zbrARr4~v}nj!(}>$fPz9P$7b1#1hlTZ$KzI?Ag^r#<}15N7g-fuDJ;~+Tefe*dJM% zZELdah!JYKi|mL&3$r&NU;mD4?{6*VErVPdenElZm;pReC|k#3!vNzNh~99QXnT0) z_NPyntYd4HkeQ6l>GH2{Z%(_DeV8Uyv9PV9YF^=N(u1Nw=1-$bFivKdJ?E@^&-ulo z4#Sk8tPX?YDsWpv(UhfeIMun6|{5nq6a&P^(L>v^=L z^9)r-M{QyX969r4$D55vkxvbFZOo)*$QrL`58ySBBDW-x_i?jdV1B>mM2Cw}OzVk% z4GUP(_U-`sr#{2%-!sT9?qJJsXe5OF1~cP-Tc8Z6)t-yiyO`IDtzqT);{#~X408n zzaQNWG>wtt$qFaA^aThuWPG)pX^S^OKPy| zf3F5NZ1(#eYUTNCKM$|ez4kwO@DQQ|$gg1I5BH0Ep=-wUpC}8V$SLu{TU70qpZPNY zg8hd4P)z-#VMb>_s0j3vz!=J!uv$S#fnxRIP8RTaos#SN>uh=Q@hCi$N3V`)8;s-6vtP5s<@ms-(<-=SPT6EG(QI;G(38R;e2YyZfB|$x zC{w`SWyWjc`zIL^9|fz!()lo1bW6c)W}iT4(+XDU!$22)Z9pi%MI%qv1R|DSa#;#= z(@fItYQ?y$bIhbOZcvme4T0tu>4_GCiUcg;hz!x>3bCga@t(7QStwX76Irg1f2*8d zr;g5!zOV%@NF*!LY$05V=eN_=tDFi`57L9=V1YxMQ;`|5RQOgoOpb#mbgwM|8W;{5 zYoW3R7J`aFnzFUhws0yBxR%nvLi*eazAYyFWtU!~SWw*KZd;}r$4(_KENrvzDe62c zm;mH^b~?~OuEz)`n-{L5Nkt!|i|_O#@fNW%c5L7;BY@1oxc81hrcD_%RTWICG!gc} z#kV~y?!0_sS|ui=6n#q@ftyIq#N{V8jl^`_Rnl~8q>E~|{lRke{DLQwlxfAQsYNW= zS!08JCb{qt@lHLF7fUvC2`H8z1L-7k>W!D#wt7T-o1|2Fv1ILw1-*t}&Q|%|k~q6k zTs%b%tlh`Fd?%XfABN&<%Q|x$XUC~O@fsU(6HXLSR~pXh8sE#3o8TA)>o?k5T>nhp z93MO_zvrW)@F!AYJL69vosbM}BBG*>j{Tgy+Io9ByaP};Dv3%*YKf8KSLj8cJ`BH7N@zU(>q}Af25ZdGc|pki zwuSI^qC33VEd#MH!{^Axp<`jAz8*9?(zha1^UD$M5i`U>ip27_f&S3eYYRqC!<{O} zM08BPC_!5If;W@;!yr=+TO%l{dDb~+o(yk;9Aq@G z+@YD*>EN>y6yAwGWjmpX2t>ws3{msHzmb0lWI;fD=*y7baB3u`Yj-bd)v4VQPV6Vq zdXpqx(J`HgI!xNrNjhSb>O}`X=m>IE ztG{k#y>*JQeNOZDcfH(xPrl#U`Bck5PgzhLe%Z$}oLw|A9SS6r!4J{v`=XJXefJ(v?(#c1LgKns!Q;kNFj`eYZCYzaN_K$_-|9ei!6 z=7ld^np6%jpzD_A#l;vodc*{P7r?Kc72g=|5&{d5@|9x}Zw#FFmjRar`%5wA7Lq4z zwZ~opm2&y*#JUQe@Wu~X2_37P@&G=O5JPh@?8Z1`P5Ak9^;#d9W%ZfMalWn}9P9i6J2z-${ZFi!I; zHl({a%Xwris@>kVXzOpZv`7TUXq^RE4xSE#e>cW@qZ=!Q6GdD4_Vg zgfUpD#`Oz?Hs~bR~8Q+^?S6E+98@LkD8va zTtLP-SU)M)vmG=-z^B#!5IvPja&MJVj9%axMY-Ijnv3%&f2N z*U^tPe_J26wU|0EU99)Hc})AC5u_|FPSDIpRu+ z=4vN_Q33#z_Wlp39RR?{(Ao5Vx{_{ufAs$AN;>%aLBV3@mh6%Q>TUM!6*xa6es&NB zhBkD64S1NB1o7Z*WNrhVeZ3cW!+A4OFQu1m%Hc@p+vK-%%O+`4siI1)k}6GVc`l63N?!hPcKTeVx(PlxkC=!u!sMyO+Eo+YHmXQIDYdc;J(eNFW&`*2ElHl=Ya_gT0W&P*i&R zUF7BF=iz)+i)`Q1vaa=xo&7%frQ^eY-5e$;=IenhE1sDjV*HWEQRFYx)E(%p*|fJ_ zSGZfP&bDNk7~&vWPI3Cp2^aPfD<+g3I!{}{KE9$Zxp6~z3r-wyPUe-iV3Q?cl02{F zhie+t-L>{E5mhM;_DBN4f>@IWtjlK@XtkyQ5mldz^55eHW}>&|fAK2+1^s?>=W~nq zhUq1T?Ozd!TTu_V6ewD^OO9tD-oz!v#FZBtNJ#0`2oyJ#;yO+<^Iir)nD8nBKp4N! z=qv^dx@IW6FD!vaF;QTtT}SC~gOxlw&?;FwP0b)#At}h_m_q{_q0S5#6U3l}_|FzC z@ag#NDbY-T^PlRew*blkX?GD+&=3Wj?4~M$d9FNg14a*5E9>*rUU3gNuU|fL?#SA35t6w3Tq}ezK~+X3uPhy>>-DFBc}#u zmpxO_A#9~TIOs{i@(Td9sH1z5L)ZR=K^2###c~(~o(a4Y3O50hjfi!mhC0_c`nWh5 zR6wMUH%eK&d1hr-L+1h5GPu;fk1x@;YyDr(yX*URVhZekLj@%ba%B{ko@7*tIk+Rs z78%5Yq@>~lNBO@Oo04}XcgGXmcAm%Kt@sm+3A2}8K{krZ-19*;S#~JU4~+#0yjQpQ zd9H6>0e5nD|8P=l!LLv}Tpit9ut)|mGH^hRF{r7B!~{G|>gM=XwSUL$>IM7$^d6A? z^qW4{uN!{@eAWTSI54x(ofwq=DGq3y-z7tOE9ggVrfZ@>Ii_da=H`6+Z1keE*1={j zPeBU%TreJu&ScgMUc83NWvVKL*D8wj%ZNQ7)V@(M`>{!7S1lnI5<5ubC_ufmSYfeO zFCJg!J^rf;w3znWQ}jMCs{|yFK1%}v`U#6h~9WbWnRqJDwSXL5o z*#KjM%Ru6MKX(I!gk-FXAN}Zv3kmez>O;| z)8N+|#Zzd!9FCBqqm*7M_M8{@3ea^JqF9Gca49?w~Tl@$HHy{!}VKfVYS`-La z%&V4zyUYUm2g^0^8r@SJkwBaQWLwcDAXKTY07BBkpOq# z3kNRkEoVz{sXO?W1^pd@=Gns1wa}p73PudVvxkE*q?4 zG)O2T%Der3@gv5C`{-xeODNd|Ie@}>?UE)_8OaD|U$+H7luZPcUCF!na$A2|4ubPz@8 zEp{<9o`?y#lrRfUMWY2n+kh2XD8Kdbtvnw$xrJETEOUrqQ{A4|G6Uw5S4^2yL0c3v z+CW%Y*j?d+L=RcP7bgAOIY(c)NWmPy6>==Q)hV*$Eb4y52VBJ!caq%r5rL=9CA#5%`b(7 z-QCvR+S>Zo)j|E?adl)7w#h7mm5~ly2KCZ=v%`tK&y1A~VllN0F6Fe=w?G_TD6);Itr9$x%joE})PY3WOx<*9LND2(k9HuWmQ|9g>SJ7SXelre}O{S01ckW38!p6|9z2Zq^J^%mFqDKpaLkj30Syc1c^WPKEA6r zNZo?4v!D;e!8T|d&+X~GwVdJK;Q04!d~DQaDw8U(&twxWLmm>rhXh$=hPVKztU3cF zV)h5Z;+invV0)4~iWT|HSh_DWtY|f~uKl8tf$Hz`vSwWyhf1=AYZsY5-d}K`V<1g&0(AtSl=da+1Xdso0OQUbF)Z@ z-+m#ts5E7het|upe8bfO7-$|SD5^ZSf1I-yFn|Wg+gJphf&0uHaU>26u6p9WcxC~% z2ZMkCpRa0jCb4)fMkWNOw}b6%>Fd~1NkwFxF_0dyI?kPX2g#$kR*`Kq{1;-|hd(2J z>%DFJdFsk7l>`B|!h!~YAOa-O<;jp?Ln~h|*5DQ8L&$Y+dCB%Nmr=x~GdUTg!vGFh&XQ!xtVzUApA!=DMqhi*K4k(_90D12(N2RuDV9InvBg=In4487KR`gaYfoZ3Q@EaVhqh?? z($7u|%txedE2?1As1-)`Jn4XJ4`U%ZAlnT)RckWFVdeF)tnZ=LW?Av^)%(U6Ewc>P zp^LIJzTd6xH|}>^g3Pev$%wXK$&yIH04&WNoJ$U9eg4}x{zV`aE0elFw)I8V!IHNu zgT=a%6mzs6DW-BN`Rc+)?PZ**I26&FEkztfdDTN+lAz`vH%tGF7p|Ou*8GGWJjrkp z=AR!3n1suPT^eZR6be@cNEE*Ey$JPp8K*;cBxOH!Mu5(PurZ0z`dAItlDz_)J~)j|T~p zTLI@f|IR)p86&^`#v<9X8f8WUhGORFfH00Mv4ZdNLjRi|#J@;O$0@+{O(@FVtS91= zdcMdSc(4}%HuNa99ktv?8Pi80b9bJAVQUdfEj-{$jsd{{&jcER3GQL|mWEsYxYgh1 zx68fB@A;GEnXNH;0wPQ7(lH}8L5kK-=L(e{B}8&Uf`48*q*6PNm}aWxg3>9WcAcX{ zF(r+=e4M7G6F{am`!CkXyOc{NL%zuJYzdHVm#252wBk%>^`yQA;mv^}z0fkuImnX9 zsDEM8Y+7pE$1=|?pn z35*`K1Aa?n-9kSb6+1%41aP?3L>UI3Od2k(M9V>)Nx&SwZs@FEQLyf!V~TOuQ1?_P zO}MP#`I;gM~ zn7>qzsbjbW{5<|e$S91$J#n|^ERx7oKn+rr1w%G`#hk5kOq6?uK^>B+eIU0IQ{r6> z5?`kfP*xCi<5`r`(bF1es^ji#*$4(4MKOe{y2Ndf+oG@Dae^oEfg*-4`i0;Cd_zUX z?b(}O*Jq1&kCW%o`;Y6UNCPUIE)QnejH?hhZ2=>0@VBM8`=SHi&}gL$_Us;chLmc6 zVr^&h>udDz!|?9@*u(9|;C`D$M)+6}aq3}?ACCVPLttPVClq+>+AU%9s9k@oSoVOc zY7P#VcVKnm-R+5)qb`@C1Ku8({dqYzK71TMA9_RkIHuCcD|iaHaX{Weo5SRqlC9=v zPJ0#4N_I#&?b`G+pTXP0&RAH6`50$m&*MOy@pZ&Wddyvo8k%uMJme$ z!v)jPA-hmwf!;@V*%BD_gSjxE-GNVHNHUCT1t3Ik>y!}Rg)^6FqdWkL?<&A78XoVpkX!^ zc3l7+mSQ69=r1?JH{nw}Et$A!1S6}3Ba&b^%mtgA!AmR z(rL>X8`lBe!>xvr&JMjJ@2uh%E-AP<7%Yq6IfB%fHj)aAd*)QoagiRP7zNgRFB7t~ zQKOmqHqE*3T)k*1_Tz z4H@gn5JV1KR?bdjDY#jz-hh=6-4^`EnU!jZJ%ffYowjEXWkp9 ztk8c5(lq{StyNe6%Cy$YyCAoN)%h;(-J`sIZ>Ps*IFai71;G1dpap0<&!4@yaiJr$ z0Gf_gt7!-(a6;gDES%c57*`E~*D}g?O&($BudLv$ZjQTLAEN*k1Yor_AO|pB6iA}E z0iOW|*2x9UfhjEjji4*A%T1S2=UUT?Tn;S5K_>`o;;hD+-%)~`qK;B`m5HT`(c8tt z5BXi492N*<&9p%S0<7%PzAy~LUI!W3_E8lcqlv5F3L1aU2`7s;cQ0Lka4tzq!Qxvp z$qG@{jHSidu`nE;(6*U%hDV2KrCrE27~1MkPdQ8uk&1g+vXd*UAhAmCcPQ|0Dw>*T zT;1!^8_P)_eCBr$(-32r-f@GIg2m>KQGL zk$x(X(!SS`6(PpRUSl<2W11ck=>F_Mh;8U0pmM=K`X;E>APz$bkhe??a zv0{>VLAh)Ms?*OwE$u|B^DrY_DyEvp^L$FyOXF(b*8u0dSoGGX9Ty8hV2h4uF>#r(pf*`o zA4t4ca%BYc^|Yf+LJy5C_hwNQoP;YUFp$XFvG9tV46uU`f%1(x8PKU)d?VA_k7G{j z?uYYZW0X_TY|SLtrcS|OD2*GKvF|Y`=yxs9^xH-TOi3pm!+`FE!JEtHI-wIV9;>{GNG008we5Ci^vs8(sZktnH0trp5nnNuQ@ zX?gOQ8PDoP(c!RYWl`*knPhuYPn7>2BCJpzIL3-j;rYzvCtzsW-Ks&^KcQ*%&rsuv__6y9jIH2zf5z}7_Pk;9UgZy!9}&us3<^K+va z`WfA*hB0Lssl5ir66{kWh5C5)2c9OhQ5zKuyFh$b`JzHC#U-KxP3T$GHQ}in-4l&nb37MAS)6?;?&y-Fk3VS!Qm5yj-!tSQ z!OMLJmak8H<%!cK)SBl9s#qt$G64%peEAkL7Qa~_J+D|BN!G)EZ7P-9tW0a0yhvlG zFlS=SDA5pMx#8ZZY}Hn>IURXphGs;zj)P#gNUA@RJjF31E!zawO!MX_rSUJH~;VDS!Q|oJM35@QDy^b(t zsEF2o)rjHTU*#Yt$ejQ15J{4SJ)~u!BKFW%A0jWMt-@bQxpO3S&3vSjD;&CZfcbNT z!un)yTl5N48xdro%BmVAzvNjp@JAnx#Vr}KHh|WerZdIt^VRm5>NaO65^UNhe|enI zQojX=FBN-Sz?sI~*x=X)_7{=?SI0eTTp8MiI5s&KCSTabz@63_#&peF9&{Q^3k_$G zFJpAx*I@1GRQ_h_QCGU9b3aaUh&wD}rmCmieW(I(gL`N?n5I%bf z9R!tlH4zJX6Z(9#-NU6NHUcC<4S;evH8oGn0`G#=<~t}a{Nza-Iy*a98L2aE0AG$w z9tcb;24q1~W_v%~+8rkbE2cA?CDj3+ab9~NKY%JfqlxD}Kbp%2Rl|f$%VdyN{i|^m zoK>V6i+Jiq4{b{|PGZ+YkhIerenyVzc3>)6O1u=4V0$a3S&!40OENAj80m#k#<(y< zaR8rnq8V)|zvV!%#qoI(B##WO-?lI>C(?;$qXfV03Lzp^wg?M-PIAh!yI1YnPA+;JO9+k4$E120b$fHgEiBu8l1wmd$e#a@Utf zz=DVEMvtCO{xlDM4^~mMN`z-N7o591T7<*55?6HqBErzfl>_8XWbCe$Lz_{$IE6fE z|E!}DHbsEdLCHlb2vCNA#EO;@soHe36C?6m@WR7p#_vpE zPFT3}cqhjPyJF4UWvr&flpOh5G={XXkSDIdPZhC=XIW)Ut7(VA<}@Ns`JS}|r%6AB zEp7BZ_5@}aW|c%{j1$DDxnycDSwYMoZ~H#BQpNe!ssxJ>0C!$fB;CH$A<5o^j3&~D zPo59w@rnI0`H=S)hz4$ZtKD+FK?sNmXCS{)lW#hpgoz zec_c!^d$ZY7qu`Gv*pkp?(HdVDPTrJCn-UL{pH@%cW$78nv$#$7{m-NeyQr>ut5a$ zR8wtQ34XA)Y~sL~aU8TtJ)WcXWwL0NVRKe|yxsCs6-2Z-Am zRJ}TV%usS@$gXfA<#S9dhW=Nj+28{!MaX{bz~#os1*w`Ghc;42EG>}ft1Y2>+O8?D?!eRL%eTzL@@ zRpzcU1{1r0kVvCVzcorejjWpL<%N+~w7I^I^5$>?_&$R+@5J9EWqWYFid3Fuc@7Zygcpi8nAi}yTYW!`O&O|e;zepTr+%5%GJd<+|);+ z0#!S(v&bMg`&{%AGtoWo`dAzhktAM}L;kd42>9e?q%uv)IYrQl0pPXcxHYQvFcTF^ ziCiI)xz4$G_2CZX05w<6IQmKTl|rkNz{|cm7+GrwPUU%3rJtqWm9`F*BS#u)gu2fONqYTg+J|_WtL-sh4S( zXEPe?o)qPik3Ul-+AVKZVo9`INw?$vH}ZK>sSNmg@_NG?q6Ik61Z?1-@15|ZlV?L8 zI+cHT@&w*2t90FCpvyi1NM9}ivPVLMnPw(f!a7Uo*??x((~DLxUt()W4#N#o!k*Hy z{0r%K>ML=;vWRwlPCLXyBIk#3|2We{fTSjY^@O=QqLq1KUIU?|1IuHN5{IgGnw_Vd zn|3gd(|&QYD9`2NdJmEQ#W+Wy3*2*Bp79ua2S0cnT}|Cv2KqR}d+f7B`cNcIH2;?+ z3A&LkS^5Uz)TY&NaHFHv?$|_`ou%@ZS4rIX$*ImD_{s5>dYIq(8kkd7X0v84^pJ$B zdZd5b6hgH(P>|BN$7|f;3s<Cb7eIsZ<4cM zCOZ7^zVBWi_ce9ZNtQ5%vn<%rfR$xLKgtOBq_uzuFc@nCp|ECF!Buzp(MJO{JS-1q<|UK6f0U0lork-1&)=6**^5zg+&-{)U%X25QPR^4 zH9V7w4CN?$=Nk)1u^0==MlPhrE;bt&HrP@Ih)md0HfWsN zQYJhC?8-RIBS0{q$#mqINrvHp$ZPP($ppN}p4i-0?*kuYZSg9&DW5TnffftMoxYPM zS}}#EW0x9%sOPRXE;m`ta} zBk<9>J2%OhAD*%AmVNU&BmR5=Q{g#`aI-#?p3?e&1d>!3C-jzxL5EX&H>=M$*jKms717_?y6j-W z?IaMQzR`V~ek}pHTRm#eZu{`{WoV}I#-)g^I$OLqRZ+{;UNhlo1x;cWsEGrx+eYL1 z1-0dQ$o)6uU5|UTOzC&gXBn&HV2P19j{U*lce-c$$O>pAH9*n6_hX?$NZ|X@9T4p9 zF$=%x1jI;Fsi)jy%_Ugf=OLz8g&*elyuNKF?=9Yqn>QY@2;BtLTae==v~V#U+?0Au zLmx;aCsqMe$ZsVeHGycJ{H-NXa~JygxZ-fztePItrZgF#%#VXXpjGz4>kO7D@?qi3 zq&X}-F(|_Cc12AKm?4<3R=+aP8`M^}Fgqg<98>20OueUp0z`42!2kD3e?r;#i7+PY zK^Pho)wHJ>2tez6HvU}J?SxfJFpcycM!qXFKfCpY*9M`y!sr6K?`DdvZ7bsT^(mbd zi<$0uklW2K?(5->A9#+~YxURJ`sVHScJuf1bIU6@*THVD$p^6iJ2!s!NN?8Bvgdk9 zEqtY|V~_N(;fPVsdt#Ft0d(u(y%oeerne++cW2|d&Dykm#+j3X;!qQ7acq1$suR#q ztyuZ1%8G9_;?(#mO!A<&svYR^zfsiPtEUF-y_$V(lNoGhF>-aw7WA3F3|Rs5VeGUn zR+0=bM_PM?ti8f;NggverGDR{ZgQ|+jbpKqgIwPT^j1%v)!+3sn*d%W(obch#Fg$ux^57KM(G-qa z>(1qHUTroUU0(af#TZ+!_CXf+7&2s);#RkDtkQ<{YX$1Hg+D`k2KR|!pxno%xk_t{ z^7W@oxo0Ias{t{yqs`DG9gkLF%N$P@um@e@V}>gaSy%U@?@JGB`?a;6CP)Tr$UJ{9 zO&_nH!zWr#_UrcQJk8O18@%5c5&Ui~DQ=*_x|PHmfuTl5HT`w>tkn?s*sG;=$R1Ht zAG^qi`j8PH+Ey){|YB(y+&&Q2_Ez;Jk%fo>3>`TtT8-b^f(AW zb7aK8t&Oe!v$7-cZ}A+>seY~37BH%Zeh3VHa}J7;)X2WLYu9d&D4B4wnwV$4F~+1 zS7fApHY)imJ;~bZI)fFN8_GVgRY#32R5s>3)L>;(7_rV1?-nV;tL78q+3}%&@|Eh} z7w>cusJYh{CP01nKe3$yy}|c1ic`eoOj~)}cKU66Pe|J0RZ*|zxeqVOD^@WAT=C0p^97ImztcJ#urC_FAt&B54-?~_@*0QT| z*w8@bw4<7mx+3zxlHzxa70tyDyn+HgeEeUfhh3vOJ+Myqbp3^ zCBOQ~we-P~Lv$~4lMNc5RSjR8VZk_qCLUR^TDvdQoY}l}*Vy1cLGOnt4JPgW{BfiLBBYwCHIBZQr^+PcSL6}aN3tJjuC z6{A_t_*b!0lFZGo*~?jea4FkO`gQq81x!Nd1p9b8#t0nBBd;0=364EZ`5?pv`9WIw z(CDd79jK5072wOBkp!hsb`vunnc)zpq(GQ9EP}>}Csi{nWesZt3SLbW%XEXZ_q;=E74sSX@69oM3Bwz8%mT1vw*> z-7+EVHDD@|e)<&aFJc;__E8NDL13c6RIWOHd(gLkX4yJ^bMus}^c}L*4-!i?$mbnB z`jSX;=SjSu&e8W&CZ_1 zNUv8h0NrmS}0UrHJXhQljiM3UX@2N=v# zPc&gkQz^{lT1IXc-Do`?)Zln3kGLP(iw4<<+@^V6Hz0P~CJhtbLLE?(Gs~;0=aupR z(m4lqNJeWVC?#`QVsjHow_?;Q<->`(RIyEG=**?!D;P&w*j&BKnBt>f!{QxzVC?ZW zYANX?+c!ek4-=VXSctxsv*4?ag4l^Kg=3-5P~FZ!JdK}Uql1z1DcxS(=%-m`9>%D3H)ij6B@>2)J?HM&HT+ln5jd zkZMdy%FY%e0SkH`G%y3G=l||br)}-z=GL|e!`0V;OLx8c_$xcSF>*ZdN4K}b1Q^fv zAYo>-7klh#^^x-*yMn%#{X}pY^UKrMb5xJPI+Y}<$L?RjQOgXQn!}LkMyjx#L-#dH zlkv&+?3y+~6J1Y@{q=~?ZkO%BV_-hjfZdd5M5q6S^!Zl$Z}uZpceAQC{M-6O#0M3` z*wzXd>Ha6k*1K;R>2aKyB_iS3HX+MnKxMa8EXQoEO4-e>WBRHFss7Up#x@&VC(!>G;qM&36Epf8})U=%5`JF>E|m=2B7s-Xxt9z z84Rm8wix^0;1S7ST4R9=G9CcLV8BP93I`8da&2V4OVDi1tsr;vqN1oMeej~DCH0{N zfBmPqHr&;RciX{1(?Q}F?{MFt_iS*<>A^4eQ!*I-M&QujVO;yh5v-r&1f{Wrc}1Rw zo;~8ix?bNW0i+DTE)RgO2ioX<1zRl4=h;~WF2>h)4nuz)e}gtf4s;34DA#nc?7P;H zK?|Va?QLni0|qG>W1Mfc&Tc-gOZdOpdYItYrmNKH4w;q~$(c8ExY7O3!l^BT+XjP7 z7#43C-wmJf&bh1^?|v(NSTF$>`}LvE^uvcv4FFsoLjSeAuw` zbo2b2d3>F|NiWRZm235$XTf&qwCC7OFTcEo2u>T2p*tW3L4;MM;pAjWnOfNQ&MMij z^7?+fuI3k|qv#N#r>ezN<3zud2>jmv0C6KcK8}Trr7ulw+xVGbOTHnhJ<>nSjUMPA z4kSg*G|HG|DQ0BU!YY}jQk|W?kiGaUV*6>+ffF-QKXSi>Rt-!3UOaic&3r7*XktCf z_j1;bf2o_F@B9;V+3R}?*0Wtq@q0TWnJ+PDeDo5imJ-F1F)OMO82b_JN8KLE?ag+` zAUXQ+(@tPWaUa)rhH4<{5Enn3Krc}&B9CPoq()Sm32UAZ`=KBg(o6g5%{e@w#$s7s zQWIG{6WdoUi{*ya4NHIFNE))Sqfzy<=H$Zny%hiDr5M?aU_W&{m_<*%1g3YctEG8q z3F2fuuc{JHbW1rXSm?5gK)OP7JIzDJli3@H8PG-cRmn8%X-W>dy!?SAu%<0Cu!uBB*p7^rz@Bs_C-r6c}XoJvxIuA*qD;3SMskK8&;< zk#F*$ehAHu$=M0lJS59VcFb@*bI8mN2J?{|k28Z}q)#AIC`+ynytD0dQ;r}Oh=b=6 zaD~dIAZ*j%suGQ9s%M3b7)Vi!#vRo@Ca3&F^+uRJMmMx)?HKNE5+XO%c+z+A^uL9V8%YZK%*&#ikoC5tKT#?s*KJhQ}ySvxg~(QeB;jVkPo*PXG3$E^eP7`Ul)^ zac(qF0Hd{c()S=U=i&qPId4>52{~;Kh`+W^P;Sc`Soakp*T%tC_~)J#|NRsc*nY+5 zS$P!f;#AsQ{19F5(6wCjt<#~jwh2a!tuk?i6}4iC?LfNvRy?Y0OHG?0i#u}kQ_*;j zIa=)sRsS^;#uD3wg~(=1>fx}JFbx3aExxABf}EM&*Ht_bfYtEs=doFXof$&pBD8>| ziOZkQ4#{x(^pxj>8n+VTPR_)A`t(RBh)ysH82*=+QXb9@&U*p^i9v|>uyo4nyp7;R zO;!w33fyudLC#_<02MEZrO5*5)>42%&r^kt25N$eo>K$O?1Uk&w&@Qzc%kS;9l;l{ zhVH<%;gXdPUq;)F)=G!3rRzpX2(`ftkI^xFXj@gH+|wdHmEg=9VQHzAji-Eeae_M* ziNenx5Z6>>w0n?1vGAs^t)3nufep*+7OqGD*SCRIq;CfCS96|$7||+N0YoGUy=n%o zm}_K~M1`x};S<**OHG^a?mwEo^A|MR5H=?Ew@8BsSPm{uTvyL?Ts5~n6M}54+Ooho zcf-$Lm*ezsYkFcoCD3Oyz~CyvpzcyV74F5E_ExGzySo#Gg~{_(e6WCz|(D-`i@PIJR_ z8Szunrh{l%g784ZoPzg{XL!sk*~%Fk>z$t3D48PbBtDYAoN53rRCg!P`0Q{sXh$8f z8u4Pz?gP~@QKV^dXE_T5e|flvCkOew9Z-m8NK-Qvh+Tns@*Y6TheX~Gmvzk)1&dyq z00xWwSqI1O5)n=0vo-`n+gSpr(D?g1mP~FymZ#}vgpsQ(+eO;LML$|Fy@RVGSpUtl zBifp1$f!HDqF10AG**%BJ|3#6c_Al0kiPY?ynMKq@)K;(6_B z98m;zUgpNuuHH&WMQBh}v6>na((c~Fb6cx~Jlw|lAMcTbc%`AJ)(U}q*&pZE+RzPU z5LGwdQ^^lEMrLj)sM5VKeHQ))UynRS2(=zPJc(t%UJ|ID9NBS;&wfH1^q#~7lxHUx=ZbJ5H!+Oa$! zOJro#d<7#}OOLnyU8V$Q-|))JC+0JpxD&31MH+yr0wSaok1jI^-=~GnV{l+0r-&~X zM4-h{wB+q5Au~WEcEfZG5;L?=phN?fLgdM#M`H0>fImt-!J-{OY&NZhcx2FeAOdm# zQm#iz2V#(U{q1ey;&$tbl9S61#$TRfm719U+vztg{m6Vsa{cS~8dQlhBelVF<8R43 zi#7H>$>7Qz4{n3)ZmtBzRo!A+wOBkX`Jjg=ISZZJM8I>9lKQNoDIoy5x(7zE;sp&? ziVxt(Gg^&8KEQx;XTSvGAHouaRJy2Qy$f(fO@%w)PpZ;t)htI}7dLOKliNM$@Ado1 zPk+DLhA#e{+L=q7O3g0t&bLL|BhCbcO07jd7~XZ5p;ao816a$f;#383PuwSOi9NC% zQ_e3G*hGegL(5N^7Ue~xvWqJLZMy4EACG^My^e)n*BEj4=>;*tpxD~kChyHg_Ik8Q zar8{~rl4p!Og_b!XHu95R)yFyluRlRjze!`k}l08A&E*fHn;+qlpl$y?(9=94rgs4 zrC}WFLRu*ivmaMZw{bPcKlMz`lT}RKyRw*Cm(QwGsIIhSf8VdXRg{U&FzH7HyJSj# z_YKc)QOaF#3DA4{``q_)cs%8MUB3eOlf%2^5s&{IRIG)(M}1UAuHjPy!LO?b#j54a zOKFV0yPKvvxDgr;WY&U9Zcy^y-eNT0m3SiG*{0ql|WrNpKo z`a3D{Zm*H*2c#K1@Pwca$B$#o6WG=%q=6YIlB;I90kWYgpcv?cJRsH8;M4~<`<;4i zA$15hRONCX7)J<#HK#)p4uDP++dSgIj(Cap!#b}e&U*27UZ-n);QQfxU-oIYAm)B(WPc_qID7t4zZc$Uy^pNl4GA&o9ywEJxqJ-82}Gi18g!OWIiOBU_YCoxN?<9Gan=`S1^HbAoG1U`s@hK-u_(rseO4)1}tCbos@XrOGPkv z^!=1bf#@_Ai1;C9*x^=EEyS(|e|!_%iKhmzF!mvBH55E(^C0{};*islDEWD8B zJVtcD@y&BG2(l&CH!;=}-{LgRn~?8}^*|eET#sQL)8faWJ!=oN_DETqz2`Xe679W& zN!GN_q)CI^!K9EfmX4^XABpkk4irZzMvrQ~JSp9YhIuOXw`NO}4r2xdO?X^GC-e^1 zz-uOnPY8wqh4g8qasf9s{O&f-pF*}kbG2F9>cWljLV#TtLz}rI_)oJN`useILXPAx zm;eq@xDqkyfiXOmiv-=vhUMIq-Dj;yUvse41OZ#fqKwOQcZt8D_(oHT=(*@J0lz88~nh1!od%`6ylC~rO!-jO1nD%5?G?BYSxMHKvQcks+F)T{?MO*0WU6OQ)}=W@GqWojzW!+vmB9 z(Y5p!sS(Mbr$r}FwDALd;D366SLogwu*5;H-h4vXK>v`jzxQ32Kl%Ju`q|QSQJ6wA ze*XZ{*%Ma4GdFOb$4S^FGY=?Iox4lJ7+kjhaI4=(vO9wv(8mTy7BPv)e1JKaQYacD zrylK9#GS@hr7UC6yV8rw`pvNO1>ZPS#^nL^w)J6G^(R`#*gKY?Ehd5#t0*H_E14+% zxTlsqeJvumi_c2rX9Jot-0G&o=*IJsvw+F>!jV-6YL=URx zNGuywMJ9J#@={(nvsWurCMUIOZbe`@>E zJJ@kZ&OXvJAUxME=o<^vb_kdx*W}c`F=wNFu)!6;W<}NRAcPuYlZ`td^dv@;qvVM@ zUBDnW3|-fX1c`yBs6Hqzid}H48jAFIom_UKke!rdVQPy@W>`y@QYfnvN`0Gx*ejLW zIE^>=SUHN{&h%*7&NDai@;x!<7|QrmKLqZToSCO2L(&RLG>z)SGuH>2j%*{vlgMsL zkBUny*a>O5u`G|-S@2{H+;Zs36a{-BGf)hMnIJq^d|iU*%4CUlf@=%7OO}M<$Sl{D zQKTT)3CU|{v^K8O#gS9>K&C6E6s;vx;Q49KG~~2>1n$%M^2cLS!kF^e4e^GpmGM%v z1EqqF0xcGEs+guE6bw+u3v*H%^XCz@ulo#T_V#pX@<~SL3{kw4SVSFxQ)e`Em3~dY zwYMGwkm;P5ic670KR0DDL25PsJiu02p|H zMaN_G{vOnpNKQPeubOmrgeWwNQ|03<=z?eeJw$%GQ6HO@m#eJyMTG|HBgv7tzyu-% zoqY8VI{pe3PrE~ho?dB|&dr_38%sz_Z(C_p3bPTa78ygegt0k$J9uD;35hl=Ex@j| zynHDr@vL`i<2lf1BcDZ3TzMbAwUvFJgcc)e5(WrknlTM#eiyo#v-MsAIO4$EAM-3D z1f$ww!yBrMH}WM1G7?DEmm#SZx^6Zs2pE{INdY{sdg&g^d%OC z#oMsY*AS1&#ajT(&HoIu65MS^REUcaDH2w1lRo*r6P{VtrDQ6kK8qF7u$)Xiz0eBC zR)rP0(-0SfQ?nTyex9=g;Z}A7o_VW?rioTIW)FE^e#8XVPKe9Bg;rA$YlN!ML8h0d z1Dj7#KBnSD$aTId{?l5Z60|aX)x{{a-pCp=cpTWfBoua$PTB`5qYvn|PWRQ)_7K;R z9#EgFw^Z#zLrRUj0Is~pu12a{lN{SvCFRj-jXs-y`mv;voO^c@S7}g!MMVE4QK}Hq zp@~WdP3@2=6;V4(NVVin;Pzx%$S*lr%aeJ56<5wVaoZF=HBJ`AeMsw9%(T4h&I-0;PHft2R^(pJ zGPB&SlZ7+KsI!c~+JzsJdL_Nb?&cD6E&K(tXVAFFw&*fGz`4@6$}N{?|G-JKW$XgU zxboe4bv|WH_FXnZ&iTFRU|rn>MQX)_<1o5c3G+~vI^51eI5&3jub0o@@Nc-#Ut*dy ztzp`oSNwP-RGO-^^5e7_N>yeMnX45HvrHnCjqqc$_j_0+S6t$`k`E9=ck3B<9mP}GJB5rr+ zAAPQ!5CGsGSOdV=!qnK>*xt^}()>T2*JG_qr>$0`pSrSjhRj4M+6B4IjM3Dy*4C|~ z1Rcs0>XKgtLu&q?$Yq)-s|Q*C3u= zzZdv;LJcHuDd=kstm5Isld6Y4wB2ecWVI;%;VAvT_z*TFrVaa|LqcmuEBCE)9Hq_6 ziON`PSUe&J*Gg2@=^ro%?~J-e;V_R|T5GWc4(e}OzhzaRycmQY4?KP)C>To>mrrU0 zy^9hTa8fnhED_jOwKSv#oZ$4X{^e!f6f!x&y;`&{tF5=VYJv4XGoC|}KKAMu15qGb z2evgZ#5%(j)?P~%Hq5L4)?CvZ)FZ#lqe1X-zN>^ zgv*#1E$IiCfy!<5R|QTMB@$X(X_&5TT~>J^s13z3VTh$uRi&;NNIMHI-Hn+u@{m9@ z=a$S;3*-H1$_qQf(!ibZ7gnal z=fF#_?Hh8q&<}(X)hnRVTs3)_9I1(L@ib1Kx zl7u1fBzER9Dgug>tux%Vq?tpQm}cu+UCS+Skr@Z2OZj5`D5ZX33@*SCN&L0%3cj-yVtF= z_h)e?*5lh1Yz|hS^=&mY6=DPfg$p&1-bmVhoo?Tb-uDH6-)s8&{!7-|JMc;V`GAs%r;`@CV(3fC{^&nmSw=*%5uPr`_GoN$v`|(Nrp!q&w zLQU3ft_CT#|_9iTZ5fkkaX=wK&nrATkRvitkws=)jKt zz{Af>T*_c|%X^SXF083t`U32;_!1e+Lnh3oy+VdAd4LPh=yWq&6x~1aH*clfOik5E z?E1#%Jo^x-;KMg7GU4x#!?etP{xP!KEdvajp6NNkU3JH2(CFfWg@A)%Ma%f2r((ap z*{eUeR8DA{mv(9 zL23enfZQPpkY>#&)+V#an6Cn|z2tm(ULBv`nM(6 zp*~Ri>#oK|+FoTEF7|Or*88 zW0k>xNLF*ZN)(1Z_SqJCIUurM&X3kgaLoG!uYQW>gfau$j@PDN(_z0?s;Dwob=`PU ze8i{Bz}ZBEh6&<15DHilZ4@baITW@?iV@0mXv}#^khKJXXe2(EvA60Wu~TPS9e>5W z=-Ph-mD%VTmR^sy*Y)k%`Ce!r!A>*DqiL-|xq#~1MXH{`jM;;tDM@Jx@oUw2FvtJB z-cff;B^r|X{(Itb-ua2etHuW?i|E;KDH)smAglmyCi zgudzgz!oI3`4ztVv4Y(|*qL66&gEa|LV18;d8_1oRlxe@is;68Y?8X<#+(Ug z$|w4n^9UZ)-svDqjW3y$3aoX(vCL8LddWaX#+5y(jLAn`T58d@)gr>rRI%K>C#5ZM z^SyP@zp`mJ%(>p1gb+y?rnt>4)f^%>A+Gb$p$dV?+7);(VL!&0#=&P%MmMT4rWPwP|`Rtbx1=I7Vy-hIkv{mH06V|V%<;J>M-mrvjpL!J zFwW`EP)rlLE77q;jC}h++Dgnb*3M!wi5gT&sZ4Dl2W1;mak^g5i_>jne0Jk(`FF)o z&A+P2NB3`}`=zk5FIW?lq^zmUWoN&Bu!uX7F2`DrGzI>1=RQd%5eI$K?=OYP?($=* z-j1=d-_QH1l7IVyZ7Vko)F$>Bi#jh$u-#R8_j^;?`(pmPu>V!@GcY zY|nb_5>N?n%#4!B80YEsp|^c^leSq2dQF{oJ>2J*B>b0e!BK}8huq&+0#2Fyun+JH z0437sfCd!_gRos?rjc!e`L}eO0qQ$u>!})w%o($NlDa`5`9jcfktC&%jGW5+lgLT4 z5I2>x?+;J9=#=y!#S|!DZZLFgZ?TRXhw5D<>Ia^fUFwPibkE5CMI!tuNc?>bmB~;S zwASkh#xqe#9}d_G)U2Rs1?8Z8CY1SnNxU=3~HJhkm`rH4!;0peK7 z=tLTby-jDkJeNCyrt2LqJ?VdM#R|uQ^%< ztkeD}C-5nqOiowq#rvKm$-9~UIE#o$)tMep*#k7iz26IF|kjpidrGrVoLYg1jw5>9C|9c4;T;(MLYCW6+ zU;zNSr~m+v{!?`Rzj{;O#MI2t)yC!j*PUBV#BGSayLEpwD~LK0##gw~s7BlhOWGSJ zJL@GXRxde5fXoHp3Nr>w{ve8~`%&yB;7?fsIPa^j-tZMqdLeRxV8w{No-f6`pVVn4 z_gwV(eMk0~1#K+^yMpngHtE!FExZTE^x`)}jN^;`H5Ht0F>}U*hAF-Gk1{1tqQ&^3 z6H~vUy%ZTWDf|9$>bRm^EG&Bv-GyKL7Dam{N*dPXPD3YC;*>Q_`u#B1&t# zUb7pwc0-3mo74djJEjiZ51mpeg+^=7X=9ZR-X~=5MxXsR#9vp+3_mw=)0s^cN&~_s z^1xvRes@kG-#*jhJleS%+VB{c%V41ygo`mEg3VEx{Wz|VtNepT>37(qQC}P$Gkq7} z5+E9!Wk6J+Sqa0gR3cNl34zDN8b(5kj8!Kqx0#*l)T8+G_eDEf?bH6Zs2Sz5xmNvI zic(%A%J&o3`k6Q-+>f>B)-?M`TRggy!iK|tV7ToY4Q|Bp#O){A>sqg`$2Br(!NKAE z$Ep9uZewQTcqVS2Z=XoQ)Tw$uLEE3P5loRM zDv3|js&J6lyDu)cbZtv;7d)*o31obxly6_GNKSCH4pa(R93;qOA2};d6WzPkd3dB) zT)>?@!MpT81cpJv5UY&Q$S@S5**q1)W|$Dr-IDZ`0R2cT${Nyu3*tCvK;WS!Y9EuU zvBM?;g!_Aq_6!dfE8yc$fFe#ipgpoZ3glRPcT#i?lO(`!XSdXQfXH?OITa4yML)GR zG}oeRy6VH4`H*tzeiYIjhyaYP>*Oq6gSj$F@@qt9xliAhFTMCwlxQ*`ozgojGUQ$a zIGOl+c$&gSgdc_3EHSlI?eimfe~)vc-CbRMT#e}PL20zEVH;}qP?w{2XhF=Hz-TMo zCLt2j@p=H4ED2w(Ttv4MAWq@Layj_lPH>cBMY%jq|6+O;L+v_9fmunCW1aR3ViRH_ z1o7#+kk&{qdbyknXT>5`?f`8LAq8HqAn}6b7<29-7;A0b7WVB{uhZE_0N{u>(UKLY zAPEq71#azGsxsp2B}c*d~0AhP>@byI11*B`i5MIxEuItY_fXd zOWS^`kv>yRFd3~_IDy1?!za_$?5>+Nj5YgbKe!8J3-8_^?k`JWb>IHdm3F(ji@yV1 z4WF;d)>)%S7)qIQBTQ+ba1pJ$B4Q%B^_4=$x@H*=19X2BMqt=HNN+Dp_Jr)#?7{W5rz{nLgrv%!BYl9 zbNBioC~2kEJbIE5hKhndrkUJou=<0sgIovKk<&00^Z2>Bi+tXWi zw$cE57-@D`)GHjB?|>@tkj68+fV^-SH)Tpe&A72U8|0ep>g>~^jO^i*4??ZC_D5=; z6MASj1S6oJ)(1G!Io3WpWL9a2k^x2Iq(k4h%(*qSp}Fb=kvz|Eph@k7%G3@#Dw#}R z^;NvmM#Cm>uZwWZRvY&|@AsL&b+9nVpXv!An5DvTNg>R9~4jn+N`;>WBaKX2)M#2=n+ zn$;hX&V`s~^3SNn0H6Sif?-B${EKGGLF(<3NJ!h;A04MevmaRz?!V;rl*(Z<*^p1$ zglEW=QSmB}x2?`urv!fgh_mVV5|l|vwyKGoU^AvfOV6(IHz>O(QZ-8DCvYO&T-53~ zo-f?PjOH5LWDiC`HsREo7+6K6N3U)}Hm1DFysL(7qZZk0_mo<3HLgI{#137b=F_yp zE4d(D3;J5tI~P%bSEB>5$Pc(n`3l^U8wmGpHhz;=S0!TGK*WAXa@KYWDYgf}O*{IC>fS(*dd*%}Ct!!$deU*TH|8#PJ=+A^!*7P2!6M)}1 z-Lklfj8+Y95!?*m9>F0%$gt#}2*ED0Jo;u$y0n@{fl%zZv?P zd7Apwl@Cw0Oz(07J4oCtSrUBP;UoPqB*VjR9`h9)ojcyc%=gNQ8!m9RBa4gv*kRKB zRtxcap`^1r;hXM8gNtN4&5ZCe_?W=%A!jAX5u*TxA=U#90z#xh9cjMP7+?{-B?~Jz zSdsTCrgKh#3ivPn1aaUVcyad^#I6Jvlz7%_XO9-FCNrYHY&g`;t31F2-IlUk{*TE{ z9<8@=%0bDn8Z=oaMHcdNFx)vh>N!w=Rt&G@3M}j-`;AocO$iI_d1ikOwqd#7R`$#i zD)j>flFi9sGyD}=#qdm#n{9KcPzDjq)ly@SOCE;kpXrp>Mi<9=A4`^uic>w-ayJ&~ zswokTJHc=m6(Q|NrHT2nmYAKmm|dL&i5i0~`~1|NQalDlyvc-CT-^B?L3{RtYZcZ3 z#l?gcEo<{*I{KPstq?1bT@uaRpLKgeET7g9mP>%B8s}9M#TZHYt~EXzH)_YjQkSr2 z@K_h(dYzS`6O-ob{dVOwi>za-3QDi=PbALJQ{+6S>V@aqD^f)}P6gj6>m_*I$6T)q z=V3A^I}R-Q*ju?w{lAN%meXL=yFh-)fCG|)>MuV8siOvh_a;sW;V~Y~h!hnI1U8%r zQKE>>2V5$>mQYFp!c}WdVSjKz3r(aht-88EqVJ(_I)UpS%UJv`PPjiieSfz3-#cDU zc8}BAX6W^o()PRV-zO%rkYD#{`9Rz*x#_sh^t^hVK);DphsgtajSTfu$}ecVNdKGz z@KCq#tO4$5oxW%}=xYV+*65C`T_boO!lr>_g))n{oHYZmM*T?M3!q}BO6wdes!dw= z5JUAv=WpmksL>p*GoO5LU$_69+}K^*YP9?)QL6A00mxws8|BhPc5XDdSygxII-zB+ zqVecNdX8SFx4Nq9n{8}KxVPLIBDv8_VX1pq+8_BaYY(bR3ki8n67Y$x8=I4+kUyPt zP&q^|hWgp;7NkQXi?}QpAJ%6=n2{^ch>h;+;o{sv4bdsPZv*xS8o4&m6EAep-Z|$D zT=d6=ASO$`cZW_!FpPG@tZ;+#Gv92cKO{)7uE4n^pqN^;H&PCrFDh)b@$Nj1Hf-Rf z-~t9MK4*X11o(WC<~f_PvQ|QTZE?*G+Ulou#Tr;{6^$}OGx0M)iyt$)`}7Fk7(M5C zDc_Qk&)=LpoCNM{|82OxyZR#b_U9f=Y&(4o>YCcZcH_rfeFcU$?XfVnHS^x6RxU+t zT#(s65}E*}Dyw**Ym_;9fp9I3kdg0!!n1hiy2Ys4%?s1r2$aZysU<1W#zOlP`V zu6Wlmm1V!oqLZy%q15j#1Q^s59gT&O&YPM{1BV!Oh~E+0R_*Kf?De`)M=iQXo$%VY zdwLR?$#tECPtAp1DwOfjIIbiHA(Fv6t=-Sv&1Xy2w#X{U1=sGxaKW!7`q@{Ok4%AYsxx;kn8ug4J#FN~J()97nWSePG_4kG{J3 z>59bUYtaC+jXAETTushWuemG# z{|2`IbPX1G7(UWd^YGlavzh0q!A6mN6MLo(W5mFr&S(<-*v|fE# zYI6>L8i7fBPyJvp1qZQs*F?vU^-&6RFzy<}q^fcZaLsD67e?x7tJSL&3gGCLxyXbs=5hPGsg(!{~vi{RHU$Ee>Syc$v=zvQ6d1q zKOYc)v8%I-y{)mmjjOHQe-8Ru_giU80_iueEZtc#A_W6@BW^1wJ{UgfIR}`A%{xs> zk&X~n1DlXD5oeH$XP$SgXWex!`Uum~WMZ96POYMbHPy_k)7z`_bB#GMuMY<qBOz1SSLB6D3N7N3wgSvq1Cn;ngFaOp z+v|{e_Qs*)rkb7^J1H@eojHh>B22C&>I_YrTJq+XKy9ea@!R!gI%gAyM0d;~4_V^U zwWcMu2p=T4FKnYux{kZ=S3><+W7@J9()cq3s%3g)k zRCLfb2GOXLusEY#@zVCoWG7#Yg*~*AP8Xgo1*+8$<{;?>7@)^gnEqXHc0PLyyAjz5 zta%tA&-8VBDOn+?sWGwF*@yurF)}%Wlq|rOuKLMyRvNd#RF)VEgcFPOXL_YO`|&Z~ z=C={-j#@c)!caKL5H*2; zNsl$JK`Y>}Sq>ZNm&S8|rj`-O>zxPg>mWu>VGspRKAM$LBRHI{^~V16uPFX+PD-Q z85S?{k_JRqbaG25hU41Ahmo*sadn^X%H4o@+q)!yRxNS{>zuxU6;>#g||Lj zrKT^#_K~p)$e=x3k3+xPYssoz>+iC(r*MPlO*fk353UG@J=uq3o~iR*|F09-%W`yh zkC+?gBa(v~{v(&`R=KU3S`5zO0O28ztM|Ly0p>{{@y z9<{}l&}U@MH5Jph)9l)?oWmWx?dQeknTFbfTK~E8O}>kmQ_$`ijS0y$eW%Xco0m=T zI#G3$r7o$eb9_$S*Vs7jiE;!h-I;B>Bl)Wd$2Qo>17z+eVe*4WsgFWK8$RhTFmM1H z+#Y1SXCC8`2z7|;xcu*ReyVb#-DWTz(c{_v_0`w`;8hr57lKa=*vGI0MI9WZ(EwHG zsLhvFDPaIe_=kw+@dzC)k zBP*F`D}9aD*BhQ1HA2Ry2||kdv+5;8EF3UDkbNM1`mrz>o!0r@CR0zwSq6gRYY5~-bp^vQx0BrSY?Z_fJQ;O@E0fuBJ8SXTJx#to^r!%Dms2oF% z-_il8aw2DJp(qEG zFF~coxR^%^#1HIVywP^9?ywJuCiF?Pl-Z6!5;5$Qo0KEeYS%MZ%or#-fxlw=>l*z| zMBoYwc`m!)VW6CotTAA{G1fe}44d6nk)v$iBJ;SX>uA`$|uLxWhsf1@Y?-fW`LZd8oVAt+;%S$KbKkzxXL(i z8Bh*k++;#oi92g5>LQjkIf(Y5NR3V6;OY7J>ud&JYT5Fl0vM5(#bs{~*AcH#EebD7* z&7G&fQR+bYy!LwY&sB(o*WtnSG><4@?P)4Rb*5)ey{q|4peRBbXGUFX12DtwP766x z3u7~@KsgksKHW|z4X(Fx3r5`FcyikcT6T<)3L`(3NYNZ|j!b!iNM;a3Z>Agb%JBNR zi=+xo6F9nxn_0CfSx|IcU9_;I)6DKjumFGL#D5H+hw`-(k}=_d!N)HMpYib^K;RV` zMi0+h-rrGb{cBod_RGtoWFd{<=u~?5zbk6R`?0nXz;EqryirujGc*Oixqn~I$?r4^ zbo5R#Dr+Z=Fu0({?SJVCyy!yys6z6RWB49)CU6liHh>vaNm3G+rlOhr3AE{S>nLH# zRs-5YD^lAu@_JG(uGb30)SK0T;MP^c$w?)oNu&$TS#96rqLnYy=|*UM@qG5wO06g8 zM)2$ZIB%Y=M|u=$=N$HWZoX-!K5Q;EDTb>+A`2;5YyQAAI?)gcwg}#vr%joXJzt%7>136r2Ki8gS85ABK>Ed1C zJs`J{J{R zWenQZ9T^Y0n7Q-6SQrcXg+c3{8ZQDLgDgzSFZx?WBn`c!+A6 z`)P@FB_qLXEzH{2BN|$@CAkGluKCUn^jfyn@<&Xjj*1_~+nQsFqWa2wJoR9`B&T}- z09%$jtrCBf`xU^sA!p{EC_xMxB|F{$_^bpL4{0> zNCE$BP0?xI{Q?n%-w)srE`xiqP+n0;LJ3?tqcBj$bWgAp^nOfO)kTc-_wQgUAgJ{S zTl5Md_?TU3Y{Npxu~Z56xd)C(bExq(Rw=I$fXq2L_tOU8o|nuD7%K}SHny(*mj-)LBJdaghp~4K&L#S`MPu99v2EM7ZQHhO+tyC9W81cE+sVuC zoO|!P=dbs^s@1Ejx~s9eztOXMjxlCvDJSN-Rz1F=Y$^8iQ8n|vU2M+!Y9=;A*>+bN zNG(Zz13~t;t(v5$fGG*^l;m^?tE6%1w728DvkN#R+o80|UvufkF~>Om+NM&WQk6{r zG*3`aRsolM&`u&18(`p|9Q*b&KKE4j3I=Q$R+0oy_5hL~S z_MGL6u^Y1@o;fvHb~<(g3!*bf!+S+C!D}F>cb41AOtamA!Jd4FiYB+n<;3qd&$}ce zgCh26?H-bqTg-s&x&!V=#lYARlk?eHPPk5HSLI)H0#!s5p4&{XEVmsF1Da>8Iw#yE({AX_oufTjNilxu&IS7tUeA(qrtA;{ zzqE7JM56t%Z&98u?qdicN7~-0n`C$#l(Jq2NG=FoCST58WE+uI#weJH#jh!wS7P!^ z?|TtQgD}74*@3cDmM;qYgSuFrFAB=iO;BE+j8G(q@gjzC;ID`a%{&y;5)-(vEou-H zCJ2=UrMQcZPXr^~Ir!5`=2@OEh^X9amNm-dS{kNz_#Rqy(qsoNDt>~V1|hZUFa;%{ zEM6#xgqo<%N-RK0t{@O$2P--GPfLK3-T|IIpl<&yG=I>W6^C;5Z!1nHc9syARpiKR z;#M`dApEQP3{oGMxAz%WD6A4m)+;C7-k?LOC!BqKCH7n%C7ww;jku(Ur7G=-@VCA} zMD^{}`ctM3lc}W81Bot$8n&wX_`~gN=~&icboNqn`6Ap%?E~4!oZNxhUH`^swrzF` z$&}g4+}dHsY7Z^z*!;B5{Vr$V5dqDeOYMM)tSOG}+gOq=mKyo+9nbLVF6wU^)kJbo8g1B*t6OkW@0`{YZJ0 zrjv@*cdg~re^h9)G2`PNd_|({#b2>+k4;`f zlj;Mae!J)ib!xW+O`E@}k|j|mJdm;T4*!}hsQ=xwVC@=OD$EUmbyxZn3FJo1;0>M3 z>_4F2wT)p}-ePt?6gpe79Pi?|qSO`gnStC=b=1i`I?Wn7;t8RyGH-6If+3U4xQ)ua zjx3aUlG=-BV1a+WHa?(`8W9+nRjTx(g`;hh=q9j-DzQ7ZhpFHilI|)(Q!$ukDCN@a zV`FMkC<{|SWe9eQ_P4;nlV(Hw`u)6I2=NQl29i>W%`Yx4!LLIBfP5{#rLFTq?>mwP^!@h`P{`ddbe*` zu;C$Jd60LxdAtNnUlzsMs_H)pUuQR$;tofUbSRD=TR)NVpR%6|Cjv!I&;WC!=%uEm zqza2gb6Yikdv5Fw63d33WGQvA{S1*qN%6K|8O`OpHKRp;H)>^{h}Qsd3{JTjm3G;hRh5VamnB`z8+eu>)Mn z96^;G-%DO*d7KuYJd%q30Ag$?xP+zpy>6#IR#EZ2q==ocUEDp@;(O*kw?e7g;PyeM zklXJ&ls~RqDP8h^Pf{tA4ES_@njBH@sAQy)Yr=PmEALahPN=?~`&x1vChwKfnogP@ z?m)e$pxkt2TK`Sg?)`>!4ttMv2CS`py?%Fg0DI~WGKG$K19gT=+IR%Dglg{@J9bpo zI+?cQLp4ADSKYb|-EDDA=#jI>UxuwP_J5li7#lbn{O40nj{5(m*7B?8#7nwllzz=Q zoEN)NlVy%JTTbvektXfk0!c3t%YVi@xs^%@#%EgXF?D zQh3Nzmn5Ifng7$Q35_DgV(i995jOlMUbLq;tU!0-!q{evtuZ#mS4(6pj?6g4Ef&86 zLWAy$j#vu={Ee0_ngdtnXF^cMD#dM?!7mb~@4x1?aE5Z8!!b|rC@?>Weu(lswu6(L zU`k6a*k14>>Lr(*eoh5=P*3#4BAavCX~Kg}ESP#aL2KlepU^;DOyocYXGDpoL^;af z!0v`ylMRKp;J}Ui&F2g4XX-mD+B&QD+*7msVF6XvpFoYt17mm`O7U=AjxCR(WAr{| zZInpu(%m%QV_VV#jm%dFY*Ih`+}I}5qL*dJ{i4-D(^@chXXC70^3b!b=4^0DeR|4! z_Ztf?g)=(QAwH}V4;v1()*&fE*hG!Bejc>Yt4IL9xVV%CCu8<~#KAihCkCGq7_h?9 zu%44`qt3%4`i^KX<0`EB4?a`a4U>Hj%{ej1`prEPR3AJ2XRa1c5}i^2Wt;|+7A&On z4-0yx8Xj06NgVJ>iS1SgBK$hMuG8rv{7k-VC(UBFvq4=gl$4f=!J^C%zDp;U_#{}| zW}$B{5{Ev8%-_;-?24Oa2mSssS(J<7ny`Zg$)Tecu8jbhLBacrG4% z577(U__I`~#**8bY%d-T2Z60PU>zxK`DeVpO)Q8RbSpI;;^+;aJh3y{P#k~rfh7)@ z9gT^Q5jJR4_Z(#x7dB+$NpO)6HlEc9d*yQfwNoHB=s8oE3rV1fbTvrrFQiP!!)%B0 zULF;{zGS_#K2O2+l}1q#ix6!gRK%zdY&@#sgQD8V_BqEPO|-V>dZ%mWO4}64!Mv8? zELvs%yB;1ANEERa;i&%;m|0yyH$EMMC3h7IGgKB_lgMF=Rj=IQK*^MgBD2+96vyfV z5rSfMW_9!~JWI~bxjqThm4k$?tP5bGL?}%{7&U7Zsw%+^sSff{fsBPEG@xG-X&dBO zY$&cHao=V;nl`m37c3fB7%q7=?>zz2Ppr?nOx`FK8y5!|*hJfyr4&GdWqIMvh$BZk zQ+F9PHnf`iW5-&XsKr8o5>FRsf_>b#k0KH&S|hcHqaHpq*UVk4M*`;VH_lC#$>A6= z?OBv_UreQpeIO!TouZ)ZTX`Z$;V0J}V{j&yKK500i0pj1TwO%~$7smi!NW58azmq) zci-j1;RZK7D$p&Y+s#KjJnO%MHfX`WMSITrRIvCKCNAuKEWj~V2frWc5b>A~f{CCk zM3h_*eabXc)ZSfi=06FSc0!j zPCo{XdTUs_FCix8j@%@-{o}yZmN7}Dmgd2LPp79knI{uh(mxH-#Dp8LMTI*~uaT~I z@BK5js<_XJ`wb!U$K;DGdEz2+i_%#QzphuODp8#nDvNDwg>0(72eDlFk+*_d#fCEA z+HT$9XrhatJbEo@P^GvUNA?2C8+tXRjl+bj3{AK)OZ&zR&q@kKi!$-T)i_Va$?&$duVV7sR3H%rw$aF z2zC|Z605^T91`V15J4=;jOB)3vcx~xI?pWFY*cfSB7&W%>i1Z_;`t4 z!{dcR01|hzqbv8oMoFPoWQKB%k;Q&(xnng9oS;K0wX{><`WR)`enEB>|rGvmu_>Fv>G3^MpcX$i%^di4-RlFG`XumMh%#hGq20b1s3=D5A znvt=oYCW}Hk*yZhIr7qQ)2agB2Gkh+6OM)aF{a`9h@{10{#wAK1EuCLC+8U}NIL5S zZphYWwD$xwM(NFcl%R|C`G?AR3Q@oAmNWN4&A;YBvWlDN#!vlx=ZGmck@%zJpR#<7 zWy`h&Yr_&%{#)M4iRn(TuToYitI!+5@a$f@_mk&`vNt8wvC@g&|IDgs2BT)K0RsR8 zLH>6|TN8U1LsO^!#0E7gTekb6DBWWFII=iY&5-G~|IR}+62p5maC1@+-MS?K@ zHho`2ZxIXrx9G-cm=y!9y+#wo(CL_K=Z){-n)7MFv}nVU1#32NW9AxUQVR{tsc)~5 zE8G90F9Z_3$H^c7osq%-GdO!z@_-bE8&?YMwasb79Y2Q^P#yT7~R&8VwqH83V@m5p)9MQDBc#O$)=)b_bdZ>Z+bT zo9Twi()udX(^w!@GvOe!iDa?)2DgePXUHSPPB0#EmL{{{$G#R8oUd=wSX`8IxoqTZ5OegVLpb4b!-wT z#X<4D@(>r|mD91r5_0#^n;Qk?YiWt=U!F2u{|MT@HS2AcDRYh1NEe8?RTvqaxet-> znHZ3{VKe>=IZgJsP8a?Y3*q0QoSd>{9v4t#p=L4LaOiW)T+R2naHzzTJ3c@^sc_Nx zly9o>zX~iX{Nb&jd%gcL%h?7|S51&P5*f2m8|?ZS)|RF4bwZStkwTQKQ7Q(tQDIIj zv=?$@q4VWTqJ}kPU@fu`=-B}ufCdJh(4~ChFL=^tpw=G1^?fzDWb7k!4#${#EDO6! zpHv7__(^EhJI_|qt5AhIq@Er?nB+P{Fc@RNR%efrT(};v_YW$0vgm|UaLylnJazGZ z2o62nV?Raeg3%q@oPlm+)*h@Ag)d<63r)zHvDl(?VTrxDV|BK;l(9MFg&~hBag^zB zLLC%fl?Y1TxqkKnBnM8)X8pdjb^a-zGq;fI_(CFE`yd_}vQRalRnk&5Yymb`TI5I$ zk?zFRW&JrXU6;Y|leqIt7QbDHqxtOc-tc^Ab{;#i?hC1C3#=hL2B?MYd}g`WeNEl# zzlfJf2!<2B45@L~Yoxjc?qr}Ggu_tpQVITcTEJ*F0L0rtlyHWljM za5Ftj9^`1W?7-5#FX)X3K{%7^doN+-JOwP`oJ@RlAHb9XzaA|-dV`F_;OQ5Vy!<MC<>7}PV9Z2200@YP^9G$6FWk}7Wgsb4v@@);!T2~9S(ww=8G}tKTI5>{7ak@ zV7zEH-&->Q-p7MR0p^|)D|Sny3}uX_V7YdPe?*NmM_*i-!6f5?Aawwp#OIr*P{I+V zpX{kDpjGd^7ldS5!jOh@aGWf4lxW;jqTR5;evhFXjxOfZZLZH!yzXf@#C|EFg}u{d zoFqL|@fgnrbYA-DIm+xZxwTxT4OLAXelwC_noujZ0%;X!`m)Y2)ZFPWIrJ~<+~cck z^UVJPxRRpvum1bFBXenDD8|5uh+@!;T2TTZuKbQzw2rG&-VMZ`S8U3g*7g`hf_%qF zhT>5p7|$h3)M~SV5CQl<{J*&kyrSqnFfND{o<%_9j673hij1u7^KB>;hByu|T)0Wl@2t zs^Kad5b(y5^W!b*EuI8O_q8M`SIYsmwz^V01zUSvm?5Fa=mYi1a_Zp7{SjG2*bJ%E z?3zUNb0Fs-ADmWRt$nb%jj%uI`|PMLM+$w~m(PEKA9KSj)U_p1lb$oC?Jej^jy376B-R)HixY8!rFrK1nJrb*m|T4P&#uJFHGCmrD#jtIXdg;O;jH_*3R4T51T-tVc0<6v%^QAHC5|;4jj%J9h+x)w5~DTVPnpOn z%n&E8H9A}0a*&WFWTcmm&BDu5x!<~NEY`bL5MjN4e*=VL@8N5-yLBw9D|p&Z!O@a zyilF&3QykLokPLiv{zM1b&g836#Ge^JWRz}4bcu|fMgxzcn~SJGHlE4w+Jge@S35GNx@LBKC?6FgM`K`9P~ zD0m^o5k##3OeV$0r_@2>oJZ-~HeECj6T_J}ZMGX(+p_Cn8=L0-@Sdq1nB@J)s~dU9 z&c?p}>biOBI@-*#*=Qc%lbW!ZHEP~7-)J7Q+h~Rb|1q%Cx@JB5jB9w0`?)#H=}dCF zm;KIa5W@EMd(*pGE$H-WX=rGOjD&iWl$4B&j0DL(KFRa@rn4jHnuzsV(*F*6ar^vp z$knWsc;rp9^yAl<$b8|qP`#*wAz4YOP9viN8&O_S5rD?Iey(Z?qrPiav}ad^sb7X_ zUI%N_6BO%ws}y8c0$m)`#rg*u9tqsJ}*3~4&7sap8doS3cwV zt@!zeU3=uzoDM%P7dJaEY$9@bxpZa4j8-qV!%<{?cUj5)qN&M=ib@CxRZ}*Pm7cLM zF(NZF)16yaOiZjDoI2GePn?-x&d1RP_S^D!JSF5}1>J62yVb?&`CR1{LKA{c+aC*- zj&7i2w=~Gf=_QZ5Vhnn_DEwVym+$Q`DKIoNppC=4?Bt}c)84A}`>je1-EQ;s1dPcE z=_01CHkO)>42QS6s0MTx9PnTO4Zs_iGXotDe&U#o6>XOg;A1$ZB#SNWcaLo@&|pz3 zwNrX+j7{BeT#UYZ{jJ96U^97PIbR1^Y*#EAp6lr~K|ikpFVPwA9!DZ?s6(JBL$g9u zyqeQ>73I}cm4T{$#gzr^l8m7l^O;buP-utAsDEZHOr=Y6b91}9y8{9Mb7afr%%`U> z|2@8jmX3!WSGFHho?>anE;6gFKvY`(q1uBoNu=VZs;D5ZrbTWcDzRTUAj{nOJfbse zkJZF7x5epcyEX&$s`v0>;OI`r#*+>uW8J_?Itm$k8bWzBaPmQY@L}-qjT8Zt6anlg z=o{xA8#h*qCXn48myX8M2X>$B9~~XtT6?<%^z=e0AWL0L6Xr>>U{9aIp#6(Y@fZ7G zLwQ&;n3G-uWTr7BSIPUMg7E_yXohO!vw#K<-uLbNDDXBpio^Hf^{&G&>53$6H+a83 z9)yf|8gY*U-@%%A9Wla5kfeRQxV_+D_0$?Kgxc;++U`wVOc_QB3=KpJfB1DqIwmGU zm@q{Wltv#K1{RivT3RtsT8rb)6n4zBy0%%fgcTzV+v4cV_@?~8QX+zwAM9Tn5*lx)sdbqucP_5FWKapgPo_bj|f|+i0N`+vtTknJc}^mwo&26 zc=8BBNZC_ow+v}H4RZ_I(}8X%ZZytuv^%45c12grISOOO48Z~bMcE*Y3JO4{bZ^4HzO*i5v!+1bV3-YzY-*4ibrNN#|iH_8{Ssc-+EKK=Qv zsz&(hog+`o&q8Jt^MK=ZLda?HL?$GYIAJN}@P8uvYvsb|%Gg-V04YZ#Y5SqF&LU;) z6D4gEqFniblO~-p2ta^zEWAN|^sKC=j2SSbK_(Wv7W&5J$HRrfWe($BnX=Wg(%E>J z8rV2FJYHz)zxK1a(-Hf#>;!o1qYvpexoYO}e(U;ADQzrX8lw!a20cJS<}uxXxAQaNQ) zIkymA?cm6^vTytm2IHK5PJ>=rV)Z1R2iVQl#LgZ?! zpe7Cu{Jq~F&jOa0H&6G)Z_cxC>u-K;%MJqf8ieMyJW`#GaN*bCY-Npga4P&BdVai! ziTEV|*Bp=jULC|WdtnmTKIY&?=jcY~@J{AzN9*8%b$m{_f@%@;EsqLdp-6*e`W;)e zE~K?h1V+v&?!dYLC3DVZWo?v-p**={YiDL_XXT*>>FIViH#mAY-0e?Jz7-Vg<>m&u z`?iXy#Ot^{e@B&UV!=kVpo!vkzCWwrSG97_SCb68HZ0mXvDQ5mVX}u@SRxOW7fc6am( zX@^3EKJ+n{rwLcO+QjZ@C+!Urn>VbetORnji2!hy?^{`so3u|5Uk?U0d#!j%&~*W? zZugjGnxiF*owENo0kUF1oyd~f{^A|_BT4ZRiGMU*c)Pu#$H#lB!{cQ^)Ybna>v!E$ zaEZRdi;`>O#IUjj<=g9EXni@kiH(n^rx_Rwm*MmF{&a-JrfRp7+v#54+08IZms)#v zWbRDP!cE6TA|)gwrAZ@Rg@c3h+4uF4Hj{&OcD`4J4eL~OR}3v!BNjLX-s)PU9j3sK zd%~Kr%Yk{sjCe&I?S@M7F=+}~y-2cYJ=XR;khgW3WR^W_}`q@GeeSkuk2jICxMY`K1?m2PogI^H2KZx6Eeihjm|Fw%#1S_kEV zGSWCklq<$8@^0sR^2gHTyz1ixmjs)8d3_?!;>cQ7WlJ6Rb3f|$6Kr%#(9cxa%^c0x z*bs%pylP@*eAXYdwBF_&IaNn}ra~vA%FuVPK0q~*!jk%WkphJG(OY}*W`HbVLVfuZLp+EPC+f4^+FIv#GKTlIxldsMDiGjKSJIDAx&(p~O(9-tb(@fmdo9a=-=9wj?|eNTPU#cxhX--nfp}Gq5%BO*1W31% zhN~H!`vudv&`C)MZ1@1W8tVRF1zt9$rWW3vFYa1UY&%ozGHP@1^vDtWfq?129O#x{ z;@z^cwywp3R85*_wR0(}hgB=bW{X{MYe!~_M>D5zO@AO7F?Ts)9-sD*M`b-QA z3B-CzWLf%JF`VEvoXxepF^h+?md|Y0cWl>ij5ola+8qT#u>%aW2lcimt<`dK7CS#zb~Hl?C^}6oO5wJYTIspuf3SlyEp3fK z3||xF*;#mfOUu}ZN(Tq17vw1hgxd!B3G$+4i3^P&$Z_GC^u$c@2C*44z_b9K(^TQ) z`M5aSSAPX8=gjQq%nc5(wZa1V4le>#-w+>t^cw-6m0E?&K+i}`{3 zaaZbN2TNzn^T5l-o7zsN$H0^ACdO&In~SBwBHm%)&vL_wPeW=`kpU%6mTfqXv>?fT z0tON#VBGDkI0~c$@#vsJJTcE2HDjWnAQ^&!gK~y4AthQI6gX!^Aq@;nI=`>jh!4q; z&Bz8<9}a%}x|Le}UCeZ_sNUBy|3YpM+Lv}%AIMAuGoM1@i+jV&;2v<}5hA)}5nE=G zZ7%gYn5NI=QtCghEt0I272KSwtU4Lno_coouXW0q8ykw<0eH9bu`+pi3t?hibULAf$#FcA|Ic(_P= zyD(YR7j=!Mn05`az^;JBvzcoE)NT!A?m-y*qzTxh@vB^llN#uqT2`X1v+35w^cJ_y zeR0q2Tt(tY(9(>o>dxoE%@4-4i}UYx=LYKL;nVGQzMGW*T+x$4r-_RaB_Qlc;o`98 zMF<_l*(Ivs(gKSWO&ZG`*Nihz@{zrvv5LcF$qJFm9VyjG3WC zcE;#aN?-~8^~Dh17B{_OxrMA}?{mZvd*%T5r#Y7Ea*C%VmK(6H5N%d@~y_%Qr zZ|o7tg~f7nskFTfHIb2R1gmh6`Ms3!p$e~h-}Zsql_AK|B4{IB$_XYyhNBRt`3nc2 z>AO~Hqsj1sPr}I-MC~KY-6>}{+Zz)}cN37V$QSe~SELu@mX{5Yo-5i|Ut&9t<1}4h z|GUr*m+=L=@)gC|b1lQaJOs<3<8wYEzflzWTw0E%i!Ix(jaoCGc`dxS4O$@Ck!J41 zuJhqtdz4(g-x_PLqSNbybE)%r-hV-jz`ZZm;Zp+gAr?viUR7u}{1_386KZW2XUE70 zk1Wd%5bS*e!AHe)2`5eyOai_Yk+!a=H>5Dul3My>^~5>Bqq1CCqS^{G!DF&qX+nMV zhpx*gU|0uyvZE+F6uB$7B%4K`-$h{mX?c<^E6Mg>$=2EAX9LxVfZ1}I5USj;Rc_Ru zo-E!w&xX4Wr6s+sp0DEWeQUV|Ll;weU7ME~RR{HCTnSdRFna(FxCqkxedh!SAWF1& zrMV0gXHE>g%YMdv*uqg0`g##CC{WT4sVNnJA4H}SNw29QxIat!9$GP!sj^+r1(4~$ z7SO$AH(8vWez|zQ1<8$$$t}LrS8((_1ka9Y%V}m(csWOW+)D2d>&6#VYqcv2HFabg zy3Z`yUhk(O;Z8nFd+Nwtd3>PW-48-MO#tDP?8F#k1RSSP3BUzF!=(~aA-26DLABu4{%oY)?*W5-O$ftce**^*6%g$##Z61#}w>jCZ z#g5YsmUeP!yofE`eQV#(%#Vx=wi+e+qRvXw2>YVy*U5}rX23FSd3|38Q&0hhu2f|i zN}Iz&aDb6$;UIx?58@$iK_v(QTv~;RBcdfq3X(<}#=xN3_Q-t|2(V(7%y(RHa9X`~`hpkFoCT6=+rNHTpfeVq&u!o4z5cUt;Ut=+RA-1;R2cLoJtrUIbfL~#nOek(1W%CpM%MLU?CyII%kBv#dvQ|?7t{idq?-nhFK(ra-RCf?A^8r! z&N#F{!bwTVO%5LAT&u56>W!Ki57`@|s_a4{St3x!f0T%pm*lXZaN#Un8(10_2l!jd zw*I8N#Ih?Ul>J_-GFjt_0{F*;bn#<0?&D8$=msqRbc`$J6g-DszXlrdwz))?58;O| zyfXAqoET*u6qcS0TX$ygs1kJUhh^o{lJNx_szzDR*Fm~8GW({023(jDI(pjNoB}j- zRL!nf!8ZJa63o;92r>Bu#W4Rr6eryNSV1^{@aY9qM~nM480mUMFhaAo49Aj`b%hC@ z6jiVBtESj~QTF|duCo#D$4ofQC&5Fxhb(Fcjp}Iav{W-44m}s+9X#@H)AGx#`plF5 z(3@c_-PmQmn$bTn&rvLlhLSUg^JL}r)y)kJf&1J%M8MkmRCNRT5qdD8TG1TwHRgS# z0#nst)5U=99KG6uy~*bjC-L%k^0NF!`jYs58kNg}-wjG(2+9^^E`t%X0I$F@9qi9# z2b*O1$`kM!?Ng?nZzjnR{eEVg&aE~!;rk}tx5cwg$@2g1zY^<;Ui3hgc1rvVt_xGQj zmH*oq69d~Dijy!sz%L+RaB-vP=F=XO6ca<=p53~I zn2b@PHw!a!$xTYJG=RIl6F%fD5j#6ZFR)p!Spens_BLWd!H~;YPGMk`9wb*syZ&9> z#}|OW&x1K{YEoRpo|HF-PDW{e(jvDCO!+3gw@`>Tku`x5V&n`bRg)-Jji}U;q!w%d zc+F5~a&_H7bwMex874NI7(T+|S7kjv$lq zo$2ZhYu4rR<^{U8`NIU|Yvq;YR+g4PmwCOwj`%Pb^6%Q9=I}|0WkRukL3i7%%|2$; z;bpVUFzDiuZzdzm#0DGNAZ7O)VzbTDA~OT0!r=Xyz65%YO6W+7;o^3i*4 zKJJF_$i4814=2FkscC5ZSiW<(+$8-%3rb2znrOmPIW@dmLhfx*VPRp<;y{YQ!f^G0 z^8#=If&>eC)rgTG{nx}n0D|%adjl9Q!~){x0m%uM)GFa1g7X6k3VsH^<1g`T#r4ht z0az=A7Z(?cB_$GqrULf#73u#(|6sD-g22F4ARDq9=XD_go`j?W`}hmvcL}cE{d$@w zfqB0o0+fF*$9x7-1}LXDB1hbXne?Zf-wHbfnJAtc z)+AJX0P^eIMc^m^F9TS@capdO5$~R7g8;xl8^AE-Cu*JcyQiWS5fQN%OodWMt%c_y z2U?;=02_tJ4yqgc^~I5@Ae52zM*xCTM@k1U1t$_R3<=2V;e*kK?tPuT`62_%8elx* z$Ij{R=lyzI_&HTG=5hsy;!T9W_Tzos1;+6Hyc?OF7#jmB^5@Wh%Uc!)Mf1Kd`aI4P zen-R?fS(2hJ}qJ5A^|#>@lDq0aP6D)y90ORa_#)eSmp8{`>%A=PweOarRx5Vd_D-p z1r_^OIzRTC>xcMH2F=98_&+ospJW@mb$W!6ofD-^1SCMfwP!}EYMhvLNeIRU$*fXJ z$AJWO=w>S}qpd~wPCEuJf_S*(PVwZ2t()(ccx`W#4ExT$-T=VKR0ELf=)*?^Lh6AF zi2e-(!el;$X9Fp6;1qGne|OD*X&f@~6d+Dp!A|b*wxvzCJa#P`F-oe@ZPHy`N%x8g zaZFuPA12fk&ch|JA*VM)3YmmK9tjAb=uj`AQYl&!?nGrOvNI0W!GmRilF=Me2%EC~ zYoVn^N>XJ%d)YyK1``e?B|`!Q#WnyknvG81MMtZyoT;PB-=RJ2DlAKJ#bKIJMxBRsN-jBSLq={}AVbB!pn=-eC^KOEcS~LN5@@~)GX9JOR zr_j4!kZ6@V1#*n*+0+eBGy${SwrZ7&5mRDl6V9K8L^1@*ucqir@cS9>x`?TIy#1Uj__d+S}p+5;?K3 zU;qH%$N&JpY_Z=v$l1vJznEfb7m6FADBm+m*vz@&rOlwkGMdO`km=RvpG435I9_&k;Lp2NdVPmqAhquIF=RT$_=PLo_U_~yyC++R*l>OK$&q2rUD~wZQS>;%WBt<+#a-cF z0cAivRUR6Zo#X_nt?zEb#Yo)24~qs!x{|qgovFMzFvnw5#tm++;oN(EC4_qm`ZH=~YDHBR7zb-8=n|LMS6X2|zAWXcBuAKIb$eo;k=Cnt7 z1VzFnOuzo2gRQ( z5FCDjPToXhtwJ*&WAV6{y_yV>)0lt%sGD7Aai=#JpWvV>{h3Yh ztoFxUG}0aJiq1|A$i1FVqv%0ZlrS#q`7Sd|k_vz=xV50!SRHal%QcYMublqd?_U1C zGRg&lsGqW?XVfide^-CChSTajt*G~;Kh_r`s8rxiz2G^UoCeky52=@Ss|DgLjfe$k z&_SC_2;#w|N#L)!DLJf6RbJp9|Br>`l8{pxd6~$kr$j4?&k~}^#+kAgKLX=H)+LrG zWCE9d1r&@iXNm}q2tJ(|K3Q$Pcg@`j8JuWU$0f>bRTGKNj^@BfcnMFxy^*)6|A~wH zPo7S0uC|`G?=T>}htnHa574tr<5XHn*Z^Y8pvL5F4<3PQ5l3~kU{5e3$z*H4Cn#!w z@eVseD@piYXLLvt;WyH_itKm_nUJV8I|ZvtJZxT{=ZgpQuN_~rUja<(#ezcK^l7*( z4D3KjFM@dqv4;r;1s)98bGMJZIUjjtTyb0kPdkZ<;gL_k=V_lWJREC?+w8c*Y|sEK zwoMy9RyGz?fhfTt{WunsEwgOD!?^+PpU(D4%Bzv}UCp$2W&5DlZQ%gh?o}~4mBf2n zD}|%hJ%k2*9$!Pl zp6eHdx!iCkBKt$mW^E$pJE5aCh{o(ClZSM0>RKYmoVh* z-`5r!d<)%K&qv4=V4X5Z6-*akpt?it@ z=r(=VWX2Nfw4aV@4ou@B8I%46&%?p1IuUJkUSlqXh^MCB0b(o;)xqeKs z=b;`Em2IwZbbm%4v!)F{dS=br@a;w>__RJZbs7FUmdo7c5qW35xrj>)(}Np|Y6xFc zA7xJz+|&Pa&MOjRV?0}&Un3LO=ABc9X@FukHXOCD+b2x{f&$0y@<>kd=7c5YYGc!N zf~sP=?_gJFdCBB5VxHm4A8U3H==kJV(fRYolYF8@>6m>pkCc0%p|%hLs7>S?Y;8^< zgmAdS1La{>Q{kmo+SHWfM|i6SMf*d2#$doiYy_Y%*N zIWmz7M^oY({(tgzP_+SmKz>booPXPYcsph$&XP)Uvj2H%*u)9Q4$vcryl@PaR}m{3 zMW9MTD?=fvpqdM}$7#DEVU;vvaw%g+IN38?%DYb9&v?BvU4T>B^xty_U|0Gq2x{Ib z;6NJea5v9dW0@!L#xt(s=322kmGnU>E`yV3W+^}}!Vyd=DGk6D&wFVxy0&RY3dn^N z1n3ZqfN`PC=Z#pqz8#hnlnZ`*xg1VYEy~LUa;bB5f?=@@7oVPewq-&)ikE{ArssfjkSnLSF1 z%ffwa9ex~LQO~eKS>OZVSQ^L{P_lOEMvXi2_dsijHt1KOJZ4s0aHc=(35|K{;JYmW}P06Nk zq&#l~Z-l!m!M|HwW=I_(GJgo?G~K3MKJ!T*@?`K8ODyYA2$9SY@sbrkh*!aDRs~ha z&!vjVo10=-)Hkc)JKWqD+t#*N$4rBm?C~eFe>h$~uQxNeyd)@9${h3{UY4rrY>Ad{n)wCPOb8CHLV)Ah|89n8*F=m4N5Sy_pfrp%Cn9F~OzZ3* zHjITT@^$a->i`7aEfs?343c7K*#KxQuC9y7>;k$2;Pyspfl&0bjvsNQ0rZYHkgS5K zrAu7?^Z>K}*J6M0|JBV(0+@>LyN|Lf)02}CnJyz0o7 zMA|gnhcNymS3#3FHZk*XIFT`srosBhze{Klt-{P4aBYdp_PtU=+SpRf zJ(|CV6C-aN%b7rR#iQ6Pnn$BN+?1m7aTs>k@ zhN?x_C3pTV(6$VK@6!t`E!2;cGVcPdm~EB0 zWzY46+E zmH&HXxfpzDj~3|GGWGS1UD!@;(Az$7T>Vrtv_^TvY35)s@>r(dql#Gs={<7-X%P;r zi8w--fmN#?o~gxchgcJj4@_wSQwAhr+`b9xc`@@4o6GB)jyjZ9-^Wj{nxGJoHX zBG@eQATL$B9}Xf`{t5$_hBIjLhW-4$o}s4dKXTTU?}RAw-S{4&RD+N4OcGOf6ZU5b z8g|6LYb3tn8%s}J>=gDuu*`4+!1n^*0{nk=t&9LvuX$w=^=5ql!HifS2OntU$C6hl z6i#+s@87@!LzE(Z3zh%D9RLXtS>aki{lNc;VbeoRueHDU^`G`@H1>Zm%*ENRsnt2`t$}KttX!217F*_?Qw!@C^${ z6F7bb?gWxJb}~?a7@EulP=w|c9X1GGD_dtp(3@4vT@HZTA(oftOP#f)8PiRXP8@E& z;@);QCim~Zy1lL^{ieIvQY7V#KfjEHL^ZJSql7XUYA_d!9m?-DMh~}EkBOOvYOM_} zb$|c8!#9KED`z|5{|{a70Ax!Ogo&Q9ZQHhO+qP}nwt2_4@92(g+qUk^otZcPdv9Ym zHg>zCPMoT)>dvUHuB^(;FH>ov^MG&RZ;m=Q-(uh4r+FIONqhw4l8p^`xfq_aBnWC?~cr;JeqI{iNrG9vM+~Q{+Gf zlwUQrXK5#T#M5ttjli(+l8^LAOfzI^f#$hMCwe6ldm%VcwSW;_9XN3<4R1oKH?a2Q z0`lpvADbD)u)9oF4>i+!*#$7m!-Djay674O3Ijn;q3mvIW+R0Ku*7F8tD7p+4~b-Y zLYqG-3tMW(Km9QTml{P z;hY~jQ?D402+~e!shHpRgMfQePIT2b!ZVEfzG?%MvR$;EpMU${F!@I}1~$)h+FQ+_ zr5!J@M_ZUYS??Iduo~zogNKb}^bTAu=)zTO38j4mDWNG!mrmd`O&FqQ>SUdD`Paqn56W~Hok!xm0`lQx_GlZY78M_=OP&_J-H&tIsCyH?(HDxyKQBZ5kMKGt1Oc7v zQ@35lx}+l((N3wb@F@dE!<^jT>%-)yVL91Oy7y-xjX|d!Eow~i;+)&VKbVB9!-bWx zexL0(ZDRqc*vkb+xHs;`f-AQ}8=c@=4-~#^r!u&}>}Q0m&yMDE;K)CcID##vW=@4v zZ@oqHZmL)^!$jIorT_hh!zh$nTLs_$^-v8rz;oIabuWVhnlQG18eXPs_WAfwMA8N| zyQ~Lb>P1JuZA=^1a2v20kw0&6(qeI6ad{~(2^ndFj{Wu&d#l0OuE2Cz5Hg_&WXf>+ zg_9xhfv(SOy0wBE&9+a&5}=Zk@y#*2;@c+3q;D1CIKK84BzE`nRbVjDM?%QVV4(ku z*BFaULe;@)!mGcp3I^AH?aQ_?4Ad5Vid#hZ;!{RG(pb1j2*m3BAC>6r#2P`L1XS91 zIr!7w>|(Jdc8H=w*-Uv87=z?hJvFrWlt$m$eh^HzBR9k^e}*!N;aRFTGl@fr!ZdEb zfEp+lI8I9jesJ{vx5-VJHQnO=XRZ5RLj9kU+kdMw69@PIU^V~8`K{!qYRUh*M8j$g z6Z**znn)_k0RZ0Q06<_U0Py}(6nF*zxG@3%7lr@;cP0RU;h5W{#QSpr)Ivz^r%hwL z?}t*#PaeocSwa|4H-mfrlL0rDkq`xZ|92MtF8}W`l%u4U%MaXV=)VM%Mg#w2Sq~%m z|IViy*Len!%RfuP*)O6OB5SB3eBX}9Pz2?VJ(1LTVHs&DY$x+n{DRy%qS^j6^dWkVH7&eN0FqP-8)7ps)NdMx} zI~Xj4UJPAX|MC~q5=JyMu}e721P>XH;KMkh9brRX#e$V)&L}1JM6O5ma*T)Jf{ham z@<08S@}H7Rq^Zmj1+sPKrVw%l9+m*@`=v&&!t$33MyLr=0J1e2L?5$MuoNC0Y+P$^ za_+Q@3+rNV1(Zv0IvLau10O5lgjg~*)=G9&r4!N_`!ny>RSsOE@sz|5p2zJ~IkdPm zdjIX)HmZRk{+M(uW{LI*!OK9`=AY?37nh>P3(sGv@Jz^0M4gbf!JbLxD1&`G> zMALwNn*k1!+r2iLq`qzN;Q@Pimjus{@aV?Mz8AA;e=x>xr^0(F*?mw*|Q&-_#< z<`vLR+{M=Mb8mMER;u6MS}0dk;*KE)E7f09zmCh3 zBmN{47C?GlyI@5pX{>m7b*)q)$Eb9LQ*x9NkAVeYuyzhC9{L>BE32f)&Tk(Gt%6|@jtNdELo+Mp0x=E+*npPLXL&657|C&3)*#YjtaDKg)V_RpTRNM=4(jv}lNBgjXhC9_<@K`(Ty z@%390by};WDtFyBa%<|S7!Djl{y%|TGE(}c(c-BsSme$$R9i7+5}Cy5{NG1d&`KEM zX*OlH`7%oUP-GHYAq$*RA2!Lwx+^kcl*Bf{ND;o{r7^M^K|5IoEsi+#81COT^U3v? z!7OZ~w!;s?lxc-_Fy7u-P(61CVZ|k`L29XV_>JTeKZEK8()L}a|3>h?nyjXFy->cl z)M0s>Y;vM-Fc%{zkza3rlCq7GZmtgu)ZV-C;HFH{+tS!^F&w zTkNV~=S5LT_I_BupMc^6@6C*sWS zp3J9r)v2`LHIhmeLQwxhvTL zr^^9B5(h>hXMKG3MClOlb7?)caa5DXP9}rkBa9seD*H|v$^`Z-;gnf!TcJc==9RhG z@xo^$>2jOvF&xpvo??7q0t%3B6V`FmNy!^Fto+;QzlcZL!jX(*E&PN2Vw)-Gpim3K zG}x8h61o@I+KDP>ho*DykT$49+=n`eDQBmqj97UCsd)_A1Vyg9cUTK*bl_-5%1