From 5901f8cb5e6b0068b50b06203304e43a0eb405c9 Mon Sep 17 00:00:00 2001 From: polytan02 Date: Fri, 23 Dec 2016 19:01:12 +0000 Subject: [PATCH] We don't store sources anymore --- sources/CHANGELOG | 286 - sources/COPYING | 340 - sources/JSON_renderer.php | 255 - sources/OPDS_renderer.php | 278 - sources/README.md | 101 - sources/about.html | 23 - sources/author.php | 95 - sources/base.php | 1361 ---- sources/book.php | 661 -- sources/checkconfig.php | 257 - sources/config.php | 35 - sources/config_default.php | 328 - sources/config_local.php.example | 23 - sources/cops-1.0.1.zip | Bin 954968 -> 0 bytes sources/customcolumn.php | 1180 ---- sources/data.php | 209 - sources/epubfs.php | 80 - sources/epubreader.php | 74 - sources/favicon.ico | Bin 12862 -> 0 bytes sources/feed.php | 44 - sources/fetch.php | 130 - sources/getJSON.php | 17 - sources/images/allbook.png | Bin 1172 -> 0 bytes sources/images/author.png | Bin 1198 -> 0 bytes sources/images/bookcover.png | Bin 3057 -> 0 bytes sources/images/custom.png | Bin 1687 -> 0 bytes sources/images/icons/icon114.png | Bin 20281 -> 0 bytes sources/images/icons/icon144.png | Bin 31114 -> 0 bytes sources/images/icons/icon57.png | Bin 6006 -> 0 bytes sources/images/icons/icon72.png | Bin 8937 -> 0 bytes sources/images/language.png | Bin 1972 -> 0 bytes sources/images/publisher.png | Bin 215 -> 0 bytes sources/images/rating.png | Bin 1304 -> 0 bytes sources/images/recent.png | Bin 1670 -> 0 bytes sources/images/serie.png | Bin 2156 -> 0 bytes sources/images/tag.png | Bin 1082 -> 0 bytes sources/index.php | 75 - sources/lang/Localization_ca.json | 293 - sources/lang/Localization_cs.json | 293 - sources/lang/Localization_da.json | 293 - sources/lang/Localization_de.json | 293 - sources/lang/Localization_el.json | 293 - sources/lang/Localization_en.json | 293 - sources/lang/Localization_es.json | 293 - sources/lang/Localization_eu.json | 293 - sources/lang/Localization_fr.json | 293 - sources/lang/Localization_ht.json | 293 - sources/lang/Localization_hu.json | 293 - sources/lang/Localization_it.json | 293 - sources/lang/Localization_ko.json | 293 - sources/lang/Localization_nb.json | 293 - sources/lang/Localization_nl.json | 293 - sources/lang/Localization_pl.json | 293 - sources/lang/Localization_pt_BR.json | 293 - sources/lang/Localization_pt_PT.json | 293 - sources/lang/Localization_ro.json | 293 - sources/lang/Localization_ru.json | 293 - sources/lang/Localization_sl.json | 293 - sources/lang/Localization_sr.json | 293 - sources/lang/Localization_sv.json | 293 - sources/lang/Localization_tr.json | 293 - sources/lang/Localization_ua.json | 293 - sources/lang/Localization_zh.json | 293 - sources/language.php | 70 - sources/login.html | 98 - sources/publisher.php | 67 - sources/rating.php | 61 - .../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 20127 -> 0 bytes .../fonts/glyphicons-halflings-regular.svg | 288 - .../fonts/glyphicons-halflings-regular.ttf | Bin 45404 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 23424 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 18028 -> 0 bytes .../bootstrap/dist/js/bootstrap.min.js | 7 - sources/resources/doT-php/doT.php | 101 - sources/resources/doT/doT.min.js | 8 - 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/monocle/scripts/monocore.js | 5641 ----------------- sources/resources/monocle/scripts/monoctrl.js | 985 --- sources/resources/monocle/styles/monocore.css | 195 - sources/resources/monocle/styles/monoctrl.css | 169 - 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 --- .../resources/transliteration-data/x00.php | 44 - .../resources/transliteration-data/x01.php | 36 - .../resources/transliteration-data/x02.php | 20 - .../resources/transliteration-data/x03.php | 20 - .../resources/transliteration-data/x04.php | 56 - .../resources/transliteration-data/x05.php | 20 - .../resources/transliteration-data/x06.php | 20 - .../resources/transliteration-data/x07.php | 20 - .../resources/transliteration-data/x09.php | 20 - .../resources/transliteration-data/x0a.php | 20 - .../resources/transliteration-data/x0b.php | 20 - .../resources/transliteration-data/x0c.php | 20 - .../resources/transliteration-data/x0d.php | 20 - .../resources/transliteration-data/x0e.php | 20 - .../resources/transliteration-data/x0f.php | 20 - .../resources/transliteration-data/x10.php | 20 - .../resources/transliteration-data/x11.php | 20 - .../resources/transliteration-data/x12.php | 20 - .../resources/transliteration-data/x13.php | 20 - .../resources/transliteration-data/x14.php | 20 - .../resources/transliteration-data/x15.php | 20 - .../resources/transliteration-data/x16.php | 20 - .../resources/transliteration-data/x17.php | 20 - .../resources/transliteration-data/x18.php | 20 - .../resources/transliteration-data/x1e.php | 20 - .../resources/transliteration-data/x1f.php | 20 - .../resources/transliteration-data/x20.php | 23 - .../resources/transliteration-data/x21.php | 20 - .../resources/transliteration-data/x22.php | 20 - .../resources/transliteration-data/x23.php | 20 - .../resources/transliteration-data/x24.php | 20 - .../resources/transliteration-data/x25.php | 20 - .../resources/transliteration-data/x26.php | 20 - .../resources/transliteration-data/x27.php | 20 - .../resources/transliteration-data/x28.php | 20 - .../resources/transliteration-data/x2e.php | 20 - .../resources/transliteration-data/x2f.php | 20 - .../resources/transliteration-data/x30.php | 20 - .../resources/transliteration-data/x31.php | 20 - .../resources/transliteration-data/x32.php | 20 - .../resources/transliteration-data/x33.php | 20 - .../resources/transliteration-data/x4d.php | 20 - .../resources/transliteration-data/x4e.php | 20 - .../resources/transliteration-data/x4f.php | 20 - .../resources/transliteration-data/x50.php | 20 - .../resources/transliteration-data/x51.php | 20 - .../resources/transliteration-data/x52.php | 20 - .../resources/transliteration-data/x53.php | 20 - .../resources/transliteration-data/x54.php | 20 - .../resources/transliteration-data/x55.php | 20 - .../resources/transliteration-data/x56.php | 20 - .../resources/transliteration-data/x57.php | 20 - .../resources/transliteration-data/x58.php | 20 - .../resources/transliteration-data/x59.php | 20 - .../resources/transliteration-data/x5a.php | 20 - .../resources/transliteration-data/x5b.php | 20 - .../resources/transliteration-data/x5c.php | 20 - .../resources/transliteration-data/x5d.php | 20 - .../resources/transliteration-data/x5e.php | 20 - .../resources/transliteration-data/x5f.php | 20 - .../resources/transliteration-data/x60.php | 20 - .../resources/transliteration-data/x61.php | 20 - .../resources/transliteration-data/x62.php | 20 - .../resources/transliteration-data/x63.php | 20 - .../resources/transliteration-data/x64.php | 20 - .../resources/transliteration-data/x65.php | 20 - .../resources/transliteration-data/x66.php | 20 - .../resources/transliteration-data/x67.php | 20 - .../resources/transliteration-data/x68.php | 20 - .../resources/transliteration-data/x69.php | 20 - .../resources/transliteration-data/x6a.php | 20 - .../resources/transliteration-data/x6b.php | 20 - .../resources/transliteration-data/x6c.php | 20 - .../resources/transliteration-data/x6d.php | 20 - .../resources/transliteration-data/x6e.php | 20 - .../resources/transliteration-data/x6f.php | 20 - .../resources/transliteration-data/x70.php | 20 - .../resources/transliteration-data/x71.php | 20 - .../resources/transliteration-data/x72.php | 20 - .../resources/transliteration-data/x73.php | 20 - .../resources/transliteration-data/x74.php | 20 - .../resources/transliteration-data/x75.php | 20 - .../resources/transliteration-data/x76.php | 20 - .../resources/transliteration-data/x77.php | 20 - .../resources/transliteration-data/x78.php | 20 - .../resources/transliteration-data/x79.php | 20 - .../resources/transliteration-data/x7a.php | 20 - .../resources/transliteration-data/x7b.php | 20 - .../resources/transliteration-data/x7c.php | 20 - .../resources/transliteration-data/x7d.php | 20 - .../resources/transliteration-data/x7e.php | 20 - .../resources/transliteration-data/x7f.php | 20 - .../resources/transliteration-data/x80.php | 20 - .../resources/transliteration-data/x81.php | 20 - .../resources/transliteration-data/x82.php | 20 - .../resources/transliteration-data/x83.php | 20 - .../resources/transliteration-data/x84.php | 20 - .../resources/transliteration-data/x85.php | 20 - .../resources/transliteration-data/x86.php | 20 - .../resources/transliteration-data/x87.php | 20 - .../resources/transliteration-data/x88.php | 20 - .../resources/transliteration-data/x89.php | 20 - .../resources/transliteration-data/x8a.php | 20 - .../resources/transliteration-data/x8b.php | 20 - .../resources/transliteration-data/x8c.php | 20 - .../resources/transliteration-data/x8d.php | 20 - .../resources/transliteration-data/x8e.php | 20 - .../resources/transliteration-data/x8f.php | 20 - .../resources/transliteration-data/x90.php | 20 - .../resources/transliteration-data/x91.php | 20 - .../resources/transliteration-data/x92.php | 20 - .../resources/transliteration-data/x93.php | 20 - .../resources/transliteration-data/x94.php | 20 - .../resources/transliteration-data/x95.php | 20 - .../resources/transliteration-data/x96.php | 20 - .../resources/transliteration-data/x97.php | 20 - .../resources/transliteration-data/x98.php | 20 - .../resources/transliteration-data/x99.php | 20 - .../resources/transliteration-data/x9a.php | 20 - .../resources/transliteration-data/x9b.php | 20 - .../resources/transliteration-data/x9c.php | 20 - .../resources/transliteration-data/x9d.php | 20 - .../resources/transliteration-data/x9e.php | 20 - .../resources/transliteration-data/x9f.php | 20 - .../resources/transliteration-data/xa0.php | 20 - .../resources/transliteration-data/xa1.php | 20 - .../resources/transliteration-data/xa2.php | 20 - .../resources/transliteration-data/xa3.php | 20 - .../resources/transliteration-data/xa4.php | 20 - .../resources/transliteration-data/xac.php | 20 - .../resources/transliteration-data/xad.php | 20 - .../resources/transliteration-data/xae.php | 20 - .../resources/transliteration-data/xaf.php | 20 - .../resources/transliteration-data/xb0.php | 20 - .../resources/transliteration-data/xb1.php | 20 - .../resources/transliteration-data/xb2.php | 20 - .../resources/transliteration-data/xb3.php | 20 - .../resources/transliteration-data/xb4.php | 20 - .../resources/transliteration-data/xb5.php | 20 - .../resources/transliteration-data/xb6.php | 20 - .../resources/transliteration-data/xb7.php | 20 - .../resources/transliteration-data/xb8.php | 20 - .../resources/transliteration-data/xb9.php | 20 - .../resources/transliteration-data/xba.php | 20 - .../resources/transliteration-data/xbb.php | 20 - .../resources/transliteration-data/xbc.php | 20 - .../resources/transliteration-data/xbd.php | 20 - .../resources/transliteration-data/xbe.php | 20 - .../resources/transliteration-data/xbf.php | 20 - .../resources/transliteration-data/xc0.php | 20 - .../resources/transliteration-data/xc1.php | 20 - .../resources/transliteration-data/xc2.php | 20 - .../resources/transliteration-data/xc3.php | 20 - .../resources/transliteration-data/xc4.php | 20 - .../resources/transliteration-data/xc5.php | 20 - .../resources/transliteration-data/xc6.php | 20 - .../resources/transliteration-data/xc7.php | 20 - .../resources/transliteration-data/xc8.php | 20 - .../resources/transliteration-data/xc9.php | 20 - .../resources/transliteration-data/xca.php | 20 - .../resources/transliteration-data/xcb.php | 20 - .../resources/transliteration-data/xcc.php | 20 - .../resources/transliteration-data/xcd.php | 20 - .../resources/transliteration-data/xce.php | 20 - .../resources/transliteration-data/xcf.php | 20 - .../resources/transliteration-data/xd0.php | 20 - .../resources/transliteration-data/xd1.php | 20 - .../resources/transliteration-data/xd2.php | 20 - .../resources/transliteration-data/xd3.php | 20 - .../resources/transliteration-data/xd4.php | 20 - .../resources/transliteration-data/xd5.php | 20 - .../resources/transliteration-data/xd6.php | 20 - .../resources/transliteration-data/xd7.php | 20 - .../resources/transliteration-data/xf9.php | 20 - .../resources/transliteration-data/xfa.php | 20 - .../resources/transliteration-data/xfb.php | 20 - .../resources/transliteration-data/xfc.php | 20 - .../resources/transliteration-data/xfd.php | 20 - .../resources/transliteration-data/xfe.php | 20 - .../resources/transliteration-data/xff.php | 20 - .../typeahead/typeahead.bundle.min.js | 7 - sources/sendtomail.php | 90 - sources/serie.php | 65 - sources/styles/cops-monocle.css | 273 - sources/styles/cops-monocle.js | 172 - sources/tag.php | 64 - sources/templates/bootstrap/bookdetail.html | 74 - sources/templates/bootstrap/file.html | 150 - sources/templates/bootstrap/footer.html | 0 sources/templates/bootstrap/header.html | 29 - sources/templates/bootstrap/main.html | 67 - sources/templates/bootstrap/page.html | 3 - sources/templates/bootstrap/scripts/cops.js | 4 - .../templates/bootstrap/styles/style-base.css | 3 - .../bootstrap/styles/style-default.css | 3 - sources/templates/bootstrap/suggestion.html | 1 - sources/templates/default/bookdetail.html | 66 - sources/templates/default/file.html | 43 - sources/templates/default/footer.html | 15 - sources/templates/default/header.html | 50 - sources/templates/default/main.html | 50 - sources/templates/default/page.html | 5 - .../templates/default/styles/FontAwesome.otf | Bin 61896 -> 0 bytes .../templates/default/styles/font-awesome.css | 1479 ----- .../default/styles/fontawesome-webfont.eot | Bin 37405 -> 0 bytes .../default/styles/fontawesome-webfont.svg | 399 -- .../default/styles/fontawesome-webfont.ttf | Bin 79076 -> 0 bytes .../default/styles/fontawesome-webfont.woff | Bin 43572 -> 0 bytes .../templates/default/styles/style-base.css | 436 -- .../default/styles/style-default.css | 58 - .../templates/default/styles/style-eink.css | 63 - .../templates/default/styles/style-iphone.css | 116 - .../default/styles/style-iphone7.css | 116 - sources/templates/default/suggestion.html | 1 - sources/transliteration.php | 211 - sources/util.js | 499 -- sources/web.config | 20 - 315 files changed, 37625 deletions(-) delete mode 100644 sources/CHANGELOG delete mode 100644 sources/COPYING delete mode 100644 sources/JSON_renderer.php delete mode 100644 sources/OPDS_renderer.php delete mode 100644 sources/README.md delete mode 100644 sources/about.html delete mode 100644 sources/author.php delete mode 100644 sources/base.php delete mode 100644 sources/book.php delete mode 100644 sources/checkconfig.php delete mode 100644 sources/config.php delete mode 100644 sources/config_default.php delete mode 100644 sources/config_local.php.example delete mode 100644 sources/cops-1.0.1.zip delete mode 100644 sources/customcolumn.php delete mode 100644 sources/data.php delete mode 100644 sources/epubfs.php delete mode 100644 sources/epubreader.php delete mode 100644 sources/favicon.ico delete mode 100644 sources/feed.php delete mode 100644 sources/fetch.php delete mode 100644 sources/getJSON.php delete mode 100644 sources/images/allbook.png delete mode 100644 sources/images/author.png delete mode 100644 sources/images/bookcover.png delete mode 100644 sources/images/custom.png delete mode 100644 sources/images/icons/icon114.png delete mode 100644 sources/images/icons/icon144.png delete mode 100644 sources/images/icons/icon57.png delete mode 100644 sources/images/icons/icon72.png delete mode 100644 sources/images/language.png delete mode 100644 sources/images/publisher.png delete mode 100644 sources/images/rating.png delete mode 100644 sources/images/recent.png delete mode 100644 sources/images/serie.png delete mode 100644 sources/images/tag.png delete mode 100644 sources/index.php delete mode 100644 sources/lang/Localization_ca.json delete mode 100644 sources/lang/Localization_cs.json delete mode 100644 sources/lang/Localization_da.json delete mode 100644 sources/lang/Localization_de.json delete mode 100644 sources/lang/Localization_el.json delete mode 100644 sources/lang/Localization_en.json delete mode 100644 sources/lang/Localization_es.json delete mode 100644 sources/lang/Localization_eu.json delete mode 100644 sources/lang/Localization_fr.json delete mode 100644 sources/lang/Localization_ht.json delete mode 100644 sources/lang/Localization_hu.json delete mode 100644 sources/lang/Localization_it.json delete mode 100644 sources/lang/Localization_ko.json delete mode 100644 sources/lang/Localization_nb.json delete mode 100644 sources/lang/Localization_nl.json delete mode 100644 sources/lang/Localization_pl.json delete mode 100644 sources/lang/Localization_pt_BR.json delete mode 100644 sources/lang/Localization_pt_PT.json delete mode 100644 sources/lang/Localization_ro.json delete mode 100644 sources/lang/Localization_ru.json delete mode 100644 sources/lang/Localization_sl.json delete mode 100644 sources/lang/Localization_sr.json delete mode 100644 sources/lang/Localization_sv.json delete mode 100644 sources/lang/Localization_tr.json delete mode 100644 sources/lang/Localization_ua.json delete mode 100644 sources/lang/Localization_zh.json delete mode 100644 sources/language.php delete mode 100644 sources/login.html delete mode 100644 sources/publisher.php delete mode 100644 sources/rating.php delete mode 100644 sources/resources/Magnific-Popup/jquery.magnific-popup.min.js delete mode 100644 sources/resources/Magnific-Popup/magnific-popup.css delete mode 100644 sources/resources/PHPMailer/LICENSE delete mode 100644 sources/resources/PHPMailer/README.md delete mode 100644 sources/resources/PHPMailer/class.phpmailer.php delete mode 100644 sources/resources/PHPMailer/class.pop3.php delete mode 100644 sources/resources/PHPMailer/class.smtp.php delete mode 100644 sources/resources/bootstrap/LICENSE delete mode 100644 sources/resources/bootstrap/README.md delete mode 100644 sources/resources/bootstrap/dist/css/bootstrap-theme.min.css delete mode 100644 sources/resources/bootstrap/dist/css/bootstrap.min.css delete mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.eot delete mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.svg delete mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf delete mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.woff delete mode 100644 sources/resources/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 delete mode 100644 sources/resources/bootstrap/dist/js/bootstrap.min.js delete mode 100644 sources/resources/doT-php/doT.php delete mode 100644 sources/resources/doT/doT.min.js delete mode 100644 sources/resources/jQuery/jquery-1.11.1.min.js delete mode 100644 sources/resources/jquery-cookie/jquery.cookies.js delete mode 100644 sources/resources/jquery-sortelements/jquery.sortElements.js delete mode 100644 sources/resources/lru/lru.js delete mode 100644 sources/resources/monocle/scripts/monocore.js delete mode 100644 sources/resources/monocle/scripts/monoctrl.js delete mode 100644 sources/resources/monocle/styles/monocore.css delete mode 100644 sources/resources/monocle/styles/monoctrl.css delete mode 100644 sources/resources/normalize/normalize.css delete mode 100644 sources/resources/php-epub-meta/LICENSE_php-epub-meta delete mode 100644 sources/resources/php-epub-meta/epub.php delete mode 100644 sources/resources/php-epub-meta/tbszip.php delete mode 100644 sources/resources/transliteration-data/x00.php delete mode 100644 sources/resources/transliteration-data/x01.php delete mode 100644 sources/resources/transliteration-data/x02.php delete mode 100644 sources/resources/transliteration-data/x03.php delete mode 100644 sources/resources/transliteration-data/x04.php delete mode 100644 sources/resources/transliteration-data/x05.php delete mode 100644 sources/resources/transliteration-data/x06.php delete mode 100644 sources/resources/transliteration-data/x07.php delete mode 100644 sources/resources/transliteration-data/x09.php delete mode 100644 sources/resources/transliteration-data/x0a.php delete mode 100644 sources/resources/transliteration-data/x0b.php delete mode 100644 sources/resources/transliteration-data/x0c.php delete mode 100644 sources/resources/transliteration-data/x0d.php delete mode 100644 sources/resources/transliteration-data/x0e.php delete mode 100644 sources/resources/transliteration-data/x0f.php delete mode 100644 sources/resources/transliteration-data/x10.php delete mode 100644 sources/resources/transliteration-data/x11.php delete mode 100644 sources/resources/transliteration-data/x12.php delete mode 100644 sources/resources/transliteration-data/x13.php delete mode 100644 sources/resources/transliteration-data/x14.php delete mode 100644 sources/resources/transliteration-data/x15.php delete mode 100644 sources/resources/transliteration-data/x16.php delete mode 100644 sources/resources/transliteration-data/x17.php delete mode 100644 sources/resources/transliteration-data/x18.php delete mode 100644 sources/resources/transliteration-data/x1e.php delete mode 100644 sources/resources/transliteration-data/x1f.php delete mode 100644 sources/resources/transliteration-data/x20.php delete mode 100644 sources/resources/transliteration-data/x21.php delete mode 100644 sources/resources/transliteration-data/x22.php delete mode 100644 sources/resources/transliteration-data/x23.php delete mode 100644 sources/resources/transliteration-data/x24.php delete mode 100644 sources/resources/transliteration-data/x25.php delete mode 100644 sources/resources/transliteration-data/x26.php delete mode 100644 sources/resources/transliteration-data/x27.php delete mode 100644 sources/resources/transliteration-data/x28.php delete mode 100644 sources/resources/transliteration-data/x2e.php delete mode 100644 sources/resources/transliteration-data/x2f.php delete mode 100644 sources/resources/transliteration-data/x30.php delete mode 100644 sources/resources/transliteration-data/x31.php delete mode 100644 sources/resources/transliteration-data/x32.php delete mode 100644 sources/resources/transliteration-data/x33.php delete mode 100644 sources/resources/transliteration-data/x4d.php delete mode 100644 sources/resources/transliteration-data/x4e.php delete mode 100644 sources/resources/transliteration-data/x4f.php delete mode 100644 sources/resources/transliteration-data/x50.php delete mode 100644 sources/resources/transliteration-data/x51.php delete mode 100644 sources/resources/transliteration-data/x52.php delete mode 100644 sources/resources/transliteration-data/x53.php delete mode 100644 sources/resources/transliteration-data/x54.php delete mode 100644 sources/resources/transliteration-data/x55.php delete mode 100644 sources/resources/transliteration-data/x56.php delete mode 100644 sources/resources/transliteration-data/x57.php delete mode 100644 sources/resources/transliteration-data/x58.php delete mode 100644 sources/resources/transliteration-data/x59.php delete mode 100644 sources/resources/transliteration-data/x5a.php delete mode 100644 sources/resources/transliteration-data/x5b.php delete mode 100644 sources/resources/transliteration-data/x5c.php delete mode 100644 sources/resources/transliteration-data/x5d.php delete mode 100644 sources/resources/transliteration-data/x5e.php delete mode 100644 sources/resources/transliteration-data/x5f.php delete mode 100644 sources/resources/transliteration-data/x60.php delete mode 100644 sources/resources/transliteration-data/x61.php delete mode 100644 sources/resources/transliteration-data/x62.php delete mode 100644 sources/resources/transliteration-data/x63.php delete mode 100644 sources/resources/transliteration-data/x64.php delete mode 100644 sources/resources/transliteration-data/x65.php delete mode 100644 sources/resources/transliteration-data/x66.php delete mode 100644 sources/resources/transliteration-data/x67.php delete mode 100644 sources/resources/transliteration-data/x68.php delete mode 100644 sources/resources/transliteration-data/x69.php delete mode 100644 sources/resources/transliteration-data/x6a.php delete mode 100644 sources/resources/transliteration-data/x6b.php delete mode 100644 sources/resources/transliteration-data/x6c.php delete mode 100644 sources/resources/transliteration-data/x6d.php delete mode 100644 sources/resources/transliteration-data/x6e.php delete mode 100644 sources/resources/transliteration-data/x6f.php delete mode 100644 sources/resources/transliteration-data/x70.php delete mode 100644 sources/resources/transliteration-data/x71.php delete mode 100644 sources/resources/transliteration-data/x72.php delete mode 100644 sources/resources/transliteration-data/x73.php delete mode 100644 sources/resources/transliteration-data/x74.php delete mode 100644 sources/resources/transliteration-data/x75.php delete mode 100644 sources/resources/transliteration-data/x76.php delete mode 100644 sources/resources/transliteration-data/x77.php delete mode 100644 sources/resources/transliteration-data/x78.php delete mode 100644 sources/resources/transliteration-data/x79.php delete mode 100644 sources/resources/transliteration-data/x7a.php delete mode 100644 sources/resources/transliteration-data/x7b.php delete mode 100644 sources/resources/transliteration-data/x7c.php delete mode 100644 sources/resources/transliteration-data/x7d.php delete mode 100644 sources/resources/transliteration-data/x7e.php delete mode 100644 sources/resources/transliteration-data/x7f.php delete mode 100644 sources/resources/transliteration-data/x80.php delete mode 100644 sources/resources/transliteration-data/x81.php delete mode 100644 sources/resources/transliteration-data/x82.php delete mode 100644 sources/resources/transliteration-data/x83.php delete mode 100644 sources/resources/transliteration-data/x84.php delete mode 100644 sources/resources/transliteration-data/x85.php delete mode 100644 sources/resources/transliteration-data/x86.php delete mode 100644 sources/resources/transliteration-data/x87.php delete mode 100644 sources/resources/transliteration-data/x88.php delete mode 100644 sources/resources/transliteration-data/x89.php delete mode 100644 sources/resources/transliteration-data/x8a.php delete mode 100644 sources/resources/transliteration-data/x8b.php delete mode 100644 sources/resources/transliteration-data/x8c.php delete mode 100644 sources/resources/transliteration-data/x8d.php delete mode 100644 sources/resources/transliteration-data/x8e.php delete mode 100644 sources/resources/transliteration-data/x8f.php delete mode 100644 sources/resources/transliteration-data/x90.php delete mode 100644 sources/resources/transliteration-data/x91.php delete mode 100644 sources/resources/transliteration-data/x92.php delete mode 100644 sources/resources/transliteration-data/x93.php delete mode 100644 sources/resources/transliteration-data/x94.php delete mode 100644 sources/resources/transliteration-data/x95.php delete mode 100644 sources/resources/transliteration-data/x96.php delete mode 100644 sources/resources/transliteration-data/x97.php delete mode 100644 sources/resources/transliteration-data/x98.php delete mode 100644 sources/resources/transliteration-data/x99.php delete mode 100644 sources/resources/transliteration-data/x9a.php delete mode 100644 sources/resources/transliteration-data/x9b.php delete mode 100644 sources/resources/transliteration-data/x9c.php delete mode 100644 sources/resources/transliteration-data/x9d.php delete mode 100644 sources/resources/transliteration-data/x9e.php delete mode 100644 sources/resources/transliteration-data/x9f.php delete mode 100644 sources/resources/transliteration-data/xa0.php delete mode 100644 sources/resources/transliteration-data/xa1.php delete mode 100644 sources/resources/transliteration-data/xa2.php delete mode 100644 sources/resources/transliteration-data/xa3.php delete mode 100644 sources/resources/transliteration-data/xa4.php delete mode 100644 sources/resources/transliteration-data/xac.php delete mode 100644 sources/resources/transliteration-data/xad.php delete mode 100644 sources/resources/transliteration-data/xae.php delete mode 100644 sources/resources/transliteration-data/xaf.php delete mode 100644 sources/resources/transliteration-data/xb0.php delete mode 100644 sources/resources/transliteration-data/xb1.php delete mode 100644 sources/resources/transliteration-data/xb2.php delete mode 100644 sources/resources/transliteration-data/xb3.php delete mode 100644 sources/resources/transliteration-data/xb4.php delete mode 100644 sources/resources/transliteration-data/xb5.php delete mode 100644 sources/resources/transliteration-data/xb6.php delete mode 100644 sources/resources/transliteration-data/xb7.php delete mode 100644 sources/resources/transliteration-data/xb8.php delete mode 100644 sources/resources/transliteration-data/xb9.php delete mode 100644 sources/resources/transliteration-data/xba.php delete mode 100644 sources/resources/transliteration-data/xbb.php delete mode 100644 sources/resources/transliteration-data/xbc.php delete mode 100644 sources/resources/transliteration-data/xbd.php delete mode 100644 sources/resources/transliteration-data/xbe.php delete mode 100644 sources/resources/transliteration-data/xbf.php delete mode 100644 sources/resources/transliteration-data/xc0.php delete mode 100644 sources/resources/transliteration-data/xc1.php delete mode 100644 sources/resources/transliteration-data/xc2.php delete mode 100644 sources/resources/transliteration-data/xc3.php delete mode 100644 sources/resources/transliteration-data/xc4.php delete mode 100644 sources/resources/transliteration-data/xc5.php delete mode 100644 sources/resources/transliteration-data/xc6.php delete mode 100644 sources/resources/transliteration-data/xc7.php delete mode 100644 sources/resources/transliteration-data/xc8.php delete mode 100644 sources/resources/transliteration-data/xc9.php delete mode 100644 sources/resources/transliteration-data/xca.php delete mode 100644 sources/resources/transliteration-data/xcb.php delete mode 100644 sources/resources/transliteration-data/xcc.php delete mode 100644 sources/resources/transliteration-data/xcd.php delete mode 100644 sources/resources/transliteration-data/xce.php delete mode 100644 sources/resources/transliteration-data/xcf.php delete mode 100644 sources/resources/transliteration-data/xd0.php delete mode 100644 sources/resources/transliteration-data/xd1.php delete mode 100644 sources/resources/transliteration-data/xd2.php delete mode 100644 sources/resources/transliteration-data/xd3.php delete mode 100644 sources/resources/transliteration-data/xd4.php delete mode 100644 sources/resources/transliteration-data/xd5.php delete mode 100644 sources/resources/transliteration-data/xd6.php delete mode 100644 sources/resources/transliteration-data/xd7.php delete mode 100644 sources/resources/transliteration-data/xf9.php delete mode 100644 sources/resources/transliteration-data/xfa.php delete mode 100644 sources/resources/transliteration-data/xfb.php delete mode 100644 sources/resources/transliteration-data/xfc.php delete mode 100644 sources/resources/transliteration-data/xfd.php delete mode 100644 sources/resources/transliteration-data/xfe.php delete mode 100644 sources/resources/transliteration-data/xff.php delete mode 100644 sources/resources/typeahead/typeahead.bundle.min.js delete mode 100644 sources/sendtomail.php delete mode 100644 sources/serie.php delete mode 100644 sources/styles/cops-monocle.css delete mode 100644 sources/styles/cops-monocle.js delete mode 100644 sources/tag.php delete mode 100644 sources/templates/bootstrap/bookdetail.html delete mode 100644 sources/templates/bootstrap/file.html delete mode 100644 sources/templates/bootstrap/footer.html delete mode 100644 sources/templates/bootstrap/header.html delete mode 100644 sources/templates/bootstrap/main.html delete mode 100644 sources/templates/bootstrap/page.html delete mode 100644 sources/templates/bootstrap/scripts/cops.js delete mode 100644 sources/templates/bootstrap/styles/style-base.css delete mode 100644 sources/templates/bootstrap/styles/style-default.css delete mode 100644 sources/templates/bootstrap/suggestion.html delete mode 100644 sources/templates/default/bookdetail.html delete mode 100644 sources/templates/default/file.html delete mode 100644 sources/templates/default/footer.html delete mode 100644 sources/templates/default/header.html delete mode 100644 sources/templates/default/main.html delete mode 100644 sources/templates/default/page.html delete mode 100644 sources/templates/default/styles/FontAwesome.otf delete mode 100644 sources/templates/default/styles/font-awesome.css delete mode 100644 sources/templates/default/styles/fontawesome-webfont.eot delete mode 100644 sources/templates/default/styles/fontawesome-webfont.svg delete mode 100644 sources/templates/default/styles/fontawesome-webfont.ttf delete mode 100644 sources/templates/default/styles/fontawesome-webfont.woff delete mode 100644 sources/templates/default/styles/style-base.css delete mode 100644 sources/templates/default/styles/style-default.css delete mode 100644 sources/templates/default/styles/style-eink.css delete mode 100644 sources/templates/default/styles/style-iphone.css delete mode 100644 sources/templates/default/styles/style-iphone7.css delete mode 100644 sources/templates/default/suggestion.html delete mode 100644 sources/transliteration.php delete mode 100644 sources/util.js delete mode 100644 sources/web.config diff --git a/sources/CHANGELOG b/sources/CHANGELOG deleted file mode 100644 index 891c85d..0000000 --- a/sources/CHANGELOG +++ /dev/null @@ -1,286 +0,0 @@ -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. - * Fixed checkconfig.php to avoid sending content before headers. Thanks to Luke Stevenson. - * Fixed server side rendering with custom columns. - * Moved /icons to /images (Apache issues). Thanks to CgX. - -1.0.0 - 20160708 - * Updated the OPDS icons to better looking ones. Thanks to Horus68. - * Updated the README.md. - * Updated Brazillian, French, Hungarian, Portuguese, Russian translations. - * Added support of language and country code. This allow to have proper Brazil Portuguese and Portugal Portuguese. - * Added Korean translation. Thanks to Jin, Heonkyu. - * Added Romanian translation. Thanks to mtzro2003. - * Added Greek translation. Thanks to George Litos. - * Added Turkish Translation. Thanks to Yunus Emre Deligöz. - * Added Serbian Translation. Thanks to Dalibor Vinkić. - * Added the transliteration of search text. You can enable it with $config ['cops_normalized_search']. Thanks to George Litos. - * Added Ebookdroid, Chunky and AlReader in the know OPDS clients. Thanks to Mike Ferenduros and Horus68. - * Added some mime types for audio books. - * Added the rewrite rule for IIS. - * Added a now parameter to set the style ($config['cops_style']). Thanks to Pablo Santiago Blum de Aguiar. - * Added a directory cache ($config['cops_thumbnail_cache_directory']) to store the resized thumbnails (should help on slow NAS). Thanks to O2 Graphics. - * Added support of all kind of custom columns (see configuration file). Thanks to Mike Schwörer. - * Fixed COPS so that it's completely embedded (no external resources to download needed anymore). - * Fixed a Reflected XSS vulnerability. - * Fixed the tag filters with Bootstrap. Thanks to Klaus Broelemann. - * Fixed some COPS path errors with reverse proxy. Thanks to Benjamin Kitt. - * Fixed the publication date (wasn't working for date before 1901). - * Fixed the download file name (replace + by %20 to be RFC compliant). - - -1.0.0RC3 - 20141229 - * Fixed server side render with Bootstrap template (a proper unit test was also added). - * Upgraded to latest doT-php, Typeahead 0.10.5, jquery-cookie 1.4.1, JQuery 1.11.1 - * Fixed book count with custom columns. - * Updated Catalan, Dutch, French and Russian translations. - * Added AZW3 to the format that can be sent to Kindle (by mail). - * Fixed $config['cops_thumbnail_handling'] with bootstrap template. - * Added Hungarian translation. Thanks to harunibn. - * Added Ukrainian translation. Thanks to Anatoliy Zavalinich - * Added full PHP password check (without any need from specific webserver configuration). Thanks to Mark Bond. - * Added new IOS7 style with default template. Thanks to an anonymous source ;). - * Fixed display of authors names for books with more than one author. - * Added PHP version to checkconfig.php (will help debugging for me). - * Added a configuration item ($config['cops_template']) to change the default template. Thanks to Shin. - * Added a configuration item ($config['cops_language']) to force COPS language. Thanks to Sandy Pleyte. - * Added a trick to have user based configuration, check https://github.com/seblucas/cops/wiki/User-based-config for more information. Thanks to Sandy Pleyte. - * Changed the default sort order on books by author page to show books in a series before all other books. - - -1.0.0RC2 - 20140731 - * Updated Italian, Spanish, Portuguese, Norwegian translations. - * Added Polish translation. Thanks to macak_pl. - * Added Haitian Creole translation. Thanks to Ian Macdonald & Jacinta. - * Added Basque translation. Thanks to Turutarena. - * Upgraded to JQuery 1.11.0, Magnific Popup 0.9.9, Normalize 3.0.1, Typeahead 0.10.2 - * Fixed search with accentuated characters on Internet Explorer. - * Author can now be searched by sort or by name (Carroll, Lewis or Lewis Carroll will work). - * Added a new bootstrap user interface. - * Added correct mimetype for *.ibooks. Reported by Flowney. - * Added an empty line at the end of .htaccess to make it easier to modify. Reported by Mariosipad. - * Modified the README and checkconfig.php to check for php5-json. Reported by Mariosipad. - * Handled properly the cancelling of a mail. Reported by coach0742. - * Added an ugly hack to try to fix bad rendering with Kindle. Please report if it's better or not. - -1.0.0RC1 - 20140404 - * Updated English, Spanish, German, Italian, Portuguese, Dutch translation files. Huge thanks to all to the translators. - * Added Swedish translation. Thanks to Bo Rosén. - * Added Czech translation. Thanks to Zdenek Hadrava. - * Added a lot of refactoring to simplify the code. - * Added a lot of new unit tests. - * Fixed a caching bug causing problems with IE. - * Added an embedded Epub Reader based on Monocle. Thanks to all the beta testers. - * Cleaned up a lot of stuff to prepare for bootstrap template. Note to all CSS hackers, the stylesheets are now in templates/default/styles. - * Fixed the charset of most of the pages. Thanks to edent. - * Added a new category : ratings. Thanks to Michael. - * Fixed the URL rewriting in the OPDS stream, should fix file naming with FBReader. Reported by Rassie. - * Fixed a confusion between author's name and author's sort. Reported by At_Libitum. - * Fixed the style of the tag filters to show that they're clickable. Thanks to cycojesus. - * Replaced | by space in author name. - -0.9.0 - 20131231 - * Add a lot of unit testing. I hope it will limit the risks of regression. - * Added a "smart / autocomplete" search. - * Updated the way locales are handled. Should be easier to add new languages. - * Fixed display of Cyrillic characters. - * Upgraded doT to version 1.0.1, Magnific-Popup to 0.9.8, Normalize.css to 2.1.3, Jquery-cookie to 1.4.0. - * Fixed OPDS stream validity. Reported by Didier. - * Added a new check in checkconfig.php to detect case problem between the actual path and the path stored in Calibre database. Try checkconfig.php?full=1. Reported by Ruud. - * Fixed the display of the rating stars with Chrome. Thanks to At_Libitum. - * Added a new parameter ($config['cops_titles_split_first_letter']) to avoid splitting the books by first letter. Thanks to At_Libitum. - * Fixed non compliant OPDS search (for Stanza, Moon+ Reader, ...). Reported by At_Libitum. - * Fixed the redirection in case the Calibre database is not found. Reported by At_Libitum - * Changed .htaccess to allow the use of password protected catalogs with Sony's eReader (PRS-TX). Thanks to Ruud for the beta testing. - * Updated Chinese, German, Norwegian, Portuguese, Russian translations. Huge thanks to all the translators. - * Fixed a small problem : If a book had no summary the cover could be cut. - * Fix COPS on Internet Explorer 9. Reported by At_Libitum. - * Added publishers in home categories / search / autocomplete search. - * Added a new configuration item ($config ['cops_ignored_categories']) to ignore some categories (author, tag, publisher, ...) in home screen and searches. It's also available in the "Customize UI" page. - * Updated .htaccess to allow downloading books with a password protected COPS on a Sony PRS-TX. Reported by Ruud. - * Changed the default search to search by categories also (should help with OPDS). Thanks to At_Libitum. - * Fixed the tag filtering in the HTML catalog when two tags starts by the same word. Reported by Tyler. - -0.6.2 - 20130913 - * Added server side rendering for devices like PRS-TX / Kindle / Cybook. Thanks to all the testers. - * Added a configuration item to tweak how thumbnail are handled. - * Fixed the click on cog on IOS. Thanks to sb domo. - * Added dashboard icons / standalone mode for IOS. Thanks to sb domo. - * Fixed a regression about custom favicon.ico. Thanks to Tyler. - * Fixed another regression about COPS's version in the about box. Reported by Ian. - * Upgraded Magnific Popup to v0.9.5. - * Added a style for IPhone. Thanks to sb domo. - * Added Portuguese translation. Thanks to Pablo Aguiar. - * Fixed rendering on Internet Explorer < 9.0. - -0.6.1 - 20130730 - * Properly close the lightbox when clicking in a link. Reported by le_. - * Fix the book by languages list when the language is not found in the resources. Reported by le_. - * Fix the string for Portuguese. Reported by le_. - * Add again the series Index in the book list. Reported by fatzgenfatz. - -0.6.0 - 20130724 - * COPS HTML catalog now use templated client side rendering. You can build your own template if you want. Should be a lot faster. - * Fancybox has been replaced by Magnific Popup, it seems faster. - * Added a way to send book by mail (to send to Kindle or to send to your friends). - * Added expires instruction in .htaccess (won't crash if you haven't enabled mod_expires). - * Upgrade to JQuery 1.10.2. - * Changed the way thumbnails are handled to offer greater visual quality (especially on high pixel density devices : Retina, Nexus, ...). - * Changed all icon by a vectorial font (again better visual quality). - * Added a way to filter books by tags. - * Added a login page (login.html) to allow access to a password protected COPS on a Kobo ereader (that does not support basic auth). - * Fixed cookie expiry date. - * Added a default web.config for IIS installation. - * The eink style doesn't use shadow anymore. - * Fixed the link to the series in book detail. - -0.5.0 - 20130605 - * Upgrade COPS UI to HTML5 / CSS3 to hopefully make it prettier. Most of the code was contributed by Thomas Severinsen. - * Add the number of books in each databases (when multiple database is enabled). - * Add Norwegian Bokmål strings. Thanks to Rune Mathisen for the pull request. - * Add a split by language of catalog. Thanks to Puiu Ionut for the pull request. - * You can now change the theme and fancybox use on all your devices (You have to enable cookies). - * Add an eink theme. Thanks to Gregory Bodin for the code. - -0.4.0 - 20130507 - * Add multiple database support. Check the documentation of $config['calibre_directory'] in config-default.php to see how to enable it. - * Include jquery library in COPS's repository to be sure that COPS will work on LAN (without Internet access). - * Prepare the switch to HTML5. Thanks to Thomas Severinsen for most of the code. - * Update the locale strings to be more strict with plurals. Thanks to Tobias Ausländer for the code. - * If Fancybox is not enabled ($config['cops_use_fancyapps'] = "0") then it's not used at all (even in the about box). - * Fix book comments if it contains UTF8 characters. Reported by Alain. - * Link to the book permalink was not working correctly in some cases. Reported by celta. - * Moved some external resources to a resources directory. - * Add chinese translation. Thanks to wogong for the pull request. - -0.3.4 - 20130327 - * Hopefully fix metadata update. Beware you should remove the directory php-epub-meta if you have one. Thanks to Mario for his time. - * Fix two warnings. Reported by Goner and Mario. - -0.3.3 - 20130323 - * Fix catalog if book summary contains bad HTML again :(. - * Upgrade to Fancybox 2.4.0 and JQuery 1.9.1. - * Search is now dependant on the page you're in. For now if you're on author page it'll look for author name. - * Update checkconfig to check if the database provided comes from Calibre. - * Update to latest php-epub-meta should fix the metadata update with Epub. - * Fix OPDS catalog with Ibis Reader. It didn't like empty language. - -0.3.2 - 20130303 - * Add dutch translation. Provided by Northguy. - * Fix an ugly bug introduced in 0.3.1. Reported by mariosipad. - * Small fixes/enhancement to the update metadata tools : - * The book's name is Author - Title.epub - * Add the Calibre uuid so that the book is automatically recognised by Calibre. - * Update the cover - * Fix display of the HTML catalog on Kobo's browser. - * Enable kepub.epub download with cover fix (enable with $config['cops_provide_kepub']). - * Hopefully fix browsing with PRS-T1. Thanks to Northguy. - * Hopefully fix the OPDS catalog when the summary is full of HTML crap. - * Merged 3 patches from Tyler J. Wagner : - * Detect empty publication date set in Calibre to avoid having (0101) as publication year. - * Don't print "Languages" if there are none defined. - * Don't print the tag string if there's no tags. - * If an OPDS client try to access index.php it will be automatically redirected to feed.php. - * Move the search & sort tool box to a new line (also fix a w3c error). - - -0.3.1 - 20130127 - * Add Facets to the OPDS catalog (check config item cops_books_filter). - So far the only OPDS client that support facets are Mantano Reader and Bluefire - * Fix book sort in some list. Patch provided by Tyler J. Wagner. - * Update .htaccess to check if Xsendfile is available. Thanks to Gaspine for the patch. - * Add basic support of custom columns. Check the following config item : cops_calibre_custom_column - * Usage of X-Accel-Redirect / X-Sendfile is not necessary anymore. Warning all Nginx users - who wants to still use X-Accel-Redirect must add - $config['cops_x_accel_redirect'] = "X-Accel-Redirect" in their config_local.php - * Fix COPS on IIS / Windows. Reported by Kevnancy. - * Simplified config_default.php - * Add a new config_local.php.example with the minimal configuration item to change. - - -0.3.0 - 20130106 - * Add a config item to avoid using Fancyapps (pop-ups). Reported by mcister and Northguy. - * Update documentation of .htaccess. Thanks to Stephane. - * Add a config item to specify a custom icon. Based on a patch by Tyler J. Wagner. - * Better handling of content type for book. Reported by Morg. - * Upped the size of thumbnails for OPDS. They look way better with Mantano. - * Add language in OPDS feed (shown in Mantano for example). - * Update metadata on downloaded epub. Disabled by default (check config item cops_update_epub-metadata). - * New Catalan translation provided by David Ciscar Presas. - * Add a permalink to books, that way direct link to books can be shared. Reported by mcister and Tyler J. Wagner. - * Add checkconfig.php that should allow to better detect the configuration problem (page in english only for now). - * Fix some plural strings / some missing title. Reported by David Ciscar Presas. - * Add an hint about the OPDS catalog in the HTML catalog. - -0.2.3 - 20121205 - * Add a .htaccess to make it easier to use with Apache - * Fix a typo in book download. Reported by jillmess - * Update localization (thanks to Calibre2Opds) - * Add some missing information from Calibre (language, rating for now). Reported by mcister - * Upgrade Fancybox to 2.1.3 - - -0.2.2 - 20121020 - * Changed JQuery URL to https (thanks to Dan Greve for the patch) - * Added paging to both OPDS and HTML catalog (use new config item cops_max_item_per_page) - * lots of code refactoring - * Authors are now splitted by first letter, this is the new default. You can go back to the old way with the config item cops_author_split_first_letter (reported by Northguy) - * Fix the link to books starting by special characters (reported by vinpel) - * Upgrade to Fancyapps 2.1.0. I had to adapt the CSS so maybe it'll display better in PRS-T1 - * Add an about box on the HTML catalog which show the current version - -0.2.1 - 20120916 - * Fix one last error (hopefully) in link generation (thanks to gaspine) - * Add Sony PRS-T1 to the list of E-Ink device (thanks to Northguy) - * Fix another HTML special characters problem (thanks to NeilBryant) - * Add an ugly config parameter to allow search in non-compliant OPDS reader (thanks to Don Caruana and David Lee) - -0.2.0 - 20120722 - * Fix all rewriting rule I forgot to change it in last release - * Fix
in book comment (thanks to jillmess) - * Fix cover zoom in HTML catalog (you can also navigate through cover with keyboard) - * Simplify Fancybox transition for e-Ink devices (for now Kobo and Kindle) - -0.1.1 - 20120702 - * A lot of bug fixes in HTML catalog - * Fixed the book comment in OPDS (broken in some rare case) - * Fixed handling of HTML reserved characters - * Changed book OPDS id to use an UUID (thanks to ilovejedd for the bug report) - * Add new config item for the default timezone (thanks to gaspine) - * Better handling of missing covers - * Should support every book format supported by Calibre (thanks to Artem) - * URL rewriting is off by default for the HTML catalog - * Add some documentation about URL rewriting (thanks to gaspine and Christophe) - * Tested and ready to use with PHP5.4 - -0.1.0 - 20120605 - * Add localization support (thanks to Calibre2Opds) - * Hopefully fixed an issue with & in comment - * HTML catalog is in the sources with no support (WIP) - -0.0.4 - 20120523 - * More code refactoring to simplify code. - * Changed OPDS Page id to match Calibre2Opds - * Add icons to author, serie, tags and recent items (there is config item to disable it) - * Fixed author URL - * Added publishing date (works on Mantano) - * Added Tags support - -0.0.3 - 20120507 - * Fixed many things blocking opensearch from working - * There was a bug introduced in 0.0.2 - * The URL can't be relative for Mantano reader, so I added a configuration item. - * I continued the refactoring to bring HTML to COPS - * Thumbnails have bigger size (I'll add a configuration item later) - * Add headers to help caching image and thumbnail to the browser - * - -0.0.2 - 20120411 - * Add support for MOBI and PDF - * Major refactoring to prepare something nice for the future ;) - * Add a config item to make use of X-Sendfile instead of X-Accel-Redirect if needed - -0.0.1 - 20120302 - * First public release diff --git a/sources/COPYING b/sources/COPYING deleted file mode 100644 index d60c31a..0000000 --- a/sources/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/sources/JSON_renderer.php b/sources/JSON_renderer.php deleted file mode 100644 index ecca867..0000000 --- a/sources/JSON_renderer.php +++ /dev/null @@ -1,255 +0,0 @@ - - */ - -require_once ("base.php"); -require_once ("book.php"); - -class JSONRenderer -{ - /** - * @param Book $book - * @return array - */ - public static function getBookContentArray ($book) { - global $config; - $i = 0; - $preferedData = array (); - foreach ($config['cops_prefered_format'] as $format) - { - if ($i == 2) { break; } - if ($data = $book->getDataFormat ($format)) { - $i++; - array_push ($preferedData, array ("url" => $data->getHtmlLink (), "name" => $format)); - } - } - - $publisher = $book->getPublisher(); - if (is_null ($publisher)) { - $pn = ""; - $pu = ""; - } else { - $pn = $publisher->name; - $link = new LinkNavigation ($publisher->getUri ()); - $pu = $link->hrefXhtml (); - } - - $serie = $book->getSerie (); - if (is_null ($serie)) { - $sn = ""; - $scn = ""; - $su = ""; - } else { - $sn = $serie->name; - $scn = str_format (localize ("content.series.data"), $book->seriesIndex, $serie->name); - $link = new LinkNavigation ($serie->getUri ()); - $su = $link->hrefXhtml (); - } - $cc = $book->getCustomColumnValues($config['cops_calibre_custom_column_list'], true); - - return array ("id" => $book->id, - "hasCover" => $book->hasCover, - "preferedData" => $preferedData, - "rating" => $book->getRating (), - "publisherName" => $pn, - "publisherurl" => $pu, - "pubDate" => $book->getPubDate (), - "languagesName" => $book->getLanguages (), - "authorsName" => $book->getAuthorsName (), - "tagsName" => $book->getTagsName (), - "seriesName" => $sn, - "seriesIndex" => $book->seriesIndex, - "seriesCompleteName" => $scn, - "seriesurl" => $su, - "customcolumns_list" => $cc); - } - - /** - * @param Book $book - * @return array - */ - public static function getFullBookContentArray ($book) { - global $config; - $out = self::getBookContentArray ($book); - $database = GetUrlParam (DB); - - $out ["coverurl"] = Data::getLink ($book, "jpg", "image/jpeg", Link::OPDS_IMAGE_TYPE, "cover.jpg", NULL)->hrefXhtml (); - $out ["thumbnailurl"] = Data::getLink ($book, "jpg", "image/jpeg", Link::OPDS_THUMBNAIL_TYPE, "cover.jpg", NULL, NULL, $config['cops_html_thumbnail_height'] * 2)->hrefXhtml (); - $out ["content"] = $book->getComment (false); - $out ["datas"] = array (); - $dataKindle = $book->GetMostInterestingDataToSendToKindle (); - foreach ($book->getDatas() as $data) { - $tab = array ("id" => $data->id, "format" => $data->format, "url" => $data->getHtmlLink (), "mail" => 0, "readerUrl" => ""); - if (!empty ($config['cops_mail_configuration']) && !is_null ($dataKindle) && $data->id == $dataKindle->id) { - $tab ["mail"] = 1; - } - if ($data->format == "EPUB") { - $tab ["readerUrl"] = "epubreader.php?data={$data->id}&db={$database}"; - } - array_push ($out ["datas"], $tab); - } - $out ["authors"] = array (); - foreach ($book->getAuthors () as $author) { - $link = new LinkNavigation ($author->getUri ()); - array_push ($out ["authors"], array ("name" => $author->name, "url" => $link->hrefXhtml ())); - } - $out ["tags"] = array (); - foreach ($book->getTags () as $tag) { - $link = new LinkNavigation ($tag->getUri ()); - array_push ($out ["tags"], array ("name" => $tag->name, "url" => $link->hrefXhtml ())); - } - $out ["customcolumns_preview"] = $book->getCustomColumnValues($config['cops_calibre_custom_column_preview'], true); - - return $out; - } - - public static function getContentArray ($entry) { - if ($entry instanceof EntryBook) { - $out = array ( "title" => $entry->title); - $out ["book"] = self::getBookContentArray ($entry->book); - return $out; - } - return array ( "title" => $entry->title, "content" => $entry->content, "navlink" => $entry->getNavLink (), "number" => $entry->numberOfElement ); - } - - public static function getContentArrayTypeahead ($page) { - $out = array (); - foreach ($page->entryArray as $entry) { - if ($entry instanceof EntryBook) { - array_push ($out, array ("class" => $entry->className, "title" => $entry->title, "navlink" => $entry->book->getDetailUrl ())); - } else { - if (empty ($entry->className) xor Base::noDatabaseSelected ()) { - array_push ($out, array ("class" => $entry->className, "title" => $entry->title, "navlink" => $entry->getNavLink ())); - } else { - array_push ($out, array ("class" => $entry->className, "title" => $entry->content, "navlink" => $entry->getNavLink ())); - } - } - } - return $out; - } - - public static function addCompleteArray ($in) { - global $config; - $out = $in; - - $out ["c"] = array ("version" => VERSION, "i18n" => array ( - "coverAlt" => localize("i18n.coversection"), - "authorsTitle" => localize("authors.title"), - "bookwordTitle" => localize("bookword.title"), - "tagsTitle" => localize("tags.title"), - "seriesTitle" => localize("series.title"), - "customizeTitle" => localize ("customize.title"), - "aboutTitle" => localize ("about.title"), - "previousAlt" => localize ("paging.previous.alternate"), - "nextAlt" => localize ("paging.next.alternate"), - "searchAlt" => localize ("search.alternate"), - "sortAlt" => localize ("sort.alternate"), - "homeAlt" => localize ("home.alternate"), - "cogAlt" => localize ("cog.alternate"), - "permalinkAlt" => localize ("permalink.alternate"), - "publisherName" => localize("publisher.name"), - "pubdateTitle" => localize("pubdate.title"), - "languagesTitle" => localize("language.title"), - "contentTitle" => localize("content.summary"), - "sortorderAsc" => localize("search.sortorder.asc"), - "sortorderDesc" => localize("search.sortorder.desc"), - "customizeEmail" => localize("customize.email")), - "url" => array ( - "detailUrl" => "index.php?page=13&id={0}&db={1}", - "coverUrl" => "fetch.php?id={0}&db={1}", - "thumbnailUrl" => "fetch.php?height=" . $config['cops_html_thumbnail_height'] . "&id={0}&db={1}"), - "config" => array ( - "use_fancyapps" => $config ["cops_use_fancyapps"], - "max_item_per_page" => $config['cops_max_item_per_page'], - "kindleHack" => "", - "server_side_rendering" => useServerSideRendering (), - "html_tag_filter" => $config['cops_html_tag_filter'])); - if ($config['cops_thumbnail_handling'] == "1") { - $out ["c"]["url"]["thumbnailUrl"] = $out ["c"]["url"]["coverUrl"]; - } else if (!empty ($config['cops_thumbnail_handling'])) { - $out ["c"]["url"]["thumbnailUrl"] = $config['cops_thumbnail_handling']; - } - if (preg_match("/./", $_SERVER['HTTP_USER_AGENT'])) { - $out ["c"]["config"]["kindleHack"] = 'style="text-decoration: none !important;"'; - } - return $out; - } - - public static function getJson ($complete = false) { - global $config; - $page = getURLParam ("page", Base::PAGE_INDEX); - $query = getURLParam ("query"); - $search = getURLParam ("search"); - $qid = getURLParam ("id"); - $n = getURLParam ("n", "1"); - $database = GetUrlParam (DB); - - $currentPage = Page::getPage ($page, $qid, $query, $n); - $currentPage->InitializeContent (); - - if ($search) { - return self::getContentArrayTypeahead ($currentPage); - } - - $out = array ( "title" => $currentPage->title); - $entries = array (); - foreach ($currentPage->entryArray as $entry) { - array_push ($entries, self::getContentArray ($entry)); - } - if (!is_null ($currentPage->book)) { - $out ["book"] = self::getFullBookContentArray ($currentPage->book); - } - $out ["databaseId"] = GetUrlParam (DB, ""); - $out ["databaseName"] = Base::getDbName (); - if ($out ["databaseId"] == "") { - $out ["databaseName"] = ""; - } - $out ["fullTitle"] = $out ["title"]; - if ($out ["databaseId"] != "" && $out ["databaseName"] != $out ["fullTitle"]) { - $out ["fullTitle"] = $out ["databaseName"] . " > " . $out ["fullTitle"]; - } - $out ["page"] = $page; - $out ["multipleDatabase"] = Base::isMultipleDatabaseEnabled () ? 1 : 0; - $out ["entries"] = $entries; - $out ["isPaginated"] = 0; - if ($currentPage->isPaginated ()) { - $prevLink = $currentPage->getPrevLink (); - $nextLink = $currentPage->getNextLink (); - $out ["isPaginated"] = 1; - $out ["prevLink"] = ""; - if (!is_null ($prevLink)) { - $out ["prevLink"] = $prevLink->hrefXhtml (); - } - $out ["nextLink"] = ""; - if (!is_null ($nextLink)) { - $out ["nextLink"] = $nextLink->hrefXhtml (); - } - $out ["maxPage"] = $currentPage->getMaxPage (); - $out ["currentPage"] = $currentPage->n; - } - if (!is_null (getURLParam ("complete")) || $complete) { - $out = self::addCompleteArray ($out); - } - - $out ["containsBook"] = 0; - if ($currentPage->containsBook ()) { - $out ["containsBook"] = 1; - } - - $out["abouturl"] = "index.php" . addURLParameter ("?page=" . Base::PAGE_ABOUT, DB, $database); - - if ($page == Base::PAGE_ABOUT) { - $temp = preg_replace ("/\About COPS\<\/h1\>/", "

About COPS " . VERSION . "

", file_get_contents('about.html')); - $out ["fullhtml"] = $temp; - } - - $out ["homeurl"] = "index.php"; - if ($page != Base::PAGE_INDEX && !is_null ($database)) $out ["homeurl"] = $out ["homeurl"] . "?" . addURLParameter ("", DB, $database); - - return $out; - } -} \ No newline at end of file diff --git a/sources/OPDS_renderer.php b/sources/OPDS_renderer.php deleted file mode 100644 index 14d1f33..0000000 --- a/sources/OPDS_renderer.php +++ /dev/null @@ -1,278 +0,0 @@ - - */ - -require_once ("base.php"); - -class OPDSRenderer -{ - private $xmlStream = NULL; - private $updated = NULL; - - private function getUpdatedTime () { - if (is_null ($this->updated)) { - $this->updated = time(); - } - return date (DATE_ATOM, $this->updated); - } - - private function getXmlStream () { - if (is_null ($this->xmlStream)) { - $this->xmlStream = new XMLWriter(); - $this->xmlStream->openMemory(); - $this->xmlStream->setIndent (true); - } - return $this->xmlStream; - } - - public function getOpenSearch () { - global $config; - $xml = new XMLWriter (); - $xml->openMemory (); - $xml->setIndent (true); - $xml->startDocument('1.0','UTF-8'); - $xml->startElement ("OpenSearchDescription"); - $xml->writeAttribute ("xmlns", "http://a9.com/-/spec/opensearch/1.1/"); - $xml->startElement ("ShortName"); - $xml->text ("My catalog"); - $xml->endElement (); - $xml->startElement ("Description"); - $xml->text ("Search for ebooks"); - $xml->endElement (); - $xml->startElement ("InputEncoding"); - $xml->text ("UTF-8"); - $xml->endElement (); - $xml->startElement ("OutputEncoding"); - $xml->text ("UTF-8"); - $xml->endElement (); - $xml->startElement ("Image"); - $xml->writeAttribute ("type", "image/x-icon"); - $xml->writeAttribute ("width", "16"); - $xml->writeAttribute ("height", "16"); - $xml->text ($config['cops_icon']); - $xml->endElement (); - $xml->startElement ("Url"); - $xml->writeAttribute ("type", 'application/atom+xml'); - $urlparam = "?query={searchTerms}"; - if (!is_null (GetUrlParam (DB))) $urlparam = addURLParameter ($urlparam, DB, GetUrlParam (DB)); - $urlparam = str_replace ("%7B", "{", $urlparam); - $urlparam = str_replace ("%7D", "}", $urlparam); - $xml->writeAttribute ("template", $config['cops_full_url'] . 'feed.php' . $urlparam); - $xml->endElement (); - $xml->startElement ("Query"); - $xml->writeAttribute ("role", "example"); - $xml->writeAttribute ("searchTerms", "robot"); - $xml->endElement (); - $xml->endElement (); - $xml->endDocument(); - return $xml->outputMemory(true); - } - - private function startXmlDocument ($page) { - global $config; - self::getXmlStream ()->startDocument('1.0','UTF-8'); - self::getXmlStream ()->startElement ("feed"); - self::getXmlStream ()->writeAttribute ("xmlns", "http://www.w3.org/2005/Atom"); - self::getXmlStream ()->writeAttribute ("xmlns:xhtml", "http://www.w3.org/1999/xhtml"); - self::getXmlStream ()->writeAttribute ("xmlns:opds", "http://opds-spec.org/2010/catalog"); - self::getXmlStream ()->writeAttribute ("xmlns:opensearch", "http://a9.com/-/spec/opensearch/1.1/"); - self::getXmlStream ()->writeAttribute ("xmlns:dcterms", "http://purl.org/dc/terms/"); - self::getXmlStream ()->startElement ("title"); - self::getXmlStream ()->text ($page->title); - self::getXmlStream ()->endElement (); - if ($page->subtitle != "") - { - self::getXmlStream ()->startElement ("subtitle"); - self::getXmlStream ()->text ($page->subtitle); - self::getXmlStream ()->endElement (); - } - self::getXmlStream ()->startElement ("id"); - if ($page->idPage) - { - $idPage = $page->idPage; - if (!is_null (GetUrlParam (DB))) $idPage = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":", $idPage); - self::getXmlStream ()->text ($idPage); - } - else - { - self::getXmlStream ()->text ($_SERVER['REQUEST_URI']); - } - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("updated"); - self::getXmlStream ()->text (self::getUpdatedTime ()); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("icon"); - self::getXmlStream ()->text ($page->favicon); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("author"); - self::getXmlStream ()->startElement ("name"); - self::getXmlStream ()->text ($page->authorName); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("uri"); - self::getXmlStream ()->text ($page->authorUri); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("email"); - self::getXmlStream ()->text ($page->authorEmail); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->endElement (); - $link = new LinkNavigation ("", "start", "Home"); - self::renderLink ($link); - $link = new LinkNavigation ("?" . getQueryString (), "self"); - self::renderLink ($link); - $urlparam = "?"; - if (!is_null (GetUrlParam (DB))) $urlparam = addURLParameter ($urlparam, DB, GetUrlParam (DB)); - if ($config['cops_generate_invalid_opds_stream'] == 0 || preg_match("/(MantanoReader|FBReader)/", $_SERVER['HTTP_USER_AGENT'])) { - // Good and compliant way of handling search - $urlparam = addURLParameter ($urlparam, "page", Base::PAGE_OPENSEARCH); - $link = new Link ("feed.php" . $urlparam, "application/opensearchdescription+xml", "search", "Search here"); - } - else - { - // Bad way, will be removed when OPDS client are fixed - $urlparam = addURLParameter ($urlparam, "query", "{searchTerms}"); - $urlparam = str_replace ("%7B", "{", $urlparam); - $urlparam = str_replace ("%7D", "}", $urlparam); - $link = new Link ($config['cops_full_url'] . 'feed.php' . $urlparam, "application/atom+xml", "search", "Search here"); - } - self::renderLink ($link); - if ($page->containsBook () && !is_null ($config['cops_books_filter']) && count ($config['cops_books_filter']) > 0) { - $Urlfilter = getURLParam ("tag", ""); - foreach ($config['cops_books_filter'] as $lib => $filter) { - $link = new LinkFacet ("?" . addURLParameter (getQueryString (), "tag", $filter), $lib, localize ("tagword.title"), $filter == $Urlfilter); - self::renderLink ($link); - } - } - } - - private function endXmlDocument () { - self::getXmlStream ()->endElement (); - self::getXmlStream ()->endDocument (); - return self::getXmlStream ()->outputMemory(true); - } - - private function renderLink ($link) { - self::getXmlStream ()->startElement ("link"); - self::getXmlStream ()->writeAttribute ("href", $link->href); - self::getXmlStream ()->writeAttribute ("type", $link->type); - if (!is_null ($link->rel)) { - self::getXmlStream ()->writeAttribute ("rel", $link->rel); - } - if (!is_null ($link->title)) { - self::getXmlStream ()->writeAttribute ("title", $link->title); - } - if (!is_null ($link->facetGroup)) { - self::getXmlStream ()->writeAttribute ("opds:facetGroup", $link->facetGroup); - } - if ($link->activeFacet) { - self::getXmlStream ()->writeAttribute ("opds:activeFacet", "true"); - } - self::getXmlStream ()->endElement (); - } - - private function getPublicationDate($book) { - $dateYmd = substr($book->pubdate, 0, 10); - $pubdate = \DateTime::createFromFormat('Y-m-d', $dateYmd); - if ($pubdate === false || - $pubdate->format ("Y") == "0101" || - $pubdate->format ("Y") == "0100") { - return ""; - } - return $pubdate->format("Y-m-d"); - } - - private function renderEntry ($entry) { - self::getXmlStream ()->startElement ("title"); - self::getXmlStream ()->text ($entry->title); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("updated"); - self::getXmlStream ()->text (self::getUpdatedTime ()); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("id"); - self::getXmlStream ()->text ($entry->id); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("content"); - self::getXmlStream ()->writeAttribute ("type", $entry->contentType); - if ($entry->contentType == "text") { - self::getXmlStream ()->text ($entry->content); - } else { - self::getXmlStream ()->writeRaw ($entry->content); - } - self::getXmlStream ()->endElement (); - foreach ($entry->linkArray as $link) { - self::renderLink ($link); - } - - if (get_class ($entry) != "EntryBook") { - return; - } - - foreach ($entry->book->getAuthors () as $author) { - self::getXmlStream ()->startElement ("author"); - self::getXmlStream ()->startElement ("name"); - self::getXmlStream ()->text ($author->name); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("uri"); - self::getXmlStream ()->text ("feed.php" . $author->getUri ()); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->endElement (); - } - foreach ($entry->book->getTags () as $category) { - self::getXmlStream ()->startElement ("category"); - self::getXmlStream ()->writeAttribute ("term", $category->name); - self::getXmlStream ()->writeAttribute ("label", $category->name); - self::getXmlStream ()->endElement (); - } - if ($entry->book->getPubDate () != "") { - self::getXmlStream ()->startElement ("dcterms:issued"); - self::getXmlStream ()->text (self::getPublicationDate($entry->book)); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("published"); - self::getXmlStream ()->text (self::getPublicationDate($entry->book) . "T08:08:08Z"); - self::getXmlStream ()->endElement (); - } - - $lang = $entry->book->getLanguages (); - if (!empty ($lang)) { - self::getXmlStream ()->startElement ("dcterms:language"); - self::getXmlStream ()->text ($lang); - self::getXmlStream ()->endElement (); - } - - } - - public function render ($page) { - global $config; - self::startXmlDocument ($page); - if ($page->isPaginated ()) - { - self::getXmlStream ()->startElement ("opensearch:totalResults"); - self::getXmlStream ()->text ($page->totalNumber); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("opensearch:itemsPerPage"); - self::getXmlStream ()->text ($config['cops_max_item_per_page']); - self::getXmlStream ()->endElement (); - self::getXmlStream ()->startElement ("opensearch:startIndex"); - self::getXmlStream ()->text (($page->n - 1) * $config['cops_max_item_per_page'] + 1); - self::getXmlStream ()->endElement (); - $prevLink = $page->getPrevLink (); - $nextLink = $page->getNextLink (); - if (!is_null ($prevLink)) { - self::renderLink ($prevLink); - } - if (!is_null ($nextLink)) { - self::renderLink ($nextLink); - } - } - foreach ($page->entryArray as $entry) { - self::getXmlStream ()->startElement ("entry"); - self::renderEntry ($entry); - self::getXmlStream ()->endElement (); - } - return self::endXmlDocument (); - } -} - diff --git a/sources/README.md b/sources/README.md deleted file mode 100644 index 526c220..0000000 --- a/sources/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# COPS - -COPS stands for Calibre OPDS (and HTML) Php Server. - -See : [COPS's home](http://blog.slucas.fr/en/oss/calibre-opds-php-server) for more details. - -Don't forget to check the [Wiki](https://github.com/seblucas/cops/wiki). - -[![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?s=1e21d8c3bf96d7b0b7cc0e54429fa897ddea1506)](https://scrutinizer-ci.com/g/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) - -# Why ? - -In my opinion Calibre is a marvelous tool but is too big and has too much -dependencies to be used for its content server. - -That's the main reason why I coded this OPDS server. I needed a simple -tool to be installed on a small server (Seagate Dockstar in my case). - -I initially thought of Calibre2OPDS but as it generate static file no -search was possible. - -Later I added an simple HTML catalog that should be usable on my Kobo. - -So COPS's main advantages are : - * No need for many dependencies. - * No need for a lot of CPU or RAM. - * Not much code. - * Search is available. - * With Dropbox / owncloud it's very easy to have an up to date OPDS server. - * It was fun to code. - -If you want to use the OPDS feed don't forget to specify feed.php at the end of your URL. - -# Prerequisites - -1. PHP 5.3, 5.4, 5.5, 5.6 or hhvm with GD image processing, Libxml, Intl, Json & SQLite3 support. -2. A web server with PHP support. I only tested with various version of Nginx. - Other people reported it working with Apache and Cherokee. You can also use PHP - embedded server (https://github.com/seblucas/cops/wiki/Howto---PhpEmbeddedServer) -3. The path to a calibre library (metadata.db, format, & cover files). - -On any Debian base Linux you can use : - aptitude install php5-gd php5-sqlite php5-json php5-intl - -On Centos you may have to add : - yum install php-xml - -# Install - -1. Extract the zip file to a folder in web space (visible to the web server). -2. If you're doing a first-time install, copy config_local.php.example to config_local.php -3. Edit config_local.php to match your config. -4. If needed add other configuration item from config_default.php - -If you choose to put your Calibre directory inside your web directory then you -will have to edit /etc/nginx/mime.types to add this line : -application/epub+zip epub; - -If you like Docker, you can also try [this project](https://github.com/linuxserver/docker-cops) - -# Known problems - -Not a lot, except for the bad quality of the code (first PHP project ever) ;) - -Please see https://github.com/seblucas/cops/issues for open issues - -# Need help - -Please read https://github.com/seblucas/cops/wiki and check the FAQ. - -# Credits - - * Locale message handling is inspired of http://www.mind-it.info/2010/02/22/a-simple-approach-to-localization-in-php/ - * str_format function come from http://tmont.com/blargh/2010/1/string-format-in-php - * All icons come from Font Awesome : http://fontawesome.github.io/Font-Awesome/ - * The unofficial OPDS validator : http://opds-validator.appspot.com/ - * Thanks to all testers, translators and contributors. - * Feed icons made by Freepik from Flaticon website licensed under Creative Commons BY 3.0 http://www.flaticon.com and http://www.freepik.com - -External libraries used : - * JQuery : http://jquery.com/ - * Magnific Popup : http://dimsemenov.com/plugins/magnific-popup/ - * Php-epub-meta : https://github.com/splitbrain/php-epub-meta with some modification by me - https://github.com/seblucas/php-epub-meta - * TbsZip : http://www.tinybutstrong.com/apps/tbszip/tbszip_help.html - * DoT.js : http://olado.github.io/doT/index.html - * PHPMailer : https://github.com/PHPMailer/PHPMailer - * js-lru : https://github.com/rsms/js-lru - -# Copyright & License - -COPS - 2012-2016 (c) Sbastien Lucas - -See COPYING and file headers for license info - diff --git a/sources/about.html b/sources/about.html deleted file mode 100644 index d3369f9..0000000 --- a/sources/about.html +++ /dev/null @@ -1,23 +0,0 @@ -
-

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/author.php b/sources/author.php deleted file mode 100644 index 6149bd3..0000000 --- a/sources/author.php +++ /dev/null @@ -1,95 +0,0 @@ - - */ - -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"; - const SQL_AUTHORS_BY_FIRST_LETTER = "select {0} from authors, books_authors_link where author = authors.id and upper (authors.sort) like ? group by authors.id, authors.name, authors.sort order by sort"; - const SQL_AUTHORS_FOR_SEARCH = "select {0} from authors, books_authors_link where author = authors.id and (upper (authors.sort) like ? or upper (authors.name) like ?) group by authors.id, authors.name, authors.sort order by sort"; - const SQL_ALL_AUTHORS = "select {0} from authors, books_authors_link where author = authors.id group by authors.id, authors.name, authors.sort order by sort"; - - public $id; - public $name; - public $sort; - - public function __construct($post) { - $this->id = $post->id; - $this->name = str_replace("|", ",", $post->name); - $this->sort = $post->sort; - } - - public function getUri () { - return "?page=".parent::PAGE_AUTHOR_DETAIL."&id=$this->id"; - } - - public function getEntryId () { - return self::ALL_AUTHORS_ID.":".$this->id; - } - - public static function getEntryIdByLetter ($startingLetter) { - return self::ALL_AUTHORS_ID.":letter:".$startingLetter; - } - - public static function getCount() { - // str_format (localize("authors.alphabetical", count(array)) - return parent::getCountGeneric ("authors", self::ALL_AUTHORS_ID, parent::PAGE_ALL_AUTHORS); - } - - public static function getAllAuthorsByFirstLetter() { - list (, $result) = parent::executeQuery ("select {0} -from authors -group by substr (upper (sort), 1, 1) -order by substr (upper (sort), 1, 1)", "substr (upper (sort), 1, 1) as title, count(*) as count", "", array (), -1); - $entryArray = array(); - while ($post = $result->fetchObject ()) - { - array_push ($entryArray, new Entry ($post->title, Author::getEntryIdByLetter ($post->title), - str_format (localize("authorword", $post->count), $post->count), "text", - array ( new LinkNavigation ("?page=".parent::PAGE_AUTHORS_FIRST_LETTER."&id=". rawurlencode ($post->title))), "", $post->count)); - } - return $entryArray; - } - - public static function getAuthorsByStartingLetter($letter) { - return self::getEntryArray (self::SQL_AUTHORS_BY_FIRST_LETTER, array ($letter . "%")); - } - - public static function getAuthorsForSearch($query) { - return self::getEntryArray (self::SQL_AUTHORS_FOR_SEARCH, array ($query . "%", $query . "%")); - } - - public static function getAllAuthors() { - return self::getEntryArray (self::SQL_ALL_AUTHORS, array ()); - } - - public static function getEntryArray ($query, $params) { - return Base::getEntryArrayWithBookNumber ($query, self::AUTHOR_COLUMNS, $params, "Author"); - } - - public static function getAuthorById ($authorId) { - $result = parent::getDb ()->prepare('select ' . self::AUTHOR_COLUMNS . ' from authors where id = ?'); - $result->execute (array ($authorId)); - $post = $result->fetchObject (); - return new Author ($post); - } - - public static function getAuthorByBookId ($bookId) { - $result = parent::getDb ()->prepare('select authors.id as id, authors.name as name, authors.sort as sort from authors, books_authors_link -where author = authors.id -and book = ?'); - $result->execute (array ($bookId)); - $authorArray = array (); - while ($post = $result->fetchObject ()) { - array_push ($authorArray, new Author ($post)); - } - return $authorArray; - } -} diff --git a/sources/base.php b/sources/base.php deleted file mode 100644 index e3cfc7d..0000000 --- a/sources/base.php +++ /dev/null @@ -1,1361 +0,0 @@ - - */ - -/** @var array $config */ - -define ("VERSION", "1.0.1"); -define ("DB", "db"); -date_default_timezone_set($config['default_timezone']); - - -function useServerSideRendering () { - global $config; - return preg_match("/" . $config['cops_server_side_render'] . "/", $_SERVER['HTTP_USER_AGENT']); -} - -function serverSideRender ($data) { - // Get the templates - $theme = getCurrentTemplate (); - $header = file_get_contents('templates/' . $theme . '/header.html'); - $footer = file_get_contents('templates/' . $theme . '/footer.html'); - $main = file_get_contents('templates/' . $theme . '/main.html'); - $bookdetail = file_get_contents('templates/' . $theme . '/bookdetail.html'); - $page = file_get_contents('templates/' . $theme . '/page.html'); - - // Generate the function for the template - $template = new doT (); - $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) { - return FALSE; - } - // Execute the template - if (!empty ($data)) { - return $dot ($data); - } - - return NULL; -} - -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"); - - $_SERVER['REDIRECT_STATUS'] = 404; -} - -function getURLParam ($name, $default = NULL) { - if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != "") { - return $_GET[$name]; - } - return $default; -} - -function getCurrentOption ($option) { - global $config; - if (isset($_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]; - } - - return ""; -} - -function getCurrentCss () { - return "templates/" . getCurrentTemplate () . "/styles/style-" . getCurrentOption ("style") . ".css"; -} - -function getCurrentTemplate () { - return getCurrentOption ("template"); -} - -function getUrlWithVersion ($url) { - return $url . "?v=" . VERSION; -} - -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 .= str_repeat('-', $error->column) . "^\n"; - - switch ($error->level) { - case LIBXML_ERR_WARNING: - $return .= "Warning $error->code: "; - break; - case LIBXML_ERR_ERROR: - $return .= "Error $error->code: "; - break; - case LIBXML_ERR_FATAL: - $return .= "Fatal Error $error->code: "; - break; - } - - $return .= trim($error->message) . - "\n Line: $error->line" . - "\n Column: $error->column"; - - if ($error->file) { - $return .= "\n File: $error->file"; - } - - return "$return\n\n--------------------------------------------\n\n"; -} - -function are_libxml_errors_ok () -{ - $errors = libxml_get_errors(); - - foreach ($errors as $error) { - if ($error->code == 801) return false; - } - return true; -} - -function html2xhtml ($html) { - $doc = new DOMDocument(); - libxml_use_internal_errors(true); - - $doc->loadHTML('' . - $html . ''); // Load the HTML - $output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream - $output = xml2xhtml($output); - if (preg_match ('#(.*)#ms', $output, $matches)) { - $output = $matches [1]; // Remove - } - /* - // In case of error with summary, use it to debug - $errors = libxml_get_errors(); - - foreach ($errors as $error) { - $output .= display_xml_error($error); - } - */ - - if (!are_libxml_errors_ok ()) $output = "HTML code not valid."; - - libxml_use_internal_errors(false); - return $output; -} - -/** - * This method is a direct copy-paste from - * http://tmont.com/blargh/2010/1/string-format-in-php - */ -function str_format($format) { - $args = func_get_args(); - $format = array_shift($args); - - preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE); - $offset = 0; - foreach ($matches[1] as $data) { - $i = $data[0]; - $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i)); - $offset += strlen(@$args[$i]) - 2 - strlen($i); - } - - return $format; -} - -/** - * Get all accepted languages from the browser and put them in a sorted array - * languages id are normalized : fr-fr -> fr_FR - * @return array of languages - */ -function getAcceptLanguages() { - $langs = array(); - - if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - // break up string into pieces (languages and q factors) - $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"; - } - preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $accept, $lang_parse); - - if (count($lang_parse[1])) { - $langs = array(); - 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]); - } - array_push($langs, $lang); - } - // create a list like "en" => 0.8 - $langs = array_combine($langs, $lang_parse[4]); - - // set default to 1 for any without q factor - foreach ($langs as $lang => $val) { - if ($val === '') $langs[$lang] = 1; - } - - // sort list based on value - arsort($langs, SORT_NUMERIC); - } - } - - return $langs; -} - -/** - * Find the best translation file possible based on the accepted languages - * @return array of language and language file - */ -function getLangAndTranslationFile() { - global $config; - $langs = array(); - $lang = "en"; - if (!empty($config['cops_language'])) { - $lang = $config['cops_language']; - } - elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - $langs = getAcceptLanguages(); - } - //echo var_dump($langs); - $lang_file = NULL; - foreach ($langs as $language => $val) { - $temp_file = dirname(__FILE__). '/lang/Localization_' . $language . '.json'; - if (file_exists($temp_file)) { - $lang = $language; - $lang_file = $temp_file; - break; - } - } - if (empty ($lang_file)) { - $lang_file = dirname(__FILE__). '/lang/Localization_' . $lang . '.json'; - } - return array($lang, $lang_file); -} - -/** - * 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) { - global $config; - if ($count == 0) - $phrase .= ".none"; - if ($count == 1) - $phrase .= ".one"; - if ($count > 1) - $phrase .= ".many"; - - /* Static keyword is used to ensure the file is loaded only once */ - static $translations = NULL; - if ($reset) { - $translations = NULL; - } - /* If no instance of $translations has occured load the language file */ - if (is_null($translations)) { - $lang_file_en = NULL; - list ($lang, $lang_file) = getLangAndTranslationFile(); - if ($lang != "en") { - $lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json'; - } - - $lang_file_content = file_get_contents($lang_file); - /* Load the language file as a JSON object and transform it into an associative array */ - $translations = json_decode($lang_file_content, true); - - /* Clean the array of all unfinished translations */ - foreach (array_keys ($translations) as $key) { - if (preg_match ("/^##TODO##/", $key)) { - unset ($translations [$key]); - } - } - 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); - } - } - if (array_key_exists ($phrase, $translations)) { - return $translations[$phrase]; - } - return $phrase; -} - -function addURLParameter($urlParams, $paramName, $paramValue) { - if (empty ($urlParams)) { - $urlParams = ""; - } - $start = ""; - if (preg_match ("#^\?(.*)#", $urlParams, $matches)) { - $start = "?"; - $urlParams = $matches[1]; - } - $params = array(); - parse_str($urlParams, $params); - if (empty ($paramValue) && $paramValue != 0) { - unset ($params[$paramName]); - } else { - $params[$paramName] = $paramValue; - } - return $start . http_build_query($params); -} - -function useNormAndUp () { - global $config; - return $config ['cops_normalized_search'] == "1"; -} - -function normalizeUtf8String( $s) { - include_once 'transliteration.php'; - return _transliteration_process($s); -} - -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 deleted file mode 100644 index a61f950..0000000 --- a/sources/book.php +++ /dev/null @@ -1,661 +0,0 @@ - - */ - -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/checkconfig.php b/sources/checkconfig.php deleted file mode 100644 index 4ef2a29..0000000 --- a/sources/checkconfig.php +++ /dev/null @@ -1,257 +0,0 @@ - - - - * - */ - - require_once ("config.php"); - require_once ("base.php"); - - $err = getURLParam ("err", -1); - $full = getURLParam ("full"); - $error = NULL; - switch ($err) { - case 1 : - $error = "Database error"; - break; - } - -?> - - - - COPS Configuration Check - - - -
-
-
-

COPS Configuration Check

-
-
- -
- -
-

You've been redirected because COPS is not configured properly

-

-
- -
-

Check if PHP version is correct

-

- = 50300) { - echo "OK (" . PHP_VERSION . ")"; - } else { - echo "Please install PHP >= 5.3 (" . PHP_VERSION . ")"; - } - } else { - echo "Please install PHP >= 5.3"; - } - ?> -

-
-
-

Check if GD is properly installed and loaded

-

- -

-
-
-

Check if Sqlite is properly installed and loaded

-

- -

-
-
-

Check if libxml is properly installed and loaded

-

- -

-
-
-

Check if Json is properly installed and loaded

-

- -

-
-
-

Check if mbstring is properly installed and loaded

-

- -

-
-
-

Check if intl is properly installed and loaded

-

- -

-
-
-

Check if Normalizer class is properly installed and loaded

-

- -

-
-
-

Check if the rendering will be done on client side or server side

-

- -

-
- $database) { -?> -
-

Check if Calibre database path is not an URL

-

- -

-
-
-

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
  • -
  • The access rights of the Calibre Database
  • -
  • Synology users please read this
  • -"; - } - ?> -

    -
    - -
    -

    Check if Calibre database file can be opened with PHP

    -

    - -

    -
    -
    -

    Check if Calibre database file contains at least some of the needed tables

    -

    - query("select count(*) FROM sqlite_master WHERE type='table' AND name in ('books', 'authors', 'tags', 'series')")->fetchColumn(); - if ($count == 4) { - echo "{$name} OK"; - } else { - 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; - } - ?> -

    -
    - -
    -

    Check if all Calibre books are found

    -

    - 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 . "

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

    -
    - - - -
    -
    -
    - - diff --git a/sources/config.php b/sources/config.php deleted file mode 100644 index 2990244..0000000 --- a/sources/config.php +++ /dev/null @@ -1,35 +0,0 @@ - - */ - -require_once 'config_default.php'; -if (file_exists(dirname(__FILE__) . '/config_local.php') && (php_sapi_name() !== 'cli')) { - 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); -$user_config_file = 'config_local.' . $remote_user . '.php'; -if (file_exists(dirname(__FILE__) . '/' . $user_config_file) && (php_sapi_name() !== 'cli')) { - require_once $user_config_file; -} - -if(!is_null($config['cops_basic_authentication']) && - is_array($config['cops_basic_authentication'])) -{ - if (!isset($_SERVER['PHP_AUTH_USER']) || - (isset($_SERVER['PHP_AUTH_USER']) && - ($_SERVER['PHP_AUTH_USER']!=$config['cops_basic_authentication']['username'] || - $_SERVER['PHP_AUTH_PW'] != $config['cops_basic_authentication']['password']))) - { - header('WWW-Authenticate: Basic realm="COPS Authentication"'); - header('HTTP/1.0 401 Unauthorized'); - echo 'This site is password protected'; - exit; - } -} diff --git a/sources/config_default.php b/sources/config_default.php deleted file mode 100644 index 4b7b5f7..0000000 --- a/sources/config_default.php +++ /dev/null @@ -1,328 +0,0 @@ - - */ - - if (!isset($config)) - $config = array(); - - /* - * The directory containing calibre's metadata.db file, with sub-directories - * containing all the formats. - * BEWARE : it has to end with a / - * You can enable multiple database with this notation instead of a simple string : - * $config['calibre_directory'] = array ("My database name" => "/home/directory/calibre1/", "My other database name" => "/home/directory/calibre2/"); - */ - $config['calibre_directory'] = './'; - - /* - * SPECIFIC TO NGINX - * The internal directory set in nginx config file - * Leave empty if you don't know what you're doing - */ - $config['calibre_internal_directory'] = ''; - - /* - * Full URL prefix (with trailing /) - * useful especially for Opensearch where a full URL is often required - * For example Mantano, Aldiko and Marvin require it. - */ - $config['cops_full_url'] = ''; - - /* - * Number of recent books to show - */ - $config['cops_recentbooks_limit'] = '50'; - - /* - * Catalog's author name - */ - $config['cops_author_name'] = "Sébastien Lucas"; - - /* - * Catalog's author uri - */ - $config['cops_author_uri'] = "http://blog.slucas.fr"; - - /* - * Catalog's author email - */ - $config['cops_author_email'] = "sebastien@slucas.fr"; - - /* - * Catalog's title - */ - $config['cops_title_default'] = "COPS"; - - /* - * Catalog's subtitle - */ - $config['cops_subtitle_default'] = ""; - - /* - * Wich header to use when downloading books outside the web directory - * Possible values are : - * X-Accel-Redirect : For Nginx - * X-Sendfile : For Lightttpd or Apache (with mod_xsendfile) - * No value (default) : Let PHP handle the download - */ - $config['cops_x_accel_redirect'] = ""; - - /* - * Height of thumbnail image for OPDS - */ - $config['cops_opds_thumbnail_height'] = "164"; - - /* - * Height of thumbnail image for HTML - */ - $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"; - - /* - * Show icon for authors, series, tags and books on OPDS feed - * 1 : enable - * 0 : disable - */ - $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"; - - /* - * 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"); - - /* - * use URL rewriting for downloading of ebook in HTML catalog - * See Github wiki for more information - * 1 : enable - * 0 : disable - */ - $config['cops_use_url_rewriting'] = "0"; - - /* - * generate a invalid OPDS stream to allow bad OPDS client to use search - * Example of non compliant OPDS client : Moon+ Reader - * Example of good OPDS client : Mantano, FBReader - * 1 : enable support for non compliant OPDS client - * 0 : always generate valid OPDS code - */ - $config['cops_generate_invalid_opds_stream'] = "0"; - - /* - * Max number of items per page - * -1 unlimited - */ - $config['cops_max_item_per_page'] = "-1"; - - /* - * split authors by first letter - * 1 : Yes - * 0 : No - */ - $config['cops_author_split_first_letter'] = "1"; - - /* - * split titles by first letter - * 1 : Yes - * 0 : No - */ - $config['cops_titles_split_first_letter'] = "1"; - - /* - * Enable the Lightboxes (for popups) - * 1 : Yes (enable) - * 0 : No - */ - $config['cops_use_fancyapps'] = "1"; - - /* - * Update Epub metadata before download - * 1 : Yes (enable) - * 0 : No - */ - $config['cops_update_epub-metadata'] = "0"; - - /* - * Filter on tags to book list - * Only works with the OPDS catalog - * Usage : array ("I only want to see books using the tag : Tag1" => "Tag1", - * "I only want to see books not using the tag : Tag1" => "!Tag1", - * "I want to see every books" => "", - * - * Example : array ("All" => "", "Unread" => "!Read", "Read" => "Read") - */ - $config['cops_books_filter'] = array (); - - /* - * Custom Columns for the index page - * to add as an array containing the lookup names configured in Calibre - * - * For example : array ("genre", "mycolumn"); - * - * Note that the composite custom columns are not supported - */ - $config['cops_calibre_custom_column'] = array (); - - /* - * Custom Columns for the list representation - * to add as an array containing the lookup names configured in Calibre - * - * For example : array ("genre", "mycolumn"); - * - * Note that the composite custom columns are not supported - */ - $config['cops_calibre_custom_column_list'] = array (); - - /* - * Custom Columns for the book preview panel - * to add as an array containing the lookup names configured in Calibre - * - * For example : array ("genre", "mycolumn"); - * - * Note that the composite custom columns are not supported - */ - $config['cops_calibre_custom_column_preview'] = array (); - - /* - * Rename .epub to .kepub.epub if downloaded from a Kobo eReader - * The ebook will then be recognized a Kepub so with chaptered paging, statistics, ... - * You have to enable URL rewriting if you want to enable kepup.epub download - * 1 : Yes (enable) - * 0 : No - */ - $config['cops_provide_kepub'] = "0"; - - /* - * Enable and configure Send To Kindle (or Email) feature. - * - * Don't forget to authorize the sender email you configured in your Kindle's Approved Personal Document E-mail List. - * - * If you want to use a simple smtp server (provided by your ISP for example), you can configure it like that : - * $config['cops_mail_configuration'] = array( "smtp.host" => "smtp.free.fr", - * "smtp.username" => "", - * "smtp.password" => "", - * "smtp.secure" => "", - * "address.from" => "cops@slucas.fr" - * ); - * - * For Gmail (ssl is mandatory) : - * $config['cops_mail_configuration'] = array( "smtp.host" => "smtp.gmail.com", - * "smtp.username" => "YOUR GMAIL ADRESS", - * "smtp.password" => "YOUR GMAIL PASSWORD", - * "smtp.secure" => "ssl", - * "address.from" => "cops@slucas.fr" - * ); - */ - $config['cops_mail_configuration'] = NULL; - - /* - * Use filter in HTML catalog - * 1 : Yes (enable) - * 0 : No - */ - $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, ...). - * This configuration item allow to customize how thumbnail will be generated - * "" : Generate thumbnail (CPU hungry) - * "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'] = ""; - - /* - * Directory to keep resized thumbnails: allow to resize thumbnails only on first access, then use this cache. - * $config['cops_thumbnail_handling'] must be "" - * "" : don't cache thumbnail - * "/tmp/cache/" (example) : will generate thumbnails in /tmp/cache/ - * BEWARE : it has to end with a / - */ - $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"; - - /* - * Specify the ignored categories for the home screen and with search - * Meaning that if you don't want to search in publishers or tags just add them from the list - * Only accepted values : - * - author - * - book - * - series - * - tag - * - publisher - * - rating - * - language - */ - $config ['cops_ignored_categories'] = array (); - - /* - * If you use a Sony eReader or Aldiko you can't download ebooks if your catalog - * is password protected. A simple workaround is to leave fetch.php not protected (see .htaccess). - * But In that case your COPS installation is not completely safe. - * Setting this parameter to "1" ensure that nobody can access fetch.php before accessing - * 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"; - - /* - * WARNING NOT READY FOR PRODUCTION USE - * Make the search better (don't care about diacritics, uppercase should work on Cyrillic) but slower. - * 1 : Yes (enable) - * 0 : No - */ - $config ['cops_normalized_search'] = "0"; - - /* - * Enable PHP password protection (You can use if htpasswd is not possible for you) - * If possible prefer htpasswd ! - * array( "username" => "xxx", "password" => "secret") : Enable PHP password protection - * NULL : Disable PHP password protection (You can still use htpasswd) - */ - $config['cops_basic_authentication'] = NULL; - - /* - * Which template is used by default : - * 'default' - * 'bootstrap' - */ - $config['cops_template'] = 'default'; - - /* - * Which style is used by default : - * 'base' - * 'default' - * 'eink' (only available for the 'default' template) - * 'iphone' (only available for the 'default' template) - * 'iphone7' (only available for the 'default' template) - */ - $config['cops_style'] = 'default'; - - /* - * Set language code to force a language (see lang/ directory for available languages). - * When empty it will auto detect the language. - */ - $config['cops_language'] = ''; diff --git a/sources/config_local.php.example b/sources/config_local.php.example deleted file mode 100644 index 2bf34bf..0000000 --- a/sources/config_local.php.example +++ /dev/null @@ -1,23 +0,0 @@ -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