aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNicolas Lœuillet <nicolas.loeuillet@gmail.com>2013-08-07 10:41:26 -0700
committerNicolas Lœuillet <nicolas.loeuillet@gmail.com>2013-08-07 10:41:26 -0700
commit01c0e050ad8eca54f115dfa21db99e4f61ab7ca7 (patch)
treee1bdacb68b3a56644f4525974844dd954d6e3c6b
parentda2c5d6fc33587c775a7d8a738c2c18de41f83b2 (diff)
parent339d510fda0a43b08981309f7540acedf3a4976c (diff)
downloadwallabag-01c0e050ad8eca54f115dfa21db99e4f61ab7ca7.tar.gz
wallabag-01c0e050ad8eca54f115dfa21db99e4f61ab7ca7.tar.zst
wallabag-01c0e050ad8eca54f115dfa21db99e4f61ab7ca7.zip
Merge pull request #104 from inthepoche/twig
Twig version on dev branch
-rw-r--r--.gitignore3
-rw-r--r--CREDITS11
-rw-r--r--INSTALL.md53
-rw-r--r--README.md29
-rw-r--r--composer.json7
-rw-r--r--composer.lock744
-rw-r--r--css/style-dark.css90
-rw-r--r--css/style-light.css100
-rw-r--r--css/style.css223
-rw-r--r--img/dark/checkmark-off.pngbin267 -> 0 bytes
-rw-r--r--img/dark/checkmark-on.pngbin221 -> 0 bytes
-rw-r--r--img/dark/down.pngbin223 -> 0 bytes
-rw-r--r--img/dark/logo.pngbin786 -> 0 bytes
-rw-r--r--img/dark/remove.pngbin265 -> 0 bytes
-rw-r--r--img/dark/star-off.pngbin330 -> 0 bytes
-rw-r--r--img/dark/star-on.pngbin277 -> 0 bytes
-rw-r--r--img/dark/up.pngbin225 -> 0 bytes
-rw-r--r--img/logo.pngbin911 -> 0 bytes
-rw-r--r--import.php73
-rw-r--r--inc/3rdparty/Encoding.php (renamed from inc/Encoding.php)0
-rw-r--r--inc/3rdparty/JSLikeHTMLElement.php (renamed from inc/JSLikeHTMLElement.php)0
-rw-r--r--inc/3rdparty/Readability.php (renamed from inc/Readability.php)0
-rw-r--r--inc/3rdparty/Session.class.php (renamed from inc/Session.class.php)2
-rwxr-xr-x[-rw-r--r--]inc/3rdparty/class.messages.php (renamed from inc/class.messages.php)460
-rw-r--r--inc/3rdparty/paginator.php202
-rw-r--r--inc/3rdparty/simple_html_dom.php (renamed from inc/simple_html_dom.php)0
-rw-r--r--inc/MyTool.class.php265
-rw-r--r--inc/config.php73
-rw-r--r--inc/functions.php400
-rw-r--r--inc/poche/Database.class.php216
-rw-r--r--inc/poche/Poche.class.php429
-rw-r--r--inc/poche/Tools.class.php226
-rw-r--r--inc/poche/Url.class.php94
-rw-r--r--inc/poche/User.class.php50
-rw-r--r--inc/poche/config.inc.php61
-rw-r--r--inc/poche/pochePictures.php110
-rw-r--r--inc/rain.tpl.class.php1043
-rw-r--r--inc/store/file.class.php51
-rw-r--r--inc/store/sqlite.class.php202
-rw-r--r--inc/store/store.class.php63
-rw-r--r--index.php107
-rw-r--r--install/mysql.sql34
-rwxr-xr-xinstall/poche.sqlite (renamed from db/poche.sqlite)bin294912 -> 294912 bytes
-rw-r--r--install/postgres.sql30
-rw-r--r--install/update_sqlite_from_0_to_1.php64
-rw-r--r--js/jquery-1.9.1.min.js5
-rw-r--r--js/jquery.masonry.min.js10
-rw-r--r--js/poche.js57
-rw-r--r--locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mobin2775 -> 5699 bytes
-rw-r--r--locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po399
-rw-r--r--tpl/_bookmarklet.twig3
-rw-r--r--tpl/_footer.twig4
-rw-r--r--tpl/_head.twig9
-rw-r--r--tpl/_menu.twig7
-rw-r--r--tpl/_messages.twig1
-rw-r--r--tpl/_top.twig3
-rw-r--r--tpl/config.html27
-rw-r--r--tpl/config.twig57
-rw-r--r--tpl/css/knacss.css (renamed from css/knacss.css)0
-rwxr-xr-xtpl/css/messages.css13
-rw-r--r--tpl/css/style-light.css53
-rw-r--r--tpl/css/style.css244
-rw-r--r--tpl/entries.html21
-rw-r--r--tpl/export.html1
-rw-r--r--tpl/export.twig1
-rw-r--r--tpl/footer.html7
-rw-r--r--tpl/head.html42
-rw-r--r--tpl/home.html19
-rw-r--r--tpl/home.twig29
-rw-r--r--tpl/img/apple-touch-icon-144x144-precomposed.png (renamed from img/apple-touch-icon-144x144-precomposed.png)bin7349 -> 7349 bytes
-rw-r--r--tpl/img/apple-touch-icon-72x72-precomposed.png (renamed from img/apple-touch-icon-72x72-precomposed.png)bin6168 -> 6168 bytes
-rw-r--r--tpl/img/apple-touch-icon.png (renamed from img/apple-touch-icon.png)bin5803 -> 5803 bytes
-rw-r--r--tpl/img/favicon.ico (renamed from img/favicon.ico)bin346 -> 346 bytes
-rw-r--r--tpl/img/light/checkmark-off.png (renamed from img/light/checkmark-off.png)bin277 -> 277 bytes
-rw-r--r--tpl/img/light/checkmark-on.png (renamed from img/light/checkmark-on.png)bin235 -> 235 bytes
-rw-r--r--tpl/img/light/down.png (renamed from img/down.png)bin216 -> 216 bytes
-rwxr-xr-xtpl/img/light/envelop.pngbin0 -> 285 bytes
-rwxr-xr-xtpl/img/light/left.pngbin0 -> 196 bytes
-rw-r--r--tpl/img/light/remove.png (renamed from img/light/remove.png)bin252 -> 252 bytes
-rw-r--r--tpl/img/light/star-off.png (renamed from img/light/star-off.png)bin314 -> 314 bytes
-rw-r--r--tpl/img/light/star-on.png (renamed from img/light/star-on.png)bin281 -> 281 bytes
-rwxr-xr-x[-rw-r--r--]tpl/img/light/top.png (renamed from img/up.png)bin212 -> 212 bytes
-rwxr-xr-xtpl/img/light/twitter.pngbin0 -> 297 bytes
-rw-r--r--tpl/img/logo.pngbin0 -> 454 bytes
-rwxr-xr-x[-rw-r--r--]tpl/img/messages/close.png (renamed from img/messages/close.png)bin662 -> 662 bytes
-rwxr-xr-x[-rw-r--r--]tpl/img/messages/cross.png (renamed from img/messages/cross.png)bin655 -> 655 bytes
-rwxr-xr-x[-rw-r--r--]tpl/img/messages/help.png (renamed from img/messages/help.png)bin786 -> 786 bytes
-rwxr-xr-x[-rw-r--r--]tpl/img/messages/tick.png (renamed from img/messages/tick.png)bin537 -> 537 bytes
-rwxr-xr-x[-rw-r--r--]tpl/img/messages/warning.png (renamed from img/messages/warning.png)bin666 -> 666 bytes
-rw-r--r--tpl/install.html30
-rw-r--r--tpl/install.twig28
-rw-r--r--tpl/js.html22
-rw-r--r--tpl/layout.twig29
-rw-r--r--tpl/login.html33
-rw-r--r--tpl/login.twig32
-rw-r--r--tpl/messages.html1
-rw-r--r--tpl/view.html58
-rw-r--r--tpl/view.twig40
98 files changed, 3486 insertions, 3314 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..050a1386
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
1vendor
2composer.phar
3db/poche.sqlite \ No newline at end of file
diff --git a/CREDITS b/CREDITS
index 77a3f663..d6874a7b 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1,17 +1,14 @@
1poche is based on : 1poche is based on :
2* ReadItYourself http://www.memiks.fr/readityourself/
3* PHP Readability http://www.keyvan.net/2010/08/php-readability/ 2* PHP Readability http://www.keyvan.net/2010/08/php-readability/
4* Encoding https://github.com/neitanod/forceutf8 3* Encoding https://github.com/neitanod/forceutf8
5* logo by Brightmix http://www.iconfinder.com/icondetails/43256/128/jeans_monotone_pocket_icon 4* logo by Brightmix http://www.iconfinder.com/icondetails/43256/128/jeans_monotone_pocket_icon
6* icons http://icomoon.io 5* icons http://icomoon.io
7* PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/ 6* PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/
8* Session https://github.com/tontof/kriss_feed/blob/master/src/class/Session.php 7* Session https://github.com/tontof/kriss_feed/blob/master/src/class/Session.php
9* RainTPL http://www.raintpl.com/ 8* Twig http://twig.sensiolabs.org
9* Flash messages https://github.com/plasticbrain/PHP-Flash-Messages
10* Pagination https://github.com/daveismyname/pagination
10 11
11poche is developed by Nicolas Lœuillet under the Do What the Fuck You Want to Public License 12poche is developed by Nicolas Lœuillet under the Do What the Fuck You Want to Public License
12 13
13Contributors : 14Contributors : https://github.com/inthepoche/poche/graphs/contributors \ No newline at end of file
14Nicolas Lœuillet aka nico_somb
15Tom.C. aka tmos
16PeaceCopathe
17Gregoire_M \ No newline at end of file
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 00000000..47208ef0
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,53 @@
1# Installing poche
2
3Get the [latest twig version](https://github.com/inthepoche/poche/archive/twig.zip) of poche on github. Unzip it and upload it on your server.
4
5your datas can be stored on sqlite, postgres or mysql databases.
6
7Edit /inc/poche/config.inc.php :
8
9```php
10define ('STORAGE','sqlite'); # postgres, mysql, sqlite
11define ('STORAGE_SERVER', 'localhost'); # leave blank for sqlite
12define ('STORAGE_DB', 'poche'); # only for postgres & mysql
13define ('STORAGE_SQLITE', './db/poche.sqlite');
14define ('STORAGE_USER', 'user'); # leave blank for sqlite
15define ('STORAGE_PASSWORD', 'pass'); # leave blank for sqlite
16```
17
18poche must have write access on assets, cache and db directories.
19
20[PHP cURL](http://www.php.net/manual/en/book.curl.php) & [tidy_parse_string](http://www.php.net/manual/en/tidy.parsestring.php) are recommended.
21
22## twig
23poche now uses twig for templating. You have to install twig.
24
25Install composer in your project :
26```bash
27curl -s http://getcomposer.org/installer | php
28```
29Install via composer :
30```bash
31php composer.phar install
32```
33
34If you don't want to install twig by yourself, you can download [this file](http://static.inthepoche.com/files/poche-1.0-latest-with-twig.zip).
35
36## storage in sqlite
37You have to install [sqlite for php](http://www.php.net/manual/en/book.sqlite.php) on your server.
38
39Copy /install/poche.sqlite in /db
40
41## storage in mysql
42Execute /install/mysql.sql file in your database.
43
44## storage in postgres
45Execute /install/postgres.sql file in your database.
46
47## upgrading from poche <= 0.3
48With poche <= 0.3, all your datas were stored in a sqlite file. The structure of this file changed.
49
50You have to execute http://yourpoche/install/update_sqlite_from_0_to_1.php before using this new version.
51
52## installing poche
53you can go on your poche http://yourpoche. You have to fill the fields and that's all ! \ No newline at end of file
diff --git a/README.md b/README.md
index b44e7d36..25385da8 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
1# poche 1# poche
2Abandon Pocket, Instapaper and other Readability service : adopt poche. It is the same, but it is open source. 2Abandon Pocket, Instapaper and other Readability service : adopt poche. It is the same, but it is open source. Moreover, you can migrate from Pocket & Readability.
3 3
4![poche](http://inthepoche.com/img/logo.png) 4![poche](http://inthepoche.com/img/logo.png)
5 5
@@ -11,24 +11,6 @@ To get news from poche, [follow us on twitter](http://twitter.com/getpoche) or [
11 11
12[![flattr](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/1265480/poche-a-read-it-later-open-source-system) 12[![flattr](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/1265480/poche-a-read-it-later-open-source-system)
13 13
14## Usage
15You can easily add a "poched" page with the bookmarklet.
16
17poche save the entire content of a poched links : text and pictures are stored on your server.
18
19You can :
20* read a page in a comfortable reading view
21* archive a link
22* put a link in favorite
23* delete a link
24
25## Requirements & installation
26You have to install [sqlite for php](http://www.php.net/manual/en/book.sqlite.php) on your server.
27
28Get the [latest version](https://github.com/inthepoche/poche) of poche on github. Unzip it and upload it on your server. poche must have write access on assets, cache and db directories.
29
30That's all, **poche works** !
31
32## Security 14## Security
33You **have** to protect your db/poche.sqlite file. Modify the virtual host of your website to add this condition : 15You **have** to protect your db/poche.sqlite file. Modify the virtual host of your website to add this condition :
34```apache 16```apache
@@ -46,12 +28,11 @@ location ~ /(db) {
46} 28}
47``` 29```
48 30
49## Import from Pocket 31## Usage
50 32See the documentation on our website : [inthepoche.com](http://inthepoche.com).
51If you want to import your Pocket datas, [export them here](https://getpocket.com/export). Put the HTML file in your poche directory, execute import.php file locally by following instructions. Be careful, the script can take a very long time.
52 33
53## License 34## License
54Copyright © 2010-2013 Nicolas Lœuillet <nicolas@loeuillet.org> 35Copyright © 2010-2013 Nicolas Lœuillet <nicolas.loeuillet@gmail.com>
55This work is free. You can redistribute it and/or modify it under the 36This work is free. You can redistribute it and/or modify it under the
56terms of the Do What The Fuck You Want To Public License, Version 2, 37terms of the Do What The Fuck You Want To Public License, Version 2,
57as published by Sam Hocevar. See the COPYING file for more details. 38as published by Sam Hocevar. See the COPYING file for more details. \ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 00000000..6c69e48d
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,7 @@
1{
2 "require": {
3 "twig/twig": "1.*",
4 "twig/extensions": "1.0.*",
5 "umpirsky/twig-gettext-extractor": "1.1.*"
6 }
7} \ No newline at end of file
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 00000000..9e17fca9
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,744 @@
1{
2 "_readme": [
3 "This file locks the dependencies of your project to a known state",
4 "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
5 ],
6 "hash": "1c8badb14d91f4f3ef1cfae23252a2c4",
7 "packages": [
8 {
9 "name": "symfony/event-dispatcher",
10 "version": "v2.3.2",
11 "target-dir": "Symfony/Component/EventDispatcher",
12 "source": {
13 "type": "git",
14 "url": "https://github.com/symfony/EventDispatcher.git",
15 "reference": "v2.3.2"
16 },
17 "dist": {
18 "type": "zip",
19 "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.2",
20 "reference": "v2.3.2",
21 "shasum": ""
22 },
23 "require": {
24 "php": ">=5.3.3"
25 },
26 "require-dev": {
27 "symfony/dependency-injection": "~2.0"
28 },
29 "suggest": {
30 "symfony/dependency-injection": "",
31 "symfony/http-kernel": ""
32 },
33 "type": "library",
34 "extra": {
35 "branch-alias": {
36 "dev-master": "2.3-dev"
37 }
38 },
39 "autoload": {
40 "psr-0": {
41 "Symfony\\Component\\EventDispatcher\\": ""
42 }
43 },
44 "notification-url": "https://packagist.org/downloads/",
45 "license": [
46 "MIT"
47 ],
48 "authors": [
49 {
50 "name": "Fabien Potencier",
51 "email": "fabien@symfony.com"
52 },
53 {
54 "name": "Symfony Community",
55 "homepage": "http://symfony.com/contributors"
56 }
57 ],
58 "description": "Symfony EventDispatcher Component",
59 "homepage": "http://symfony.com",
60 "time": "2013-05-13 14:36:40"
61 },
62 {
63 "name": "symfony/filesystem",
64 "version": "v2.3.2",
65 "target-dir": "Symfony/Component/Filesystem",
66 "source": {
67 "type": "git",
68 "url": "https://github.com/symfony/Filesystem.git",
69 "reference": "v2.3.2"
70 },
71 "dist": {
72 "type": "zip",
73 "url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.2",
74 "reference": "v2.3.2",
75 "shasum": ""
76 },
77 "require": {
78 "php": ">=5.3.3"
79 },
80 "type": "library",
81 "extra": {
82 "branch-alias": {
83 "dev-master": "2.3-dev"
84 }
85 },
86 "autoload": {
87 "psr-0": {
88 "Symfony\\Component\\Filesystem\\": ""
89 }
90 },
91 "notification-url": "https://packagist.org/downloads/",
92 "license": [
93 "MIT"
94 ],
95 "authors": [
96 {
97 "name": "Fabien Potencier",
98 "email": "fabien@symfony.com"
99 },
100 {
101 "name": "Symfony Community",
102 "homepage": "http://symfony.com/contributors"
103 }
104 ],
105 "description": "Symfony Filesystem Component",
106 "homepage": "http://symfony.com",
107 "time": "2013-06-04 15:02:05"
108 },
109 {
110 "name": "symfony/form",
111 "version": "v2.3.2",
112 "target-dir": "Symfony/Component/Form",
113 "source": {
114 "type": "git",
115 "url": "https://github.com/symfony/Form.git",
116 "reference": "v2.3.2"
117 },
118 "dist": {
119 "type": "zip",
120 "url": "https://api.github.com/repos/symfony/Form/zipball/v2.3.2",
121 "reference": "v2.3.2",
122 "shasum": ""
123 },
124 "require": {
125 "php": ">=5.3.3",
126 "symfony/event-dispatcher": "~2.1",
127 "symfony/intl": "~2.3",
128 "symfony/options-resolver": "~2.1",
129 "symfony/property-access": "~2.2"
130 },
131 "require-dev": {
132 "symfony/http-foundation": "~2.2",
133 "symfony/validator": "~2.2"
134 },
135 "suggest": {
136 "symfony/http-foundation": "",
137 "symfony/validator": ""
138 },
139 "type": "library",
140 "extra": {
141 "branch-alias": {
142 "dev-master": "2.3-dev"
143 }
144 },
145 "autoload": {
146 "psr-0": {
147 "Symfony\\Component\\Form\\": ""
148 }
149 },
150 "notification-url": "https://packagist.org/downloads/",
151 "license": [
152 "MIT"
153 ],
154 "authors": [
155 {
156 "name": "Fabien Potencier",
157 "email": "fabien@symfony.com"
158 },
159 {
160 "name": "Symfony Community",
161 "homepage": "http://symfony.com/contributors"
162 }
163 ],
164 "description": "Symfony Form Component",
165 "homepage": "http://symfony.com",
166 "time": "2013-07-01 12:24:43"
167 },
168 {
169 "name": "symfony/icu",
170 "version": "v1.0.0",
171 "target-dir": "Symfony/Component/Icu",
172 "source": {
173 "type": "git",
174 "url": "https://github.com/symfony/Icu.git",
175 "reference": "v1.0.0"
176 },
177 "dist": {
178 "type": "zip",
179 "url": "https://api.github.com/repos/symfony/Icu/zipball/v1.0.0",
180 "reference": "v1.0.0",
181 "shasum": ""
182 },
183 "require": {
184 "php": ">=5.3.3",
185 "symfony/intl": ">=2.3,<3.0"
186 },
187 "type": "library",
188 "autoload": {
189 "psr-0": {
190 "Symfony\\Component\\Icu\\": ""
191 }
192 },
193 "notification-url": "https://packagist.org/downloads/",
194 "license": [
195 "MIT"
196 ],
197 "authors": [
198 {
199 "name": "Symfony Community",
200 "homepage": "http://symfony.com/contributors"
201 },
202 {
203 "name": "Bernhard Schussek",
204 "email": "bschussek@gmail.com"
205 }
206 ],
207 "description": "Contains an excerpt of the ICU data and classes to load it.",
208 "homepage": "http://symfony.com",
209 "keywords": [
210 "icu",
211 "intl"
212 ],
213 "time": "2013-06-03 18:32:07"
214 },
215 {
216 "name": "symfony/intl",
217 "version": "v2.3.2",
218 "target-dir": "Symfony/Component/Intl",
219 "source": {
220 "type": "git",
221 "url": "https://github.com/symfony/Intl.git",
222 "reference": "v2.3.2"
223 },
224 "dist": {
225 "type": "zip",
226 "url": "https://api.github.com/repos/symfony/Intl/zipball/v2.3.2",
227 "reference": "v2.3.2",
228 "shasum": ""
229 },
230 "require": {
231 "php": ">=5.3.3",
232 "symfony/icu": "~1.0-RC"
233 },
234 "require-dev": {
235 "symfony/filesystem": ">=2.1"
236 },
237 "suggest": {
238 "ext-intl": "to use the component with locales other than \"en\""
239 },
240 "type": "library",
241 "extra": {
242 "branch-alias": {
243 "dev-master": "2.3-dev"
244 }
245 },
246 "autoload": {
247 "psr-0": {
248 "Symfony\\Component\\Intl\\": ""
249 },
250 "classmap": [
251 "Symfony/Component/Intl/Resources/stubs"
252 ],
253 "files": [
254 "Symfony/Component/Intl/Resources/stubs/functions.php"
255 ]
256 },
257 "notification-url": "https://packagist.org/downloads/",
258 "license": [
259 "MIT"
260 ],
261 "authors": [
262 {
263 "name": "Symfony Community",
264 "homepage": "http://symfony.com/contributors"
265 },
266 {
267 "name": "Igor Wiedler",
268 "email": "igor@wiedler.ch",
269 "homepage": "http://wiedler.ch/igor/"
270 },
271 {
272 "name": "Bernhard Schussek",
273 "email": "bschussek@gmail.com"
274 },
275 {
276 "name": "Eriksen Costa",
277 "email": "eriksen.costa@infranology.com.br"
278 }
279 ],
280 "description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
281 "homepage": "http://symfony.com",
282 "keywords": [
283 "i18n",
284 "icu",
285 "internationalization",
286 "intl",
287 "l10n",
288 "localization"
289 ],
290 "time": "2013-07-08 13:00:35"
291 },
292 {
293 "name": "symfony/options-resolver",
294 "version": "v2.3.2",
295 "target-dir": "Symfony/Component/OptionsResolver",
296 "source": {
297 "type": "git",
298 "url": "https://github.com/symfony/OptionsResolver.git",
299 "reference": "v2.3.2"
300 },
301 "dist": {
302 "type": "zip",
303 "url": "https://api.github.com/repos/symfony/OptionsResolver/zipball/v2.3.2",
304 "reference": "v2.3.2",
305 "shasum": ""
306 },
307 "require": {
308 "php": ">=5.3.3"
309 },
310 "type": "library",
311 "extra": {
312 "branch-alias": {
313 "dev-master": "2.3-dev"
314 }
315 },
316 "autoload": {
317 "psr-0": {
318 "Symfony\\Component\\OptionsResolver\\": ""
319 }
320 },
321 "notification-url": "https://packagist.org/downloads/",
322 "license": [
323 "MIT"
324 ],
325 "authors": [
326 {
327 "name": "Fabien Potencier",
328 "email": "fabien@symfony.com"
329 },
330 {
331 "name": "Symfony Community",
332 "homepage": "http://symfony.com/contributors"
333 }
334 ],
335 "description": "Symfony OptionsResolver Component",
336 "homepage": "http://symfony.com",
337 "keywords": [
338 "config",
339 "configuration",
340 "options"
341 ],
342 "time": "2013-04-11 06:50:46"
343 },
344 {
345 "name": "symfony/property-access",
346 "version": "v2.3.2",
347 "target-dir": "Symfony/Component/PropertyAccess",
348 "source": {
349 "type": "git",
350 "url": "https://github.com/symfony/PropertyAccess.git",
351 "reference": "v2.3.2"
352 },
353 "dist": {
354 "type": "zip",
355 "url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/v2.3.2",
356 "reference": "v2.3.2",
357 "shasum": ""
358 },
359 "require": {
360 "php": ">=5.3.3"
361 },
362 "type": "library",
363 "extra": {
364 "branch-alias": {
365 "dev-master": "2.3-dev"
366 }
367 },
368 "autoload": {
369 "psr-0": {
370 "Symfony\\Component\\PropertyAccess\\": ""
371 }
372 },
373 "notification-url": "https://packagist.org/downloads/",
374 "license": [
375 "MIT"
376 ],
377 "authors": [
378 {
379 "name": "Fabien Potencier",
380 "email": "fabien@symfony.com"
381 },
382 {
383 "name": "Symfony Community",
384 "homepage": "http://symfony.com/contributors"
385 }
386 ],
387 "description": "Symfony PropertyAccess Component",
388 "homepage": "http://symfony.com",
389 "keywords": [
390 "access",
391 "array",
392 "extraction",
393 "index",
394 "injection",
395 "object",
396 "property",
397 "property path",
398 "reflection"
399 ],
400 "time": "2013-07-01 12:24:43"
401 },
402 {
403 "name": "symfony/routing",
404 "version": "v2.3.2",
405 "target-dir": "Symfony/Component/Routing",
406 "source": {
407 "type": "git",
408 "url": "https://github.com/symfony/Routing.git",
409 "reference": "v2.3.2"
410 },
411 "dist": {
412 "type": "zip",
413 "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.2",
414 "reference": "v2.3.2",
415 "shasum": ""
416 },
417 "require": {
418 "php": ">=5.3.3"
419 },
420 "require-dev": {
421 "doctrine/common": "~2.2",
422 "psr/log": "~1.0",
423 "symfony/config": "~2.2",
424 "symfony/yaml": "~2.0"
425 },
426 "suggest": {
427 "doctrine/common": "",
428 "symfony/config": "",
429 "symfony/yaml": ""
430 },
431 "type": "library",
432 "extra": {
433 "branch-alias": {
434 "dev-master": "2.3-dev"
435 }
436 },
437 "autoload": {
438 "psr-0": {
439 "Symfony\\Component\\Routing\\": ""
440 }
441 },
442 "notification-url": "https://packagist.org/downloads/",
443 "license": [
444 "MIT"
445 ],
446 "authors": [
447 {
448 "name": "Fabien Potencier",
449 "email": "fabien@symfony.com"
450 },
451 {
452 "name": "Symfony Community",
453 "homepage": "http://symfony.com/contributors"
454 }
455 ],
456 "description": "Symfony Routing Component",
457 "homepage": "http://symfony.com",
458 "time": "2013-06-23 08:16:02"
459 },
460 {
461 "name": "symfony/translation",
462 "version": "v2.3.2",
463 "target-dir": "Symfony/Component/Translation",
464 "source": {
465 "type": "git",
466 "url": "https://github.com/symfony/Translation.git",
467 "reference": "v2.3.2"
468 },
469 "dist": {
470 "type": "zip",
471 "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.2",
472 "reference": "v2.3.2",
473 "shasum": ""
474 },
475 "require": {
476 "php": ">=5.3.3"
477 },
478 "require-dev": {
479 "symfony/config": "~2.0",
480 "symfony/yaml": "~2.2"
481 },
482 "suggest": {
483 "symfony/config": "",
484 "symfony/yaml": ""
485 },
486 "type": "library",
487 "extra": {
488 "branch-alias": {
489 "dev-master": "2.3-dev"
490 }
491 },
492 "autoload": {
493 "psr-0": {
494 "Symfony\\Component\\Translation\\": ""
495 }
496 },
497 "notification-url": "https://packagist.org/downloads/",
498 "license": [
499 "MIT"
500 ],
501 "authors": [
502 {
503 "name": "Fabien Potencier",
504 "email": "fabien@symfony.com"
505 },
506 {
507 "name": "Symfony Community",
508 "homepage": "http://symfony.com/contributors"
509 }
510 ],
511 "description": "Symfony Translation Component",
512 "homepage": "http://symfony.com",
513 "time": "2013-05-13 14:36:40"
514 },
515 {
516 "name": "symfony/twig-bridge",
517 "version": "v2.3.2",
518 "target-dir": "Symfony/Bridge/Twig",
519 "source": {
520 "type": "git",
521 "url": "https://github.com/symfony/TwigBridge.git",
522 "reference": "v2.3.2"
523 },
524 "dist": {
525 "type": "zip",
526 "url": "https://api.github.com/repos/symfony/TwigBridge/zipball/v2.3.2",
527 "reference": "v2.3.2",
528 "shasum": ""
529 },
530 "require": {
531 "php": ">=5.3.3",
532 "twig/twig": "~1.11"
533 },
534 "require-dev": {
535 "symfony/form": "2.2.*",
536 "symfony/http-kernel": "~2.2",
537 "symfony/routing": "~2.2",
538 "symfony/security": "~2.0",
539 "symfony/templating": "~2.1",
540 "symfony/translation": "~2.2",
541 "symfony/yaml": "~2.0"
542 },
543 "suggest": {
544 "symfony/form": "",
545 "symfony/http-kernel": "",
546 "symfony/routing": "",
547 "symfony/security": "",
548 "symfony/templating": "",
549 "symfony/translation": "",
550 "symfony/yaml": ""
551 },
552 "type": "symfony-bridge",
553 "extra": {
554 "branch-alias": {
555 "dev-master": "2.3-dev"
556 }
557 },
558 "autoload": {
559 "psr-0": {
560 "Symfony\\Bridge\\Twig\\": ""
561 }
562 },
563 "notification-url": "https://packagist.org/downloads/",
564 "license": [
565 "MIT"
566 ],
567 "authors": [
568 {
569 "name": "Fabien Potencier",
570 "email": "fabien@symfony.com"
571 },
572 {
573 "name": "Symfony Community",
574 "homepage": "http://symfony.com/contributors"
575 }
576 ],
577 "description": "Symfony Twig Bridge",
578 "homepage": "http://symfony.com",
579 "time": "2013-05-16 10:19:58"
580 },
581 {
582 "name": "twig/extensions",
583 "version": "v1.0.0",
584 "source": {
585 "type": "git",
586 "url": "https://github.com/fabpot/Twig-extensions.git",
587 "reference": "v1.0.0"
588 },
589 "dist": {
590 "type": "zip",
591 "url": "https://api.github.com/repos/fabpot/Twig-extensions/zipball/v1.0.0",
592 "reference": "v1.0.0",
593 "shasum": ""
594 },
595 "require": {
596 "twig/twig": "1.*"
597 },
598 "type": "library",
599 "extra": {
600 "branch-alias": {
601 "dev-master": "1.0.x-dev"
602 }
603 },
604 "autoload": {
605 "psr-0": {
606 "Twig_Extensions_": "lib/"
607 }
608 },
609 "notification-url": "https://packagist.org/downloads/",
610 "license": [
611 "MIT"
612 ],
613 "authors": [
614 {
615 "name": "Fabien Potencier",
616 "email": "fabien@symfony.com"
617 }
618 ],
619 "description": "Common additional features for Twig that do not directly belong in core",
620 "homepage": "https://github.com/fabpot/Twig-extensions",
621 "keywords": [
622 "debug",
623 "i18n",
624 "text"
625 ],
626 "time": "2013-02-28 14:21:30"
627 },
628 {
629 "name": "twig/twig",
630 "version": "v1.13.2",
631 "source": {
632 "type": "git",
633 "url": "https://github.com/fabpot/Twig.git",
634 "reference": "v1.13.2"
635 },
636 "dist": {
637 "type": "zip",
638 "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.13.2",
639 "reference": "v1.13.2",
640 "shasum": ""
641 },
642 "require": {
643 "php": ">=5.2.4"
644 },
645 "type": "library",
646 "extra": {
647 "branch-alias": {
648 "dev-master": "1.13-dev"
649 }
650 },
651 "autoload": {
652 "psr-0": {
653 "Twig_": "lib/"
654 }
655 },
656 "notification-url": "https://packagist.org/downloads/",
657 "license": [
658 "BSD-3-Clause"
659 ],
660 "authors": [
661 {
662 "name": "Fabien Potencier",
663 "email": "fabien@symfony.com"
664 },
665 {
666 "name": "Armin Ronacher",
667 "email": "armin.ronacher@active-4.com"
668 }
669 ],
670 "description": "Twig, the flexible, fast, and secure template language for PHP",
671 "homepage": "http://twig.sensiolabs.org",
672 "keywords": [
673 "templating"
674 ],
675 "time": "2013-08-03 15:35:31"
676 },
677 {
678 "name": "umpirsky/twig-gettext-extractor",
679 "version": "1.1.3",
680 "source": {
681 "type": "git",
682 "url": "https://github.com/umpirsky/Twig-Gettext-Extractor.git",
683 "reference": "1.1.3"
684 },
685 "dist": {
686 "type": "zip",
687 "url": "https://api.github.com/repos/umpirsky/Twig-Gettext-Extractor/zipball/1.1.3",
688 "reference": "1.1.3",
689 "shasum": ""
690 },
691 "require": {
692 "php": ">=5.3.3",
693 "symfony/filesystem": ">=2.0,<3.0",
694 "symfony/form": ">=2.0,<3.0",
695 "symfony/routing": ">=2.0,<3.0",
696 "symfony/translation": ">=2.0,<3.0",
697 "symfony/twig-bridge": ">=2.0,<3.0",
698 "twig/extensions": "1.0.*",
699 "twig/twig": ">=1.2.0,<2.0-dev"
700 },
701 "require-dev": {
702 "symfony/config": "2.1.*"
703 },
704 "bin": [
705 "twig-gettext-extractor"
706 ],
707 "type": "application",
708 "autoload": {
709 "psr-0": {
710 "Twig\\Gettext": "."
711 }
712 },
713 "notification-url": "https://packagist.org/downloads/",
714 "license": [
715 "MIT"
716 ],
717 "authors": [
718 {
719 "name": "Саша Стаменковић",
720 "email": "umpirsky@gmail.com",
721 "homepage": "http://umpirsky.com"
722 }
723 ],
724 "description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates.",
725 "time": "2013-02-14 16:41:48"
726 }
727 ],
728 "packages-dev": [
729
730 ],
731 "aliases": [
732
733 ],
734 "minimum-stability": "stable",
735 "stability-flags": [
736
737 ],
738 "platform": [
739
740 ],
741 "platform-dev": [
742
743 ]
744}
diff --git a/css/style-dark.css b/css/style-dark.css
deleted file mode 100644
index 0fcced24..00000000
--- a/css/style-dark.css
+++ /dev/null
@@ -1,90 +0,0 @@
1/*** GENERAL ***/
2body {
3 color: #fff;
4 background-color: #0d0d0d;
5}
6
7a, a:hover, a:visited {
8 color: #fff;
9}
10
11#main ul#links li a.current {
12 background-color: #000;
13 color: #fff;
14}
15
16#links a:hover, .backhome a:hover, .support a:hover{
17 background-color: #fff;
18 color: #000;
19}
20
21input[type=submit].delete {
22 background : url('../img/dark/remove.png') no-repeat center center;
23 color : transparent;
24}
25
26#main .entrie {
27 color: #fff;
28 background-color: #000;
29 border: 1px solid #fff;
30}
31
32#main .entrie h2 a:hover {
33 color: #29B1E3;
34}
35
36a.fav span {
37 background: url('../img/dark/star-on.png') no-repeat;
38}
39
40a.fav span:hover {
41 background: url('../img/dark/star-off.png') no-repeat;
42}
43
44a.fav-off span {
45 background: url('../img/dark/star-off.png') no-repeat;
46}
47
48a.fav-off span:hover {
49 background: url('../img/dark/star-on.png') no-repeat;
50}
51
52a.archive span {
53 background: url('../img/dark/checkmark-on.png') no-repeat;
54}
55
56a.archive span:hover {
57 background: url('../img/dark/checkmark-off.png') no-repeat;
58}
59
60a.archive-off span {
61 background: url('../img/dark/checkmark-off.png') no-repeat;
62}
63
64a.archive-off span:hover {
65 background: url('../img/dark/checkmark-on.png') no-repeat;
66}
67
68/*** ***/
69/*** ARTICLE PAGE ***/
70
71body.article {
72 color: #fff;
73 background-color: #0d0d0d;
74}
75
76#article header {
77 border-bottom: 1px solid #222222;
78}
79
80#article article {
81 border-bottom: 1px solid #222222;
82}
83
84.vieworiginal a {
85 color: #888888;
86}
87
88.entrie {
89 background-color: #fff;
90}
diff --git a/css/style-light.css b/css/style-light.css
deleted file mode 100644
index c1d98326..00000000
--- a/css/style-light.css
+++ /dev/null
@@ -1,100 +0,0 @@
1/*** GENERAL ***/
2body {
3 color: #222222;
4 background-color: #F1F1F1;
5}
6
7a, a:hover, a:visited {
8 color: #000;
9}
10
11.bouton {
12 background-color: #000;
13 color: #fff;
14 border: none;
15}
16.bouton:hover {
17 background-color: #222222;
18 color: #F1F1F1;
19}
20
21#main ul#links li a.current {
22 background-color: #000;
23 color: #fff;
24}
25
26#links a:hover, .backhome a:hover, .support a:hover{
27 background-color: #040707;
28 color: #F1F1F1;
29}
30
31input[type=submit].delete {
32 background : url('../img/light/remove.png') no-repeat center center;
33 color : transparent;
34}
35
36#main .entrie {
37 color: #2e2e2e;
38 background-color: #ffffff;
39 border: 1px solid #000;
40}
41
42#main .entrie h2 a:hover {
43 color: #F5BE00;
44}
45
46a.fav span {
47 background: url('../img/light/star-on.png') no-repeat;
48}
49
50a.fav span:hover {
51 background: url('../img/light/star-off.png') no-repeat;
52}
53
54a.fav-off span {
55 background: url('../img/light/star-off.png') no-repeat;
56}
57
58a.fav-off span:hover {
59 background: url('../img/light/star-on.png') no-repeat;
60}
61
62a.archive span {
63 background: url('../img/light/checkmark-on.png') no-repeat;
64}
65
66a.archive span:hover {
67 background: url('../img/light/checkmark-off.png') no-repeat;
68}
69
70a.archive-off span {
71 background: url('../img/light/checkmark-off.png') no-repeat;
72}
73
74a.archive-off span:hover {
75 background: url('../img/light/checkmark-on.png') no-repeat;
76}
77
78/*** ***/
79/*** ARTICLE PAGE ***/
80
81body.article {
82 color: #222222;
83 background-color: #F1F1F1;
84}
85
86#article header {
87 border-bottom: 1px solid #222222;
88}
89
90#article article {
91 border-bottom: 1px solid #222222;
92}
93
94.vieworiginal a {
95 color: #888888;
96}
97
98.entrie {
99 background-color: #fff;
100}
diff --git a/css/style.css b/css/style.css
deleted file mode 100644
index 28e18b96..00000000
--- a/css/style.css
+++ /dev/null
@@ -1,223 +0,0 @@
1/*** GENERAL ***/
2body {
3 font: 20px/1.3em Palatino,Georgia,serif;
4 margin: 10px;
5}
6
7header {
8 text-align: center;
9}
10
11.bouton {
12 border-radius: 2px;
13}
14
15#main ul#links {
16 padding: 0;
17 list-style-type: none;
18 text-align: center;
19}
20
21#main ul#links li {
22 display: inline;
23}
24
25#main ul#links li a.current {
26 -webkit-border-radius: 2px;
27 border-radius: 2px;
28}
29
30#main ul#sort {
31 padding: 0;
32 list-style-type: none;
33 text-align: center;
34}
35
36#main ul#sort li {
37 display: inline;
38 font-size: 0.9em;
39}
40
41#main ul#sort img:hover {
42 cursor: pointer;
43}
44
45#main, #article {
46 margin: 0 auto;
47}
48
49#links a, .backhome a, .support a{
50 text-decoration: none;
51 padding: 5px 10px;
52}
53#links a:hover, .backhome a:hover, .support a:hover{
54 -webkit-border-radius: 2px;
55 border-radius: 2px;
56}
57
58.support {
59 font-size: 14px;
60}
61
62footer {
63 text-align: right;
64}
65
66/*** ***/
67/*** LINKS DISPLAY ***/
68
69#main a.tool {
70 text-decoration: none;
71 cursor: pointer;
72}
73
74input[type=submit].delete {
75 width : 16px;
76 height :16px;
77 border : none;
78 cursor: pointer;
79 font-size : 0;
80}
81
82#main #content {
83 margin-top: 20px;
84}
85
86#main .entrie {
87 padding: 15px;
88 min-height: 8em;
89 border: 1px solid;
90}
91
92#main .entrie h2 a {
93 text-decoration: none;
94}
95
96.tools {
97 text-align: right;
98}
99
100.tools ul {
101 padding: 0; margin: 0;
102 list-style-type: none;
103}
104
105.tools ul li {
106 line-height: 20px;
107}
108
109.tools a.tool {
110 cursor: pointer;
111}
112
113#article .tools {
114 position: relative;
115 display: inline;
116 top: 0px;
117 right: 0px;
118 width: 100%;
119 text-align: left;
120}
121
122#article .tools ul li{
123 display: inline;
124}
125
126#main .entrie .tools a.tool span, #article .tools a.tool span {
127 display: inline-block;
128 width: 16px;
129 height: 16px;
130}
131
132#main .entrie .url {
133 font-size: 13px;
134}
135
136
137/*** ***/
138/*** ARTICLE PAGE ***/
139
140body.article {
141 font: 20px/1.3em Palatino,Georgia,serif;
142}
143
144#article header {
145 text-align: left;
146}
147
148#article header a {
149 text-decoration: none;
150}
151
152.vieworiginal a {
153 text-decoration: none;
154}
155
156.backhome {
157 display: inline;
158}
159
160/*** ***/
161
162#main
163{
164 max-width: 60em; /* 960 px */
165 margin: 0 auto;
166}
167#content
168{
169 width: 103.125%; /* 990px */
170 overflow: hidden;
171 margin-left: -1.562%; /* 15px */
172 margin-bottom: -1.875em; /* 30px */
173}
174
175.entrie
176{
177 width: 30.303%; /* 300px */
178 background-color: #fff;
179 float: left;
180 margin: 0 1.515% 1.875em; /* 15px 30px */
181}
182
183@media only screen and ( max-width: 40em ) /* 640px */
184{
185 .entrie
186 {
187 width: 46.876%; /* 305px */
188 margin-bottom: 0.938em; /* 15px */
189 }
190}
191
192@media only screen and ( max-width: 20em ) /* 320px */
193{
194 #content
195 {
196 width: 100%;
197 margin-left: 0;
198 }
199
200 .entrie
201 {
202 width: 100%;
203 margin-left: 0;
204 margin-right: 0;
205 }
206}
207
208/*** ***/
209/*** MESSAGES ***/
210
211.messages { width: 100%; -moz-border-radius: 4px; border-radius: 4px; display: block; padding: 10px 0; margin: 10px auto 10px; clear: both; }
212.messages a.closeMessage { margin: -14px -8px 0 0; display:none; width: 16px; height: 16px; float: right; background: url(../img/messages/close.png) no-repeat; }
213/*.messages:hover a.closeMessage { visibility:visible; }*/
214.messages p { margin: 3px 0 3px 10px !important; padding: 0 10px 0 23px !important; font-size: 14px; line-height: 16px; }
215.messages.error { border: 1px solid #C42608; color: #c00 !important; background: #FFF0EF; }
216.messages.error p { background: url(../img/messages/cross.png ) no-repeat 0px 50%; color:#c00 !important; }
217.messages.success {background: #E0FBCC; border: 1px solid #6DC70C; }
218.messages.success p { background: url(../img/messages/tick.png) no-repeat 0px 50%; color: #2B6301 !important; }
219.messages.warning { background: #FFFCD3; border: 1px solid #EBCD41; color: #000; }
220.messages.warning p { background: url(../img/messages/warning.png ) no-repeat 0px 50%; color: #5F4E01; }
221.messages.information, .messages.info { background: #DFEBFB; border: 1px solid #82AEE7; }
222.messages.information p, .messages.info p { background: url(../img/messages/help.png ) no-repeat 0px 50%; color: #064393; }
223.messages.information a { text-decoration: underline; }
diff --git a/img/dark/checkmark-off.png b/img/dark/checkmark-off.png
deleted file mode 100644
index efc3439f..00000000
--- a/img/dark/checkmark-off.png
+++ /dev/null
Binary files differ
diff --git a/img/dark/checkmark-on.png b/img/dark/checkmark-on.png
deleted file mode 100644
index 24391c2e..00000000
--- a/img/dark/checkmark-on.png
+++ /dev/null
Binary files differ
diff --git a/img/dark/down.png b/img/dark/down.png
deleted file mode 100644
index 41ea9604..00000000
--- a/img/dark/down.png
+++ /dev/null
Binary files differ
diff --git a/img/dark/logo.png b/img/dark/logo.png
deleted file mode 100644
index 9fba0642..00000000
--- a/img/dark/logo.png
+++ /dev/null
Binary files differ
diff --git a/img/dark/remove.png b/img/dark/remove.png
deleted file mode 100644
index 41786fd7..00000000
--- a/img/dark/remove.png
+++ /dev/null
Binary files differ
diff --git a/img/dark/star-off.png b/img/dark/star-off.png
deleted file mode 100644
index 90651b54..00000000
--- a/img/dark/star-off.png
+++ /dev/null
Binary files differ
diff --git a/img/dark/star-on.png b/img/dark/star-on.png
deleted file mode 100644
index 7fc14477..00000000
--- a/img/dark/star-on.png
+++ /dev/null
Binary files differ
diff --git a/img/dark/up.png b/img/dark/up.png
deleted file mode 100644
index 1679e18f..00000000
--- a/img/dark/up.png
+++ /dev/null
Binary files differ
diff --git a/img/logo.png b/img/logo.png
deleted file mode 100644
index f917857f..00000000
--- a/img/logo.png
+++ /dev/null
Binary files differ
diff --git a/import.php b/import.php
deleted file mode 100644
index 45fe8334..00000000
--- a/import.php
+++ /dev/null
@@ -1,73 +0,0 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11set_time_limit(0);
12
13include dirname(__FILE__).'/inc/config.php';
14include dirname(__FILE__).'/inc/simple_html_dom.php';
15
16if (!isset($_GET['start'])) {
17 echo _('Please execute the import script locally, it can take a very long time.') . '<br /><br />' . _('Please choose between Pocket & Readabilty :') . '<br /><a href="import.php?start=pocket">' . _('Bye bye Pocket, let\'s go !') . '</a><br /><a href="import.php?start=readability">' . _('Bye bye Readability, let\'s go !') . '</a>';
18}
19else {
20 if ($_GET['start'] == 'pocket') {
21 $html = new simple_html_dom();
22 $html->load_file('ril_export.html');
23
24 $read = 0;
25 $errors = array();
26 foreach($html->find('ul') as $ul)
27 {
28 foreach($ul->find('li') as $li)
29 {
30 $a = $li->find('a');
31 $url = $a[0]->href;
32
33 action_to_do('add', $url);
34 if ($read == '1') {
35 $last_id = $db->getHandle()->lastInsertId();
36 $sql_update = "UPDATE entries SET is_read=~is_read WHERE id=?";
37 $params_update = array($last_id);
38 $query_update = $db->getHandle()->prepare($sql_update);
39 $query_update->execute($params_update);
40 }
41 }
42 # Pocket génère un fichier HTML avec deux <ul>
43 # Le premier concerne les éléments non lus
44 # Le second concerne les éléments archivés
45 $read = 1;
46 }
47
48 echo _('Import from Pocket completed.') . '<a href="index.php">' . _('Welcome to poche !') .'</a>';
49 logm('import from pocket completed');
50 }
51 else if ($_GET['start'] == 'readability') {
52 $str_data = file_get_contents("readability");
53 $data = json_decode($str_data,true);
54
55 foreach ($data as $key => $value) {
56 $url = '';
57 foreach ($value as $key2 => $value2) {
58 if ($key2 == 'article__url') {
59 $url = $value2;
60 }
61 }
62 if ($url != '')
63 action_to_do('add', $url);
64 }
65
66 echo _('Import from Readability completed.') . '<a href="index.php">' . _('Welcome to poche !') . '</a>';
67 logm('import from Readability completed');
68 }
69 else {
70 echo _('Error with the import.') . '<a href="index.php">' . _('Back to poche'). '</a>';
71 logm('error with the import');
72 }
73} \ No newline at end of file
diff --git a/inc/Encoding.php b/inc/3rdparty/Encoding.php
index 577763b4..577763b4 100644
--- a/inc/Encoding.php
+++ b/inc/3rdparty/Encoding.php
diff --git a/inc/JSLikeHTMLElement.php b/inc/3rdparty/JSLikeHTMLElement.php
index 238ba8a8..238ba8a8 100644
--- a/inc/JSLikeHTMLElement.php
+++ b/inc/3rdparty/JSLikeHTMLElement.php
diff --git a/inc/Readability.php b/inc/3rdparty/Readability.php
index e1e8738b..e1e8738b 100644
--- a/inc/Readability.php
+++ b/inc/3rdparty/Readability.php
diff --git a/inc/Session.class.php b/inc/3rdparty/Session.class.php
index eff924cc..3162f507 100644
--- a/inc/Session.class.php
+++ b/inc/3rdparty/Session.class.php
@@ -93,7 +93,7 @@ class Session
93 // Force logout 93 // Force logout
94 public static function logout() 94 public static function logout()
95 { 95 {
96 unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on'],$_SESSION['tokens'], $_SESSION['login'], $_SESSION['pass']); 96 unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on'],$_SESSION['tokens'], $_SESSION['login'], $_SESSION['pass'], $_SESSION['poche_user']);
97 } 97 }
98 98
99 // Make sure user is logged in. 99 // Make sure user is logged in.
diff --git a/inc/class.messages.php b/inc/3rdparty/class.messages.php
index 6d515bf6..e60bd3a1 100644..100755
--- a/inc/class.messages.php
+++ b/inc/3rdparty/class.messages.php
@@ -1,231 +1,231 @@
1<?php 1<?php
2//-------------------------------------------------------------------------------------------------- 2//--------------------------------------------------------------------------------------------------
3// Session-Based Flash Messages v1.0 3// Session-Based Flash Messages v1.0
4// Copyright 2012 Mike Everhart (http://mikeeverhart.net) 4// Copyright 2012 Mike Everhart (http://mikeeverhart.net)
5// 5//
6// Licensed under the Apache License, Version 2.0 (the "License"); 6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License. 7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at 8// You may obtain a copy of the License at
9// 9//
10// http://www.apache.org/licenses/LICENSE-2.0 10// http://www.apache.org/licenses/LICENSE-2.0
11// 11//
12// Unless required by applicable law or agreed to in writing, software 12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS, 13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and 15// See the License for the specific language governing permissions and
16// limitations under the License. 16// limitations under the License.
17// 17//
18//------------------------------------------------------------------------------ 18//------------------------------------------------------------------------------
19// Description: 19// Description:
20//------------------------------------------------------------------------------ 20//------------------------------------------------------------------------------
21// 21//
22// Stores messages in Session data to be easily retrieved later on. 22// Stores messages in Session data to be easily retrieved later on.
23// This class includes four different types of messages: 23// This class includes four different types of messages:
24// - Success 24// - Success
25// - Error 25// - Error
26// - Warning 26// - Warning
27// - Information 27// - Information
28// 28//
29// See README for basic usage instructions, or see samples/index.php for more advanced samples 29// See README for basic usage instructions, or see samples/index.php for more advanced samples
30// 30//
31//-------------------------------------------------------------------------------------------------- 31//--------------------------------------------------------------------------------------------------
32// Changelog 32// Changelog
33//-------------------------------------------------------------------------------------------------- 33//--------------------------------------------------------------------------------------------------
34// 34//
35// 2011-05-15 - v1.0 - Initial Version 35// 2011-05-15 - v1.0 - Initial Version
36// 36//
37//-------------------------------------------------------------------------------------------------- 37//--------------------------------------------------------------------------------------------------
38 38
39class Messages { 39class Messages {
40 40
41 //----------------------------------------------------------------------------------------------- 41 //-----------------------------------------------------------------------------------------------
42 // Class Variables 42 // Class Variables
43 //----------------------------------------------------------------------------------------------- 43 //-----------------------------------------------------------------------------------------------
44 var $msgId; 44 var $msgId;
45 var $msgTypes = array( 'help', 'info', 'warning', 'success', 'error' ); 45 var $msgTypes = array( 'help', 'info', 'warning', 'success', 'error' );
46 var $msgClass = 'messages'; 46 var $msgClass = 'messages';
47 var $msgWrapper = "<div class='%s %s'><a href='#' class='closeMessage'></a>\n%s</div>\n"; 47 var $msgWrapper = "<div class='%s %s'><a href='#' class='closeMessage'>X</a>\n%s</div>\n";
48 var $msgBefore = '<p>'; 48 var $msgBefore = '<p>';
49 var $msgAfter = "</p>\n"; 49 var $msgAfter = "</p>\n";
50 50
51 51
52 /** 52 /**
53 * Constructor 53 * Constructor
54 * @author Mike Everhart 54 * @author Mike Everhart
55 */ 55 */
56 public function __construct() { 56 public function __construct() {
57 57
58 // Generate a unique ID for this user and session 58 // Generate a unique ID for this user and session
59 $this->msgId = md5(uniqid()); 59 $this->msgId = md5(uniqid());
60 60
61 // Create the session array if it doesnt already exist 61 // Create the session array if it doesnt already exist
62 if( !array_key_exists('flash_messages', $_SESSION) ) $_SESSION['flash_messages'] = array(); 62 if( !array_key_exists('flash_messages', $_SESSION) ) $_SESSION['flash_messages'] = array();
63 63
64 } 64 }
65 65
66 /** 66 /**
67 * Add a message to the queue 67 * Add a message to the queue
68 * 68 *
69 * @author Mike Everhart 69 * @author Mike Everhart
70 * 70 *
71 * @param string $type The type of message to add 71 * @param string $type The type of message to add
72 * @param string $message The message 72 * @param string $message The message
73 * @param string $redirect_to (optional) If set, the user will be redirected to this URL 73 * @param string $redirect_to (optional) If set, the user will be redirected to this URL
74 * @return bool 74 * @return bool
75 * 75 *
76 */ 76 */
77 public function add($type, $message, $redirect_to=null) { 77 public function add($type, $message, $redirect_to=null) {
78 78
79 if( !isset($_SESSION['flash_messages']) ) return false; 79 if( !isset($_SESSION['flash_messages']) ) return false;
80 80
81 if( !isset($type) || !isset($message[0]) ) return false; 81 if( !isset($type) || !isset($message[0]) ) return false;
82 82
83 // Replace any shorthand codes with their full version 83 // Replace any shorthand codes with their full version
84 if( strlen(trim($type)) == 1 ) { 84 if( strlen(trim($type)) == 1 ) {
85 $type = str_replace( array('h', 'i', 'w', 'e', 's'), array('help', 'info', 'warning', 'error', 'success'), $type ); 85 $type = str_replace( array('h', 'i', 'w', 'e', 's'), array('help', 'info', 'warning', 'error', 'success'), $type );
86 86
87 // Backwards compatibility... 87 // Backwards compatibility...
88 } elseif( $type == 'information' ) { 88 } elseif( $type == 'information' ) {
89 $type = 'info'; 89 $type = 'info';
90 } 90 }
91 91
92 // Make sure it's a valid message type 92 // Make sure it's a valid message type
93 if( !in_array($type, $this->msgTypes) ) die('"' . strip_tags($type) . '" is not a valid message type!' ); 93 if( !in_array($type, $this->msgTypes) ) die('"' . strip_tags($type) . '" is not a valid message type!' );
94 94
95 // If the session array doesn't exist, create it 95 // If the session array doesn't exist, create it
96 if( !array_key_exists( $type, $_SESSION['flash_messages'] ) ) $_SESSION['flash_messages'][$type] = array(); 96 if( !array_key_exists( $type, $_SESSION['flash_messages'] ) ) $_SESSION['flash_messages'][$type] = array();
97 97
98 $_SESSION['flash_messages'][$type][] = $message; 98 $_SESSION['flash_messages'][$type][] = $message;
99 99
100 if( !is_null($redirect_to) ) { 100 if( !is_null($redirect_to) ) {
101 header("Location: $redirect_to"); 101 header("Location: $redirect_to");
102 exit(); 102 exit();
103 } 103 }
104 104
105 return true; 105 return true;
106 106
107 } 107 }
108 108
109 //----------------------------------------------------------------------------------------------- 109 //-----------------------------------------------------------------------------------------------
110 // display() 110 // display()
111 // print queued messages to the screen 111 // print queued messages to the screen
112 //----------------------------------------------------------------------------------------------- 112 //-----------------------------------------------------------------------------------------------
113 /** 113 /**
114 * Display the queued messages 114 * Display the queued messages
115 * 115 *
116 * @author Mike Everhart 116 * @author Mike Everhart
117 * 117 *
118 * @param string $type Which messages to display 118 * @param string $type Which messages to display
119 * @param bool $print True = print the messages on the screen 119 * @param bool $print True = print the messages on the screen
120 * @return mixed 120 * @return mixed
121 * 121 *
122 */ 122 */
123 public function display($type='all', $print=true) { 123 public function display($type='all', $print=true) {
124 $messages = ''; 124 $messages = '';
125 $data = ''; 125 $data = '';
126 126
127 if( !isset($_SESSION['flash_messages']) ) return false; 127 if( !isset($_SESSION['flash_messages']) ) return false;
128 128
129 if( $type == 'g' || $type == 'growl' ) { 129 if( $type == 'g' || $type == 'growl' ) {
130 $this->displayGrowlMessages(); 130 $this->displayGrowlMessages();
131 return true; 131 return true;
132 } 132 }
133 133
134 // Print a certain type of message? 134 // Print a certain type of message?
135 if( in_array($type, $this->msgTypes) ) { 135 if( in_array($type, $this->msgTypes) ) {
136 foreach( $_SESSION['flash_messages'][$type] as $msg ) { 136 foreach( $_SESSION['flash_messages'][$type] as $msg ) {
137 $messages .= $this->msgBefore . $msg . $this->msgAfter; 137 $messages .= $this->msgBefore . $msg . $this->msgAfter;
138 } 138 }
139 139
140 $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); 140 $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages);
141 141
142 // Clear the viewed messages 142 // Clear the viewed messages
143 $this->clear($type); 143 $this->clear($type);
144 144
145 // Print ALL queued messages 145 // Print ALL queued messages
146 } elseif( $type == 'all' ) { 146 } elseif( $type == 'all' ) {
147 foreach( $_SESSION['flash_messages'] as $type => $msgArray ) { 147 foreach( $_SESSION['flash_messages'] as $type => $msgArray ) {
148 $messages = ''; 148 $messages = '';
149 foreach( $msgArray as $msg ) { 149 foreach( $msgArray as $msg ) {
150 $messages .= $this->msgBefore . $msg . $this->msgAfter; 150 $messages .= $this->msgBefore . $msg . $this->msgAfter;
151 } 151 }
152 $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); 152 $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages);
153 } 153 }
154 154
155 // Clear ALL of the messages 155 // Clear ALL of the messages
156 $this->clear(); 156 $this->clear();
157 157
158 // Invalid Message Type? 158 // Invalid Message Type?
159 } else { 159 } else {
160 return false; 160 return false;
161 } 161 }
162 162
163 // Print everything to the screen or return the data 163 // Print everything to the screen or return the data
164 if( $print ) { 164 if( $print ) {
165 echo $data; 165 echo $data;
166 } else { 166 } else {
167 return $data; 167 return $data;
168 } 168 }
169 } 169 }
170 170
171 171
172 /** 172 /**
173 * Check to see if there are any queued error messages 173 * Check to see if there are any queued error messages
174 * 174 *
175 * @author Mike Everhart 175 * @author Mike Everhart
176 * 176 *
177 * @return bool true = There ARE error messages 177 * @return bool true = There ARE error messages
178 * false = There are NOT any error messages 178 * false = There are NOT any error messages
179 * 179 *
180 */ 180 */
181 public function hasErrors() { 181 public function hasErrors() {
182 return empty($_SESSION['flash_messages']['error']) ? false : true; 182 return empty($_SESSION['flash_messages']['error']) ? false : true;
183 } 183 }
184 184
185 /** 185 /**
186 * Check to see if there are any ($type) messages queued 186 * Check to see if there are any ($type) messages queued
187 * 187 *
188 * @author Mike Everhart 188 * @author Mike Everhart
189 * 189 *
190 * @param string $type The type of messages to check for 190 * @param string $type The type of messages to check for
191 * @return bool 191 * @return bool
192 * 192 *
193 */ 193 */
194 public function hasMessages($type=null) { 194 public function hasMessages($type=null) {
195 if( !is_null($type) ) { 195 if( !is_null($type) ) {
196 if( !empty($_SESSION['flash_messages'][$type]) ) return $_SESSION['flash_messages'][$type]; 196 if( !empty($_SESSION['flash_messages'][$type]) ) return $_SESSION['flash_messages'][$type];
197 } else { 197 } else {
198 foreach( $this->msgTypes as $type ) { 198 foreach( $this->msgTypes as $type ) {
199 if( !empty($_SESSION['flash_messages']) ) return true; 199 if( !empty($_SESSION['flash_messages']) ) return true;
200 } 200 }
201 } 201 }
202 return false; 202 return false;
203 } 203 }
204 204
205 /** 205 /**
206 * Clear messages from the session data 206 * Clear messages from the session data
207 * 207 *
208 * @author Mike Everhart 208 * @author Mike Everhart
209 * 209 *
210 * @param string $type The type of messages to clear 210 * @param string $type The type of messages to clear
211 * @return bool 211 * @return bool
212 * 212 *
213 */ 213 */
214 public function clear($type='all') { 214 public function clear($type='all') {
215 if( $type == 'all' ) { 215 if( $type == 'all' ) {
216 unset($_SESSION['flash_messages']); 216 unset($_SESSION['flash_messages']);
217 } else { 217 } else {
218 unset($_SESSION['flash_messages'][$type]); 218 unset($_SESSION['flash_messages'][$type]);
219 } 219 }
220 return true; 220 return true;
221 } 221 }
222 222
223 public function __toString() { return $this->hasMessages(); } 223 public function __toString() { return $this->hasMessages(); }
224 224
225 public function __destruct() { 225 public function __destruct() {
226 //$this->clear(); 226 //$this->clear();
227 } 227 }
228 228
229 229
230} // end class 230} // end class
231?> \ No newline at end of file 231?> \ No newline at end of file
diff --git a/inc/3rdparty/paginator.php b/inc/3rdparty/paginator.php
new file mode 100644
index 00000000..306756c0
--- /dev/null
+++ b/inc/3rdparty/paginator.php
@@ -0,0 +1,202 @@
1<?php
2/*
3 * PHP Pagination Class
4 *
5 * @author David Carr - dave@daveismyname.com - http://www.daveismyname.com
6 * @version 1.0
7 * @date October 20, 2013
8 */
9class Paginator{
10
11 /**
12 * set the number of items per page.
13 *
14 * @var numeric
15 */
16 private $_perPage;
17
18 /**
19 * set get parameter for fetching the page number
20 *
21 * @var string
22 */
23 private $_instance;
24
25 /**
26 * sets the page number.
27 *
28 * @var numeric
29 */
30 private $_page;
31
32 /**
33 * set the limit for the data source
34 *
35 * @var string
36 */
37 private $_limit;
38
39 /**
40 * set the total number of records/items.
41 *
42 * @var numeric
43 */
44 private $_totalRows = 0;
45
46
47
48 /**
49 * __construct
50 *
51 * pass values when class is istantiated
52 *
53 * @param numeric $_perPage sets the number of iteems per page
54 * @param numeric $_instance sets the instance for the GET parameter
55 */
56 public function __construct($perPage,$instance){
57 $this->_instance = $instance;
58 $this->_perPage = $perPage;
59 $this->set_instance();
60 }
61
62 /**
63 * get_start
64 *
65 * creates the starting point for limiting the dataset
66 * @return numeric
67 */
68 private function get_start(){
69 return ($this->_page * $this->_perPage) - $this->_perPage;
70 }
71
72 /**
73 * set_instance
74 *
75 * sets the instance parameter, if numeric value is 0 then set to 1
76 *
77 * @var numeric
78 */
79 private function set_instance(){
80 $this->_page = (int) (!isset($_GET[$this->_instance]) ? 1 : $_GET[$this->_instance]);
81 $this->_page = ($this->_page == 0 ? 1 : $this->_page);
82 }
83
84 /**
85 * set_total
86 *
87 * collect a numberic value and assigns it to the totalRows
88 *
89 * @var numeric
90 */
91 public function set_total($_totalRows){
92 $this->_totalRows = $_totalRows;
93 }
94
95 /**
96 * get_limit
97 *
98 * returns the limit for the data source, calling the get_start method and passing in the number of items perp page
99 *
100 * @return string
101 */
102 public function get_limit(){
103 if (STORAGE == 'postgres') {
104 return "LIMIT ".$this->_perPage." OFFSET ".$this->get_start();
105 } else {
106 return "LIMIT ".$this->get_start().",".$this->_perPage;
107 }
108 }
109
110 /**
111 * page_links
112 *
113 * create the html links for navigating through the dataset
114 *
115 * @var sting $path optionally set the path for the link
116 * @var sting $ext optionally pass in extra parameters to the GET
117 * @return string returns the html menu
118 */
119 public function page_links($path='?',$ext=null)
120 {
121 $adjacents = "2";
122 $prev = $this->_page - 1;
123 $next = $this->_page + 1;
124 $lastpage = ceil($this->_totalRows/$this->_perPage);
125 $lpm1 = $lastpage - 1;
126
127 $pagination = "";
128 if($lastpage > 1)
129 {
130 $pagination .= "<div class='pagination'>";
131 if ($this->_page > 1)
132 $pagination.= "<a href='".$path."$this->_instance=$prev"."$ext'>« previous</a>";
133 else
134 $pagination.= "<span class='disabled'>« previous</span>";
135
136 if ($lastpage < 7 + ($adjacents * 2))
137 {
138 for ($counter = 1; $counter <= $lastpage; $counter++)
139 {
140 if ($counter == $this->_page)
141 $pagination.= "<span class='current'>$counter</span>";
142 else
143 $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
144 }
145 }
146 elseif($lastpage > 5 + ($adjacents * 2))
147 {
148 if($this->_page < 1 + ($adjacents * 2))
149 {
150 for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++)
151 {
152 if ($counter == $this->_page)
153 $pagination.= "<span class='current'>$counter</span>";
154 else
155 $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
156 }
157 $pagination.= "...";
158 $pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>";
159 $pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>";
160 }
161 elseif($lastpage - ($adjacents * 2) > $this->_page && $this->_page > ($adjacents * 2))
162 {
163 $pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>";
164 $pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>";
165 $pagination.= "...";
166 for ($counter = $this->_page - $adjacents; $counter <= $this->_page + $adjacents; $counter++)
167 {
168 if ($counter == $this->_page)
169 $pagination.= "<span class='current'>$counter</span>";
170 else
171 $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
172 }
173 $pagination.= "..";
174 $pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>";
175 $pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>";
176 }
177 else
178 {
179 $pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>";
180 $pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>";
181 $pagination.= "..";
182 for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++)
183 {
184 if ($counter == $this->_page)
185 $pagination.= "<span class='current'>$counter</span>";
186 else
187 $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
188 }
189 }
190 }
191
192 if ($this->_page < $counter - 1)
193 $pagination.= "<a href='".$path."$this->_instance=$next"."$ext'>next »</a>";
194 else
195 $pagination.= "<span class='disabled'>next »</span>";
196 $pagination.= "</div>\n";
197 }
198
199
200 return $pagination;
201 }
202}
diff --git a/inc/simple_html_dom.php b/inc/3rdparty/simple_html_dom.php
index 43b94e57..43b94e57 100644
--- a/inc/simple_html_dom.php
+++ b/inc/3rdparty/simple_html_dom.php
diff --git a/inc/MyTool.class.php b/inc/MyTool.class.php
deleted file mode 100644
index b11f18e9..00000000
--- a/inc/MyTool.class.php
+++ /dev/null
@@ -1,265 +0,0 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class MyTool
12{
13 public static function initPhp()
14 {
15 define('START_TIME', microtime(true));
16
17 if (phpversion() < 5) {
18 die(_('Oops, it seems you don\'t have PHP 5.'));
19 }
20
21 error_reporting(E_ALL);
22
23 function stripslashesDeep($value) {
24 return is_array($value)
25 ? array_map('stripslashesDeep', $value)
26 : stripslashes($value);
27 }
28
29 if (get_magic_quotes_gpc()) {
30 $_POST = array_map('stripslashesDeep', $_POST);
31 $_GET = array_map('stripslashesDeep', $_GET);
32 $_COOKIE = array_map('stripslashesDeep', $_COOKIE);
33 }
34
35 ob_start();
36 register_shutdown_function('ob_end_flush');
37 }
38
39 public static function isUrl($url)
40 {
41 // http://neo22s.com/check-if-url-exists-and-is-online-php/
42 $pattern='|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i';
43
44 return preg_match($pattern, $url);
45 }
46
47 public static function isEmail($email)
48 {
49 $pattern = "/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2, 4}$/i";
50
51 return (preg_match($pattern, $email));
52 }
53
54 public static function formatBBCode($text)
55 {
56 $replace = array(
57 '/\[m\](.+?)\[\/m\]/is'
58 => '/* moderate */',
59 '/\[b\](.+?)\[\/b\]/is'
60 => '<strong>$1</strong>',
61 '/\[i\](.+?)\[\/i\]/is'
62 => '<em>$1</em>',
63 '/\[s\](.+?)\[\/s\]/is'
64 => '<del>$1</del>',
65 '/\[u\](.+?)\[\/u\]/is'
66 => '<span style="text-decoration: underline;">$1</span>',
67 '/\[url\](.+?)\[\/url]/is'
68 => '<a href="$1">$1</a>',
69 '/\[url=(\w+:\/\/[^\]]+)\](.+?)\[\/url]/is'
70 => '<a href="$1">$2</a>',
71 '/\[quote\](.+?)\[\/quote\]/is'
72 => '<blockquote>$1</blockquote>',
73 '/\[code\](.+?)\[\/code\]/is'
74 => '<code>$1</code>',
75 '/\[([^[]+)\|([^[]+)\]/is'
76 => '<a href="$2">$1</a>'
77 );
78 $text = preg_replace(
79 array_keys($replace),
80 array_values($replace),
81 $text
82 );
83
84 return $text;
85 }
86
87 public static function formatText($text)
88 {
89 $text = preg_replace_callback(
90 '/<code_html>(.*?)<\/code_html>/is',
91 create_function(
92 '$matches',
93 'return htmlspecialchars($matches[1]);'
94 ),
95 $text
96 );
97 $text = preg_replace_callback(
98 '/<code_php>(.*?)<\/code_php>/is',
99 create_function(
100 '$matches',
101 'return highlight_string("<?php $matches[1] ?>", true);'
102 ),
103 $text
104 );
105 $text = preg_replace('/<br \/>/is', '', $text);
106
107 $text = preg_replace(
108 '#(^|\s)([a-z]+://([^\s\w/]?[\w/])*)(\s|$)#im',
109 '\\1<a href="\\2">\\2</a>\\4',
110 $text
111 );
112 $text = preg_replace(
113 '#(^|\s)wp:?([a-z]{2}|):([\w]+)#im',
114 '\\1<a href="http://\\2.wikipedia.org/wiki/\\3">\\3</a>',
115 $text
116 );
117 $text = str_replace(
118 'http://.wikipedia.org/wiki/',
119 'http://www.wikipedia.org/wiki/',
120 $text
121 );
122 $text = str_replace('\wp:', 'wp:', $text);
123 $text = str_replace('\http:', 'http:', $text);
124 $text = MyTool::formatBBCode($text);
125 $text = nl2br($text);
126
127 return $text;
128 }
129
130 public static function getUrl()
131 {
132 $https = (!empty($_SERVER['HTTPS'])
133 && (strtolower($_SERVER['HTTPS']) == 'on'))
134 || (isset($_SERVER["SERVER_PORT"])
135 && $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection.
136 $serverport = (!isset($_SERVER["SERVER_PORT"])
137 || $_SERVER["SERVER_PORT"] == '80'
138 || ($https && $_SERVER["SERVER_PORT"] == '443')
139 ? ''
140 : ':' . $_SERVER["SERVER_PORT"]);
141
142 $scriptname = str_replace('/index.php', '/', $_SERVER["SCRIPT_NAME"]);
143
144 if (!isset($_SERVER["SERVER_NAME"])) {
145 return $scriptname;
146 }
147
148 return 'http' . ($https ? 's' : '') . '://'
149 . $_SERVER["SERVER_NAME"] . $serverport . $scriptname;
150 }
151
152 public static function rrmdir($dir)
153 {
154 if (is_dir($dir) && ($d = @opendir($dir))) {
155 while (($file = @readdir($d)) !== false) {
156 if ( $file == '.' || $file == '..' ) {
157 continue;
158 } else {
159 unlink($dir . '/' . $file);
160 }
161 }
162 }
163 }
164
165 public static function humanBytes($bytes)
166 {
167 $siPrefix = array( 'bytes', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB' );
168 $base = 1024;
169 $class = min((int) log($bytes, $base), count($siPrefix) - 1);
170 $val = sprintf('%1.2f', $bytes / pow($base, $class));
171
172 return $val . ' ' . $siPrefix[$class];
173 }
174
175 public static function returnBytes($val)
176 {
177 $val = trim($val);
178 $last = strtolower($val[strlen($val)-1]);
179 switch($last)
180 {
181 case 'g': $val *= 1024;
182 case 'm': $val *= 1024;
183 case 'k': $val *= 1024;
184 }
185
186 return $val;
187 }
188
189 public static function getMaxFileSize()
190 {
191 $sizePostMax = MyTool::returnBytes(ini_get('post_max_size'));
192 $sizeUploadMax = MyTool::returnBytes(ini_get('upload_max_filesize'));
193
194 // Return the smaller of two:
195 return min($sizePostMax, $sizeUploadMax);
196 }
197
198 public static function smallHash($text)
199 {
200 $t = rtrim(base64_encode(hash('crc32', $text, true)), '=');
201 // Get rid of characters which need encoding in URLs.
202 $t = str_replace('+', '-', $t);
203 $t = str_replace('/', '_', $t);
204 $t = str_replace('=', '@', $t);
205
206 return $t;
207 }
208
209 public static function renderJson($data)
210 {
211 header('Cache-Control: no-cache, must-revalidate');
212 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
213 header('Content-type: application/json; charset=UTF-8');
214
215 echo json_encode($data);
216 exit();
217 }
218
219 public static function grabToLocal($url, $file, $force = false)
220 {
221 if ((!file_exists($file) || $force) && in_array('curl', get_loaded_extensions())){
222 $ch = curl_init ($url);
223 curl_setopt($ch, CURLOPT_HEADER, false);
224 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
225 curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
226 $raw = curl_exec($ch);
227 if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) {
228 $fp = fopen($file, 'x');
229 fwrite($fp, $raw);
230 fclose($fp);
231 }
232 curl_close ($ch);
233 }
234 }
235
236 public static function redirect($rurl = '')
237 {
238 if ($rurl === '') {
239 // if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['SERVER_NAME'])==0)
240 $rurl = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']);
241 if (isset($_POST['returnurl'])) {
242 $rurl = $_POST['returnurl'];
243 }
244 }
245
246 // prevent loop
247 if (empty($rurl) || parse_url($rurl, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) {
248 $rurl = MyTool::getUrl();
249 }
250
251 if (substr($rurl, 0, 1) !== '?') {
252 $ref = MyTool::getUrl();
253 if (substr($rurl, 0, strlen($ref)) !== $ref) {
254 $rurl = $ref;
255 }
256 }
257 header('Location: '.$rurl);
258 exit();
259 }
260
261 public static function silence_errors($num, $str)
262 {
263// No-op
264 }
265} \ No newline at end of file
diff --git a/inc/config.php b/inc/config.php
deleted file mode 100644
index 6e3f80b8..00000000
--- a/inc/config.php
+++ /dev/null
@@ -1,73 +0,0 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11define ('POCHE_VERSION', '0.3');
12
13if (!is_dir('db/')) {
14 @mkdir('db/',0705);
15}
16
17define ('MODE_DEMO', FALSE);
18define ('ABS_PATH', 'assets/');
19define ('CONVERT_LINKS_FOOTNOTES', TRUE);
20define ('REVERT_FORCED_PARAGRAPH_ELEMENTS',FALSE);
21define ('DOWNLOAD_PICTURES', TRUE);
22define ('SALT', '464v54gLLw928uz4zUBqkRJeiPY68zCX');
23define ('LANG', 'fr_FR.UTF8');
24
25putenv("LC_ALL=".LANG);
26setlocale(LC_ALL, LANG);
27bindtextdomain(LANG, "./locale");
28textdomain(LANG);
29
30$storage_type = 'sqlite'; # sqlite or file
31
32include 'functions.php';
33require_once 'Readability.php';
34require_once 'Encoding.php';
35require_once 'rain.tpl.class.php';
36require_once 'MyTool.class.php';
37require_once 'Session.class.php';
38require_once 'store/store.class.php';
39require_once 'store/sqlite.class.php';
40require_once 'store/file.class.php';
41require_once 'class.messages.php';
42
43Session::init();
44
45$store = new $storage_type();
46# initialisation de RainTPL
47raintpl::$tpl_dir = './tpl/';
48raintpl::$cache_dir = './cache/';
49raintpl::$base_url = get_poche_url();
50raintpl::configure('path_replace', false);
51raintpl::configure('debug', false);
52$tpl = new raintpl();
53
54if(!$store->isInstalled())
55{
56 logm('poche still not installed');
57 $tpl->draw('install');
58 if (isset($_GET['install'])) {
59 if (($_POST['password'] == $_POST['password_repeat'])
60 && $_POST['password'] != "" && $_POST['login'] != "") {
61 $store->install($_POST['login'], encode_string($_POST['password'] . $_POST['login']));
62 Session::logout();
63 MyTool::redirect();
64 }
65 }
66 exit();
67}
68
69$_SESSION['login'] = (isset ($_SESSION['login'])) ? $_SESSION['login'] : $store->getLogin();
70$_SESSION['pass'] = (isset ($_SESSION['pass'])) ? $_SESSION['pass'] : $store->getPassword();
71
72$msg = new Messages();
73$tpl->assign('msg', $msg); \ No newline at end of file
diff --git a/inc/functions.php b/inc/functions.php
deleted file mode 100644
index ee26fbaa..00000000
--- a/inc/functions.php
+++ /dev/null
@@ -1,400 +0,0 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11/**
12 * Permet de générer l'URL de poche pour le bookmarklet
13 */
14function get_poche_url()
15{
16 $protocol = "http";
17 if(isset($_SERVER['HTTPS'])) {
18 if($_SERVER['HTTPS'] != "off" && $_SERVER['HTTPS'] != "") {
19 $protocol = "https";
20 }
21 }
22
23 return $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
24}
25
26function encode_string($string)
27{
28 return sha1($string . SALT);
29}
30
31// function define to retrieve url content
32function get_external_file($url)
33{
34 $timeout = 15;
35 // spoofing FireFox 18.0
36 $useragent="Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0";
37
38 if (in_array ('curl', get_loaded_extensions())) {
39 // Fetch feed from URL
40 $curl = curl_init();
41 curl_setopt($curl, CURLOPT_URL, $url);
42 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
43 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
44 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
45 curl_setopt($curl, CURLOPT_HEADER, false);
46
47 // FOR SSL do not verified certificate
48 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
49 curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE );
50
51 // FeedBurner requires a proper USER-AGENT...
52 curl_setopt($curl, CURL_HTTP_VERSION_1_1, true);
53 curl_setopt($curl, CURLOPT_ENCODING, "gzip, deflate");
54 curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
55
56 $data = curl_exec($curl);
57
58 $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
59
60 $httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301);
61
62 curl_close($curl);
63 } else {
64
65 // create http context and add timeout and user-agent
66 $context = stream_context_create(array(
67 'http'=>array('timeout' => $timeout,
68 'header'=> "User-Agent: ".$useragent, /*spoot Mozilla Firefox*/
69 'follow_location' => true),
70 // FOR SSL do not verified certificate
71 'ssl' => array('verify_peer' => false,
72 'allow_self_signed' => true)
73 )
74 );
75
76 // only download page lesser than 4MB
77 $data = @file_get_contents($url, false, $context, -1, 4000000); // We download at most 4 MB from source.
78
79 if(isset($http_response_header) and isset($http_response_header[0])) {
80 $httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE));
81 }
82 }
83
84 // if response is not empty and response is OK
85 if (isset($data) and isset($httpcodeOK) and $httpcodeOK ) {
86
87 // take charset of page and get it
88 preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
89
90 // if meta tag is found
91 if (!empty($meta[0])) {
92 // retrieve encoding in $enc
93 preg_match('#charset="?(.*)"#si', $meta[0], $enc);
94
95 // if charset is found set it otherwise, set it to utf-8
96 $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8';
97
98 } else {
99 $html_charset = 'utf-8';
100 $enc[1] = '';
101 }
102
103 // replace charset of url to charset of page
104 $data = str_replace('charset='.$enc[1], 'charset='.$html_charset, $data);
105
106 return $data;
107 }
108 else {
109 return FALSE;
110 }
111}
112
113/**
114 * Préparation de l'URL avec récupération du contenu avant insertion en base
115 */
116function prepare_url($url)
117{
118 $parametres = array();
119 $url = html_entity_decode(trim($url));
120
121 // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...)
122 // from shaarli, by sebsauvage
123 $i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i);
124 $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i);
125 $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i);
126
127 $title = $url;
128 $html = Encoding::toUTF8(get_external_file($url,15));
129 // If get_external_file if not able to retrieve HTTPS content try the same URL with HTTP protocol
130 if (!preg_match('!^https?://!i', $url) && (!isset($html) || strlen($html) <= 0)) {
131 $url = 'http://' . $url;
132 $html = Encoding::toUTF8(get_external_file($url,15));
133 }
134
135 if (function_exists('tidy_parse_string')) {
136 $tidy = tidy_parse_string($html, array(), 'UTF8');
137 $tidy->cleanRepair();
138 $html = $tidy->value;
139 }
140
141 if (isset($html) and strlen($html) > 0)
142 {
143 $r = new Readability($html, $url);
144
145 $r->convertLinksToFootnotes = CONVERT_LINKS_FOOTNOTES;
146 $r->revertForcedParagraphElements = REVERT_FORCED_PARAGRAPH_ELEMENTS;
147
148 if($r->init())
149 {
150 $content = $r->articleContent->innerHTML;
151 $parametres['title'] = $r->articleTitle->innerHTML;
152 $parametres['content'] = $content;
153 return $parametres;
154 }
155 }
156
157 return FALSE;
158}
159
160/**
161 * On modifie les URLS des images dans le corps de l'article
162 */
163function filtre_picture($content, $url, $id)
164{
165 $matches = array();
166 preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER);
167 foreach($matches as $i => $link)
168 {
169 $link[1] = trim($link[1]);
170 if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1]) )
171 {
172 $absolute_path = get_absolute_link($link[2],$url);
173 $filename = basename(parse_url($absolute_path, PHP_URL_PATH));
174 $directory = create_assets_directory($id);
175 $fullpath = $directory . '/' . $filename;
176 download_pictures($absolute_path, $fullpath);
177 $content = str_replace($matches[$i][2], $fullpath, $content);
178 }
179
180 }
181
182 return $content;
183}
184
185/**
186 * Retourne le lien absolu
187 */
188function get_absolute_link($relative_link, $url)
189{
190 /* return if already absolute URL */
191 if (parse_url($relative_link, PHP_URL_SCHEME) != '') return $relative_link;
192
193 /* queries and anchors */
194 if ($relative_link[0]=='#' || $relative_link[0]=='?') return $url . $relative_link;
195
196 /* parse base URL and convert to local variables:
197 $scheme, $host, $path */
198 extract(parse_url($url));
199
200 /* remove non-directory element from path */
201 $path = preg_replace('#/[^/]*$#', '', $path);
202
203 /* destroy path if relative url points to root */
204 if ($relative_link[0] == '/') $path = '';
205
206 /* dirty absolute URL */
207 $abs = $host . $path . '/' . $relative_link;
208
209 /* replace '//' or '/./' or '/foo/../' with '/' */
210 $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
211 for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
212
213 /* absolute URL is ready! */
214 return $scheme.'://'.$abs;
215}
216
217/**
218 * Téléchargement des images
219 */
220
221function download_pictures($absolute_path, $fullpath)
222{
223 $rawdata = get_external_file($absolute_path);
224
225 if(file_exists($fullpath)) {
226 unlink($fullpath);
227 }
228 $fp = fopen($fullpath, 'x');
229 fwrite($fp, $rawdata);
230 fclose($fp);
231}
232
233/**
234 * Crée un répertoire de médias pour l'article
235 */
236function create_assets_directory($id)
237{
238 $assets_path = ABS_PATH;
239 if(!is_dir($assets_path)) {
240 mkdir($assets_path, 0705);
241 }
242
243 $article_directory = $assets_path . $id;
244 if(!is_dir($article_directory)) {
245 mkdir($article_directory, 0705);
246 }
247
248 return $article_directory;
249}
250
251/**
252 * Suppression du répertoire d'images
253 */
254function remove_directory($directory)
255{
256 if(is_dir($directory)) {
257 $files = array_diff(scandir($directory), array('.','..'));
258 foreach ($files as $file) {
259 (is_dir("$directory/$file")) ? remove_directory("$directory/$file") : unlink("$directory/$file");
260 }
261 return rmdir($directory);
262 }
263}
264
265function display_view($view, $id = 0, $full_head = 'yes')
266{
267 global $tpl, $store, $msg;
268
269 switch ($view)
270 {
271 case 'export':
272 $entries = $store->retrieveAll();
273 $tpl->assign('export', myTool::renderJson($entries));
274 $tpl->draw('export');
275 logm('export view');
276 break;
277 case 'config':
278 $tpl->assign('load_all_js', 0);
279 $tpl->draw('head');
280 $tpl->draw('home');
281 $tpl->draw('config');
282 $tpl->draw('js');
283 $tpl->draw('footer');
284 logm('config view');
285 break;
286 case 'view':
287 $entry = $store->retrieveOneById($id);
288
289 if ($entry != NULL) {
290 $tpl->assign('id', $entry['id']);
291 $tpl->assign('url', $entry['url']);
292 $tpl->assign('title', $entry['title']);
293 $content = $entry['content'];
294 if (function_exists('tidy_parse_string')) {
295 $tidy = tidy_parse_string($content, array('indent'=>true, 'show-body-only' => true), 'UTF8');
296 $tidy->cleanRepair();
297 $content = $tidy->value;
298 }
299 $tpl->assign('content', $content);
300 $tpl->assign('is_fav', $entry['is_fav']);
301 $tpl->assign('is_read', $entry['is_read']);
302 $tpl->assign('load_all_js', 0);
303 $tpl->draw('view');
304 }
305 else {
306 logm('error in view call : entry is NULL');
307 }
308
309 logm('view link #' . $id);
310 break;
311 default: # home view
312 $entries = $store->getEntriesByView($view);
313
314 $tpl->assign('entries', $entries);
315
316 if ($full_head == 'yes') {
317 $tpl->assign('load_all_js', 1);
318 $tpl->draw('head');
319 $tpl->draw('home');
320 }
321
322 $tpl->draw('entries');
323
324 if ($full_head == 'yes') {
325 $tpl->draw('js');
326 $tpl->draw('footer');
327 }
328 break;
329 }
330}
331
332/**
333 * Appel d'une action (mark as fav, archive, delete)
334 */
335function action_to_do($action, $url, $id = 0)
336{
337 global $store, $msg;
338
339 switch ($action)
340 {
341 case 'add':
342 if ($url == '')
343 continue;
344
345 $url = base64_decode($url);
346 error_log(print_r($url, TRUE));
347 if (MyTool::isUrl($url)) {
348 if($parametres_url = prepare_url($url)) {
349 if ($store->add($url, $parametres_url['title'], $parametres_url['content'])) {
350 $last_id = $store->getLastId();
351 if (DOWNLOAD_PICTURES) {
352 $content = filtre_picture($parametres_url['content'], $url, $last_id);
353 }
354 $msg->add('s', _('the link has been added successfully'));
355 }
356 else {
357 $msg->add('e', _('error during insertion : the link wasn\'t added'));
358 }
359 }
360 else {
361 $msg->add('e', _('error during url preparation : the link wasn\'t added'));
362 logm('error during url preparation');
363 }
364 }
365 else {
366 $msg->add('e', _('error during url preparation : the link is not valid'));
367 logm($url . ' is not a valid url');
368 }
369
370 logm('add link ' . $url);
371 break;
372 case 'delete':
373 if ($store->deleteById($id)) {
374 remove_directory(ABS_PATH . $id);
375 $msg->add('s', _('the link has been deleted successfully'));
376 logm('delete link #' . $id);
377 }
378 else {
379 $msg->add('e', _('the link wasn\'t deleted'));
380 logm('error : can\'t delete link #' . $id);
381 }
382 break;
383 case 'toggle_fav' :
384 $store->favoriteById($id);
385 logm('mark as favorite link #' . $id);
386 break;
387 case 'toggle_archive' :
388 $store->archiveById($id);
389 logm('archive link #' . $id);
390 break;
391 default:
392 break;
393 }
394}
395
396function logm($message)
397{
398 $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n";
399 file_put_contents('./log.txt',$t,FILE_APPEND);
400}
diff --git a/inc/poche/Database.class.php b/inc/poche/Database.class.php
new file mode 100644
index 00000000..cd5a9a31
--- /dev/null
+++ b/inc/poche/Database.class.php
@@ -0,0 +1,216 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class Database {
12 var $handle;
13
14 function __construct()
15 {
16 switch (STORAGE) {
17 case 'sqlite':
18 $db_path = 'sqlite:' . STORAGE_SQLITE;
19 $this->handle = new PDO($db_path);
20 break;
21 case 'mysql':
22 $db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
23 $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
24 break;
25 case 'postgres':
26 $db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
27 $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
28 break;
29 }
30
31 $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
32 Tools::logm('storage type ' . STORAGE);
33 }
34
35 private function getHandle() {
36 return $this->handle;
37 }
38
39 public function isInstalled() {
40 $sql = "SELECT username FROM users";
41 $query = $this->executeQuery($sql, array());
42 $hasAdmin = count($query->fetchAll());
43
44 if ($hasAdmin == 0)
45 return FALSE;
46
47 return TRUE;
48 }
49
50 public function install($login, $password) {
51 $sql = 'INSERT INTO users ( username, password, name, email) VALUES (?, ?, ?, ?)';
52 $params = array($login, $password, $login, ' ');
53 $query = $this->executeQuery($sql, $params);
54
55 $sequence = '';
56 if (STORAGE == 'postgres') {
57 $sequence = 'users_id_seq';
58 }
59
60 $id_user = intval($this->getLastId($sequence));
61
62 $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
63 $params = array($id_user, 'pager', '10');
64 $query = $this->executeQuery($sql, $params);
65
66 $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
67 $params = array($id_user, 'language', 'en_EN.UTF8');
68 $query = $this->executeQuery($sql, $params);
69
70 return TRUE;
71 }
72
73 private function getConfigUser($id) {
74 $sql = "SELECT * FROM users_config WHERE user_id = ?";
75 $query = $this->executeQuery($sql, array($id));
76 $result = $query->fetchAll();
77 $user_config = array();
78
79 foreach ($result as $key => $value) {
80 $user_config[$value['name']] = $value['value'];
81 }
82
83 return $user_config;
84 }
85
86 public function login($username, $password) {
87 $sql = "SELECT * FROM users WHERE username=? AND password=?";
88 $query = $this->executeQuery($sql, array($username, $password));
89 $login = $query->fetchAll();
90
91 $user = array();
92 if (isset($login[0])) {
93 $user['id'] = $login[0]['id'];
94 $user['username'] = $login[0]['username'];
95 $user['password'] = $login[0]['password'];
96 $user['name'] = $login[0]['name'];
97 $user['email'] = $login[0]['email'];
98 $user['config'] = $this->getConfigUser($login[0]['id']);
99 }
100
101 return $user;
102 }
103
104 public function updatePassword($id, $password)
105 {
106 $sql_update = "UPDATE users SET password=? WHERE id=?";
107 $params_update = array($password, $id);
108 $query = $this->executeQuery($sql_update, $params_update);
109 }
110
111 private function executeQuery($sql, $params) {
112 try
113 {
114 $query = $this->getHandle()->prepare($sql);
115 $query->execute($params);
116 return $query;
117 }
118 catch (Exception $e)
119 {
120 Tools::logm('execute query error : '.$e->getMessage());
121 return FALSE;
122 }
123 }
124
125 public function retrieveAll($user_id) {
126 $sql = "SELECT * FROM entries WHERE user_id=? ORDER BY id";
127 $query = $this->executeQuery($sql, array($user_id));
128 $entries = $query->fetchAll();
129
130 return $entries;
131 }
132
133 public function retrieveOneById($id, $user_id) {
134 $entry = NULL;
135 $sql = "SELECT * FROM entries WHERE id=? AND user_id=?";
136 $params = array(intval($id), $user_id);
137 $query = $this->executeQuery($sql, $params);
138 $entry = $query->fetchAll();
139
140 return $entry[0];
141 }
142
143 public function getEntriesByView($view, $user_id, $limit = '') {
144 switch ($_SESSION['sort'])
145 {
146 case 'ia':
147 $order = 'ORDER BY id';
148 break;
149 case 'id':
150 $order = 'ORDER BY id DESC';
151 break;
152 case 'ta':
153 $order = 'ORDER BY lower(title)';
154 break;
155 case 'td':
156 $order = 'ORDER BY lower(title) DESC';
157 break;
158 default:
159 $order = 'ORDER BY id';
160 break;
161 }
162
163 switch ($view)
164 {
165 case 'archive':
166 $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? " . $order;
167 $params = array($user_id, 1);
168 break;
169 case 'fav' :
170 $sql = "SELECT * FROM entries WHERE user_id=? AND is_fav=? " . $order;
171 $params = array($user_id, 1);
172 break;
173 default:
174 $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? " . $order;
175 $params = array($user_id, 0);
176 break;
177 }
178
179 $sql .= ' ' . $limit;
180
181 $query = $this->executeQuery($sql, $params);
182 $entries = $query->fetchAll();
183
184 return $entries;
185 }
186
187 public function add($url, $title, $content, $user_id) {
188 $sql_action = 'INSERT INTO entries ( url, title, content, user_id ) VALUES (?, ?, ?, ?)';
189 $params_action = array($url, $title, $content, $user_id);
190 $query = $this->executeQuery($sql_action, $params_action);
191 return $query;
192 }
193
194 public function deleteById($id, $user_id) {
195 $sql_action = "DELETE FROM entries WHERE id=? AND user_id=?";
196 $params_action = array($id, $user_id);
197 $query = $this->executeQuery($sql_action, $params_action);
198 return $query;
199 }
200
201 public function favoriteById($id, $user_id) {
202 $sql_action = "UPDATE entries SET is_fav=NOT is_fav WHERE id=? AND user_id=?";
203 $params_action = array($id, $user_id);
204 $query = $this->executeQuery($sql_action, $params_action);
205 }
206
207 public function archiveById($id, $user_id) {
208 $sql_action = "UPDATE entries SET is_read=NOT is_read WHERE id=? AND user_id=?";
209 $params_action = array($id, $user_id);
210 $query = $this->executeQuery($sql_action, $params_action);
211 }
212
213 public function getLastId($column = '') {
214 return $this->getHandle()->lastInsertId($column);
215 }
216}
diff --git a/inc/poche/Poche.class.php b/inc/poche/Poche.class.php
new file mode 100644
index 00000000..38b4a98e
--- /dev/null
+++ b/inc/poche/Poche.class.php
@@ -0,0 +1,429 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class Poche
12{
13 public $user;
14 public $store;
15 public $tpl;
16 public $messages;
17 public $pagination;
18
19 function __construct()
20 {
21 $this->store = new Database();
22 $this->init();
23 $this->messages = new Messages();
24
25 # installation
26 if(!$this->store->isInstalled())
27 {
28 $this->install();
29 }
30 }
31
32 private function init()
33 {
34 Tools::initPhp();
35 Session::init();
36
37 if (isset($_SESSION['poche_user']) && $_SESSION['poche_user'] != array()) {
38 $this->user = $_SESSION['poche_user'];
39 }
40 else {
41 # fake user, just for install & login screens
42 $this->user = new User();
43 $this->user->setConfig($this->getDefaultConfig());
44 }
45
46 # l10n
47 $language = $this->user->getConfigValue('language');
48 putenv('LC_ALL=' . $language);
49 setlocale(LC_ALL, $language);
50 bindtextdomain($language, LOCALE);
51 textdomain($language);
52
53 # template engine
54 $loader = new Twig_Loader_Filesystem(TPL);
55 if (DEBUG_POCHE) {
56 $twig_params = array();
57 }
58 else {
59 $twig_params = array('cache' => CACHE);
60 }
61 $this->tpl = new Twig_Environment($loader, $twig_params);
62 $this->tpl->addExtension(new Twig_Extensions_Extension_I18n());
63 # filter to display domain name of an url
64 $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain');
65 $this->tpl->addFilter($filter);
66
67 # Pagination
68 $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p');
69 }
70
71 private function install()
72 {
73 Tools::logm('poche still not installed');
74 echo $this->tpl->render('install.twig', array(
75 'token' => Session::getToken()
76 ));
77 if (isset($_GET['install'])) {
78 if (($_POST['password'] == $_POST['password_repeat'])
79 && $_POST['password'] != "" && $_POST['login'] != "") {
80 # let's rock, install poche baby !
81 $this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']));
82 Session::logout();
83 Tools::logm('poche is now installed');
84 Tools::redirect();
85 }
86 else {
87 Tools::logm('error during installation');
88 Tools::redirect();
89 }
90 }
91 exit();
92 }
93
94 public function getDefaultConfig()
95 {
96 return array(
97 'pager' => PAGINATION,
98 'language' => LANG,
99 );
100 }
101
102 /**
103 * Call action (mark as fav, archive, delete, etc.)
104 */
105 public function action($action, Url $url, $id = 0, $import = FALSE)
106 {
107 switch ($action)
108 {
109 case 'add':
110 if($parametres_url = $url->fetchContent()) {
111 if ($this->store->add($url->getUrl(), $parametres_url['title'], $parametres_url['content'], $this->user->getId())) {
112 Tools::logm('add link ' . $url->getUrl());
113 $sequence = '';
114 if (STORAGE == 'postgres') {
115 $sequence = 'entries_id_seq';
116 }
117 $last_id = $this->store->getLastId($sequence);
118 if (DOWNLOAD_PICTURES) {
119 $content = filtre_picture($parametres_url['content'], $url->getUrl(), $last_id);
120 }
121 if (!$import) {
122 $this->messages->add('s', _('the link has been added successfully'));
123 }
124 }
125 else {
126 if (!$import) {
127 $this->messages->add('e', _('error during insertion : the link wasn\'t added'));
128 Tools::logm('error during insertion : the link wasn\'t added ' . $url->getUrl());
129 }
130 }
131 }
132 else {
133 if (!$import) {
134 $this->messages->add('e', _('error during fetching content : the link wasn\'t added'));
135 Tools::logm('error during content fetch ' . $url->getUrl());
136 }
137 }
138 if (!$import) {
139 Tools::redirect();
140 }
141 break;
142 case 'delete':
143 $msg = 'delete link #' . $id;
144 if ($this->store->deleteById($id, $this->user->getId())) {
145 if (DOWNLOAD_PICTURES) {
146 remove_directory(ABS_PATH . $id);
147 }
148 $this->messages->add('s', _('the link has been deleted successfully'));
149 }
150 else {
151 $this->messages->add('e', _('the link wasn\'t deleted'));
152 $msg = 'error : can\'t delete link #' . $id;
153 }
154 Tools::logm($msg);
155 Tools::redirect('?');
156 break;
157 case 'toggle_fav' :
158 $this->store->favoriteById($id, $this->user->getId());
159 Tools::logm('mark as favorite link #' . $id);
160 if (!$import) {
161 Tools::redirect();
162 }
163 break;
164 case 'toggle_archive' :
165 $this->store->archiveById($id, $this->user->getId());
166 Tools::logm('archive link #' . $id);
167 if (!$import) {
168 Tools::redirect();
169 }
170 break;
171 default:
172 break;
173 }
174 }
175
176 function displayView($view, $id = 0)
177 {
178 $tpl_vars = array();
179
180 switch ($view)
181 {
182 case 'config':
183 $dev = $this->getPocheVersion('dev');
184 $prod = $this->getPocheVersion('prod');
185 $compare_dev = version_compare(POCHE_VERSION, $dev);
186 $compare_prod = version_compare(POCHE_VERSION, $prod);
187 $tpl_vars = array(
188 'dev' => $dev,
189 'prod' => $prod,
190 'compare_dev' => $compare_dev,
191 'compare_prod' => $compare_prod,
192 );
193 Tools::logm('config view');
194 break;
195 case 'view':
196 $entry = $this->store->retrieveOneById($id, $this->user->getId());
197 if ($entry != NULL) {
198 Tools::logm('view link #' . $id);
199 $content = $entry['content'];
200 if (function_exists('tidy_parse_string')) {
201 $tidy = tidy_parse_string($content, array('indent'=>true, 'show-body-only' => true), 'UTF8');
202 $tidy->cleanRepair();
203 $content = $tidy->value;
204 }
205 $tpl_vars = array(
206 'entry' => $entry,
207 'content' => $content,
208 );
209 }
210 else {
211 Tools::logm('error in view call : entry is NULL');
212 }
213 break;
214 default: # home view
215 $entries = $this->store->getEntriesByView($view, $this->user->getId());
216 $this->pagination->set_total(count($entries));
217 $page_links = $this->pagination->page_links('?view=' . $view . '&sort=' . $_SESSION['sort'] . '&');
218 $datas = $this->store->getEntriesByView($view, $this->user->getId(), $this->pagination->get_limit());
219 $tpl_vars = array(
220 'entries' => $datas,
221 'page_links' => $page_links,
222 );
223 Tools::logm('display ' . $view . ' view');
224 break;
225 }
226
227 return $tpl_vars;
228 }
229
230 public function updatePassword()
231 {
232 if (MODE_DEMO) {
233 $this->messages->add('i', _('in demo mode, you can\'t update your password'));
234 Tools::logm('in demo mode, you can\'t do this');
235 Tools::redirect('?view=config');
236 }
237 else {
238 if (isset($_POST['password']) && isset($_POST['password_repeat'])) {
239 if ($_POST['password'] == $_POST['password_repeat'] && $_POST['password'] != "") {
240 $this->messages->add('s', _('your password has been updated'));
241 $this->store->updatePassword($this->user->getId(), Tools::encodeString($_POST['password'] . $this->user->getUsername()));
242 Session::logout();
243 Tools::logm('password updated');
244 Tools::redirect();
245 }
246 else {
247 $this->messages->add('e', _('the two fields have to be filled & the password must be the same in the two fields'));
248 Tools::redirect('?view=config');
249 }
250 }
251 }
252 }
253
254 public function login($referer)
255 {
256 if (!empty($_POST['login']) && !empty($_POST['password'])) {
257 $user = $this->store->login($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']));
258 if ($user != array()) {
259 # Save login into Session
260 Session::login($user['username'], $user['password'], $_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']), array('poche_user' => new User($user)));
261
262 $this->messages->add('s', _('welcome to your poche'));
263 if (!empty($_POST['longlastingsession'])) {
264 $_SESSION['longlastingsession'] = 31536000;
265 $_SESSION['expires_on'] = time() + $_SESSION['longlastingsession'];
266 session_set_cookie_params($_SESSION['longlastingsession']);
267 } else {
268 session_set_cookie_params(0);
269 }
270 session_regenerate_id(true);
271 Tools::logm('login successful');
272 Tools::redirect($referer);
273 }
274 $this->messages->add('e', _('login failed: bad login or password'));
275 Tools::logm('login failed');
276 Tools::redirect();
277 } else {
278 $this->messages->add('e', _('login failed: you have to fill all fields'));
279 Tools::logm('login failed');
280 Tools::redirect();
281 }
282 }
283
284 public function logout()
285 {
286 $this->user = array();
287 Session::logout();
288 $this->messages->add('s', _('see you soon!'));
289 Tools::logm('logout');
290 Tools::redirect();
291 }
292
293 private function importFromInstapaper()
294 {
295 # TODO gestion des articles favs
296 $html = new simple_html_dom();
297 $html->load_file('./instapaper-export.html');
298 Tools::logm('starting import from instapaper');
299
300 $read = 0;
301 $errors = array();
302 foreach($html->find('ol') as $ul)
303 {
304 foreach($ul->find('li') as $li)
305 {
306 $a = $li->find('a');
307 $url = new Url(base64_encode($a[0]->href));
308 $this->action('add', $url, 0, TRUE);
309 if ($read == '1') {
310 $sequence = '';
311 if (STORAGE == 'postgres') {
312 $sequence = 'entries_id_seq';
313 }
314 $last_id = $this->store->getLastId($sequence);
315 $this->action('toggle_archive', $url, $last_id, TRUE);
316 }
317 }
318
319 # the second <ol> is for read links
320 $read = 1;
321 }
322 $this->messages->add('s', _('import from instapaper completed'));
323 Tools::logm('import from instapaper completed');
324 Tools::redirect();
325 }
326
327 private function importFromPocket()
328 {
329 # TODO gestion des articles favs
330 $html = new simple_html_dom();
331 $html->load_file('./ril_export.html');
332 Tools::logm('starting import from pocket');
333
334 $read = 0;
335 $errors = array();
336 foreach($html->find('ul') as $ul)
337 {
338 foreach($ul->find('li') as $li)
339 {
340 $a = $li->find('a');
341 $url = new Url(base64_encode($a[0]->href));
342 $this->action('add', $url, 0, TRUE);
343 if ($read == '1') {
344 $sequence = '';
345 if (STORAGE == 'postgres') {
346 $sequence = 'entries_id_seq';
347 }
348 $last_id = $this->store->getLastId($sequence);
349 $this->action('toggle_archive', $url, $last_id, TRUE);
350 }
351 }
352
353 # the second <ul> is for read links
354 $read = 1;
355 }
356 $this->messages->add('s', _('import from pocket completed'));
357 Tools::logm('import from pocket completed');
358 Tools::redirect();
359 }
360
361 private function importFromReadability()
362 {
363 # TODO gestion des articles lus / favs
364 $str_data = file_get_contents("./readability");
365 $data = json_decode($str_data,true);
366 Tools::logm('starting import from Readability');
367
368 foreach ($data as $key => $value) {
369 $url = '';
370 foreach ($value as $attr => $attr_value) {
371 if ($attr == 'article__url') {
372 $url = new Url(base64_encode($attr_value));
373 }
374 $sequence = '';
375 if (STORAGE == 'postgres') {
376 $sequence = 'entries_id_seq';
377 }
378 // if ($attr_value == 'favorite' && $attr_value == 'true') {
379 // $last_id = $this->store->getLastId($sequence);
380 // $this->store->favoriteById($last_id);
381 // $this->action('toogle_fav', $url, $last_id, TRUE);
382 // }
383 if ($attr_value == 'archive' && $attr_value == 'true') {
384 $last_id = $this->store->getLastId($sequence);
385 $this->action('toggle_archive', $url, $last_id, TRUE);
386 }
387 }
388 if ($url->isCorrect())
389 $this->action('add', $url, 0, TRUE);
390 }
391 $this->messages->add('s', _('import from Readability completed'));
392 Tools::logm('import from Readability completed');
393 Tools::redirect();
394 }
395
396 public function import($from)
397 {
398 if ($from == 'pocket') {
399 $this->importFromPocket();
400 }
401 else if ($from == 'readability') {
402 $this->importFromReadability();
403 }
404 else if ($from == 'instapaper') {
405 $this->importFromInstapaper();
406 }
407 }
408
409 public function export()
410 {
411 $entries = $this->store->retrieveAll($this->user->getId());
412 echo $this->tpl->render('export.twig', array(
413 'export' => Tools::renderJson($entries),
414 ));
415 Tools::logm('export view');
416 }
417
418 private function getPocheVersion($which = 'prod')
419 {
420 $cache_file = CACHE . '/' . $which;
421 if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) {
422 $version = file_get_contents($cache_file);
423 } else {
424 $version = file_get_contents('http://static.inthepoche.com/versions/' . $which);
425 file_put_contents($cache_file, $version, LOCK_EX);
426 }
427 return $version;
428 }
429} \ No newline at end of file
diff --git a/inc/poche/Tools.class.php b/inc/poche/Tools.class.php
new file mode 100644
index 00000000..d0e43166
--- /dev/null
+++ b/inc/poche/Tools.class.php
@@ -0,0 +1,226 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class Tools
12{
13 public static function initPhp()
14 {
15 define('START_TIME', microtime(true));
16
17 if (phpversion() < 5) {
18 die(_('Oops, it seems you don\'t have PHP 5.'));
19 }
20
21 error_reporting(E_ALL);
22
23 function stripslashesDeep($value) {
24 return is_array($value)
25 ? array_map('stripslashesDeep', $value)
26 : stripslashes($value);
27 }
28
29 if (get_magic_quotes_gpc()) {
30 $_POST = array_map('stripslashesDeep', $_POST);
31 $_GET = array_map('stripslashesDeep', $_GET);
32 $_COOKIE = array_map('stripslashesDeep', $_COOKIE);
33 }
34
35 ob_start();
36 register_shutdown_function('ob_end_flush');
37 }
38
39 public static function getPocheUrl()
40 {
41 $https = (!empty($_SERVER['HTTPS'])
42 && (strtolower($_SERVER['HTTPS']) == 'on'))
43 || (isset($_SERVER["SERVER_PORT"])
44 && $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection.
45 $serverport = (!isset($_SERVER["SERVER_PORT"])
46 || $_SERVER["SERVER_PORT"] == '80'
47 || ($https && $_SERVER["SERVER_PORT"] == '443')
48 ? '' : ':' . $_SERVER["SERVER_PORT"]);
49
50 $scriptname = str_replace('/index.php', '/', $_SERVER["SCRIPT_NAME"]);
51
52 if (!isset($_SERVER["SERVER_NAME"])) {
53 return $scriptname;
54 }
55
56 return 'http' . ($https ? 's' : '') . '://'
57 . $_SERVER["SERVER_NAME"] . $serverport . $scriptname;
58 }
59
60 public static function redirect($url = '')
61 {
62 if ($url === '') {
63 $url = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']);
64 if (isset($_POST['returnurl'])) {
65 $url = $_POST['returnurl'];
66 }
67 }
68
69 # prevent loop
70 if (empty($url) || parse_url($url, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) {
71 $url = Tools::getPocheUrl();
72 }
73
74 if (substr($url, 0, 1) !== '?') {
75 $ref = Tools::getPocheUrl();
76 if (substr($url, 0, strlen($ref)) !== $ref) {
77 $url = $ref;
78 }
79 }
80 self::logm('redirect to ' . $url);
81 header('Location: '.$url);
82 exit();
83 }
84
85 public static function getTplFile($view)
86 {
87 $tpl_file = 'home.twig';
88 switch ($view)
89 {
90 case 'install':
91 $tpl_file = 'install.twig';
92 break;
93 case 'import';
94 $tpl_file = 'import.twig';
95 break;
96 case 'export':
97 $tpl_file = 'export.twig';
98 break;
99 case 'config':
100 $tpl_file = 'config.twig';
101 break;
102 case 'view':
103 $tpl_file = 'view.twig';
104 break;
105 default:
106 break;
107 }
108 return $tpl_file;
109 }
110
111 public static function getFile($url)
112 {
113 $timeout = 15;
114 $useragent = "Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0";
115
116 if (in_array ('curl', get_loaded_extensions())) {
117 # Fetch feed from URL
118 $curl = curl_init();
119 curl_setopt($curl, CURLOPT_URL, $url);
120 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
121 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
122 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
123 curl_setopt($curl, CURLOPT_HEADER, false);
124
125 # for ssl, do not verified certificate
126 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
127 curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE );
128
129 # FeedBurner requires a proper USER-AGENT...
130 curl_setopt($curl, CURL_HTTP_VERSION_1_1, true);
131 curl_setopt($curl, CURLOPT_ENCODING, "gzip, deflate");
132 curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
133
134 $data = curl_exec($curl);
135 $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
136 $httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301);
137 curl_close($curl);
138 } else {
139 # create http context and add timeout and user-agent
140 $context = stream_context_create(
141 array(
142 'http' => array(
143 'timeout' => $timeout,
144 'header' => "User-Agent: " . $useragent,
145 'follow_location' => true
146 ),
147 'ssl' => array(
148 'verify_peer' => false,
149 'allow_self_signed' => true
150 )
151 )
152 );
153
154 # only download page lesser than 4MB
155 $data = @file_get_contents($url, false, $context, -1, 4000000);
156
157 if (isset($http_response_header) and isset($http_response_header[0])) {
158 $httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE));
159 }
160 }
161
162 # if response is not empty and response is OK
163 if (isset($data) and isset($httpcodeOK) and $httpcodeOK) {
164
165 # take charset of page and get it
166 preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
167
168 # if meta tag is found
169 if (!empty($meta[0])) {
170 preg_match('#charset="?(.*)"#si', $meta[0], $encoding);
171 # if charset is found set it otherwise, set it to utf-8
172 $html_charset = (!empty($encoding[1])) ? strtolower($encoding[1]) : 'utf-8';
173 } else {
174 $html_charset = 'utf-8';
175 $encoding[1] = '';
176 }
177
178 # replace charset of url to charset of page
179 $data = str_replace('charset=' . $encoding[1], 'charset=' . $html_charset, $data);
180
181 return $data;
182 }
183 else {
184 return FALSE;
185 }
186 }
187
188 public static function renderJson($data)
189 {
190 header('Cache-Control: no-cache, must-revalidate');
191 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
192 header('Content-type: application/json; charset=UTF-8');
193 echo json_encode($data);
194 exit();
195 }
196
197 public static function logm($message)
198 {
199 if (DEBUG_POCHE) {
200 $t = strval(date('Y/m/d_H:i:s')) . ' - ' . $_SERVER["REMOTE_ADDR"] . ' - ' . strval($message) . "\n";
201 file_put_contents(CACHE . '/log.txt', $t, FILE_APPEND);
202 error_log('DEBUG POCHE : ' . $message);
203 }
204 }
205
206 public static function encodeString($string)
207 {
208 return sha1($string . SALT);
209 }
210
211 public static function checkVar($var, $default = '')
212 {
213 return ((isset ($_REQUEST["$var"])) ? htmlentities($_REQUEST["$var"]) : $default);
214 }
215
216 public static function getDomain($url)
217 {
218 $pieces = parse_url($url);
219 $domain = isset($pieces['host']) ? $pieces['host'] : '';
220 if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
221 return $regs['domain'];
222 }
223
224 return FALSE;
225 }
226} \ No newline at end of file
diff --git a/inc/poche/Url.class.php b/inc/poche/Url.class.php
new file mode 100644
index 00000000..f4a8f99e
--- /dev/null
+++ b/inc/poche/Url.class.php
@@ -0,0 +1,94 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class Url
12{
13 public $url;
14
15 function __construct($url)
16 {
17 $this->url = base64_decode($url);
18 }
19
20 public function getUrl() {
21 return $this->url;
22 }
23
24 public function setUrl($url) {
25 $this->url = $url;
26 }
27
28 public function isCorrect()
29 {
30 $pattern = '|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i';
31
32 return preg_match($pattern, $this->url);
33 }
34
35 public function clean()
36 {
37 $url = html_entity_decode(trim($this->url));
38
39 $stuff = strpos($url,'&utm_source=');
40 if ($stuff !== FALSE)
41 $url = substr($url, 0, $stuff);
42 $stuff = strpos($url,'?utm_source=');
43 if ($stuff !== FALSE)
44 $url = substr($url, 0, $stuff);
45 $stuff = strpos($url,'#xtor=RSS-');
46 if ($stuff !== FALSE)
47 $url = substr($url, 0, $stuff);
48
49 $this->url = $url;
50 }
51
52 public function fetchContent()
53 {
54 if ($this->isCorrect()) {
55 $this->clean();
56 $html = Encoding::toUTF8(Tools::getFile($this->getUrl()));
57
58 # if Tools::getFile() if not able to retrieve HTTPS content, try the same URL with HTTP protocol
59 if (!preg_match('!^https?://!i', $this->getUrl()) && (!isset($html) || strlen($html) <= 0)) {
60 $this->setUrl('http://' . $this->getUrl());
61 $html = Encoding::toUTF8(Tools::getFile($this->getUrl()));
62 }
63
64 if (function_exists('tidy_parse_string')) {
65 $tidy = tidy_parse_string($html, array(), 'UTF8');
66 $tidy->cleanRepair();
67 $html = $tidy->value;
68 }
69
70 $parameters = array();
71 if (isset($html) and strlen($html) > 0)
72 {
73 $readability = new Readability($html, $this->getUrl());
74 $readability->convertLinksToFootnotes = CONVERT_LINKS_FOOTNOTES;
75 $readability->revertForcedParagraphElements = REVERT_FORCED_PARAGRAPH_ELEMENTS;
76
77 if($readability->init())
78 {
79 $content = $readability->articleContent->innerHTML;
80 $parameters['title'] = $readability->articleTitle->innerHTML;
81 $parameters['content'] = $content;
82
83 return $parameters;
84 }
85 }
86 }
87 else {
88 #$msg->add('e', _('error during url preparation : the link is not valid'));
89 Tools::logm($this->getUrl() . ' is not a valid url');
90 }
91
92 return FALSE;
93 }
94} \ No newline at end of file
diff --git a/inc/poche/User.class.php b/inc/poche/User.class.php
new file mode 100644
index 00000000..6dac7839
--- /dev/null
+++ b/inc/poche/User.class.php
@@ -0,0 +1,50 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class User
12{
13 public $id;
14 public $username;
15 public $name;
16 public $password;
17 public $email;
18 public $config;
19
20 function __construct($user = array())
21 {
22 if ($user != array()) {
23 $this->id = $user['id'];
24 $this->username = $user['username'];
25 $this->name = $user['name'];
26 $this->password = $user['password'];
27 $this->email = $user['email'];
28 $this->config = $user['config'];
29 }
30 }
31
32 public function getId()
33 {
34 return $this->id;
35 }
36
37 public function getUsername()
38 {
39 return $this->username;
40 }
41
42 public function setConfig($config)
43 {
44 $this->config = $config;
45 }
46
47 public function getConfigValue($name) {
48 return (isset($this->config[$name])) ? $this->config[$name] : FALSE;
49 }
50} \ No newline at end of file
diff --git a/inc/poche/config.inc.php b/inc/poche/config.inc.php
new file mode 100644
index 00000000..930b31e5
--- /dev/null
+++ b/inc/poche/config.inc.php
@@ -0,0 +1,61 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11# storage
12define ('STORAGE','sqlite'); # postgres, mysql, sqlite
13define ('STORAGE_SERVER', 'localhost'); # leave blank for sqlite
14define ('STORAGE_DB', 'poche'); # only for postgres & mysql
15define ('STORAGE_SQLITE', './db/poche.sqlite');
16define ('STORAGE_USER', 'postgres'); # leave blank for sqlite
17define ('STORAGE_PASSWORD', 'postgres'); # leave blank for sqlite
18
19define ('POCHE_VERSION', '1.0-beta');
20define ('MODE_DEMO', FALSE);
21define ('DEBUG_POCHE', FALSE);
22define ('CONVERT_LINKS_FOOTNOTES', FALSE);
23define ('REVERT_FORCED_PARAGRAPH_ELEMENTS', FALSE);
24define ('DOWNLOAD_PICTURES', FALSE);
25define ('SHARE_TWITTER', TRUE);
26define ('SHARE_MAIL', TRUE);
27define ('SALT', '464v54gLLw928uz4zUBqkRJeiPY68zCX');
28define ('ABS_PATH', 'assets/');
29define ('TPL', './tpl');
30define ('LOCALE', './locale');
31define ('CACHE', './cache');
32define ('LANG', 'en_EN.UTF8');
33define ('PAGINATION', '10');
34define ('THEME', 'light');
35
36# /!\ Be careful if you change the lines below /!\
37require_once './inc/poche/User.class.php';
38require_once './inc/poche/Tools.class.php';
39require_once './inc/poche/Url.class.php';
40require_once './inc/3rdparty/class.messages.php';
41require_once './inc/poche/Poche.class.php';
42require_once './inc/3rdparty/Readability.php';
43require_once './inc/3rdparty/Encoding.php';
44require_once './inc/poche/Database.class.php';
45require_once './vendor/autoload.php';
46require_once './inc/3rdparty/simple_html_dom.php';
47require_once './inc/3rdparty/paginator.php';
48require_once './inc/3rdparty/Session.class.php';
49
50if (DOWNLOAD_PICTURES) {
51 require_once './inc/poche/pochePictures.php';
52}
53
54$poche = new Poche();
55#XSRF protection with token
56// if (!empty($_POST)) {
57// if (!Session::isToken($_POST['token'])) {
58// die(_('Wrong token'));
59// }
60// unset($_SESSION['tokens']);
61// } \ No newline at end of file
diff --git a/inc/poche/pochePictures.php b/inc/poche/pochePictures.php
new file mode 100644
index 00000000..4e4a0b08
--- /dev/null
+++ b/inc/poche/pochePictures.php
@@ -0,0 +1,110 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11/**
12 * On modifie les URLS des images dans le corps de l'article
13 */
14function filtre_picture($content, $url, $id)
15{
16 $matches = array();
17 preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER);
18 foreach($matches as $i => $link) {
19 $link[1] = trim($link[1]);
20 if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1])) {
21 $absolute_path = get_absolute_link($link[2],$url);
22 $filename = basename(parse_url($absolute_path, PHP_URL_PATH));
23 $directory = create_assets_directory($id);
24 $fullpath = $directory . '/' . $filename;
25 download_pictures($absolute_path, $fullpath);
26 $content = str_replace($matches[$i][2], $fullpath, $content);
27 }
28
29 }
30
31 return $content;
32}
33
34/**
35 * Retourne le lien absolu
36 */
37function get_absolute_link($relative_link, $url) {
38 /* return if already absolute URL */
39 if (parse_url($relative_link, PHP_URL_SCHEME) != '') return $relative_link;
40
41 /* queries and anchors */
42 if ($relative_link[0]=='#' || $relative_link[0]=='?') return $url . $relative_link;
43
44 /* parse base URL and convert to local variables:
45 $scheme, $host, $path */
46 extract(parse_url($url));
47
48 /* remove non-directory element from path */
49 $path = preg_replace('#/[^/]*$#', '', $path);
50
51 /* destroy path if relative url points to root */
52 if ($relative_link[0] == '/') $path = '';
53
54 /* dirty absolute URL */
55 $abs = $host . $path . '/' . $relative_link;
56
57 /* replace '//' or '/./' or '/foo/../' with '/' */
58 $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
59 for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
60
61 /* absolute URL is ready! */
62 return $scheme.'://'.$abs;
63}
64
65/**
66 * Téléchargement des images
67 */
68function download_pictures($absolute_path, $fullpath)
69{
70 $rawdata = Tools::getFile($absolute_path);
71
72 if(file_exists($fullpath)) {
73 unlink($fullpath);
74 }
75 $fp = fopen($fullpath, 'x');
76 fwrite($fp, $rawdata);
77 fclose($fp);
78}
79
80/**
81 * Crée un répertoire de médias pour l'article
82 */
83function create_assets_directory($id)
84{
85 $assets_path = ABS_PATH;
86 if(!is_dir($assets_path)) {
87 mkdir($assets_path, 0705);
88 }
89
90 $article_directory = $assets_path . $id;
91 if(!is_dir($article_directory)) {
92 mkdir($article_directory, 0705);
93 }
94
95 return $article_directory;
96}
97
98/**
99 * Suppression du répertoire d'images
100 */
101function remove_directory($directory)
102{
103 if(is_dir($directory)) {
104 $files = array_diff(scandir($directory), array('.','..'));
105 foreach ($files as $file) {
106 (is_dir("$directory/$file")) ? remove_directory("$directory/$file") : unlink("$directory/$file");
107 }
108 return rmdir($directory);
109 }
110} \ No newline at end of file
diff --git a/inc/rain.tpl.class.php b/inc/rain.tpl.class.php
deleted file mode 100644
index 6522c798..00000000
--- a/inc/rain.tpl.class.php
+++ /dev/null
@@ -1,1043 +0,0 @@
1<?php
2
3/**
4 * RainTPL
5 * -------
6 * Realized by Federico Ulfo & maintained by the Rain Team
7 * Distributed under GNU/LGPL 3 License
8 *
9 * @version 2.7.2
10 */
11
12
13class RainTPL{
14
15 // -------------------------
16 // CONFIGURATION
17 // -------------------------
18
19 /**
20 * Template directory
21 *
22 * @var string
23 */
24 static $tpl_dir = "tpl/";
25
26
27 /**
28 * Cache directory. Is the directory where RainTPL will compile the template and save the cache
29 *
30 * @var string
31 */
32 static $cache_dir = "tmp/";
33
34
35 /**
36 * Template base URL. RainTPL will add this URL to the relative paths of element selected in $path_replace_list.
37 *
38 * @var string
39 */
40 static $base_url = null;
41
42
43 /**
44 * Template extension.
45 *
46 * @var string
47 */
48 static $tpl_ext = "html";
49
50
51 /**
52 * Path replace is a cool features that replace all relative paths of images (<img src="...">), stylesheet (<link href="...">), script (<script src="...">) and link (<a href="...">)
53 * Set true to enable the path replace.
54 *
55 * @var unknown_type
56 */
57 static $path_replace = true;
58
59
60 /**
61 * You can set what the path_replace method will replace.
62 * Avaible options: a, img, link, script, input
63 *
64 * @var array
65 */
66 static $path_replace_list = array( 'a', 'img', 'link', 'script', 'input' );
67
68
69 /**
70 * You can define in the black list what string are disabled into the template tags
71 *
72 * @var unknown_type
73 */
74 static $black_list = array( '\$this', 'raintpl::', 'self::', '_SESSION', '_SERVER', '_ENV', 'eval', 'exec', 'unlink', 'rmdir' );
75
76
77 /**
78 * Check template.
79 * true: checks template update time, if changed it compile them
80 * false: loads the compiled template. Set false if server doesn't have write permission for cache_directory.
81 *
82 */
83 static $check_template_update = true;
84
85
86 /**
87 * PHP tags <? ?>
88 * True: php tags are enabled into the template
89 * False: php tags are disabled into the template and rendered as html
90 *
91 * @var bool
92 */
93 static $php_enabled = true;
94
95
96 /**
97 * Debug mode flag.
98 * True: debug mode is used, syntax errors are displayed directly in template. Execution of script is not terminated.
99 * False: exception is thrown on found error.
100 *
101 * @var bool
102 */
103 static $debug = false;
104
105 // -------------------------
106
107
108 // -------------------------
109 // RAINTPL VARIABLES
110 // -------------------------
111
112 /**
113 * Is the array where RainTPL keep the variables assigned
114 *
115 * @var array
116 */
117 public $var = array();
118
119 protected $tpl = array(), // variables to keep the template directories and info
120 $cache = false, // static cache enabled / disabled
121 $cache_id = null; // identify only one cache
122
123 protected static $config_name_sum = array(); // takes all the config to create the md5 of the file
124
125 // -------------------------
126
127
128
129 const CACHE_EXPIRE_TIME = 3600; // default cache expire time = hour
130
131
132
133 /**
134 * Assign variable
135 * eg. $t->assign('name','mickey');
136 *
137 * @param mixed $variable_name Name of template variable or associative array name/value
138 * @param mixed $value value assigned to this variable. Not set if variable_name is an associative array
139 */
140
141 function assign( $variable, $value = null ){
142 if( is_array( $variable ) )
143 $this->var += $variable;
144 else
145 $this->var[ $variable ] = $value;
146 }
147
148
149
150 /**
151 * Draw the template
152 * eg. $html = $tpl->draw( 'demo', TRUE ); // return template in string
153 * or $tpl->draw( $tpl_name ); // echo the template
154 *
155 * @param string $tpl_name template to load
156 * @param boolean $return_string true=return a string, false=echo the template
157 * @return string
158 */
159
160 function draw( $tpl_name, $return_string = false ){
161
162 try {
163 // compile the template if necessary and set the template filepath
164 $this->check_template( $tpl_name );
165 } catch (RainTpl_Exception $e) {
166 $output = $this->printDebug($e);
167 die($output);
168 }
169
170 // Cache is off and, return_string is false
171 // Rain just echo the template
172
173 if( !$this->cache && !$return_string ){
174 extract( $this->var );
175 include $this->tpl['compiled_filename'];
176 unset( $this->tpl );
177 }
178
179
180 // cache or return_string are enabled
181 // rain get the output buffer to save the output in the cache or to return it as string
182
183 else{
184
185 //----------------------
186 // get the output buffer
187 //----------------------
188 ob_start();
189 extract( $this->var );
190 include $this->tpl['compiled_filename'];
191 $raintpl_contents = ob_get_clean();
192 //----------------------
193
194
195 // save the output in the cache
196 if( $this->cache )
197 file_put_contents( $this->tpl['cache_filename'], "<?php if(!class_exists('raintpl')){exit;}?>" . $raintpl_contents );
198
199 // free memory
200 unset( $this->tpl );
201
202 // return or print the template
203 if( $return_string ) return $raintpl_contents; else echo $raintpl_contents;
204
205 }
206
207 }
208
209
210
211 /**
212 * If exists a valid cache for this template it returns the cache
213 *
214 * @param string $tpl_name Name of template (set the same of draw)
215 * @param int $expiration_time Set after how many seconds the cache expire and must be regenerated
216 * @return string it return the HTML or null if the cache must be recreated
217 */
218
219 function cache( $tpl_name, $expire_time = self::CACHE_EXPIRE_TIME, $cache_id = null ){
220
221 // set the cache_id
222 $this->cache_id = $cache_id;
223
224 if( !$this->check_template( $tpl_name ) && file_exists( $this->tpl['cache_filename'] ) && ( time() - filemtime( $this->tpl['cache_filename'] ) < $expire_time ) )
225 return substr( file_get_contents( $this->tpl['cache_filename'] ), 43 );
226 else{
227 //delete the cache of the selected template
228 if (file_exists($this->tpl['cache_filename']))
229 unlink($this->tpl['cache_filename'] );
230 $this->cache = true;
231 }
232 }
233
234
235
236 /**
237 * Configure the settings of RainTPL
238 *
239 */
240 static function configure( $setting, $value = null ){
241 if( is_array( $setting ) )
242 foreach( $setting as $key => $value )
243 self::configure( $key, $value );
244 else if( property_exists( __CLASS__, $setting ) ){
245 self::$$setting = $value;
246 self::$config_name_sum[ $setting ] = $value; // take trace of all config
247 }
248 }
249
250
251
252 // check if has to compile the template
253 // return true if the template has changed
254 protected function check_template( $tpl_name ){
255
256 if( !isset($this->tpl['checked']) ){
257
258 $tpl_basename = basename( $tpl_name ); // template basename
259 $tpl_basedir = strpos($tpl_name,"/") ? dirname($tpl_name) . '/' : null; // template basedirectory
260 $tpl_dir = self::$tpl_dir . $tpl_basedir; // template directory
261 $this->tpl['tpl_filename'] = $tpl_dir . $tpl_basename . '.' . self::$tpl_ext; // template filename
262 $temp_compiled_filename = self::$cache_dir . $tpl_basename . "." . md5( $tpl_dir . serialize(self::$config_name_sum));
263 $this->tpl['compiled_filename'] = $temp_compiled_filename . '.rtpl.php'; // cache filename
264 $this->tpl['cache_filename'] = $temp_compiled_filename . '.s_' . $this->cache_id . '.rtpl.php'; // static cache filename
265
266 // if the template doesn't exsist throw an error
267 if( self::$check_template_update && !file_exists( $this->tpl['tpl_filename'] ) ){
268 $e = new RainTpl_NotFoundException( 'Template '. $tpl_basename .' not found!' );
269 throw $e->setTemplateFile($this->tpl['tpl_filename']);
270 }
271
272 // file doesn't exsist, or the template was updated, Rain will compile the template
273 if( !file_exists( $this->tpl['compiled_filename'] ) || ( self::$check_template_update && filemtime($this->tpl['compiled_filename']) < filemtime( $this->tpl['tpl_filename'] ) ) ){
274 $this->compileFile( $tpl_basename, $tpl_basedir, $this->tpl['tpl_filename'], self::$cache_dir, $this->tpl['compiled_filename'] );
275 return true;
276 }
277 $this->tpl['checked'] = true;
278 }
279 }
280
281
282 /**
283 * execute stripslaches() on the xml block. Invoqued by preg_replace_callback function below
284 * @access protected
285 */
286 protected function xml_reSubstitution($capture) {
287 return "<?php echo '<?xml ".stripslashes($capture[1])." ?>'; ?>";
288 }
289
290 /**
291 * Compile and write the compiled template file
292 * @access protected
293 */
294 protected function compileFile( $tpl_basename, $tpl_basedir, $tpl_filename, $cache_dir, $compiled_filename ){
295
296 //read template file
297 $this->tpl['source'] = $template_code = file_get_contents( $tpl_filename );
298
299 //xml substitution
300 $template_code = preg_replace( "/<\?xml(.*?)\?>/s", "##XML\\1XML##", $template_code );
301
302 //disable php tag
303 if( !self::$php_enabled )
304 $template_code = str_replace( array("<?","?>"), array("&lt;?","?&gt;"), $template_code );
305
306 //xml re-substitution
307 $template_code = preg_replace_callback ( "/##XML(.*?)XML##/s", array($this, 'xml_reSubstitution'), $template_code );
308
309 //compile template
310 $template_compiled = "<?php if(!class_exists('raintpl')){exit;}?>" . $this->compileTemplate( $template_code, $tpl_basedir );
311
312
313 // fix the php-eating-newline-after-closing-tag-problem
314 $template_compiled = str_replace( "?>\n", "?>\n\n", $template_compiled );
315
316 // create directories
317 if( !is_dir( $cache_dir ) )
318 mkdir( $cache_dir, 0755, true );
319
320 if( !is_writable( $cache_dir ) )
321 throw new RainTpl_Exception ('Cache directory ' . $cache_dir . 'doesn\'t have write permission. Set write permission or set RAINTPL_CHECK_TEMPLATE_UPDATE to false. More details on http://www.raintpl.com/Documentation/Documentation-for-PHP-developers/Configuration/');
322
323 //write compiled file
324 file_put_contents( $compiled_filename, $template_compiled );
325 }
326
327
328
329 /**
330 * Compile template
331 * @access protected
332 */
333 protected function compileTemplate( $template_code, $tpl_basedir ){
334
335 //tag list
336 $tag_regexp = array( 'loop' => '(\{loop(?: name){0,1}="\${0,1}[^"]*"\})',
337 'loop_close' => '(\{\/loop\})',
338 'if' => '(\{if(?: condition){0,1}="[^"]*"\})',
339 'elseif' => '(\{elseif(?: condition){0,1}="[^"]*"\})',
340 'else' => '(\{else\})',
341 'if_close' => '(\{\/if\})',
342 'function' => '(\{function="[^"]*"\})',
343 'noparse' => '(\{noparse\})',
344 'noparse_close'=> '(\{\/noparse\})',
345 'ignore' => '(\{ignore\}|\{\*)',
346 'ignore_close' => '(\{\/ignore\}|\*\})',
347 'include' => '(\{include="[^"]*"(?: cache="[^"]*")?\})',
348 'template_info'=> '(\{\$template_info\})',
349 'function' => '(\{function="(\w*?)(?:.*?)"\})'
350 );
351
352 $tag_regexp = "/" . join( "|", $tag_regexp ) . "/";
353
354 //split the code with the tags regexp
355 $template_code = preg_split ( $tag_regexp, $template_code, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
356
357 //path replace (src of img, background and href of link)
358 $template_code = $this->path_replace( $template_code, $tpl_basedir );
359
360 //compile the code
361 $compiled_code = $this->compileCode( $template_code );
362
363 //return the compiled code
364 return $compiled_code;
365
366 }
367
368
369
370 /**
371 * Compile the code
372 * @access protected
373 */
374 protected function compileCode( $parsed_code ){
375
376 //variables initialization
377 $compiled_code = $open_if = $comment_is_open = $ignore_is_open = null;
378 $loop_level = 0;
379
380 //read all parsed code
381 while( $html = array_shift( $parsed_code ) ){
382
383 //close ignore tag
384 if( !$comment_is_open && ( strpos( $html, '{/ignore}' ) !== FALSE || strpos( $html, '*}' ) !== FALSE ) )
385 $ignore_is_open = false;
386
387 //code between tag ignore id deleted
388 elseif( $ignore_is_open ){
389 //ignore the code
390 }
391
392 //close no parse tag
393 elseif( strpos( $html, '{/noparse}' ) !== FALSE )
394 $comment_is_open = false;
395
396 //code between tag noparse is not compiled
397 elseif( $comment_is_open )
398 $compiled_code .= $html;
399
400 //ignore
401 elseif( strpos( $html, '{ignore}' ) !== FALSE || strpos( $html, '{*' ) !== FALSE )
402 $ignore_is_open = true;
403
404 //noparse
405 elseif( strpos( $html, '{noparse}' ) !== FALSE )
406 $comment_is_open = true;
407
408 //include tag
409 elseif( preg_match( '/\{include="([^"]*)"(?: cache="([^"]*)"){0,1}\}/', $html, $code ) ){
410
411 //variables substitution
412 $include_var = $this->var_replace( $code[ 1 ], $left_delimiter = null, $right_delimiter = null, $php_left_delimiter = '".' , $php_right_delimiter = '."', $loop_level );
413
414 // if the cache is active
415 if( isset($code[ 2 ]) ){
416
417 //dynamic include
418 $compiled_code .= '<?php $tpl = new '.get_class($this).';' .
419 'if( $cache = $tpl->cache( $template = basename("'.$include_var.'") ) )' .
420 ' echo $cache;' .
421 'else{' .
422 ' $tpl_dir_temp = self::$tpl_dir;' .
423 ' $tpl->assign( $this->var );' .
424 ( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ).
425 ' $tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'.
426 '} ?>';
427 }
428 else{
429
430 //dynamic include
431 $compiled_code .= '<?php $tpl = new '.get_class($this).';' .
432 '$tpl_dir_temp = self::$tpl_dir;' .
433 '$tpl->assign( $this->var );' .
434 ( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ).
435 '$tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'.
436 '?>';
437
438
439 }
440
441 }
442
443 //loop
444 elseif( preg_match( '/\{loop(?: name){0,1}="\${0,1}([^"]*)"\}/', $html, $code ) ){
445
446 //increase the loop counter
447 $loop_level++;
448
449 //replace the variable in the loop
450 $var = $this->var_replace( '$' . $code[ 1 ], $tag_left_delimiter=null, $tag_right_delimiter=null, $php_left_delimiter=null, $php_right_delimiter=null, $loop_level-1 );
451
452 //loop variables
453 $counter = "\$counter$loop_level"; // count iteration
454 $key = "\$key$loop_level"; // key
455 $value = "\$value$loop_level"; // value
456
457 //loop code
458 $compiled_code .= "<?php $counter=-1; if( isset($var) && is_array($var) && sizeof($var) ) foreach( $var as $key => $value ){ $counter++; ?>";
459
460 }
461
462 //close loop tag
463 elseif( strpos( $html, '{/loop}' ) !== FALSE ) {
464
465 //iterator
466 $counter = "\$counter$loop_level";
467
468 //decrease the loop counter
469 $loop_level--;
470
471 //close loop code
472 $compiled_code .= "<?php } ?>";
473
474 }
475
476 //if
477 elseif( preg_match( '/\{if(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){
478
479 //increase open if counter (for intendation)
480 $open_if++;
481
482 //tag
483 $tag = $code[ 0 ];
484
485 //condition attribute
486 $condition = $code[ 1 ];
487
488 // check if there's any function disabled by black_list
489 $this->function_check( $tag );
490
491 //variable substitution into condition (no delimiter into the condition)
492 $parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
493
494 //if code
495 $compiled_code .= "<?php if( $parsed_condition ){ ?>";
496
497 }
498
499 //elseif
500 elseif( preg_match( '/\{elseif(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){
501
502 //tag
503 $tag = $code[ 0 ];
504
505 //condition attribute
506 $condition = $code[ 1 ];
507
508 //variable substitution into condition (no delimiter into the condition)
509 $parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
510
511 //elseif code
512 $compiled_code .= "<?php }elseif( $parsed_condition ){ ?>";
513 }
514
515 //else
516 elseif( strpos( $html, '{else}' ) !== FALSE ) {
517
518 //else code
519 $compiled_code .= '<?php }else{ ?>';
520
521 }
522
523 //close if tag
524 elseif( strpos( $html, '{/if}' ) !== FALSE ) {
525
526 //decrease if counter
527 $open_if--;
528
529 // close if code
530 $compiled_code .= '<?php } ?>';
531
532 }
533
534 //function
535 elseif( preg_match( '/\{function="(\w*)(.*?)"\}/', $html, $code ) ){
536
537 //tag
538 $tag = $code[ 0 ];
539
540 //function
541 $function = $code[ 1 ];
542
543 // check if there's any function disabled by black_list
544 $this->function_check( $tag );
545
546 if( empty( $code[ 2 ] ) )
547 $parsed_function = $function . "()";
548 else
549 // parse the function
550 $parsed_function = $function . $this->var_replace( $code[ 2 ], $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
551
552 //if code
553 $compiled_code .= "<?php echo $parsed_function; ?>";
554 }
555
556 // show all vars
557 elseif ( strpos( $html, '{$template_info}' ) !== FALSE ) {
558
559 //tag
560 $tag = '{$template_info}';
561
562 //if code
563 $compiled_code .= '<?php echo "<pre>"; print_r( $this->var ); echo "</pre>"; ?>';
564 }
565
566
567 //all html code
568 else{
569
570 //variables substitution (es. {$title})
571 $html = $this->var_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
572 //const substitution (es. {#CONST#})
573 $html = $this->const_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
574 //functions substitution (es. {"string"|functions})
575 $compiled_code .= $this->func_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
576 }
577 }
578
579 if( $open_if > 0 ) {
580 $e = new RainTpl_SyntaxException('Error! You need to close an {if} tag in ' . $this->tpl['tpl_filename'] . ' template');
581 throw $e->setTemplateFile($this->tpl['tpl_filename']);
582 }
583 return $compiled_code;
584 }
585
586
587 /**
588 * Reduce a path, eg. www/library/../filepath//file => www/filepath/file
589 * @param type $path
590 * @return type
591 */
592 protected function reduce_path( $path ){
593 $path = str_replace( "://", "@not_replace@", $path );
594 $path = str_replace( "//", "/", $path );
595 $path = str_replace( "@not_replace@", "://", $path );
596 return preg_replace('/\w+\/\.\.\//', '', $path );
597 }
598
599
600
601 /**
602 * replace the path of image src, link href and a href.
603 * url => template_dir/url
604 * url# => url
605 * http://url => http://url
606 *
607 * @param string $html
608 * @return string html sostituito
609 */
610 protected function path_replace( $html, $tpl_basedir ){
611
612 if( self::$path_replace ){
613
614 $tpl_dir = self::$base_url . self::$tpl_dir . $tpl_basedir;
615
616 // reduce the path
617 $path = $this->reduce_path($tpl_dir);
618
619 $exp = $sub = array();
620
621 if( in_array( "img", self::$path_replace_list ) ){
622 $exp = array( '/<img(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<img(.*?)src=(?:")([^"]+?)#(?:")/i', '/<img(.*?)src="(.*?)"/', '/<img(.*?)src=(?:\@)([^"]+?)(?:\@)/i' );
623 $sub = array( '<img$1src=@$2://$3@', '<img$1src=@$2@', '<img$1src="' . $path . '$2"', '<img$1src="$2"' );
624 }
625
626 if( in_array( "script", self::$path_replace_list ) ){
627 $exp = array_merge( $exp , array( '/<script(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<script(.*?)src=(?:")([^"]+?)#(?:")/i', '/<script(.*?)src="(.*?)"/', '/<script(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) );
628 $sub = array_merge( $sub , array( '<script$1src=@$2://$3@', '<script$1src=@$2@', '<script$1src="' . $path . '$2"', '<script$1src="$2"' ) );
629 }
630
631 if( in_array( "link", self::$path_replace_list ) ){
632 $exp = array_merge( $exp , array( '/<link(.*?)href=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<link(.*?)href=(?:")([^"]+?)#(?:")/i', '/<link(.*?)href="(.*?)"/', '/<link(.*?)href=(?:\@)([^"]+?)(?:\@)/i' ) );
633 $sub = array_merge( $sub , array( '<link$1href=@$2://$3@', '<link$1href=@$2@' , '<link$1href="' . $path . '$2"', '<link$1href="$2"' ) );
634 }
635
636 if( in_array( "a", self::$path_replace_list ) ){
637 $exp = array_merge( $exp , array( '/<a(.*?)href=(?:")(http\:\/\/|https\:\/\/|javascript:)([^"]+?)(?:")/i', '/<a(.*?)href="(.*?)"/', '/<a(.*?)href=(?:\@)([^"]+?)(?:\@)/i' ) );
638 $sub = array_merge( $sub , array( '<a$1href=@$2$3@', '<a$1href="' . self::$base_url . '$2"', '<a$1href="$2"' ) );
639 }
640
641 if( in_array( "input", self::$path_replace_list ) ){
642 $exp = array_merge( $exp , array( '/<input(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<input(.*?)src=(?:")([^"]+?)#(?:")/i', '/<input(.*?)src="(.*?)"/', '/<input(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) );
643 $sub = array_merge( $sub , array( '<input$1src=@$2://$3@', '<input$1src=@$2@', '<input$1src="' . $path . '$2"', '<input$1src="$2"' ) );
644 }
645
646 return preg_replace( $exp, $sub, $html );
647
648 }
649 else
650 return $html;
651
652 }
653
654
655
656
657
658 // replace const
659 function const_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
660 // const
661 return preg_replace( '/\{\#(\w+)\#{0,1}\}/', $php_left_delimiter . ( $echo ? " echo " : null ) . '\\1' . $php_right_delimiter, $html );
662 }
663
664
665
666 // replace functions/modifiers on constants and strings
667 function func_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
668
669 preg_match_all( '/' . '\{\#{0,1}(\"{0,1}.*?\"{0,1})(\|\w.*?)\#{0,1}\}' . '/', $html, $matches );
670
671 for( $i=0, $n=count($matches[0]); $i<$n; $i++ ){
672
673 //complete tag ex: {$news.title|substr:0,100}
674 $tag = $matches[ 0 ][ $i ];
675
676 //variable name ex: news.title
677 $var = $matches[ 1 ][ $i ];
678
679 //function and parameters associate to the variable ex: substr:0,100
680 $extra_var = $matches[ 2 ][ $i ];
681
682 // check if there's any function disabled by black_list
683 $this->function_check( $tag );
684
685 $extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
686
687
688 // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
689 $is_init_variable = preg_match( "/^(\s*?)\=[^=](.*?)$/", $extra_var );
690
691 //function associate to variable
692 $function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
693
694 //variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
695 $temp = preg_split( "/\.|\[|\-\>/", $var );
696
697 //variable name
698 $var_name = $temp[ 0 ];
699
700 //variable path
701 $variable_path = substr( $var, strlen( $var_name ) );
702
703 //parentesis transform [ e ] in [" e in "]
704 $variable_path = str_replace( '[', '["', $variable_path );
705 $variable_path = str_replace( ']', '"]', $variable_path );
706
707 //transform .$variable in ["$variable"]
708 $variable_path = preg_replace('/\.\$(\w+)/', '["$\\1"]', $variable_path );
709
710 //transform [variable] in ["variable"]
711 $variable_path = preg_replace('/\.(\w+)/', '["\\1"]', $variable_path );
712
713 //if there's a function
714 if( $function_var ){
715
716 // check if there's a function or a static method and separate, function by parameters
717 $function_var = str_replace("::", "@double_dot@", $function_var );
718
719 // get the position of the first :
720 if( $dot_position = strpos( $function_var, ":" ) ){
721
722 // get the function and the parameters
723 $function = substr( $function_var, 0, $dot_position );
724 $params = substr( $function_var, $dot_position+1 );
725
726 }
727 else{
728
729 //get the function
730 $function = str_replace( "@double_dot@", "::", $function_var );
731 $params = null;
732
733 }
734
735 // replace back the @double_dot@ with ::
736 $function = str_replace( "@double_dot@", "::", $function );
737 $params = str_replace( "@double_dot@", "::", $params );
738
739
740 }
741 else
742 $function = $params = null;
743
744 $php_var = $var_name . $variable_path;
745
746 // compile the variable for php
747 if( isset( $function ) ){
748 if( $php_var )
749 $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
750 else
751 $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $params ) )" : "$function()" ) . $php_right_delimiter;
752 }
753 else
754 $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
755
756 $html = str_replace( $tag, $php_var, $html );
757
758 }
759
760 return $html;
761
762 }
763
764
765
766 function var_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
767
768 //all variables
769 if( preg_match_all( '/' . $tag_left_delimiter . '\$(\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*)(.*?)' . $tag_right_delimiter . '/', $html, $matches ) ){
770
771 for( $parsed=array(), $i=0, $n=count($matches[0]); $i<$n; $i++ )
772 $parsed[$matches[0][$i]] = array('var'=>$matches[1][$i],'extra_var'=>$matches[2][$i]);
773
774 foreach( $parsed as $tag => $array ){
775
776 //variable name ex: news.title
777 $var = $array['var'];
778
779 //function and parameters associate to the variable ex: substr:0,100
780 $extra_var = $array['extra_var'];
781
782 // check if there's any function disabled by black_list
783 $this->function_check( $tag );
784
785 $extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
786
787 // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
788 $is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var );
789
790 //function associate to variable
791 $function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
792
793 //variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
794 $temp = preg_split( "/\.|\[|\-\>/", $var );
795
796 //variable name
797 $var_name = $temp[ 0 ];
798
799 //variable path
800 $variable_path = substr( $var, strlen( $var_name ) );
801
802 //parentesis transform [ e ] in [" e in "]
803 $variable_path = str_replace( '[', '["', $variable_path );
804 $variable_path = str_replace( ']', '"]', $variable_path );
805
806 //transform .$variable in ["$variable"] and .variable in ["variable"]
807 $variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path );
808
809 // if is an assignment also assign the variable to $this->var['value']
810 if( $is_init_variable )
811 $extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var;
812
813
814
815 //if there's a function
816 if( $function_var ){
817
818 // check if there's a function or a static method and separate, function by parameters
819 $function_var = str_replace("::", "@double_dot@", $function_var );
820
821
822 // get the position of the first :
823 if( $dot_position = strpos( $function_var, ":" ) ){
824
825 // get the function and the parameters
826 $function = substr( $function_var, 0, $dot_position );
827 $params = substr( $function_var, $dot_position+1 );
828
829 }
830 else{
831
832 //get the function
833 $function = str_replace( "@double_dot@", "::", $function_var );
834 $params = null;
835
836 }
837
838 // replace back the @double_dot@ with ::
839 $function = str_replace( "@double_dot@", "::", $function );
840 $params = str_replace( "@double_dot@", "::", $params );
841 }
842 else
843 $function = $params = null;
844
845 //if it is inside a loop
846 if( $loop_level ){
847 //verify the variable name
848 if( $var_name == 'key' )
849 $php_var = '$key' . $loop_level;
850 elseif( $var_name == 'value' )
851 $php_var = '$value' . $loop_level . $variable_path;
852 elseif( $var_name == 'counter' )
853 $php_var = '$counter' . $loop_level;
854 else
855 $php_var = '$' . $var_name . $variable_path;
856 }else
857 $php_var = '$' . $var_name . $variable_path;
858
859 // compile the variable for php
860 if( isset( $function ) )
861 $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
862 else
863 $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
864
865 $html = str_replace( $tag, $php_var, $html );
866
867
868 }
869 }
870
871 return $html;
872 }
873
874
875
876 /**
877 * Check if function is in black list (sandbox)
878 *
879 * @param string $code
880 * @param string $tag
881 */
882 protected function function_check( $code ){
883
884 $preg = '#(\W|\s)' . implode( '(\W|\s)|(\W|\s)', self::$black_list ) . '(\W|\s)#';
885
886 // check if the function is in the black list (or not in white list)
887 if( count(self::$black_list) && preg_match( $preg, $code, $match ) ){
888
889 // find the line of the error
890 $line = 0;
891 $rows=explode("\n",$this->tpl['source']);
892 while( !strpos($rows[$line],$code) )
893 $line++;
894
895 // stop the execution of the script
896 $e = new RainTpl_SyntaxException('Unallowed syntax in ' . $this->tpl['tpl_filename'] . ' template');
897 throw $e->setTemplateFile($this->tpl['tpl_filename'])
898 ->setTag($code)
899 ->setTemplateLine($line);
900 }
901
902 }
903
904 /**
905 * Prints debug info about exception or passes it further if debug is disabled.
906 *
907 * @param RainTpl_Exception $e
908 * @return string
909 */
910 protected function printDebug(RainTpl_Exception $e){
911 if (!self::$debug) {
912 throw $e;
913 }
914 $output = sprintf('<h2>Exception: %s</h2><h3>%s</h3><p>template: %s</p>',
915 get_class($e),
916 $e->getMessage(),
917 $e->getTemplateFile()
918 );
919 if ($e instanceof RainTpl_SyntaxException) {
920 if (null != $e->getTemplateLine()) {
921 $output .= '<p>line: ' . $e->getTemplateLine() . '</p>';
922 }
923 if (null != $e->getTag()) {
924 $output .= '<p>in tag: ' . htmlspecialchars($e->getTag()) . '</p>';
925 }
926 if (null != $e->getTemplateLine() && null != $e->getTag()) {
927 $rows=explode("\n", htmlspecialchars($this->tpl['source']));
928 $rows[$e->getTemplateLine()] = '<font color=red>' . $rows[$e->getTemplateLine()] . '</font>';
929 $output .= '<h3>template code</h3>' . implode('<br />', $rows) . '</pre>';
930 }
931 }
932 $output .= sprintf('<h3>trace</h3><p>In %s on line %d</p><pre>%s</pre>',
933 $e->getFile(), $e->getLine(),
934 nl2br(htmlspecialchars($e->getTraceAsString()))
935 );
936 return $output;
937 }
938}
939
940
941/**
942 * Basic Rain tpl exception.
943 */
944class RainTpl_Exception extends Exception{
945 /**
946 * Path of template file with error.
947 */
948 protected $templateFile = '';
949
950 /**
951 * Returns path of template file with error.
952 *
953 * @return string
954 */
955 public function getTemplateFile()
956 {
957 return $this->templateFile;
958 }
959
960 /**
961 * Sets path of template file with error.
962 *
963 * @param string $templateFile
964 * @return RainTpl_Exception
965 */
966 public function setTemplateFile($templateFile)
967 {
968 $this->templateFile = (string) $templateFile;
969 return $this;
970 }
971}
972
973/**
974 * Exception thrown when template file does not exists.
975 */
976class RainTpl_NotFoundException extends RainTpl_Exception{
977}
978
979/**
980 * Exception thrown when syntax error occurs.
981 */
982class RainTpl_SyntaxException extends RainTpl_Exception{
983 /**
984 * Line in template file where error has occured.
985 *
986 * @var int | null
987 */
988 protected $templateLine = null;
989
990 /**
991 * Tag which caused an error.
992 *
993 * @var string | null
994 */
995 protected $tag = null;
996
997 /**
998 * Returns line in template file where error has occured
999 * or null if line is not defined.
1000 *
1001 * @return int | null
1002 */
1003 public function getTemplateLine()
1004 {
1005 return $this->templateLine;
1006 }
1007
1008 /**
1009 * Sets line in template file where error has occured.
1010 *
1011 * @param int $templateLine
1012 * @return RainTpl_SyntaxException
1013 */
1014 public function setTemplateLine($templateLine)
1015 {
1016 $this->templateLine = (int) $templateLine;
1017 return $this;
1018 }
1019
1020 /**
1021 * Returns tag which caused an error.
1022 *
1023 * @return string
1024 */
1025 public function getTag()
1026 {
1027 return $this->tag;
1028 }
1029
1030 /**
1031 * Sets tag which caused an error.
1032 *
1033 * @param string $tag
1034 * @return RainTpl_SyntaxException
1035 */
1036 public function setTag($tag)
1037 {
1038 $this->tag = (string) $tag;
1039 return $this;
1040 }
1041}
1042
1043// -- end
diff --git a/inc/store/file.class.php b/inc/store/file.class.php
deleted file mode 100644
index ad20937d..00000000
--- a/inc/store/file.class.php
+++ /dev/null
@@ -1,51 +0,0 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class File extends Store {
12 function __construct() {
13
14 }
15
16 public function add() {
17
18 }
19
20 public function retrieveOneById($id) {
21
22 }
23
24 public function retrieveOneByURL($url) {
25
26 }
27
28 public function deleteById($id) {
29
30 }
31
32 public function favoriteById($id) {
33
34 }
35
36 public function archiveById($id) {
37
38 }
39
40 public function getEntriesByView($view) {
41
42 }
43
44 public function getLastId() {
45
46 }
47
48 public function updateContentById($id) {
49
50 }
51}
diff --git a/inc/store/sqlite.class.php b/inc/store/sqlite.class.php
deleted file mode 100644
index 21081608..00000000
--- a/inc/store/sqlite.class.php
+++ /dev/null
@@ -1,202 +0,0 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class Sqlite extends Store {
12
13 public static $db_path = 'sqlite:./db/poche.sqlite';
14 var $handle;
15
16 function __construct() {
17 parent::__construct();
18
19 $this->handle = new PDO(self::$db_path);
20 $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
21 }
22
23 private function getHandle() {
24 return $this->handle;
25 }
26
27 public function isInstalled() {
28 $sql = "SELECT name FROM sqlite_sequence WHERE name=?";
29 $query = $this->executeQuery($sql, array('config'));
30 $hasConfig = $query->fetchAll();
31
32 if (count($hasConfig) == 0)
33 return FALSE;
34
35 if (!$this->getLogin() || !$this->getPassword())
36 return FALSE;
37
38 return TRUE;
39 }
40
41 public function install($login, $password) {
42 $this->getHandle()->exec('CREATE TABLE IF NOT EXISTS "config" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "name" VARCHAR UNIQUE, "value" BLOB)');
43
44 $this->handle->exec('CREATE TABLE IF NOT EXISTS "entries" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "title" VARCHAR, "url" VARCHAR UNIQUE , "is_read" INTEGER DEFAULT 0, "is_fav" INTEGER DEFAULT 0, "content" BLOB)');
45
46 if (!$this->getLogin()) {
47 $sql_login = 'INSERT INTO config ( name, value ) VALUES (?, ?)';
48 $params_login = array('login', $login);
49 $query = $this->executeQuery($sql_login, $params_login);
50 }
51
52 if (!$this->getPassword()) {
53 $sql_pass = 'INSERT INTO config ( name, value ) VALUES (?, ?)';
54 $params_pass = array('password', $password);
55 $query = $this->executeQuery($sql_pass, $params_pass);
56 }
57
58 return TRUE;
59 }
60
61 public function getLogin() {
62 $sql = "SELECT value FROM config WHERE name=?";
63 $query = $this->executeQuery($sql, array('login'));
64 $login = $query->fetchAll();
65
66 return isset($login[0]['value']) ? $login[0]['value'] : FALSE;
67 }
68
69 public function getPassword() {
70 $sql = "SELECT value FROM config WHERE name=?";
71 $query = $this->executeQuery($sql, array('password'));
72 $pass = $query->fetchAll();
73
74 return isset($pass[0]['value']) ? $pass[0]['value'] : FALSE;
75 }
76
77 public function updatePassword($password)
78 {
79 $sql_update = "UPDATE config SET value=? WHERE name='password'";
80 $params_update = array($password);
81 $query = $this->executeQuery($sql_update, $params_update);
82 }
83
84 private function executeQuery($sql, $params) {
85 try
86 {
87 $query = $this->getHandle()->prepare($sql);
88 $query->execute($params);
89 return $query;
90 }
91 catch (Exception $e)
92 {
93 logm('execute query error : '.$e->getMessage());
94 }
95 }
96
97 public function retrieveAll() {
98 $sql = "SELECT * FROM entries ORDER BY id";
99 $query = $this->executeQuery($sql, array());
100 $entries = $query->fetchAll();
101
102 return $entries;
103 }
104
105 public function retrieveOneById($id) {
106 parent::__construct();
107
108 $entry = NULL;
109 $sql = "SELECT * FROM entries WHERE id=?";
110 $params = array(intval($id));
111 $query = $this->executeQuery($sql, $params);
112 $entry = $query->fetchAll();
113
114 return $entry[0];
115 }
116
117 public function getEntriesByView($view) {
118 parent::__construct();
119
120 switch ($_SESSION['sort'])
121 {
122 case 'ia':
123 $order = 'ORDER BY id';
124 break;
125 case 'id':
126 $order = 'ORDER BY id DESC';
127 break;
128 case 'ta':
129 $order = 'ORDER BY lower(title)';
130 break;
131 case 'td':
132 $order = 'ORDER BY lower(title) DESC';
133 break;
134 default:
135 $order = 'ORDER BY id';
136 break;
137 }
138
139 switch ($view)
140 {
141 case 'archive':
142 $sql = "SELECT * FROM entries WHERE is_read=? " . $order;
143 $params = array(-1);
144 break;
145 case 'fav' :
146 $sql = "SELECT * FROM entries WHERE is_fav=? " . $order;
147 $params = array(-1);
148 break;
149 default:
150 $sql = "SELECT * FROM entries WHERE is_read=? " . $order;
151 $params = array(0);
152 break;
153 }
154
155 $query = $this->executeQuery($sql, $params);
156 $entries = $query->fetchAll();
157
158 return $entries;
159 }
160
161 public function add($url, $title, $content) {
162 parent::__construct();
163 $sql_action = 'INSERT INTO entries ( url, title, content ) VALUES (?, ?, ?)';
164 $params_action = array($url, $title, $content);
165 $query = $this->executeQuery($sql_action, $params_action);
166 return $query;
167 }
168
169 public function deleteById($id) {
170 parent::__construct();
171 $sql_action = "DELETE FROM entries WHERE id=?";
172 $params_action = array($id);
173 $query = $this->executeQuery($sql_action, $params_action);
174 return $query;
175 }
176
177 public function favoriteById($id) {
178 parent::__construct();
179 $sql_action = "UPDATE entries SET is_fav=~is_fav WHERE id=?";
180 $params_action = array($id);
181 $query = $this->executeQuery($sql_action, $params_action);
182 }
183
184 public function archiveById($id) {
185 parent::__construct();
186 $sql_action = "UPDATE entries SET is_read=~is_read WHERE id=?";
187 $params_action = array($id);
188 $query = $this->executeQuery($sql_action, $params_action);
189 }
190
191 public function getLastId() {
192 parent::__construct();
193 return $this->getHandle()->lastInsertId();
194 }
195
196 public function updateContentById($id) {
197 parent::__construct();
198 $sql_update = "UPDATE entries SET content=? WHERE id=?";
199 $params_update = array($content, $id);
200 $query = $this->executeQuery($sql_update, $params_update);
201 }
202}
diff --git a/inc/store/store.class.php b/inc/store/store.class.php
deleted file mode 100644
index dd7d4cfe..00000000
--- a/inc/store/store.class.php
+++ /dev/null
@@ -1,63 +0,0 @@
1<?php
2/**
3 * poche, a read it later open source system
4 *
5 * @category poche
6 * @author Nicolas Lœuillet <support@inthepoche.com>
7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file
9 */
10
11class Store {
12 function __construct() {
13
14 }
15
16 public function getLogin() {
17
18 }
19
20 public function getPassword() {
21
22 }
23
24 public function add() {
25
26 }
27
28 public function retrieveAll() {
29
30 }
31
32 public function retrieveOneById($id) {
33
34 }
35
36 public function retrieveOneByURL($url) {
37
38 }
39
40 public function deleteById($id) {
41
42 }
43
44 public function favoriteById($id) {
45
46 }
47
48 public function archiveById($id) {
49
50 }
51
52 public function getEntriesByView($view) {
53
54 }
55
56 public function getLastId() {
57
58 }
59
60 public function updateContentById($id) {
61
62 }
63}
diff --git a/index.php b/index.php
index fdaeabc3..40cadf88 100644
--- a/index.php
+++ b/index.php
@@ -8,85 +8,54 @@
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://www.wtfpl.net/ see COPYING file
9 */ 9 */
10 10
11include dirname(__FILE__).'/inc/config.php'; 11include dirname(__FILE__).'/inc/poche/config.inc.php';
12 12
13myTool::initPhp(); 13$referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
14 14$view = Tools::checkVar('view', 'home');
15# XSRF protection with token 15$action = Tools::checkVar('action');
16if (!empty($_POST)) { 16$id = Tools::checkVar('id');
17 if (!Session::isToken($_POST['token'])) { 17$_SESSION['sort'] = Tools::checkVar('sort', 'id');
18 die(_('Wrong token.')); 18$url = new Url((isset ($_GET['url'])) ? $_GET['url'] : '');
19 }
20 unset($_SESSION['tokens']);
21}
22
23$ref = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
24 19
25if (isset($_GET['login'])) { 20if (isset($_GET['login'])) {
26 // Login 21 # hello you
27 if (!empty($_POST['login']) && !empty($_POST['password'])) { 22 $poche->login($referer);
28 if (Session::login($_SESSION['login'], $_SESSION['pass'], $_POST['login'], encode_string($_POST['password'] . $_POST['login']))) {
29 logm('login successful');
30 $msg->add('s', 'welcome in your poche!');
31 if (!empty($_POST['longlastingsession'])) {
32 $_SESSION['longlastingsession'] = 31536000;
33 $_SESSION['expires_on'] = time() + $_SESSION['longlastingsession'];
34 session_set_cookie_params($_SESSION['longlastingsession']);
35 } else {
36 session_set_cookie_params(0); // when browser closes
37 }
38 session_regenerate_id(true);
39
40 MyTool::redirect($ref);
41 }
42 logm('login failed');
43 die(_("Login failed !"));
44 } else {
45 logm('login failed');
46 }
47} 23}
48elseif (isset($_GET['logout'])) { 24elseif (isset($_GET['logout'])) {
49 logm('logout'); 25 # see you soon !
50 Session::logout(); 26 $poche->logout();
51 MyTool::redirect();
52} 27}
53elseif (isset($_GET['config'])) { 28elseif (isset($_GET['config'])) {
54 if (isset($_POST['password']) && isset($_POST['password_repeat'])) { 29 # Update password
55 if ($_POST['password'] == $_POST['password_repeat'] && $_POST['password'] != "") { 30 $poche->updatePassword();
56 logm('password updated'); 31}
57 if (!MODE_DEMO) { 32elseif (isset($_GET['import'])) {
58 $store->updatePassword(encode_string($_POST['password'] . $_SESSION['login'])); 33 $poche->import($_GET['from']);
59 $msg->add('s', _('your password has been updated')); 34}
60 } 35elseif (isset($_GET['export'])) {
61 else { 36 $poche->export();
62 $msg->add('i', _('in demo mode, you can\'t update password'));
63 }
64 }
65 else
66 $msg->add('e', _('your password can\'t be empty and you have to repeat it in the second field'));
67 }
68} 37}
69 38
70# Traitement des paramètres et déclenchement des actions 39$tpl_vars = array(
71$view = (isset ($_REQUEST['view'])) ? htmlentities($_REQUEST['view']) : 'index'; 40 'referer' => $referer,
72$full_head = (isset ($_REQUEST['full_head'])) ? htmlentities($_REQUEST['full_head']) : 'yes'; 41 'view' => $view,
73$action = (isset ($_REQUEST['action'])) ? htmlentities($_REQUEST['action']) : ''; 42 'poche_url' => Tools::getPocheUrl(),
74$_SESSION['sort'] = (isset ($_REQUEST['sort'])) ? htmlentities($_REQUEST['sort']) : 'id'; 43 'title' => _('poche, a read it later open source system'),
75$id = (isset ($_REQUEST['id'])) ? htmlspecialchars($_REQUEST['id']) : ''; 44 'token' => Session::getToken(),
76$url = (isset ($_GET['url'])) ? $_GET['url'] : ''; 45);
77
78$tpl->assign('isLogged', Session::isLogged());
79$tpl->assign('referer', $ref);
80$tpl->assign('view', $view);
81$tpl->assign('poche_url', myTool::getUrl());
82$tpl->assign('demo', MODE_DEMO);
83$tpl->assign('title', _('poche, a read it later open source system'));
84 46
85if (Session::isLogged()) { 47if (Session::isLogged()) {
86 action_to_do($action, $url, $id); 48 $poche->action($action, $url, $id);
87 display_view($view, $id, $full_head); 49 $tpl_file = Tools::getTplFile($view);
50 $tpl_vars = array_merge($tpl_vars, $poche->displayView($view, $id));
88} 51}
89else { 52else {
90 53 $tpl_file = 'login.twig';
91 $tpl->draw('login');
92} 54}
55
56# because messages can be added in $poche->action(), we have to add this entry now (we can add it before)
57$messages = $poche->messages->display('all', FALSE);
58$tpl_vars = array_merge($tpl_vars, array('messages' => $messages));
59
60# Aaaaaaand action !
61echo $poche->tpl->render($tpl_file, $tpl_vars); \ No newline at end of file
diff --git a/install/mysql.sql b/install/mysql.sql
new file mode 100644
index 00000000..cb232a84
--- /dev/null
+++ b/install/mysql.sql
@@ -0,0 +1,34 @@
1CREATE TABLE IF NOT EXISTS `config` (
2 `id` int(11) NOT NULL AUTO_INCREMENT,
3 `name` varchar(255) NOT NULL,
4 `value` varchar(255) NOT NULL,
5 PRIMARY KEY (`id`)
6) ENGINE=InnoDB DEFAULT CHARSET=latin1;
7
8CREATE TABLE IF NOT EXISTS `entries` (
9 `id` int(11) NOT NULL AUTO_INCREMENT,
10 `title` varchar(255) NOT NULL,
11 `url` varchar(255) NOT NULL,
12 `is_read` tinyint(1) NOT NULL,
13 `is_fav` tinyint(1) NOT NULL,
14 `content` blob NOT NULL,
15 `user_id` int(11) NOT NULL,
16 PRIMARY KEY (`id`)
17) ENGINE=InnoDB DEFAULT CHARSET=latin1;
18
19CREATE TABLE IF NOT EXISTS `users` (
20 `id` int(11) NOT NULL AUTO_INCREMENT,
21 `username` varchar(255) NOT NULL,
22 `password` varchar(255) NOT NULL,
23 `name` int(255) NOT NULL,
24 `email` varchar(255) NOT NULL,
25 PRIMARY KEY (`id`)
26) ENGINE=InnoDB DEFAULT CHARSET=latin1;
27
28CREATE TABLE IF NOT EXISTS `users_config` (
29 `id` int(11) NOT NULL AUTO_INCREMENT,
30 `user_id` int(11) NOT NULL,
31 `name` varchar(255) NOT NULL,
32 `value` varchar(255) NOT NULL,
33 PRIMARY KEY (`id`)
34) ENGINE=InnoDB DEFAULT CHARSET=latin1; \ No newline at end of file
diff --git a/db/poche.sqlite b/install/poche.sqlite
index 2aee61f4..45add0d7 100755
--- a/db/poche.sqlite
+++ b/install/poche.sqlite
Binary files differ
diff --git a/install/postgres.sql b/install/postgres.sql
new file mode 100644
index 00000000..9e0e8276
--- /dev/null
+++ b/install/postgres.sql
@@ -0,0 +1,30 @@
1CREATE TABLE config (
2 id bigserial primary key,
3 name varchar(255) NOT NULL,
4 value varchar(255) NOT NULL
5);
6
7CREATE TABLE entries (
8 id bigserial primary key,
9 title varchar(255) NOT NULL,
10 url varchar(255) NOT NULL,
11 is_read boolean DEFAULT false,
12 is_fav boolean DEFAULT false,
13 content TEXT,
14 user_id integer NOT NULL
15);
16
17CREATE TABLE users (
18 id bigserial primary key,
19 username varchar(255) NOT NULL,
20 password varchar(255) NOT NULL,
21 name varchar(255) NOT NULL,
22 email varchar(255) NOT NULL
23);
24
25CREATE TABLE users_config (
26 id bigserial primary key,
27 user_id integer NOT NULL,
28 name varchar(255) NOT NULL,
29 value varchar(255) NOT NULL
30); \ No newline at end of file
diff --git a/install/update_sqlite_from_0_to_1.php b/install/update_sqlite_from_0_to_1.php
new file mode 100644
index 00000000..f3801eb1
--- /dev/null
+++ b/install/update_sqlite_from_0_to_1.php
@@ -0,0 +1,64 @@
1<?php
2
3$db_path = 'sqlite:../db/poche.sqlite';
4$handle = new PDO($db_path);
5$handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
6
7# Requêtes à exécuter pour mettre à jour poche.sqlite en 1.x
8
9# ajout d'un champ user_id sur la table entries
10$sql = 'ALTER TABLE entries RENAME TO tempEntries;';
11$query = $handle->prepare($sql);
12$query->execute();
13
14$sql = 'CREATE TABLE entries (id INTEGER PRIMARY KEY, title TEXT, url TEXT, is_read NUMERIC DEFAULT 0, is_fav NUMERIC DEFAULT 0, content BLOB, user_id NUMERIC);';
15$query = $handle->prepare($sql);
16$query->execute();
17
18$sql = 'INSERT INTO entries (id, title, url, is_read, is_fav, content) SELECT id, title, url, is_read, is_fav, content FROM tempEntries;';
19$query = $handle->prepare($sql);
20$query->execute();
21
22# Update tout pour mettre user_id = 1
23$sql = 'UPDATE entries SET user_id = 1;';
24$query = $handle->prepare($sql);
25$query->execute();
26
27# Changement des flags pour les lus / favoris
28$sql = 'UPDATE entries SET is_read = 1 WHERE is_read = -1;';
29$query = $handle->prepare($sql);
30$query->execute();
31
32$sql = 'UPDATE entries SET is_fav = 1 WHERE is_fav = -1;';
33$query = $handle->prepare($sql);
34$query->execute();
35
36# Création de la table users
37$sql = 'CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT, name TEXT, email TEXT);';
38$query = $handle->prepare($sql);
39$query->execute();
40
41$sql = 'INSERT INTO users (username) SELECT value FROM config WHERE name = "login";';
42$query = $handle->prepare($sql);
43$query->execute();
44
45$sql = "UPDATE users SET password = (SELECT value FROM config WHERE name = 'password')";
46$query = $handle->prepare($sql);
47$query->execute();
48
49# Création de la table users_config
50$sql = 'CREATE TABLE users_config (id INTEGER PRIMARY KEY, user_id NUMERIC, name TEXT, value TEXT);';
51$query = $handle->prepare($sql);
52$query->execute();
53
54# Suppression de la table temporaire
55$sql = 'DROP TABLE tempEntries;';
56$query = $handle->prepare($sql);
57$query->execute();
58
59# Vidage de la table de config
60$sql = 'DELETE FROM config;';
61$query = $handle->prepare($sql);
62$query->execute();
63
64echo 'welcome to poche 1.0 !'; \ No newline at end of file
diff --git a/js/jquery-1.9.1.min.js b/js/jquery-1.9.1.min.js
deleted file mode 100644
index 006e9531..00000000
--- a/js/jquery-1.9.1.min.js
+++ /dev/null
@@ -1,5 +0,0 @@
1/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
2//@ sourceMappingURL=jquery.min.map
3*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;
4return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&&gt(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l)
5}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window); \ No newline at end of file
diff --git a/js/jquery.masonry.min.js b/js/jquery.masonry.min.js
deleted file mode 100644
index 57c081c6..00000000
--- a/js/jquery.masonry.min.js
+++ /dev/null
@@ -1,10 +0,0 @@
1/**
2 * jQuery Masonry v2.1.08
3 * A dynamic layout plugin for jQuery
4 * The flip-side of CSS Floats
5 * http://masonry.desandro.com
6 *
7 * Licensed under the MIT license.
8 * Copyright 2012 David DeSandro
9 */
10(function(e,t,n){"use strict";var r=t.event,i;r.special.smartresize={setup:function(){t(this).bind("resize",r.special.smartresize.handler)},teardown:function(){t(this).unbind("resize",r.special.smartresize.handler)},handler:function(e,t){var n=this,s=arguments;e.type="smartresize",i&&clearTimeout(i),i=setTimeout(function(){r.dispatch.apply(n,s)},t==="execAsap"?0:100)}},t.fn.smartresize=function(e){return e?this.bind("smartresize",e):this.trigger("smartresize",["execAsap"])},t.Mason=function(e,n){this.element=t(n),this._create(e),this._init()},t.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},t.Mason.prototype={_filterFindBricks:function(e){var t=this.options.itemSelector;return t?e.filter(t).add(e.find(t)):e},_getBricks:function(e){var t=this._filterFindBricks(e).css({position:"absolute"}).addClass("masonry-brick");return t},_create:function(n){this.options=t.extend(!0,{},t.Mason.settings,n),this.styleQueue=[];var r=this.element[0].style;this.originalStyle={height:r.height||""};var i=this.options.containerStyle;for(var s in i)this.originalStyle[s]=r[s]||"";this.element.css(i),this.horizontalDirection=this.options.isRTL?"right":"left";var o=this.element.css("padding-"+this.horizontalDirection),u=this.element.css("padding-top");this.offset={x:o?parseInt(o,10):0,y:u?parseInt(u,10):0},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var a=this;setTimeout(function(){a.element.addClass("masonry")},0),this.options.isResizable&&t(e).bind("smartresize.masonry",function(){a.resize()}),this.reloadItems()},_init:function(e){this._getColumns(),this._reLayout(e)},option:function(e,n){t.isPlainObject(e)&&(this.options=t.extend(!0,this.options,e))},layout:function(e,t){for(var n=0,r=e.length;n<r;n++)this._placeBrick(e[n]);var i={};i.height=Math.max.apply(Math,this.colYs);if(this.options.isFitWidth){var s=0;n=this.cols;while(--n){if(this.colYs[n]!==0)break;s++}i.width=(this.cols-s)*this.columnWidth-this.options.gutterWidth}this.styleQueue.push({$el:this.element,style:i});var o=this.isLaidOut?this.options.isAnimated?"animate":"css":"css",u=this.options.animationOptions,a;for(n=0,r=this.styleQueue.length;n<r;n++)a=this.styleQueue[n],a.$el[o](a.style,u);this.styleQueue=[],t&&t.call(e),this.isLaidOut=!0},_getColumns:function(){var e=this.options.isFitWidth?this.element.parent():this.element,t=e.width();this.columnWidth=this.isFluid?this.options.columnWidth(t):this.options.columnWidth||this.$bricks.outerWidth(!0)||t,this.columnWidth+=this.options.gutterWidth,this.cols=Math.floor((t+this.options.gutterWidth)/this.columnWidth),this.cols=Math.max(this.cols,1)},_placeBrick:function(e){var n=t(e),r,i,s,o,u;r=Math.ceil(n.outerWidth(!0)/this.columnWidth),r=Math.min(r,this.cols);if(r===1)s=this.colYs;else{i=this.cols+1-r,s=[];for(u=0;u<i;u++)o=this.colYs.slice(u,u+r),s[u]=Math.max.apply(Math,o)}var a=Math.min.apply(Math,s),f=0;for(var l=0,c=s.length;l<c;l++)if(s[l]===a){f=l;break}var h={top:a+this.offset.y};h[this.horizontalDirection]=this.columnWidth*f+this.offset.x,this.styleQueue.push({$el:n,style:h});var p=a+n.outerHeight(!0),d=this.cols+1-c;for(l=0;l<d;l++)this.colYs[f+l]=p},resize:function(){var e=this.cols;this._getColumns(),(this.isFluid||this.cols!==e)&&this._reLayout()},_reLayout:function(e){var t=this.cols;this.colYs=[];while(t--)this.colYs.push(0);this.layout(this.$bricks,e)},reloadItems:function(){this.$bricks=this._getBricks(this.element.children())},reload:function(e){this.reloadItems(),this._init(e)},appended:function(e,t,n){if(t){this._filterFindBricks(e).css({top:this.element.height()});var r=this;setTimeout(function(){r._appended(e,n)},1)}else this._appended(e,n)},_appended:function(e,t){var n=this._getBricks(e);this.$bricks=this.$bricks.add(n),this.layout(n,t)},remove:function(e){this.$bricks=this.$bricks.not(e),e.remove()},destroy:function(){this.$bricks.removeClass("masonry-brick").each(function(){this.style.position="",this.style.top="",this.style.left=""});var n=this.element[0].style;for(var r in this.originalStyle)n[r]=this.originalStyle[r];this.element.unbind(".masonry").removeClass("masonry").removeData("masonry"),t(e).unbind(".masonry")}},t.fn.imagesLoaded=function(e){function u(){e.call(n,r)}function a(e){var n=e.target;n.src!==s&&t.inArray(n,o)===-1&&(o.push(n),--i<=0&&(setTimeout(u),r.unbind(".imagesLoaded",a)))}var n=this,r=n.find("img").add(n.filter("img")),i=r.length,s="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",o=[];return i||u(),r.bind("load.imagesLoaded error.imagesLoaded",a).each(function(){var e=this.src;this.src=s,this.src=e}),n};var s=function(t){e.console&&e.console.error(t)};t.fn.masonry=function(e){if(typeof e=="string"){var n=Array.prototype.slice.call(arguments,1);this.each(function(){var r=t.data(this,"masonry");if(!r){s("cannot call methods on masonry prior to initialization; attempted to call method '"+e+"'");return}if(!t.isFunction(r[e])||e.charAt(0)==="_"){s("no such method '"+e+"' for masonry instance");return}r[e].apply(r,n)})}else this.each(function(){var n=t.data(this,"masonry");n?(n.option(e||{}),n._init()):t.data(this,"masonry",new t.Mason(e,this))});return this}})(window,jQuery); \ No newline at end of file
diff --git a/js/poche.js b/js/poche.js
deleted file mode 100644
index 97d9911d..00000000
--- a/js/poche.js
+++ /dev/null
@@ -1,57 +0,0 @@
1function toggle_favorite(element, id) {
2 $(element).toggleClass('fav-off');
3 $.ajax ({
4 url: "index.php?action=toggle_fav",
5 data:{id:id}
6 });
7}
8
9function toggle_archive(element, id, view_article) {
10 $(element).toggleClass('archive-off');
11 $.ajax ({
12 url: "index.php?action=toggle_archive",
13 data:{id:id}
14 });
15 var obj = $('#entry-'+id);
16
17 // on vient de la vue de l'article, donc pas de gestion de grille
18 if (view_article != 1) {
19 $('#content').masonry('remove',obj);
20 $('#content').masonry('reloadItems');
21 $('#content').masonry('reload');
22 }
23}
24
25function sort_links(view, sort) {
26 $.get('index.php', { view: view, sort: sort, full_head: 'no' }, function(data) {
27 $('#content').html(data);
28 });
29}
30
31
32// ---------- Swith light or dark view
33function setActiveStyleSheet(title) {
34 var i, a, main;
35 for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
36 if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
37 a.disabled = true;
38 if(a.getAttribute("title") == title) a.disabled = false;
39 }
40 }
41}
42$('#themeswitch').click(function() {
43 // we want the dark
44 if ($('body').hasClass('light-style')) {
45 setActiveStyleSheet('dark-style');
46 $('body').addClass('dark-style');
47 $('body').removeClass('light-style');
48 $('#themeswitch').text('light');
49 // we want the light
50 } else if ($('body').hasClass('dark-style')) {
51 setActiveStyleSheet('light-style');
52 $('body').addClass('light-style');
53 $('body').removeClass('dark-style');
54 $('#themeswitch').text('dark');
55 }
56 return false;
57});
diff --git a/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo
index d996d46c..c0d4a9d6 100644
--- a/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo
+++ b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo
Binary files differ
diff --git a/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po
index d4e7f2e9..7f8cf784 100644
--- a/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po
+++ b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po
@@ -1,8 +1,8 @@
1msgid "" 1msgid ""
2msgstr "" 2msgstr ""
3"Project-Id-Version: poche\n" 3"Project-Id-Version: poche\n"
4"POT-Creation-Date: 2013-08-02 10:26+0100\n" 4"POT-Creation-Date: 2013-08-06 08:35+0100\n"
5"PO-Revision-Date: 2013-08-02 10:26+0100\n" 5"PO-Revision-Date: 2013-08-06 08:35+0100\n"
6"Last-Translator: Nicolas Lœuillet <nicolas.loeuillet@gmail.com>\n" 6"Last-Translator: Nicolas Lœuillet <nicolas.loeuillet@gmail.com>\n"
7"Language-Team: poche <support@inthepoche.com>\n" 7"Language-Team: poche <support@inthepoche.com>\n"
8"Language: Français\n" 8"Language: Français\n"
@@ -16,96 +16,361 @@ msgstr ""
16"X-Poedit-SourceCharset: UTF-8\n" 16"X-Poedit-SourceCharset: UTF-8\n"
17"X-Poedit-SearchPath-0: /var/www/poche-i18n\n" 17"X-Poedit-SearchPath-0: /var/www/poche-i18n\n"
18 18
19#: /var/www/poche-i18n/import.php:17 19#: /var/www/poche-i18n/index.php:43
20msgid "poche, a read it later open source system"
21msgstr "poche, a read it later open source system"
22
23#: /var/www/poche-i18n/inc/poche/Poche.class.php:101
24msgid "the link has been added successfully"
25msgstr "le lien a été ajouté avec succès"
26
27#: /var/www/poche-i18n/inc/poche/Poche.class.php:104
28msgid "error during insertion : the link wasn't added"
29msgstr "erreur durant l'insertion : le lien n'a pas été ajouté"
30
31#: /var/www/poche-i18n/inc/poche/Poche.class.php:109
32msgid "error during fetching content : the link wasn't added"
33msgstr "erreur durant la récupération du contenu : le lien n'a pas été ajouté"
34
35#: /var/www/poche-i18n/inc/poche/Poche.class.php:119
36msgid "the link has been deleted successfully"
37msgstr "le lien a été supprimé avec succès"
38
39#: /var/www/poche-i18n/inc/poche/Poche.class.php:123
40msgid "the link wasn't deleted"
41msgstr "le lien n'a pas été supprimé"
42
43#: /var/www/poche-i18n/inc/poche/Tools.class.php:18
44msgid "Oops, it seems you don't have PHP 5."
45msgstr "Oups, il semblerait que PHP 5 ne soit pas installé. "
46
47#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:32
48#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:70
49#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:50
50msgid "config"
51msgstr "config"
52
53#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:46
54#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:31
55#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:26
56#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:34
57msgid "home"
58msgstr "accueil"
59
60#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:54
61#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:34
62msgid "favorites"
63msgstr "favoris"
64
65#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:62
66#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:42
67msgid "archive"
68msgstr "archives"
69
70#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:74
71#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:76
72#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:54
73#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:56
74msgid "logout"
75msgstr "déconnexion"
76
77#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:87
78msgid "Bookmarklet"
79msgstr "Bookmarklet"
80
81#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:91
82msgid ""
83"Thanks to the bookmarklet, you will be able to easily add a link to your "
84"poche."
85msgstr ""
86"Grâce au bookmarklet, vous pouvez ajouter facilement un lien dans votre "
87"poche."
88
89#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:93
90msgid "Have a look to this documentation:"
91msgstr "Jetez un œil à la documentation :"
92
93#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:97
94msgid "Drag & drop this link to your bookmarks bar and have fun with poche."
95msgstr ""
96"Glissez / déposez ce lien dans votre barre de favoris de votre navigateur et "
97"prenez du bon temps avec poche."
98
99#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:103
100msgid "poche it!"
101msgstr "poche-le !"
102
103#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:108
104msgid "Updating poche"
105msgstr "Mettre à jour poche"
106
107#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:113
108msgid "your version"
109msgstr "votre version"
110
111#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:119
112msgid "latest stable version"
113msgstr "dernière version stable"
114
115#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:125
116msgid "a more recent stable version is available."
117msgstr "une version stable plus récente est disponible."
118
119#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:128
120#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:142
121msgid "you are up to date."
122msgstr "vous êtes à jour."
123
124#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:133
125msgid "latest dev version"
126msgstr "dernière version de développement"
127
128#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:139
129msgid "a more recent development version is available."
130msgstr "une version de développement plus récente est disponible."
131
132#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:150
133msgid "Change your password"
134msgstr "Modifier votre mot de passe"
135
136#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:157
137msgid "New password:"
138msgstr "Nouveau mot de passe :"
139
140#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:161
141#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:171
142#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:60
143#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:68
144msgid "Password"
145msgstr "Mot de passe"
146
147#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:167
148msgid "Repeat your new password:"
149msgstr "Répétez le nouveau mot de passe :"
150
151#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:177
152msgid "Update"
153msgstr "Mettre à jour"
154
155#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:193
156msgid "Import"
157msgstr "Import"
158
159#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:197
20msgid "Please execute the import script locally, it can take a very long time." 160msgid "Please execute the import script locally, it can take a very long time."
21msgstr "Merci d'exécuter l'import en local, cela peut prendre du temps. " 161msgstr "Merci d'exécuter l'import en local, cela peut prendre du temps. "
22 162
23#: /var/www/poche-i18n/import.php:17 163#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:201
24msgid "Please choose between Pocket & Readabilty :" 164msgid "More infos in the official doc:"
25msgstr "Merci de choisir entre Pocket & Readability :" 165msgstr "Plus d'infos sur la documentation officielle :"
26 166
27#: /var/www/poche-i18n/import.php:17 167#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:206
28msgid "Bye bye Pocket, let's go !" 168msgid "import from Pocket"
29msgstr "Bye bye Pocket, en route !" 169msgstr "l'import depuis Pocket est terminé."
30 170
31#: /var/www/poche-i18n/import.php:17 171#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:210
32msgid "Bye bye Readability, let's go !" 172msgid "import from Readability"
33msgstr "Bye bye Readability, en route !" 173msgstr "l'import depuis Readability est terminé."
34 174
35#: /var/www/poche-i18n/import.php:48 175#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:214
36msgid "Import from Pocket completed." 176msgid "import from Instapaper"
37msgstr "L'import depuis Poche est terminé." 177msgstr "Import depuis Instapaper"
38 178
39#: /var/www/poche-i18n/import.php:48 /var/www/poche-i18n/import.php:66 179#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:220
40msgid "Welcome to poche !" 180msgid "Export your poche datas"
41msgstr "Bienvenue dans poche !" 181msgstr "Exporter vos données de poche"
42 182
43#: /var/www/poche-i18n/import.php:66 183#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:224
44msgid "Import from Readability completed." 184msgid "Click here"
45msgstr "L'import depuis Readability est terminé." 185msgstr "Cliquez-ici"
46 186
47#: /var/www/poche-i18n/import.php:70 187#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:226
48msgid "Error with the import." 188msgid "to export your poche datas."
49msgstr "Erreur durant l'import." 189msgstr "pour exporter vos données de poche."
50 190
51#: /var/www/poche-i18n/import.php:70 191#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:46
52msgid "Back to poche" 192#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:139
53msgstr "Retour à poche" 193#: /var/www/poche-i18n/cache/30/97/b548692380c89d047a16cec7af79.php:22
194msgid "back to home"
195msgstr "retour à l'accueil"
54 196
55#: /var/www/poche-i18n/index.php:18 197#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:50
56msgid "Wrong token." 198#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:147
57msgstr "Mauvais jeton." 199#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:119
200msgid "toggle mark as read"
201msgstr "marquer comme lu"
58 202
59#: /var/www/poche-i18n/index.php:43 203#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:60
60msgid "Login failed !" 204#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:157
61msgstr "Connexion échouée." 205#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:129
206msgid "toggle favorite"
207msgstr "favori"
208
209#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:70
210#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:167
211#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:139
212msgid "delete"
213msgstr "supprimer"
214
215#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:82
216#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:179
217msgid "tweet"
218msgstr "tweeter"
219
220#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:93
221#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:190
222msgid "email"
223msgstr "envoyer par email"
224
225#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:109
226#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:125
227#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:153
228msgid "original"
229msgstr "original"
230
231#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:143
232msgid "back to top"
233msgstr "retour en haut de page"
234
235#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:198
236msgid "this article appears wrong?"
237msgstr "cet article s'affiche mal ?"
238
239#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:200
240msgid "create an issue"
241msgstr "créer un ticket"
242
243#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:202
244msgid "or"
245msgstr "ou"
246
247#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:206
248msgid "contact us by mail"
249msgstr "contactez-nous par email"
250
251#: /var/www/poche-i18n/cache/88/8a/ee3b7080c13204391c14947a0c2c.php:22
252msgid "powered by"
253msgstr "propulsé par"
62 254
63#: /var/www/poche-i18n/index.php:59 255#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:31
64msgid "your password has been updated" 256msgid "installation"
65msgstr "Votre mot de passe a été mis à jour. " 257msgstr "installation"
66 258
67#: /var/www/poche-i18n/index.php:62 259#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:42
68msgid "in demo mode, you can't update password" 260msgid "install your poche"
69msgstr "En mode démo, le mot de passe ne peut être modifié." 261msgstr "installez votre poche"
70 262
71#: /var/www/poche-i18n/index.php:66 263#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:47
72msgid "" 264msgid ""
73"your password can't be empty and you have to repeat it in the second field" 265"poche is still not installed. Please fill the below form to install it. "
266"Don't hesitate to <a href='http://inthepoche.com/?pages/Documentation'>read "
267"the documentation on poche website</a>."
74msgstr "" 268msgstr ""
75"Votre mot de passe ne peut être vide et vous devez le répéter dans le second " 269"poche n'est pas encore installé. Merci de remplir les champs ci-dessous pour "
76"champ." 270"l'installer. N'hésitez pas à <a href='http://inthepoche.com/?pages/"
271"Documentation'>lire la documentation sur le site de poche</a>."
77 272
78#: /var/www/poche-i18n/index.php:83 273#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:53
79msgid "poche, a read it later open source system" 274#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:55
80msgstr "poche, a read it later open source system" 275msgid "Login"
276msgstr "Nom d'utilisateur"
81 277
82#: /var/www/poche-i18n/inc/MyTool.class.php:18 278#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:67
83msgid "Oops, it seems you don't have PHP 5." 279msgid "Repeat your password"
84msgstr "Oups, il semblerait que PHP 5 ne soit pas installé. " 280msgstr "pétez votre mot de passe"
85 281
86#: /var/www/poche-i18n/inc/functions.php:352 282#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:74
87msgid "the link has been added successfully" 283msgid "Install"
88msgstr "le lien a été ajouté avec succès" 284msgstr "Installer"
89 285
90#: /var/www/poche-i18n/inc/functions.php:355 286#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:31
91msgid "error during insertion : the link wasn't added" 287#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:42
92msgstr "erreur durant l'insertion : le lien n'a pas été ajouté" 288msgid "login to your poche"
289msgstr "Se connecter à votre poche"
93 290
94#: /var/www/poche-i18n/inc/functions.php:359 291#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:48
95msgid "error during url preparation : the link wasn't added" 292msgid "you are in demo mode, some features may be disabled."
96msgstr "erreur durant l'insertion : le lien n'a pas été ajouté" 293msgstr ""
294"vous êtes en mode démo, certaines fonctionnalités sont peut-être désactivées."
97 295
98#: /var/www/poche-i18n/inc/functions.php:364 296#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:80
99msgid "error during url preparation : the link is not valid" 297msgid "Stay signed in"
100msgstr "erreur durant la préparation de l'URL : le lien n'est pas valide" 298msgstr "rester connecté"
101 299
102#: /var/www/poche-i18n/inc/functions.php:373 300#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:86
103msgid "the link has been deleted successfully" 301msgid "(Do not check on public computers)"
104msgstr "le lien a été ajou avec succès" 302msgstr " ne pas cocher sur un ordinateur public)"
105 303
106#: /var/www/poche-i18n/inc/functions.php:377 304#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:93
107msgid "the link wasn't deleted" 305msgid "Sign in"
108msgstr "le lien n'a pas été supprimé" 306msgstr ""
307
308#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:55
309#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:57
310msgid "by date asc"
311msgstr "par date asc"
312
313#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:59
314msgid "by date"
315msgstr "par date"
316
317#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:65
318#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:67
319msgid "by date desc"
320msgstr "par date desc"
321
322#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:75
323#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:77
324msgid "by title asc"
325msgstr "par titre asc"
326
327#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:79
328msgid "by title"
329msgstr "par titre"
330
331#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:85
332#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:87
333msgid "by title desc"
334msgstr "par titre desc"
335
336#~ msgid "Please choose between Pocket & Readabilty :"
337#~ msgstr "Merci de choisir entre Pocket & Readability :"
338
339#~ msgid "Bye bye Pocket, let's go !"
340#~ msgstr "Bye bye Pocket, en route !"
341
342#~ msgid "Bye bye Readability, let's go !"
343#~ msgstr "Bye bye Readability, en route !"
344
345#~ msgid "Welcome to poche !"
346#~ msgstr "Bienvenue dans poche !"
347
348#~ msgid "Error with the import."
349#~ msgstr "Erreur durant l'import."
350
351#~ msgid "Wrong token."
352#~ msgstr "Mauvais jeton."
353
354#~ msgid "Login failed !"
355#~ msgstr "Connexion échouée."
356
357#~ msgid "your password has been updated"
358#~ msgstr "Votre mot de passe a été mis à jour. "
359
360#~ msgid "in demo mode, you can't update password"
361#~ msgstr "En mode démo, le mot de passe ne peut être modifié."
362
363#~ msgid ""
364#~ "your password can't be empty and you have to repeat it in the second field"
365#~ msgstr ""
366#~ "Votre mot de passe ne peut être vide et vous devez le répéter dans le "
367#~ "second champ."
368
369#~ msgid "error during url preparation : the link wasn't added"
370#~ msgstr "erreur durant l'insertion : le lien n'a pas été ajouté"
371
372#~ msgid "error during url preparation : the link is not valid"
373#~ msgstr "erreur durant la préparation de l'URL : le lien n'est pas valide"
109 374
110#~ msgid "TEST" 375#~ msgid "TEST"
111#~ msgstr "NICOLAS" 376#~ msgstr "NICOLAS"
diff --git a/tpl/_bookmarklet.twig b/tpl/_bookmarklet.twig
new file mode 100644
index 00000000..2f3b2d16
--- /dev/null
+++ b/tpl/_bookmarklet.twig
@@ -0,0 +1,3 @@
1 <script type="text/javascript">
2 top["bookmarklet-url@inthepoche.com"]=""+"<!DOCTYPE html>"+"<html>"+"<head>"+"<title>poche it !</title>"+'<link rel="icon" href="{{poche_url}}tpl/img/favicon.ico" />'+"</head>"+"<body>"+"<script>"+"window.onload=function(){"+"window.setTimeout(function(){"+"history.back();"+"},250);"+"};"+"</scr"+"ipt>"+"</body>"+"</html>"
3 </script> \ No newline at end of file
diff --git a/tpl/_footer.twig b/tpl/_footer.twig
new file mode 100644
index 00000000..6891756a
--- /dev/null
+++ b/tpl/_footer.twig
@@ -0,0 +1,4 @@
1 <footer class="w600p center mt3 smaller txtright">
2 <p>{% trans "powered by" %} <a href="http://inthepoche.com">poche</a></p>
3 {% if constant('DEBUG_POCHE') == 1 %}<p><strong>{% trans "debug mode is on so cache is off." %} {% trans "your poche version:" %}{{constant('POCHE_VERSION')}}. {% trans "storage:" %} {{constant('STORAGE')}}</strong></p>{% endif %}
4 </footer> \ No newline at end of file
diff --git a/tpl/_head.twig b/tpl/_head.twig
new file mode 100644
index 00000000..f25f0471
--- /dev/null
+++ b/tpl/_head.twig
@@ -0,0 +1,9 @@
1 <link rel="shortcut icon" type="image/x-icon" href="./tpl/img/favicon.ico" />
2 <link rel="apple-touch-icon-precomposed" sizes="144x144" href="./tpl/img/apple-touch-icon-144x144-precomposed.png">
3 <link rel="apple-touch-icon-precomposed" sizes="72x72" href="./tpl/img/apple-touch-icon-72x72-precomposed.png">
4 <link rel="apple-touch-icon-precomposed" href="./tpl/img/apple-touch-icon-precomposed.png">
5 <link rel="stylesheet" href="./tpl/css/knacss.css" media="all">
6 <link rel="stylesheet" href="./tpl/css/style.css" media="all">
7 <link rel="stylesheet" href="./tpl/css/style-{{ constant('THEME') }}.css" media="all" title="{{ constant('THEME') }} theme">
8 <link rel="stylesheet" href="./tpl/css/messages.css" media="all">
9 <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> \ No newline at end of file
diff --git a/tpl/_menu.twig b/tpl/_menu.twig
new file mode 100644
index 00000000..699d6a0c
--- /dev/null
+++ b/tpl/_menu.twig
@@ -0,0 +1,7 @@
1 <ul id="links">
2 <li><a href="./" {% if view == 'home' %}class="current"{% endif %}>{% trans "home" %}</a></li>
3 <li><a href="./?view=fav" {% if view == 'fav' %}class="current"{% endif %}>{% trans "favorites" %}</a></li>
4 <li><a href="./?view=archive" {% if view == 'archive' %}class="current"{% endif %}>{% trans "archive" %}</a></li>
5 <li><a href="./?view=config" {% if view == 'config' %}class="current"{% endif %}>{% trans "config" %}</a></li>
6 <li><a href="./?logout" title="{% trans "logout" %}">{% trans "logout" %}</a></li>
7 </ul> \ No newline at end of file
diff --git a/tpl/_messages.twig b/tpl/_messages.twig
new file mode 100644
index 00000000..679aa098
--- /dev/null
+++ b/tpl/_messages.twig
@@ -0,0 +1 @@
{{ messages | raw }} \ No newline at end of file
diff --git a/tpl/_top.twig b/tpl/_top.twig
new file mode 100644
index 00000000..ae01cc3f
--- /dev/null
+++ b/tpl/_top.twig
@@ -0,0 +1,3 @@
1 <header class="w600p center mbm">
2 <h1><a href="./" title="{% trans "back to home" %}" ><img src="./tpl/img/logo.png" alt="logo poche" /></a></h1>
3 </header> \ No newline at end of file
diff --git a/tpl/config.html b/tpl/config.html
deleted file mode 100644
index 2c7df4f7..00000000
--- a/tpl/config.html
+++ /dev/null
@@ -1,27 +0,0 @@
1 <div id="content">
2 <h2>Bookmarklet</h2>
3 <p>Thanks to the bookmarklet, you will be able to easily add a link to your poche. If you don't know how use a bookmarklet, <a href="http://support.mozilla.org/en-US/kb/bookmarklets-perform-common-web-page-tasks">have a look here</a>.</p>
4 <p>Drag & drop this link to your bookmarks bar and have fun with poche.</p>
5 <p><a ondragend="this.click();" style="cursor: move; border: 1px dashed grey; background: white;" title="i am a bookmarklet, use me !" href="javascript:if(top['bookmarklet-url@inthepoche.com']){top['bookmarklet-url@inthepoche.com'];}else{(function(){var%20url%20=%20location.href%20||%20url;window.open('{$poche_url}?action=add&url='%20+%20btoa(url),'_self');})();void(0);}">poche it !</a></p>
6
7 <h2>Password</h2>
8 <form method="post" action="?config" name="loginform">
9 <fieldset class="w500p">
10 <div class="row">
11 <label class="col w150p" for="password">New password</label>
12 <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2">
13 </div>
14 <div class="row">
15 <label class="col w150p" for="password_repeat">Repeat your new password</label>
16 <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3">
17 </div>
18 <div class="row mts txtcenter">
19 <button class="bouton" type="submit" tabindex="4">Update</button>
20 </div>
21 </fieldset>
22 <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>">
23 <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
24 </form>
25 <h2>Export</h2>
26 <p><a href="?view=export" target="_blank">Click here</a> to export your poche datas.</p>
27 </div> \ No newline at end of file
diff --git a/tpl/config.twig b/tpl/config.twig
new file mode 100644
index 00000000..95d5d8cf
--- /dev/null
+++ b/tpl/config.twig
@@ -0,0 +1,57 @@
1{% extends "layout.twig" %}
2
3{% block title %}{% trans "config" %}{% endblock %}
4{% block menu %}
5 <ul id="links">
6 <li><a href="./" {% if view == 'home' %}class="current"{% endif %}>{% trans "home" %}</a></li>
7 <li><a href="./?view=fav" {% if view == 'fav' %}class="current"{% endif %}>{% trans "favorites" %}</a></li>
8 <li><a href="./?view=archive" {% if view == 'archive' %}class="current"{% endif %}>{% trans "archive" %}</a></li>
9 <li><a href="./?view=config" {% if view == 'config' %}class="current"{% endif %}>{% trans "config" %}</a></li>
10 <li><a href="./?logout" title="{% trans "logout" %}">{% trans "logout" %}</a></li>
11 </ul>
12{% endblock %}
13{% block content %}
14 <h2>{% trans "Bookmarklet" %}</h2>
15 <p>{% trans "Thanks to the bookmarklet, you will be able to easily add a link to your poche." %} {% trans "Have a look to this documentation:" %} <a href="http://inthepoche.com/?pages/Documentation">inthepoche.com</a>.</p>
16 <p>{% trans "Drag & drop this link to your bookmarks bar and have fun with poche." %}</p>
17 <p class="txtcenter"><a ondragend="this.click();" style="cursor: move; border: 1px dashed grey; background: white; padding: 5px;" title="i am a bookmarklet, use me !" href="javascript:if(top['bookmarklet-url@inthepoche.com']){top['bookmarklet-url@inthepoche.com'];}else{(function(){var%20url%20=%20location.href%20||%20url;window.open('{{ poche_url }}?action=add&url='%20+%20btoa(url),'_self');})();void(0);}">{% trans "poche it!" %}</a></p>
18
19 <h2>{% trans "Updating poche" %}</h2>
20 <p><ul>
21 <li>{% trans "your version" %} : <strong>{{ constant('POCHE_VERSION') }}</strong></li>
22 <li>{% trans "latest stable version" %} : {{ prod }}. {% if compare_prod == -1 %}<strong><a href="http://inthepoche.com/?pages/T%C3%A9l%C3%A9charger-poche">{% trans "a more recent stable version is available." %}</a></strong>{% else %}{% trans "you are up to date." %}{% endif %}</li>
23 <li>{% trans "latest dev version" %} : {{ dev }}. {% if compare_dev == -1 %}<strong><a href="http://inthepoche.com/?pages/T%C3%A9l%C3%A9charger-poche">{% trans "a more recent development version is available." %}</a></strong>{% else %}{% trans "you are up to date." %}{% endif %}</li>
24 </ul>
25 </p>
26
27 <h2>{% trans "Change your password" %}</h2>
28 <form method="post" action="?config" name="loginform">
29 <fieldset class="w500p">
30 <div class="row">
31 <label class="col w150p" for="password">{% trans "New password:" %}</label>
32 <input class="col" type="password" id="password" name="password" placeholder="{% trans "Password" %}" tabindex="2">
33 </div>
34 <div class="row">
35 <label class="col w150p" for="password_repeat">{% trans "Repeat your new password:" %}</label>
36 <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="{% trans "Password" %}" tabindex="3">
37 </div>
38 <div class="row mts txtcenter">
39 <button class="bouton" type="submit" tabindex="4">{% trans "Update" %}</button>
40 </div>
41 </fieldset>
42 <input type="hidden" name="returnurl" value="{{ referer }}">
43 <input type="hidden" name="token" value="{{ token }}">
44 </form>
45
46 <h2>{% trans "Import" %}</h2>
47 <p>{% trans "Please execute the import script locally, it can take a very long time." %}</p>
48 <p>{% trans "More infos in the official doc:" %} <a href="http://inthepoche.com/?pages/Documentation">inthepoche.com</a></p>
49 <p><ul>
50 <li><a href="./?import&from=pocket">{% trans "import from Pocket" %}</a> (you must have a "ril_export.html" file on your server)</li>
51 <li><a href="./?import&from=readability">{% trans "import from Readability" %}</a> (you must have a "readability" file on your server)</li>
52 <li><a href="./?import&from=instapaper">{% trans "import from Instapaper" %}</a> (you must have a "instapaper-export.html" file on your server)</li>
53 </ul></p>
54
55 <h2>{% trans "Export your poche datas" %}</h2>
56 <p><a href="./?export" target="_blank">{% trans "Click here" %}</a> {% trans "to export your poche datas." %}</p>
57{% endblock %} \ No newline at end of file
diff --git a/css/knacss.css b/tpl/css/knacss.css
index ca0696b7..ca0696b7 100644
--- a/css/knacss.css
+++ b/tpl/css/knacss.css
diff --git a/tpl/css/messages.css b/tpl/css/messages.css
new file mode 100755
index 00000000..9222bb88
--- /dev/null
+++ b/tpl/css/messages.css
@@ -0,0 +1,13 @@
1.messages { width: 400px; -moz-border-radius: 4px; border-radius: 4px; display: block; padding: 10px 0; margin: 10px auto 10px; clear: both; }
2.messages a.closeMessage { margin: -14px -8px 0 0; display:none; width: 16px; height: 16px; float: right; background: url(../img/messages/close.png) no-repeat; }
3/*.messages:hover a.closeMessage { visibility:visible; }*/
4.messages p { margin: 3px 0 3px 10px !important; padding: 0 10px 0 23px !important; font-size: 14px; line-height: 16px; }
5.messages.error { border: 1px solid #C42608; color: #c00 !important; background: #FFF0EF; }
6.messages.error p { background: url(../img/messages/cross.png ) no-repeat 0px 50%; color:#c00 !important; }
7.messages.success {background: #E0FBCC; border: 1px solid #6DC70C; }
8.messages.success p { background: url(../img/messages/tick.png) no-repeat 0px 50%; color: #2B6301 !important; }
9.messages.warning { background: #FFFCD3; border: 1px solid #EBCD41; color: #000; }
10.messages.warning p { background: url(../img/messages/warning.png ) no-repeat 0px 50%; color: #5F4E01; }
11.messages.information, .messages.info { background: #DFEBFB; border: 1px solid #82AEE7; }
12.messages.information p, .messages.info p { background: url(../img/messages/help.png ) no-repeat 0px 50%; color: #064393; }
13.messages.information a { text-decoration: underline; } \ No newline at end of file
diff --git a/tpl/css/style-light.css b/tpl/css/style-light.css
new file mode 100644
index 00000000..9ea7955a
--- /dev/null
+++ b/tpl/css/style-light.css
@@ -0,0 +1,53 @@
1
2a.back span {
3 background: url('../img/light/left.png') no-repeat;
4}
5
6a.top span {
7 background: url('../img/light/top.png') no-repeat;
8}
9
10
11a.fav span {
12 background: url('../img/light/star-on.png') no-repeat;
13}
14
15a.fav span:hover {
16 background: url('../img/light/star-off.png') no-repeat;
17}
18
19a.fav-off span {
20 background: url('../img/light/star-off.png') no-repeat;
21}
22
23a.fav-off span:hover {
24 background: url('../img/light/star-on.png') no-repeat;
25}
26
27a.archive span {
28 background: url('../img/light/checkmark-on.png') no-repeat;
29}
30
31a.archive span:hover {
32 background: url('../img/light/checkmark-off.png') no-repeat;
33}
34
35a.archive-off span {
36 background: url('../img/light/checkmark-off.png') no-repeat;
37}
38
39a.archive-off span:hover {
40 background: url('../img/light/checkmark-on.png') no-repeat;
41}
42
43a.twitter span {
44 background: url('../img/light/twitter.png') no-repeat;
45}
46
47a.email span {
48 background: url('../img/light/envelop.png') no-repeat;
49}
50
51a.delete span {
52 background: url('../img/light/remove.png') no-repeat;
53} \ No newline at end of file
diff --git a/tpl/css/style.css b/tpl/css/style.css
new file mode 100644
index 00000000..d23c1896
--- /dev/null
+++ b/tpl/css/style.css
@@ -0,0 +1,244 @@
1body {
2 font-size: 16px;
3 font-family: 'Roboto', sans-serif;
4 margin: 10px;
5}
6
7header {
8 text-align: center;
9}
10
11header h1 {
12 font-size: 1.3em;
13}
14
15.bouton {
16 border-radius: 2px;
17}
18
19#main {
20 margin: 0 auto;
21}
22
23#main ul#links {
24 padding: 0;
25 list-style-type: none;
26 text-align: center;
27 font-size: 0.9em;
28}
29
30#main ul#links li {
31 display: inline;
32}
33
34#main ul#links li a.current {
35 -webkit-border-radius: 2px;
36 border-radius: 2px;
37}
38
39#main ul#sort {
40 padding: 0;
41 list-style-type: none;
42 text-align: center;
43 opacity: 0.5;
44}
45
46#main ul#sort li {
47 display: inline;
48 font-size: 0.9em;
49}
50
51#main ul#sort img:hover {
52 cursor: pointer;
53}
54
55
56#links a{
57 text-decoration: none;
58 padding: 5px 10px;
59}
60#links a:hover{
61 -webkit-border-radius: 2px;
62 border-radius: 2px;
63}
64
65/*** ***/
66/*** LINKS DISPLAY ***/
67
68#main a.tool {
69 text-decoration: none;
70 cursor: pointer;
71}
72
73#main #content {
74 margin-top: 20px;
75}
76
77#main #content h2 {
78 font-size: 1.3em;
79 text-decoration: none;
80}
81
82#main #content .entrie {
83 border-bottom: 1px dashed #222222;
84}
85
86#main .entrie ul.tools {
87 list-style-type: none;
88}
89
90#main .entrie ul.tools li {
91 /*display: inline;*/
92}
93
94.tools {
95 float: right;
96 text-align: right;
97 opacity: 0.5;
98}
99
100.tools p {
101 font-size: 0.8em;}
102
103/*
104.tools ul {
105 padding: 0; margin: 0;
106 list-style-type: none;
107}
108
109.tools ul li {
110 line-height: 20px;
111}
112
113.tools a.tool {
114 cursor: pointer;
115}*/
116
117#main .entrie .tools a.tool span, #article .tools a.tool span {
118 display: inline-block;
119 width: 16px;
120 height: 16px;
121}
122
123#main .entrie .url {
124 font-size: 13px;
125}
126
127
128/*** ***/
129/*** ARTICLE PAGE ***/
130
131#article {
132 margin: 0 auto;
133}
134#article header {
135 text-align: left;
136}
137
138#article header a {
139 text-decoration: none;
140}
141
142.vieworiginal a, .vieworiginal a:hover, .vieworiginal a:visited {
143 text-decoration: none;
144 color: #888888;
145}
146
147.backhome {
148 display: inline;
149}
150
151#article .tools {
152 position: relative;
153 display: inline;
154 top: 0px;
155 right: 0px;
156 width: 100%;
157}
158
159#article .tools ul li{
160 display: inline;
161}
162
163
164/*** GENERAL ***/
165body {
166 color: #000;
167}
168
169a, a:hover, a:visited {
170 color: #000;
171}
172
173.bouton {
174 background-color: #000;
175 color: #fff;
176 border: none;
177}
178.bouton:hover {
179 background-color: #222222;
180 color: #F1F1F1;
181}
182
183#main ul#links li a.current {
184 background-color: #000;
185 color: #fff;
186}
187
188#links a:hover{
189 background-color: #040707;
190 color: #F1F1F1;
191}
192
193
194/*** ***/
195/*** ARTICLE PAGE ***/
196
197#article header, #article article {
198 border-bottom: 1px solid #222222;
199}
200
201
202/* Pagination */
203.pagination {
204 clear: both;
205 padding-bottom: 20px;
206 padding-top: 10px;
207 text-align: right;
208}
209.pagination a {
210 border: 1px solid #D5D5D5;
211 color: #333;
212 font-size: 11px;
213 font-weight: bold;
214 height: 25px;
215 padding: 4px 8px;
216 text-decoration: none;
217 margin:2px;
218}
219.pagination a:hover, .pagination a:active {
220 background:#efefef;
221}
222.pagination span.current {
223 background-color: #ccc;
224 border: 1px solid #D5D5D5;
225 color: #000;
226 font-size: 11px;
227 font-weight: bold;
228 height: 25px;
229 padding: 4px 8px;
230 text-decoration: none;
231 margin:2px;
232}
233.pagination span.disabled {
234 border: 1px solid #EEEEEE;
235 color: #DDDDDD;
236 margin:2px;
237 padding: 4px 8px;
238 font-size: 11px;
239 font-weight: bold;
240}
241
242footer {
243 clear: both;
244} \ No newline at end of file
diff --git a/tpl/entries.html b/tpl/entries.html
deleted file mode 100644
index 83e58c74..00000000
--- a/tpl/entries.html
+++ /dev/null
@@ -1,21 +0,0 @@
1 <div id="content">
2 {loop="entries"}
3 <div id="entry-{$value.id}" class="entrie mb2">
4 <span class="content">
5 <h2 class="h6-like">
6 <a href="index.php?&view=view&id={$value.id}">{$value.title}</a>
7 </h2>
8 <div class="tools">
9 <ul>
10 <li>
11 <a title="toggle mark as read" class="tool archive {if="$value.is_read == '0'"}archive-off{/if}" onclick="toggle_archive(this, {$value.id})"><span></span></a></li>
12 <li><a title="toggle favorite" class="tool fav {if="$value.is_fav == '0'"}fav-off{/if}" onclick="toggle_favorite(this, {$value.id})"><span></span></a></li>
13 <li><form method="post" onsubmit="return confirm('Are you sure?')" style="display: inline;"><input type="hidden" name="token" id="token" value="<?php echo Session::getToken(); ?>" /><input type="hidden" id="action" name="action" value="delete" /><input type="hidden" id="view" name="view" value="{$view}" /><input type="hidden" id="id" name="id" value="{$value.id}" /><input type="submit" class="delete" title="toggle delete" /></form>
14 </li>
15 </ul>
16 </div>
17 <div class="url">{$value.url}</div>
18 </span>
19 </div>
20 {/loop}
21 </div> \ No newline at end of file
diff --git a/tpl/export.html b/tpl/export.html
deleted file mode 100644
index d22d05fc..00000000
--- a/tpl/export.html
+++ /dev/null
@@ -1 +0,0 @@
1export {$export} \ No newline at end of file
diff --git a/tpl/export.twig b/tpl/export.twig
new file mode 100644
index 00000000..4adb9540
--- /dev/null
+++ b/tpl/export.twig
@@ -0,0 +1 @@
{{ export }} \ No newline at end of file
diff --git a/tpl/footer.html b/tpl/footer.html
deleted file mode 100644
index b8bd755c..00000000
--- a/tpl/footer.html
+++ /dev/null
@@ -1,7 +0,0 @@
1 </div>
2 <footer class="mr2 mt3 smaller">
3 <p>powered by <a href="http://inthepoche.com">poche</a><br />follow us on <a href="https://twitter.com/getpoche" title="follow us on twitter">twitter</a></p>
4 </footer>
5
6 </body>
7</html> \ No newline at end of file
diff --git a/tpl/head.html b/tpl/head.html
deleted file mode 100644
index dfb12788..00000000
--- a/tpl/head.html
+++ /dev/null
@@ -1,42 +0,0 @@
1<!DOCTYPE html>
2<!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]-->
3<!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]-->
4<!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]-->
5<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
6<html>
7 <head>
8 <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
9 <meta charset="utf-8">
10 <meta http-equiv="X-UA-Compatible" content="IE=10">
11 <title>{$title}</title>
12 <link rel="shortcut icon" type="image/x-icon" href="./img/favicon.ico" />
13 <link rel="apple-touch-icon-precomposed" sizes="144x144" href="./img/apple-touch-icon-144x144-precomposed.png">
14 <link rel="apple-touch-icon-precomposed" sizes="72x72" href="./img/apple-touch-icon-72x72-precomposed.png">
15 <link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png">
16 <link rel="stylesheet" href="./css/knacss.css" media="all">
17 <link rel="stylesheet" href="./css/style.css" media="all">
18 <!-- Light Theme -->
19 <link rel="stylesheet" href="./css/style-light.css" media="all" title="light-style">
20 <!-- Dark Theme -->
21 <link rel="alternate stylesheet" href="./css/style-dark.css" media="all" title="dark-style">
22 <script>
23 top["bookmarklet-url@inthepoche.com"] = ''
24 +'<!DOCTYPE html>'
25 +'<html>'
26 +'<head>'
27 +'<title>poche it !</title>'
28 +'<link rel="icon" href="{$poche_url}img/favicon.ico" />'
29 +'</head>'
30 +'<body>'
31 +'<script>'
32 +'window.onload=function(){'
33 +'window.setTimeout(function(){'
34 +'history.back();'
35 +'},250);'
36 +'};'
37 +'</scr'+'ipt>'
38 +'</body>'
39 +'</html>'
40 ;
41 </script>
42 </head> \ No newline at end of file
diff --git a/tpl/home.html b/tpl/home.html
deleted file mode 100644
index 90e247f7..00000000
--- a/tpl/home.html
+++ /dev/null
@@ -1,19 +0,0 @@
1 <body class="light-style">
2 <header>
3 <h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1>
4 </header>
5 <div id="main">
6 <ul id="links">
7 <li><a href="index.php" {if="$view == 'index'"}class="current"{/if}>home</a></li>
8 <li><a href="?view=fav" {if="$view == 'fav'"}class="current"{/if}>favorites</a></li>
9 <li><a href="?view=archive" {if="$view == 'archive'"}class="current"{/if}>archive</a></li>
10 <li><a href="?view=config" {if="$view == 'config'"}class="current"{/if}>config</a></li>
11 <li><a href="?logout" title="Logout">logout</a></li>
12 </ul>
13 {if condition="isset($entries)"}
14 <ul id="sort">
15 <li><img src="img/up.png" onclick="sort_links('{$view}', 'ia');" title="by date asc" /> by date <img src="img/down.png" onclick="sort_links('{$view}', 'id');" title="by date desc" /></li>
16 <li><img src="img/up.png" onclick="sort_links('{$view}', 'ta');" title="by title asc" /> by title <img src="img/down.png" onclick="sort_links('{$view}', 'td');" title="by title desc" /></li>
17 </ul>
18 {/if}
19 {include="messages"} \ No newline at end of file
diff --git a/tpl/home.twig b/tpl/home.twig
new file mode 100644
index 00000000..a6da641f
--- /dev/null
+++ b/tpl/home.twig
@@ -0,0 +1,29 @@
1{% extends "layout.twig" %}
2{% block title %}{% trans "home" %}{% endblock %}
3{% block menu %}
4{% include '_menu.twig' %}
5{% endblock %}
6{% block precontent %}
7 <ul id="sort">
8 <li><a href="./?sort=ia&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/top.png" alt="{% trans "by date asc" %}" title="{% trans "by date asc" %}" /></a> {% trans "by date" %} <a href="./?sort=id&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/down.png" alt="{% trans "by date desc" %}" title="{% trans "by date desc" %}" /></a></li>
9 <li><a href="./?sort=ta&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/top.png" alt="{% trans "by title asc" %}" title="{% trans "by title asc" %}" /></a> {% trans "by title" %} <a href="./?sort=td&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/down.png" alt="{% trans "by title desc" %}" title="{% trans "by title desc" %}" /></a></li>
10 </ul>
11{% endblock %}
12{% block content %}
13 {{ page_links | raw }}
14 {% for entry in entries %}
15 <div id="entry-{{ entry.id|e }}" class="entrie">
16 <h2><a href="index.php?view=view&id={{ entry.id|e }}">{{ entry.title|e }}</a></h2>
17 <ul class="tools">
18 <li>
19 <a title="{% trans "toggle mark as read" %}" class="tool archive {% if entry.is_read == 0 %}archive-off{% endif %}" href="./?action=toggle_archive&id={{ entry.id|e }}"><span></span></a></li>
20 <li><a title="{% trans "toggle favorite" %}" class="tool fav {% if entry.is_fav == 0 %}fav-off{% endif %}" href="./?action=toggle_fav&id={{ entry.id|e }}"><span></span></a></li>
21 <li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&id={{ entry.id|e }}"><span></span></a></li>
22 </li>
23 </ul>
24 <p>{{ entry.content|striptags|slice(0, 300) }}...</p>
25 <p class="vieworiginal txtright small"><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}">{{ entry.url | e | getDomain }}</a></p>
26 </div>
27 {% endfor %}
28 {{ page_links | raw }}
29{% endblock %} \ No newline at end of file
diff --git a/img/apple-touch-icon-144x144-precomposed.png b/tpl/img/apple-touch-icon-144x144-precomposed.png
index 557b479c..557b479c 100644
--- a/img/apple-touch-icon-144x144-precomposed.png
+++ b/tpl/img/apple-touch-icon-144x144-precomposed.png
Binary files differ
diff --git a/img/apple-touch-icon-72x72-precomposed.png b/tpl/img/apple-touch-icon-72x72-precomposed.png
index e167d3a4..e167d3a4 100644
--- a/img/apple-touch-icon-72x72-precomposed.png
+++ b/tpl/img/apple-touch-icon-72x72-precomposed.png
Binary files differ
diff --git a/img/apple-touch-icon.png b/tpl/img/apple-touch-icon.png
index 4d222fba..4d222fba 100644
--- a/img/apple-touch-icon.png
+++ b/tpl/img/apple-touch-icon.png
Binary files differ
diff --git a/img/favicon.ico b/tpl/img/favicon.ico
index 0e9ff779..0e9ff779 100644
--- a/img/favicon.ico
+++ b/tpl/img/favicon.ico
Binary files differ
diff --git a/img/light/checkmark-off.png b/tpl/img/light/checkmark-off.png
index 3db5a06d..3db5a06d 100644
--- a/img/light/checkmark-off.png
+++ b/tpl/img/light/checkmark-off.png
Binary files differ
diff --git a/img/light/checkmark-on.png b/tpl/img/light/checkmark-on.png
index cd3abb2c..cd3abb2c 100644
--- a/img/light/checkmark-on.png
+++ b/tpl/img/light/checkmark-on.png
Binary files differ
diff --git a/img/down.png b/tpl/img/light/down.png
index b9d536a7..b9d536a7 100644
--- a/img/down.png
+++ b/tpl/img/light/down.png
Binary files differ
diff --git a/tpl/img/light/envelop.png b/tpl/img/light/envelop.png
new file mode 100755
index 00000000..6be1c886
--- /dev/null
+++ b/tpl/img/light/envelop.png
Binary files differ
diff --git a/tpl/img/light/left.png b/tpl/img/light/left.png
new file mode 100755
index 00000000..a0a53631
--- /dev/null
+++ b/tpl/img/light/left.png
Binary files differ
diff --git a/img/light/remove.png b/tpl/img/light/remove.png
index f8ad56a3..f8ad56a3 100644
--- a/img/light/remove.png
+++ b/tpl/img/light/remove.png
Binary files differ
diff --git a/img/light/star-off.png b/tpl/img/light/star-off.png
index 6a0133a7..6a0133a7 100644
--- a/img/light/star-off.png
+++ b/tpl/img/light/star-off.png
Binary files differ
diff --git a/img/light/star-on.png b/tpl/img/light/star-on.png
index a9f96eaa..a9f96eaa 100644
--- a/img/light/star-on.png
+++ b/tpl/img/light/star-on.png
Binary files differ
diff --git a/img/up.png b/tpl/img/light/top.png
index 954a8c0a..954a8c0a 100644..100755
--- a/img/up.png
+++ b/tpl/img/light/top.png
Binary files differ
diff --git a/tpl/img/light/twitter.png b/tpl/img/light/twitter.png
new file mode 100755
index 00000000..cfcfe419
--- /dev/null
+++ b/tpl/img/light/twitter.png
Binary files differ
diff --git a/tpl/img/logo.png b/tpl/img/logo.png
new file mode 100644
index 00000000..549b8466
--- /dev/null
+++ b/tpl/img/logo.png
Binary files differ
diff --git a/img/messages/close.png b/tpl/img/messages/close.png
index 731aa018..731aa018 100644..100755
--- a/img/messages/close.png
+++ b/tpl/img/messages/close.png
Binary files differ
diff --git a/img/messages/cross.png b/tpl/img/messages/cross.png
index 1514d51a..1514d51a 100644..100755
--- a/img/messages/cross.png
+++ b/tpl/img/messages/cross.png
Binary files differ
diff --git a/img/messages/help.png b/tpl/img/messages/help.png
index 5c870176..5c870176 100644..100755
--- a/img/messages/help.png
+++ b/tpl/img/messages/help.png
Binary files differ
diff --git a/img/messages/tick.png b/tpl/img/messages/tick.png
index a9925a06..a9925a06 100644..100755
--- a/img/messages/tick.png
+++ b/tpl/img/messages/tick.png
Binary files differ
diff --git a/img/messages/warning.png b/tpl/img/messages/warning.png
index 628cf2da..628cf2da 100644..100755
--- a/img/messages/warning.png
+++ b/tpl/img/messages/warning.png
Binary files differ
diff --git a/tpl/install.html b/tpl/install.html
deleted file mode 100644
index d11a7810..00000000
--- a/tpl/install.html
+++ /dev/null
@@ -1,30 +0,0 @@
1{include="head"}
2 <body class="light-style">
3 <header>
4 <h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1>
5 </header>
6 <div id="main">
7 <form method="post" action="?install" name="loginform">
8 <fieldset class="w500p center">
9 <h2 class="mbs txtcenter">install your poche</h2>
10 <div class="row">
11 <label class="col w150p" for="login">Login</label>
12 <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus />
13 </div>
14 <div class="row">
15 <label class="col w150p" for="password">Password</label>
16 <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2">
17 </div>
18 <div class="row">
19 <label class="col w150p" for="password_repeat">Repeat your password</label>
20 <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3">
21 </div>
22 <div class="row mts txtcenter">
23 <button class="bouton" type="submit" tabindex="4">Install</button>
24 </div>
25 </fieldset>
26 <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>">
27 <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
28 </form>
29
30{include="footer"}
diff --git a/tpl/install.twig b/tpl/install.twig
new file mode 100644
index 00000000..8bcede0d
--- /dev/null
+++ b/tpl/install.twig
@@ -0,0 +1,28 @@
1{% extends "layout.twig" %}
2{% block title %}{% trans "installation" %}{% endblock %}
3{% block content %}
4 <form method="post" action="?install" name="loginform">
5 <fieldset class="w500p center">
6 <h2 class="mbs txtcenter">{% trans "install your poche" %}</h2>
7 <p>
8 {% trans "poche is still not installed. Please fill the below form to install it. Don't hesitate to <a href='http://inthepoche.com/?pages/Documentation'>read the documentation on poche website</a>." %}
9 </p>
10 <div class="row">
11 <label class="col w150p" for="login">{% trans "Login" %}</label>
12 <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus />
13 </div>
14 <div class="row">
15 <label class="col w150p" for="password">{% trans "Password" %}</label>
16 <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2">
17 </div>
18 <div class="row">
19 <label class="col w150p" for="password_repeat">{% trans "Repeat your password" %}</label>
20 <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3">
21 </div>
22 <div class="row mts txtcenter">
23 <button class="bouton" type="submit" tabindex="4">{% trans "Install" %}</button>
24 </div>
25 </fieldset>
26 <input type="hidden" name="token" value="{{ token }}">
27 </form>
28{% endblock %} \ No newline at end of file
diff --git a/tpl/js.html b/tpl/js.html
deleted file mode 100644
index a02212b0..00000000
--- a/tpl/js.html
+++ /dev/null
@@ -1,22 +0,0 @@
1 <script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
2 <script type="text/javascript" src="js/poche.js"></script>
3
4 {if="$load_all_js == '1'"}
5 <script type="text/javascript" src="js/jquery.masonry.min.js"></script>
6 <script type="text/javascript">
7 $( window ).load( function()
8 {
9 var columns = 3,
10 setColumns = function() { columns = $( window ).width() > 640 ? 3 : $( window ).width() > 320 ? 2 : 1; };
11
12 setColumns();
13 $( window ).resize( setColumns );
14
15 $( '#content' ).masonry(
16 {
17 itemSelector: '.entrie',
18 columnWidth: function( containerWidth ) { return containerWidth / columns; }
19 });
20 });
21 </script>
22 {/if} \ No newline at end of file
diff --git a/tpl/layout.twig b/tpl/layout.twig
new file mode 100644
index 00000000..c4bbe779
--- /dev/null
+++ b/tpl/layout.twig
@@ -0,0 +1,29 @@
1<!DOCTYPE html>
2<!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]-->
3<!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]-->
4<!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]-->
5<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
6<html>
7 <head>
8 <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
9 <meta charset="utf-8">
10 <meta http-equiv="X-UA-Compatible" content="IE=10">
11 <title>{% block title %}{% endblock %} - poche</title>
12 {% include '_head.twig' %}
13 {% include '_bookmarklet.twig' %}
14 </head>
15 <body>
16 {% include '_top.twig' %}
17 <div id="main">
18 {% block menu %}{% endblock %}
19 {% block precontent %}{% endblock %}
20 {% block messages %}
21 {% include '_messages.twig' %}
22 {% endblock %}
23 <div id="content" class="w600p center">
24 {% block content %}{% endblock %}
25 </div>
26 </div>
27 {% include '_footer.twig' %}
28 </body>
29</html> \ No newline at end of file
diff --git a/tpl/login.html b/tpl/login.html
deleted file mode 100644
index 6db742c3..00000000
--- a/tpl/login.html
+++ /dev/null
@@ -1,33 +0,0 @@
1{include="head"}
2 <body class="light-style">
3 <header>
4 <h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1>
5 </header>
6 <div id="main">
7 <form method="post" action="?login" name="loginform">
8 <fieldset class="w500p center">
9 <h2 class="mbs txtcenter">login to your poche</h2>
10 <div class="row">
11 <label class="col w150p" for="login">Login</label>
12 <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus {if="$demo == '1'"}value="poche"{/if} />
13 </div>
14 <div class="row">
15 <label class="col w150p" for="password">Password</label>
16 <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2" {if="$demo == '1'"}value="poche"{/if} />
17 </div>
18 <div class="row">
19 <label class="col w150p">Stay signed in</label>
20 <div class="col">
21 <input type="checkbox" name="longlastingsession" tabindex="3">
22 <small class="inbl">(Do not check on public computers)</small>
23 </div>
24 </div>
25 <div class="row mts txtcenter">
26 <button class="bouton" type="submit" tabindex="4">Sign in</button>
27 </div>
28 </fieldset>
29 <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>">
30 <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
31 </form>
32
33{include="footer"}
diff --git a/tpl/login.twig b/tpl/login.twig
new file mode 100644
index 00000000..0ae130bc
--- /dev/null
+++ b/tpl/login.twig
@@ -0,0 +1,32 @@
1{% extends "layout.twig" %}
2
3{% block title %}{% trans "login to your poche" %}{% endblock %}
4{% block content %}
5 <form method="post" action="?login" name="loginform">
6 <fieldset class="w500p center">
7 <h2 class="mbs txtcenter">{% trans "login to your poche" %}</h2>
8 {% if constant('MODE_DEMO') == 1 %}<p>{% trans "you are in demo mode, some features may be disabled." %}</p>{% endif %}
9 <div class="row">
10 <label class="col w150p" for="login">{% trans "Login" %}</label>
11 <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus {% if constant('MODE_DEMO') == 1 %}value="poche"{% endif %} />
12 </div>
13
14 <div class="row">
15 <label class="col w150p" for="password">{% trans "Password" %}</label>
16 <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2" {% if constant('MODE_DEMO') == 1 %}value="poche"{% endif %} />
17 </div>
18 <div class="row">
19 <label class="col w150p" for="longlastingsession">{% trans "Stay signed in" %}</label>
20 <div class="col">
21 <input type="checkbox" id="longlastingsession" name="longlastingsession" tabindex="3">
22 <small class="inbl">{% trans "(Do not check on public computers)" %}</small>
23 </div>
24 </div>
25 <div class="row mts txtcenter">
26 <button class="bouton" type="submit" tabindex="4">{% trans "Login" %}</button>
27 </div>
28 </fieldset>
29 <input type="hidden" name="returnurl" value="{{ referer }}">
30 <input type="hidden" name="token" value="{{ token }}">
31 </form>
32{% endblock %} \ No newline at end of file
diff --git a/tpl/messages.html b/tpl/messages.html
deleted file mode 100644
index 87af259b..00000000
--- a/tpl/messages.html
+++ /dev/null
@@ -1 +0,0 @@
1<div id="messages"><?php echo $msg->display(); ?></div> \ No newline at end of file
diff --git a/tpl/view.html b/tpl/view.html
deleted file mode 100644
index e68cd1a1..00000000
--- a/tpl/view.html
+++ /dev/null
@@ -1,58 +0,0 @@
1<!DOCTYPE html>
2<!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]-->
3<!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]-->
4<!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]-->
5<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
6<html>
7 <head>
8 <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
9 <meta charset="utf-8">
10 <meta http-equiv="X-UA-Compatible" content="IE=10">
11 <title>{$title}</title>
12 <link rel="shortcut icon" type="image/x-icon" href="./img/favicon.ico" />
13 <link rel="apple-touch-icon-precomposed" sizes="144x144" href="./img/apple-touch-icon-144x144-precomposed.png">
14 <link rel="apple-touch-icon-precomposed" sizes="72x72" href="./img/apple-touch-icon-72x72-precomposed.png">
15 <link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png">
16 <link rel="stylesheet" href="./css/knacss.css" media="all">
17 <link rel="stylesheet" href="./css/style.css" media="all">
18 <!-- Light Theme -->
19 <link rel="stylesheet" href="./css/style-light.css" media="all" title="light-style">
20 <!-- Dark Theme -->
21 <link rel="alternate stylesheet" href="./css/style-dark.css" media="all" title="dark-style">
22 </head>
23 <body class="article light-style">
24 <div id="article" class="w600p">
25 <div class="backhome">
26 <a href="index.php" title="back to home">&larr;</a>
27 </div>
28 <div class="tools">
29 <ul>
30 <li><a title="toggle mark as read" class="tool archive {if="$is_read == '0'"}archive-off{/if}" onclick="toggle_archive(this, {$id})"><span></span></a></li>
31 <li><a href="#" id="themeswitch">dark</a></li>
32 <li><a title="toggle favorite" class="tool fav {if="$is_fav == '0'"}fav-off{/if}" onclick="toggle_favorite(this, {$id})"><span></span></a></li>
33 <li><form method="post" onsubmit="return confirm('Are you sure?')" style="display: inline;" action="index.php"><input type="hidden" name="token" id="token" value="<?php echo Session::getToken(); ?>" /><input type="hidden" id="view" name="view" value="index" /><input type="hidden" id="action" name="action" value="delete" /><input type="hidden" id="id" name="id" value="{$id}" /><input type="submit" class="delete" title="toggle delete" /></form></li>
34 <li><a href="?logout" title="Logout">logout</a></li>
35 </ul>
36 </div>
37 <header class="mbm">
38 <h1><a href="{$url}">{$title}</a></h1>
39 <div class="vieworiginal txtright small"><a href="{$url}" target="_blank" title="original : {$title}">view original</a></div>
40 </header>
41 {include="messages"}
42 <article>
43 <div id="readityourselfcontent">
44 {$content}
45 </div>
46 </article>
47 <div class="vieworiginal txtright small"><a href="{$url}" target="_blank" title="original : {$title}">view original</a></div>
48 <div class="backhome">
49 <a href="index.php" title="back to home">&larr;</a>
50 <a href="#" title="back to top">&uarr;</a>
51 </div>
52 <div class="support">
53 this article appears wrong? <a href="https://github.com/inthepoche/poche/issues/new">create an issue</a> or <a href="mailto:support@inthepoche.com">contact us by mail</a>
54 </div>
55
56
57 {include="js"}
58 {include="footer"} \ No newline at end of file
diff --git a/tpl/view.twig b/tpl/view.twig
new file mode 100644
index 00000000..e999afa1
--- /dev/null
+++ b/tpl/view.twig
@@ -0,0 +1,40 @@
1{% extends "layout.twig" %}
2{% block title %}{% trans "home" %}{% endblock %}
3{% block content %}
4 <div id="article">
5 <div class="tools">
6 <ul class="tools">
7 <li>
8 <li><a href="{{ referer }}" title="{% trans "back to home" %}" class="tool back"><span></span></a></li>
9 <a title="{% trans "toggle mark as read" %}" class="tool archive {% if entry.is_read == 0 %}archive-off{% endif %}" href="./?action=toggle_archive&id={{ entry.id|e }}"><span></span></a></li>
10 <li><a title="{% trans "toggle favorite" %}" class="tool fav {% if entry.is_fav == 0 %}fav-off{% endif %}" href="./?action=toggle_fav&id={{ entry.id|e }}"><span></span></a></li>
11 <li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&id={{ entry.id|e }}"><span></span></a></li>
12 {% if constant('SHARE_TWITTER') == 1 %}<li><a href="https://twitter.com/home?status={{entry.title}}%20{{ entry.url|e }}%20via%20@getpoche" target="_blank" class="tool twitter" title="{% trans "tweet" %}"><span></span></a></li>{% endif %}
13 {% if constant('SHARE_MAIL') == 1 %}<li><a href="mailto:?subject={{ entry.title|e }}&body={{ entry.url|e }} via @getpoche" class="tool email" title="{% trans "email" %}"><span></span></a></li>{% endif %}
14 </li>
15 </ul>
16 </div>
17 <header class="mbm">
18 <h1>{{ entry.title|e }}</h1>
19 <div class="vieworiginal txtright small"><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}">{{ entry.url | e | getDomain }}</a></div>
20 </header>
21 <article>
22 {{ content | raw }}
23 <div class="vieworiginal txtright small"><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}">{{ entry.url | e | getDomain }}</a></div>
24 </article>
25 <div class="tools">
26 <ul class="tools">
27 <li>
28 <li><a href="{{ referer }}" title="{% trans "back to home" %}" class="tool back"><span></span></a></li>
29 <li><a href="#" title="{% trans "back to top" %}" class="tool top"><span></span></a></li>
30 <a title="{% trans "toggle mark as read" %}" class="tool archive {% if entry.is_read == 0 %}archive-off{% endif %}" href="./?action=toggle_archive&id={{ entry.id|e }}"><span></span></a></li>
31 <li><a title="{% trans "toggle favorite" %}" class="tool fav {% if entry.is_fav == 0 %}fav-off{% endif %}" href="./?action=toggle_fav&id={{ entry.id|e }}"><span></span></a></li>
32 <li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&id={{ entry.id|e }}"><span></span></a></li>
33 {% if constant('SHARE_TWITTER') == 1 %}<li><a href="https://twitter.com/home?status={{entry.title}}%20{{ entry.url|e }}%20via%20@getpoche" target="_blank" class="tool twitter" title="{% trans "tweet" %}"><span></span></a></li>{% endif %}
34 {% if constant('SHARE_MAIL') == 1 %}<li><a href="mailto:?subject={{ entry.title|e }}&body={{ entry.url|e }} via @getpoche" class="tool email" title="{% trans "email" %}"><span></span></a></li>{% endif %}
35 </li>
36 </ul>
37 <p>{% trans "this article appears wrong?" %} <a href="https://github.com/inthepoche/poche/issues/new">{% trans "create an issue" %}</a> {% trans "or" %} <a href="mailto:support@inthepoche.com?subject=Wrong display in poche&body={{ entry.url|e }}">{% trans "contact us by mail" %}</a></p>
38 </div>
39 </div>
40{% endblock %} \ No newline at end of file