From d3e7b5708deffbed864c916de22663f48333c58b Mon Sep 17 00:00:00 2001 From: yo mama Date: Tue, 22 Sep 2015 00:51:40 -0700 Subject: finishing server --- share/frontend/impattern/app.pl | 34 + share/frontend/impattern/css/main.css | 101 + share/frontend/impattern/css/normalize.css | 427 +++ share/frontend/impattern/css/overlay.css | 43 + share/frontend/impattern/css/result.css | 3 + share/frontend/impattern/css/sketch.css | 45 + .../impattern/css/unsemantic-grid-responsive.css | 1403 ++++++++ share/frontend/impattern/img/brush.png | Bin 0 -> 734 bytes share/frontend/impattern/img/eraser.png | Bin 0 -> 616 bytes share/frontend/impattern/img/impattern.png | Bin 0 -> 3577 bytes share/frontend/impattern/img/loading.gif | Bin 0 -> 135282 bytes share/frontend/impattern/img/logo.gif | Bin 0 -> 117877 bytes share/frontend/impattern/impattern.html | 254 ++ share/frontend/impattern/index.html | 340 ++ share/frontend/impattern/js/display_result.js | 1 + share/frontend/impattern/js/inputs.js | 26 + share/frontend/impattern/js/jquery.min.js | 18 + share/frontend/impattern/js/overlay.js | 19 + share/frontend/impattern/js/preview.js | 47 + share/frontend/impattern/js/sketch.js | 219 ++ share/frontend/impattern/js/urls.js | 3 + share/frontend/impattern/js/username.js | 30 + share/frontend/impattern/makePattern.py | 111 + share/frontend/impattern/myjson.json | 1 + share/frontend/impattern/newimagefromjson.py | 26 + share/frontend/impattern/old/bottle.py | 3605 ++++++++++++++++++++ share/frontend/impattern/old/index.html.old | 305 ++ share/frontend/impattern/old/oldpatterns/1.png | Bin 0 -> 90 bytes share/frontend/impattern/old/oldpatterns/10.png | Bin 0 -> 2484 bytes share/frontend/impattern/old/oldpatterns/11.png | Bin 0 -> 2484 bytes share/frontend/impattern/old/oldpatterns/12.png | Bin 0 -> 2483 bytes share/frontend/impattern/old/oldpatterns/13.png | Bin 0 -> 2467 bytes share/frontend/impattern/old/oldpatterns/14.png | Bin 0 -> 2478 bytes share/frontend/impattern/old/oldpatterns/15.png | Bin 0 -> 2487 bytes share/frontend/impattern/old/oldpatterns/16.png | Bin 0 -> 2480 bytes share/frontend/impattern/old/oldpatterns/17.png | Bin 0 -> 2461 bytes share/frontend/impattern/old/oldpatterns/18.png | Bin 0 -> 2475 bytes share/frontend/impattern/old/oldpatterns/19.png | Bin 0 -> 2471 bytes share/frontend/impattern/old/oldpatterns/2.png | Bin 0 -> 2470 bytes share/frontend/impattern/old/oldpatterns/20.png | Bin 0 -> 2472 bytes share/frontend/impattern/old/oldpatterns/21.png | Bin 0 -> 2472 bytes share/frontend/impattern/old/oldpatterns/22.png | Bin 0 -> 2477 bytes share/frontend/impattern/old/oldpatterns/23.png | Bin 0 -> 2472 bytes share/frontend/impattern/old/oldpatterns/24.png | Bin 0 -> 2467 bytes share/frontend/impattern/old/oldpatterns/25.png | Bin 0 -> 2473 bytes share/frontend/impattern/old/oldpatterns/26.png | Bin 0 -> 2480 bytes share/frontend/impattern/old/oldpatterns/27.png | Bin 0 -> 2482 bytes share/frontend/impattern/old/oldpatterns/28.png | Bin 0 -> 2482 bytes share/frontend/impattern/old/oldpatterns/29.png | Bin 0 -> 2487 bytes share/frontend/impattern/old/oldpatterns/3.png | Bin 0 -> 2469 bytes share/frontend/impattern/old/oldpatterns/30.png | Bin 0 -> 2487 bytes share/frontend/impattern/old/oldpatterns/31.png | Bin 0 -> 2478 bytes share/frontend/impattern/old/oldpatterns/32.png | Bin 0 -> 2465 bytes share/frontend/impattern/old/oldpatterns/33.png | Bin 0 -> 2484 bytes share/frontend/impattern/old/oldpatterns/34.png | Bin 0 -> 2484 bytes share/frontend/impattern/old/oldpatterns/35.png | Bin 0 -> 2476 bytes share/frontend/impattern/old/oldpatterns/36.png | Bin 0 -> 2490 bytes share/frontend/impattern/old/oldpatterns/37.png | Bin 0 -> 2495 bytes share/frontend/impattern/old/oldpatterns/38.png | Bin 0 -> 2492 bytes share/frontend/impattern/old/oldpatterns/39.png | Bin 0 -> 2482 bytes share/frontend/impattern/old/oldpatterns/4.png | Bin 0 -> 2465 bytes share/frontend/impattern/old/oldpatterns/40.png | Bin 0 -> 2485 bytes share/frontend/impattern/old/oldpatterns/41.png | Bin 0 -> 2496 bytes share/frontend/impattern/old/oldpatterns/42.png | Bin 0 -> 2494 bytes share/frontend/impattern/old/oldpatterns/43.png | Bin 0 -> 2490 bytes share/frontend/impattern/old/oldpatterns/44.png | Bin 0 -> 2491 bytes share/frontend/impattern/old/oldpatterns/45.png | Bin 0 -> 2484 bytes share/frontend/impattern/old/oldpatterns/46.png | Bin 0 -> 2490 bytes share/frontend/impattern/old/oldpatterns/47.png | Bin 0 -> 2486 bytes share/frontend/impattern/old/oldpatterns/48.png | Bin 0 -> 2490 bytes share/frontend/impattern/old/oldpatterns/49.png | Bin 0 -> 2483 bytes share/frontend/impattern/old/oldpatterns/5.png | Bin 0 -> 2476 bytes share/frontend/impattern/old/oldpatterns/50.png | Bin 0 -> 2486 bytes share/frontend/impattern/old/oldpatterns/51.png | Bin 0 -> 2485 bytes share/frontend/impattern/old/oldpatterns/52.png | Bin 0 -> 2490 bytes share/frontend/impattern/old/oldpatterns/53.png | Bin 0 -> 2494 bytes share/frontend/impattern/old/oldpatterns/54.png | Bin 0 -> 2491 bytes share/frontend/impattern/old/oldpatterns/55.png | Bin 0 -> 2474 bytes share/frontend/impattern/old/oldpatterns/56.png | Bin 0 -> 2492 bytes share/frontend/impattern/old/oldpatterns/57.png | Bin 0 -> 2492 bytes share/frontend/impattern/old/oldpatterns/58.png | Bin 0 -> 2487 bytes share/frontend/impattern/old/oldpatterns/59.png | Bin 0 -> 2493 bytes share/frontend/impattern/old/oldpatterns/6.png | Bin 0 -> 2480 bytes share/frontend/impattern/old/oldpatterns/60.png | Bin 0 -> 2488 bytes share/frontend/impattern/old/oldpatterns/61.png | Bin 0 -> 2492 bytes share/frontend/impattern/old/oldpatterns/62.png | Bin 0 -> 2487 bytes share/frontend/impattern/old/oldpatterns/63.png | Bin 0 -> 2494 bytes share/frontend/impattern/old/oldpatterns/64.png | Bin 0 -> 2487 bytes share/frontend/impattern/old/oldpatterns/65.png | Bin 0 -> 2467 bytes share/frontend/impattern/old/oldpatterns/66.png | Bin 0 -> 2471 bytes share/frontend/impattern/old/oldpatterns/67.png | Bin 0 -> 2470 bytes share/frontend/impattern/old/oldpatterns/68.png | Bin 0 -> 2471 bytes share/frontend/impattern/old/oldpatterns/69.png | Bin 0 -> 2470 bytes share/frontend/impattern/old/oldpatterns/7.png | Bin 0 -> 2474 bytes share/frontend/impattern/old/oldpatterns/70.png | Bin 0 -> 2473 bytes share/frontend/impattern/old/oldpatterns/71.png | Bin 0 -> 2477 bytes share/frontend/impattern/old/oldpatterns/72.png | Bin 0 -> 2476 bytes share/frontend/impattern/old/oldpatterns/73.png | Bin 0 -> 2484 bytes share/frontend/impattern/old/oldpatterns/74.png | Bin 0 -> 2486 bytes share/frontend/impattern/old/oldpatterns/75.png | Bin 0 -> 2490 bytes share/frontend/impattern/old/oldpatterns/76.png | Bin 0 -> 2484 bytes share/frontend/impattern/old/oldpatterns/77.png | Bin 0 -> 2492 bytes share/frontend/impattern/old/oldpatterns/78.png | Bin 0 -> 2491 bytes share/frontend/impattern/old/oldpatterns/79.png | Bin 0 -> 2496 bytes share/frontend/impattern/old/oldpatterns/8.png | Bin 0 -> 2476 bytes share/frontend/impattern/old/oldpatterns/80.png | Bin 0 -> 2493 bytes share/frontend/impattern/old/oldpatterns/81.png | Bin 0 -> 2462 bytes share/frontend/impattern/old/oldpatterns/82.png | Bin 0 -> 2472 bytes share/frontend/impattern/old/oldpatterns/83.png | Bin 0 -> 2462 bytes share/frontend/impattern/old/oldpatterns/84.png | Bin 0 -> 2467 bytes share/frontend/impattern/old/oldpatterns/85.png | Bin 0 -> 2462 bytes share/frontend/impattern/old/oldpatterns/86.png | Bin 0 -> 2468 bytes share/frontend/impattern/old/oldpatterns/87.png | Bin 0 -> 2472 bytes share/frontend/impattern/old/oldpatterns/88.png | Bin 0 -> 2475 bytes share/frontend/impattern/old/oldpatterns/89.png | Bin 0 -> 2467 bytes share/frontend/impattern/old/oldpatterns/9.png | Bin 0 -> 2477 bytes share/frontend/impattern/old/oldpatterns/90.png | Bin 0 -> 2471 bytes share/frontend/impattern/old/oldpatterns/91.png | Bin 0 -> 2467 bytes share/frontend/impattern/old/oldpatterns/92.png | Bin 0 -> 2470 bytes share/frontend/impattern/old/oldpatterns/93.png | Bin 0 -> 2483 bytes share/frontend/impattern/old/oldpatterns/94.png | Bin 0 -> 2485 bytes share/frontend/impattern/old/oldpatterns/95.png | Bin 0 -> 2485 bytes share/frontend/impattern/old/oldpatterns/96.png | Bin 0 -> 2477 bytes share/frontend/impattern/old/oldpatterns/a0.png | Bin 0 -> 138 bytes share/frontend/impattern/old/oldpatterns/a1.png | Bin 0 -> 122 bytes share/frontend/impattern/old/oldpatterns/a10.png | Bin 0 -> 129 bytes share/frontend/impattern/old/oldpatterns/a11.png | Bin 0 -> 138 bytes share/frontend/impattern/old/oldpatterns/a12.png | Bin 0 -> 125 bytes share/frontend/impattern/old/oldpatterns/a13.png | Bin 0 -> 132 bytes share/frontend/impattern/old/oldpatterns/a14.png | Bin 0 -> 91 bytes share/frontend/impattern/old/oldpatterns/a15.png | Bin 0 -> 143 bytes share/frontend/impattern/old/oldpatterns/a16.png | Bin 0 -> 87 bytes share/frontend/impattern/old/oldpatterns/a17.png | Bin 0 -> 93 bytes share/frontend/impattern/old/oldpatterns/a18.png | Bin 0 -> 163 bytes share/frontend/impattern/old/oldpatterns/a19.png | Bin 0 -> 119 bytes share/frontend/impattern/old/oldpatterns/a2.png | Bin 0 -> 123 bytes share/frontend/impattern/old/oldpatterns/a20.png | Bin 0 -> 83 bytes share/frontend/impattern/old/oldpatterns/a21.png | Bin 0 -> 111 bytes share/frontend/impattern/old/oldpatterns/a22.png | Bin 0 -> 137 bytes share/frontend/impattern/old/oldpatterns/a23.png | Bin 0 -> 116 bytes share/frontend/impattern/old/oldpatterns/a24.png | Bin 0 -> 96 bytes share/frontend/impattern/old/oldpatterns/a25.png | Bin 0 -> 108 bytes share/frontend/impattern/old/oldpatterns/a26.png | Bin 0 -> 138 bytes share/frontend/impattern/old/oldpatterns/a27.png | Bin 0 -> 108 bytes share/frontend/impattern/old/oldpatterns/a28.png | Bin 0 -> 115 bytes share/frontend/impattern/old/oldpatterns/a29.png | Bin 0 -> 93 bytes share/frontend/impattern/old/oldpatterns/a3.png | Bin 0 -> 124 bytes share/frontend/impattern/old/oldpatterns/a30.png | Bin 0 -> 88 bytes share/frontend/impattern/old/oldpatterns/a31.png | Bin 0 -> 114 bytes share/frontend/impattern/old/oldpatterns/a32.png | Bin 0 -> 139 bytes share/frontend/impattern/old/oldpatterns/a33.png | Bin 0 -> 127 bytes share/frontend/impattern/old/oldpatterns/a34.png | Bin 0 -> 92 bytes share/frontend/impattern/old/oldpatterns/a35.png | Bin 0 -> 91 bytes share/frontend/impattern/old/oldpatterns/a36.png | Bin 0 -> 87 bytes share/frontend/impattern/old/oldpatterns/a37.png | Bin 0 -> 89 bytes share/frontend/impattern/old/oldpatterns/a38.png | Bin 0 -> 83 bytes share/frontend/impattern/old/oldpatterns/a39.png | Bin 0 -> 132 bytes share/frontend/impattern/old/oldpatterns/a4.png | Bin 0 -> 92 bytes share/frontend/impattern/old/oldpatterns/a40.png | Bin 0 -> 138 bytes share/frontend/impattern/old/oldpatterns/a41.png | Bin 0 -> 113 bytes share/frontend/impattern/old/oldpatterns/a5.png | Bin 0 -> 120 bytes share/frontend/impattern/old/oldpatterns/a6.png | Bin 0 -> 105 bytes share/frontend/impattern/old/oldpatterns/a7.png | Bin 0 -> 106 bytes share/frontend/impattern/old/oldpatterns/a8.png | Bin 0 -> 110 bytes share/frontend/impattern/old/oldpatterns/a9.png | Bin 0 -> 110 bytes share/frontend/impattern/other_script.py | 90 + share/frontend/impattern/patterns/1.png | Bin 0 -> 250 bytes share/frontend/impattern/patterns/10.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/11.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/12.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/13.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/14.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/15.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/16.png | Bin 0 -> 245 bytes share/frontend/impattern/patterns/17.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/18.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/19.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/2.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/20.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/21.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/22.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/23.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/24.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/25.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/26.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/27.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/28.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/29.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/3.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/30.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/31.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/32.png | Bin 0 -> 241 bytes share/frontend/impattern/patterns/33.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/34.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/35.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/36.png | Bin 0 -> 251 bytes share/frontend/impattern/patterns/37.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/38.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/39.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/4.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/40.png | Bin 0 -> 254 bytes share/frontend/impattern/patterns/41.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/42.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/43.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/44.png | Bin 0 -> 251 bytes share/frontend/impattern/patterns/45.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/46.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/47.png | Bin 0 -> 251 bytes share/frontend/impattern/patterns/48.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/49.png | Bin 0 -> 245 bytes share/frontend/impattern/patterns/5.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/50.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/51.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/52.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/53.png | Bin 0 -> 254 bytes share/frontend/impattern/patterns/54.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/55.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/56.png | Bin 0 -> 250 bytes share/frontend/impattern/patterns/57.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/58.png | Bin 0 -> 250 bytes share/frontend/impattern/patterns/59.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/6.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/60.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/61.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/62.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/63.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/64.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/65.png | Bin 0 -> 241 bytes share/frontend/impattern/patterns/66.png | Bin 0 -> 241 bytes share/frontend/impattern/patterns/67.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/68.png | Bin 0 -> 241 bytes share/frontend/impattern/patterns/69.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/7.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/70.png | Bin 0 -> 241 bytes share/frontend/impattern/patterns/71.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/72.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/73.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/74.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/75.png | Bin 0 -> 254 bytes share/frontend/impattern/patterns/76.png | Bin 0 -> 254 bytes share/frontend/impattern/patterns/77.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/78.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/79.png | Bin 0 -> 251 bytes share/frontend/impattern/patterns/8.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/80.png | Bin 0 -> 252 bytes share/frontend/impattern/patterns/81.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/82.png | Bin 0 -> 241 bytes share/frontend/impattern/patterns/83.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/84.png | Bin 0 -> 241 bytes share/frontend/impattern/patterns/85.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/86.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/87.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/88.png | Bin 0 -> 244 bytes share/frontend/impattern/patterns/89.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/9.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/90.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/91.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/92.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/93.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/94.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/95.png | Bin 0 -> 250 bytes share/frontend/impattern/patterns/96.png | Bin 0 -> 251 bytes share/frontend/impattern/patterns/a0.png | Bin 0 -> 266 bytes share/frontend/impattern/patterns/a1.png | Bin 0 -> 266 bytes share/frontend/impattern/patterns/a10.png | Bin 0 -> 264 bytes share/frontend/impattern/patterns/a11.png | Bin 0 -> 268 bytes share/frontend/impattern/patterns/a12.png | Bin 0 -> 265 bytes share/frontend/impattern/patterns/a13.png | Bin 0 -> 267 bytes share/frontend/impattern/patterns/a14.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/a15.png | Bin 0 -> 267 bytes share/frontend/impattern/patterns/a16.png | Bin 0 -> 245 bytes share/frontend/impattern/patterns/a17.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/a18.png | Bin 0 -> 275 bytes share/frontend/impattern/patterns/a19.png | Bin 0 -> 261 bytes share/frontend/impattern/patterns/a2.png | Bin 0 -> 264 bytes share/frontend/impattern/patterns/a20.png | Bin 0 -> 245 bytes share/frontend/impattern/patterns/a21.png | Bin 0 -> 260 bytes share/frontend/impattern/patterns/a22.png | Bin 0 -> 272 bytes share/frontend/impattern/patterns/a23.png | Bin 0 -> 256 bytes share/frontend/impattern/patterns/a24.png | Bin 0 -> 249 bytes share/frontend/impattern/patterns/a25.png | Bin 0 -> 254 bytes share/frontend/impattern/patterns/a26.png | Bin 0 -> 266 bytes share/frontend/impattern/patterns/a27.png | Bin 0 -> 253 bytes share/frontend/impattern/patterns/a28.png | Bin 0 -> 256 bytes share/frontend/impattern/patterns/a29.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/a3.png | Bin 0 -> 263 bytes share/frontend/impattern/patterns/a30.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/a31.png | Bin 0 -> 265 bytes share/frontend/impattern/patterns/a32.png | Bin 0 -> 265 bytes share/frontend/impattern/patterns/a33.png | Bin 0 -> 264 bytes share/frontend/impattern/patterns/a34.png | Bin 0 -> 245 bytes share/frontend/impattern/patterns/a35.png | Bin 0 -> 248 bytes share/frontend/impattern/patterns/a36.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/a37.png | Bin 0 -> 246 bytes share/frontend/impattern/patterns/a38.png | Bin 0 -> 243 bytes share/frontend/impattern/patterns/a39.png | Bin 0 -> 268 bytes share/frontend/impattern/patterns/a4.png | Bin 0 -> 247 bytes share/frontend/impattern/patterns/a40.png | Bin 0 -> 267 bytes share/frontend/impattern/patterns/a41.png | Bin 0 -> 258 bytes share/frontend/impattern/patterns/a5.png | Bin 0 -> 262 bytes share/frontend/impattern/patterns/a6.png | Bin 0 -> 257 bytes share/frontend/impattern/patterns/a7.png | Bin 0 -> 258 bytes share/frontend/impattern/patterns/a8.png | Bin 0 -> 256 bytes share/frontend/impattern/patterns/a9.png | Bin 0 -> 255 bytes share/frontend/impattern/semi_patterns/1.png | Bin 0 -> 90 bytes share/frontend/impattern/semi_patterns/10.png | Bin 0 -> 2484 bytes share/frontend/impattern/semi_patterns/11.png | Bin 0 -> 2484 bytes share/frontend/impattern/semi_patterns/12.png | Bin 0 -> 2483 bytes share/frontend/impattern/semi_patterns/13.png | Bin 0 -> 2467 bytes share/frontend/impattern/semi_patterns/14.png | Bin 0 -> 2478 bytes share/frontend/impattern/semi_patterns/15.png | Bin 0 -> 2487 bytes share/frontend/impattern/semi_patterns/16.png | Bin 0 -> 2480 bytes share/frontend/impattern/semi_patterns/17.png | Bin 0 -> 2461 bytes share/frontend/impattern/semi_patterns/18.png | Bin 0 -> 2475 bytes share/frontend/impattern/semi_patterns/19.png | Bin 0 -> 2471 bytes share/frontend/impattern/semi_patterns/2.png | Bin 0 -> 2470 bytes share/frontend/impattern/semi_patterns/20.png | Bin 0 -> 2472 bytes share/frontend/impattern/semi_patterns/21.png | Bin 0 -> 2472 bytes share/frontend/impattern/semi_patterns/22.png | Bin 0 -> 2477 bytes share/frontend/impattern/semi_patterns/23.png | Bin 0 -> 2472 bytes share/frontend/impattern/semi_patterns/24.png | Bin 0 -> 2467 bytes share/frontend/impattern/semi_patterns/25.png | Bin 0 -> 2473 bytes share/frontend/impattern/semi_patterns/26.png | Bin 0 -> 2480 bytes share/frontend/impattern/semi_patterns/27.png | Bin 0 -> 2482 bytes share/frontend/impattern/semi_patterns/28.png | Bin 0 -> 2482 bytes share/frontend/impattern/semi_patterns/29.png | Bin 0 -> 2487 bytes share/frontend/impattern/semi_patterns/3.png | Bin 0 -> 2469 bytes share/frontend/impattern/semi_patterns/30.png | Bin 0 -> 2487 bytes share/frontend/impattern/semi_patterns/31.png | Bin 0 -> 2478 bytes share/frontend/impattern/semi_patterns/32.png | Bin 0 -> 2465 bytes share/frontend/impattern/semi_patterns/33.png | Bin 0 -> 2484 bytes share/frontend/impattern/semi_patterns/34.png | Bin 0 -> 2484 bytes share/frontend/impattern/semi_patterns/35.png | Bin 0 -> 2476 bytes share/frontend/impattern/semi_patterns/36.png | Bin 0 -> 2490 bytes share/frontend/impattern/semi_patterns/37.png | Bin 0 -> 2495 bytes share/frontend/impattern/semi_patterns/38.png | Bin 0 -> 2492 bytes share/frontend/impattern/semi_patterns/39.png | Bin 0 -> 2482 bytes share/frontend/impattern/semi_patterns/4.png | Bin 0 -> 2465 bytes share/frontend/impattern/semi_patterns/40.png | Bin 0 -> 2485 bytes share/frontend/impattern/semi_patterns/41.png | Bin 0 -> 2496 bytes share/frontend/impattern/semi_patterns/42.png | Bin 0 -> 2494 bytes share/frontend/impattern/semi_patterns/43.png | Bin 0 -> 2490 bytes share/frontend/impattern/semi_patterns/44.png | Bin 0 -> 2491 bytes share/frontend/impattern/semi_patterns/45.png | Bin 0 -> 2484 bytes share/frontend/impattern/semi_patterns/46.png | Bin 0 -> 2490 bytes share/frontend/impattern/semi_patterns/47.png | Bin 0 -> 2486 bytes share/frontend/impattern/semi_patterns/48.png | Bin 0 -> 2490 bytes share/frontend/impattern/semi_patterns/49.png | Bin 0 -> 2483 bytes share/frontend/impattern/semi_patterns/5.png | Bin 0 -> 2476 bytes share/frontend/impattern/semi_patterns/50.png | Bin 0 -> 2486 bytes share/frontend/impattern/semi_patterns/51.png | Bin 0 -> 2485 bytes share/frontend/impattern/semi_patterns/52.png | Bin 0 -> 2490 bytes share/frontend/impattern/semi_patterns/53.png | Bin 0 -> 2494 bytes share/frontend/impattern/semi_patterns/54.png | Bin 0 -> 2491 bytes share/frontend/impattern/semi_patterns/55.png | Bin 0 -> 2474 bytes share/frontend/impattern/semi_patterns/56.png | Bin 0 -> 2492 bytes share/frontend/impattern/semi_patterns/57.png | Bin 0 -> 2492 bytes share/frontend/impattern/semi_patterns/58.png | Bin 0 -> 2487 bytes share/frontend/impattern/semi_patterns/59.png | Bin 0 -> 2493 bytes share/frontend/impattern/semi_patterns/6.png | Bin 0 -> 2480 bytes share/frontend/impattern/semi_patterns/60.png | Bin 0 -> 2488 bytes share/frontend/impattern/semi_patterns/61.png | Bin 0 -> 2492 bytes share/frontend/impattern/semi_patterns/62.png | Bin 0 -> 2487 bytes share/frontend/impattern/semi_patterns/63.png | Bin 0 -> 2494 bytes share/frontend/impattern/semi_patterns/64.png | Bin 0 -> 2487 bytes share/frontend/impattern/semi_patterns/65.png | Bin 0 -> 2467 bytes share/frontend/impattern/semi_patterns/66.png | Bin 0 -> 2471 bytes share/frontend/impattern/semi_patterns/67.png | Bin 0 -> 2470 bytes share/frontend/impattern/semi_patterns/68.png | Bin 0 -> 2471 bytes share/frontend/impattern/semi_patterns/69.png | Bin 0 -> 2470 bytes share/frontend/impattern/semi_patterns/7.png | Bin 0 -> 2474 bytes share/frontend/impattern/semi_patterns/70.png | Bin 0 -> 2473 bytes share/frontend/impattern/semi_patterns/71.png | Bin 0 -> 2477 bytes share/frontend/impattern/semi_patterns/72.png | Bin 0 -> 2476 bytes share/frontend/impattern/semi_patterns/73.png | Bin 0 -> 2484 bytes share/frontend/impattern/semi_patterns/74.png | Bin 0 -> 2486 bytes share/frontend/impattern/semi_patterns/75.png | Bin 0 -> 2490 bytes share/frontend/impattern/semi_patterns/76.png | Bin 0 -> 2484 bytes share/frontend/impattern/semi_patterns/77.png | Bin 0 -> 2492 bytes share/frontend/impattern/semi_patterns/78.png | Bin 0 -> 2491 bytes share/frontend/impattern/semi_patterns/79.png | Bin 0 -> 2496 bytes share/frontend/impattern/semi_patterns/8.png | Bin 0 -> 2476 bytes share/frontend/impattern/semi_patterns/80.png | Bin 0 -> 2493 bytes share/frontend/impattern/semi_patterns/81.png | Bin 0 -> 2462 bytes share/frontend/impattern/semi_patterns/82.png | Bin 0 -> 2472 bytes share/frontend/impattern/semi_patterns/83.png | Bin 0 -> 2462 bytes share/frontend/impattern/semi_patterns/84.png | Bin 0 -> 2467 bytes share/frontend/impattern/semi_patterns/85.png | Bin 0 -> 2462 bytes share/frontend/impattern/semi_patterns/86.png | Bin 0 -> 2468 bytes share/frontend/impattern/semi_patterns/87.png | Bin 0 -> 2472 bytes share/frontend/impattern/semi_patterns/88.png | Bin 0 -> 2475 bytes share/frontend/impattern/semi_patterns/89.png | Bin 0 -> 2467 bytes share/frontend/impattern/semi_patterns/9.png | Bin 0 -> 2477 bytes share/frontend/impattern/semi_patterns/90.png | Bin 0 -> 2471 bytes share/frontend/impattern/semi_patterns/91.png | Bin 0 -> 2467 bytes share/frontend/impattern/semi_patterns/92.png | Bin 0 -> 2470 bytes share/frontend/impattern/semi_patterns/93.png | Bin 0 -> 2483 bytes share/frontend/impattern/semi_patterns/94.png | Bin 0 -> 2485 bytes share/frontend/impattern/semi_patterns/95.png | Bin 0 -> 2485 bytes share/frontend/impattern/semi_patterns/96.png | Bin 0 -> 2477 bytes share/frontend/impattern/semi_patterns/a0.png | Bin 0 -> 138 bytes share/frontend/impattern/semi_patterns/a1.png | Bin 0 -> 122 bytes share/frontend/impattern/semi_patterns/a10.png | Bin 0 -> 129 bytes share/frontend/impattern/semi_patterns/a11.png | Bin 0 -> 138 bytes share/frontend/impattern/semi_patterns/a12.png | Bin 0 -> 125 bytes share/frontend/impattern/semi_patterns/a13.png | Bin 0 -> 132 bytes share/frontend/impattern/semi_patterns/a14.png | Bin 0 -> 91 bytes share/frontend/impattern/semi_patterns/a15.png | Bin 0 -> 143 bytes share/frontend/impattern/semi_patterns/a16.png | Bin 0 -> 87 bytes share/frontend/impattern/semi_patterns/a17.png | Bin 0 -> 93 bytes share/frontend/impattern/semi_patterns/a18.png | Bin 0 -> 163 bytes share/frontend/impattern/semi_patterns/a19.png | Bin 0 -> 119 bytes share/frontend/impattern/semi_patterns/a2.png | Bin 0 -> 123 bytes share/frontend/impattern/semi_patterns/a20.png | Bin 0 -> 83 bytes share/frontend/impattern/semi_patterns/a21.png | Bin 0 -> 111 bytes share/frontend/impattern/semi_patterns/a22.png | Bin 0 -> 137 bytes share/frontend/impattern/semi_patterns/a23.png | Bin 0 -> 116 bytes share/frontend/impattern/semi_patterns/a24.png | Bin 0 -> 96 bytes share/frontend/impattern/semi_patterns/a25.png | Bin 0 -> 108 bytes share/frontend/impattern/semi_patterns/a26.png | Bin 0 -> 138 bytes share/frontend/impattern/semi_patterns/a27.png | Bin 0 -> 108 bytes share/frontend/impattern/semi_patterns/a28.png | Bin 0 -> 115 bytes share/frontend/impattern/semi_patterns/a29.png | Bin 0 -> 93 bytes share/frontend/impattern/semi_patterns/a3.png | Bin 0 -> 124 bytes share/frontend/impattern/semi_patterns/a30.png | Bin 0 -> 88 bytes share/frontend/impattern/semi_patterns/a31.png | Bin 0 -> 114 bytes share/frontend/impattern/semi_patterns/a32.png | Bin 0 -> 139 bytes share/frontend/impattern/semi_patterns/a33.png | Bin 0 -> 127 bytes share/frontend/impattern/semi_patterns/a34.png | Bin 0 -> 92 bytes share/frontend/impattern/semi_patterns/a35.png | Bin 0 -> 91 bytes share/frontend/impattern/semi_patterns/a36.png | Bin 0 -> 87 bytes share/frontend/impattern/semi_patterns/a37.png | Bin 0 -> 89 bytes share/frontend/impattern/semi_patterns/a38.png | Bin 0 -> 83 bytes share/frontend/impattern/semi_patterns/a39.png | Bin 0 -> 132 bytes share/frontend/impattern/semi_patterns/a4.png | Bin 0 -> 92 bytes share/frontend/impattern/semi_patterns/a40.png | Bin 0 -> 138 bytes share/frontend/impattern/semi_patterns/a41.png | Bin 0 -> 113 bytes share/frontend/impattern/semi_patterns/a5.png | Bin 0 -> 120 bytes share/frontend/impattern/semi_patterns/a6.png | Bin 0 -> 105 bytes share/frontend/impattern/semi_patterns/a7.png | Bin 0 -> 106 bytes share/frontend/impattern/semi_patterns/a8.png | Bin 0 -> 110 bytes share/frontend/impattern/semi_patterns/a9.png | Bin 0 -> 110 bytes share/frontend/impattern/sketch.html | 231 ++ share/frontend/impattern/test.gif | Bin 0 -> 1584481 bytes 444 files changed, 7382 insertions(+) create mode 100644 share/frontend/impattern/app.pl create mode 100644 share/frontend/impattern/css/main.css create mode 100644 share/frontend/impattern/css/normalize.css create mode 100644 share/frontend/impattern/css/overlay.css create mode 100644 share/frontend/impattern/css/result.css create mode 100644 share/frontend/impattern/css/sketch.css create mode 100644 share/frontend/impattern/css/unsemantic-grid-responsive.css create mode 100644 share/frontend/impattern/img/brush.png create mode 100644 share/frontend/impattern/img/eraser.png create mode 100644 share/frontend/impattern/img/impattern.png create mode 100644 share/frontend/impattern/img/loading.gif create mode 100644 share/frontend/impattern/img/logo.gif create mode 100644 share/frontend/impattern/impattern.html create mode 100755 share/frontend/impattern/index.html create mode 100644 share/frontend/impattern/js/display_result.js create mode 100644 share/frontend/impattern/js/inputs.js create mode 100644 share/frontend/impattern/js/jquery.min.js create mode 100644 share/frontend/impattern/js/overlay.js create mode 100644 share/frontend/impattern/js/preview.js create mode 100644 share/frontend/impattern/js/sketch.js create mode 100644 share/frontend/impattern/js/urls.js create mode 100644 share/frontend/impattern/js/username.js create mode 100755 share/frontend/impattern/makePattern.py create mode 100644 share/frontend/impattern/myjson.json create mode 100644 share/frontend/impattern/newimagefromjson.py create mode 100644 share/frontend/impattern/old/bottle.py create mode 100644 share/frontend/impattern/old/index.html.old create mode 100644 share/frontend/impattern/old/oldpatterns/1.png create mode 100644 share/frontend/impattern/old/oldpatterns/10.png create mode 100644 share/frontend/impattern/old/oldpatterns/11.png create mode 100644 share/frontend/impattern/old/oldpatterns/12.png create mode 100644 share/frontend/impattern/old/oldpatterns/13.png create mode 100644 share/frontend/impattern/old/oldpatterns/14.png create mode 100644 share/frontend/impattern/old/oldpatterns/15.png create mode 100644 share/frontend/impattern/old/oldpatterns/16.png create mode 100644 share/frontend/impattern/old/oldpatterns/17.png create mode 100644 share/frontend/impattern/old/oldpatterns/18.png create mode 100644 share/frontend/impattern/old/oldpatterns/19.png create mode 100644 share/frontend/impattern/old/oldpatterns/2.png create mode 100644 share/frontend/impattern/old/oldpatterns/20.png create mode 100644 share/frontend/impattern/old/oldpatterns/21.png create mode 100644 share/frontend/impattern/old/oldpatterns/22.png create mode 100644 share/frontend/impattern/old/oldpatterns/23.png create mode 100644 share/frontend/impattern/old/oldpatterns/24.png create mode 100644 share/frontend/impattern/old/oldpatterns/25.png create mode 100644 share/frontend/impattern/old/oldpatterns/26.png create mode 100644 share/frontend/impattern/old/oldpatterns/27.png create mode 100644 share/frontend/impattern/old/oldpatterns/28.png create mode 100644 share/frontend/impattern/old/oldpatterns/29.png create mode 100644 share/frontend/impattern/old/oldpatterns/3.png create mode 100644 share/frontend/impattern/old/oldpatterns/30.png create mode 100644 share/frontend/impattern/old/oldpatterns/31.png create mode 100644 share/frontend/impattern/old/oldpatterns/32.png create mode 100644 share/frontend/impattern/old/oldpatterns/33.png create mode 100644 share/frontend/impattern/old/oldpatterns/34.png create mode 100644 share/frontend/impattern/old/oldpatterns/35.png create mode 100644 share/frontend/impattern/old/oldpatterns/36.png create mode 100644 share/frontend/impattern/old/oldpatterns/37.png create mode 100644 share/frontend/impattern/old/oldpatterns/38.png create mode 100644 share/frontend/impattern/old/oldpatterns/39.png create mode 100644 share/frontend/impattern/old/oldpatterns/4.png create mode 100644 share/frontend/impattern/old/oldpatterns/40.png create mode 100644 share/frontend/impattern/old/oldpatterns/41.png create mode 100644 share/frontend/impattern/old/oldpatterns/42.png create mode 100644 share/frontend/impattern/old/oldpatterns/43.png create mode 100644 share/frontend/impattern/old/oldpatterns/44.png create mode 100644 share/frontend/impattern/old/oldpatterns/45.png create mode 100644 share/frontend/impattern/old/oldpatterns/46.png create mode 100644 share/frontend/impattern/old/oldpatterns/47.png create mode 100644 share/frontend/impattern/old/oldpatterns/48.png create mode 100644 share/frontend/impattern/old/oldpatterns/49.png create mode 100644 share/frontend/impattern/old/oldpatterns/5.png create mode 100644 share/frontend/impattern/old/oldpatterns/50.png create mode 100644 share/frontend/impattern/old/oldpatterns/51.png create mode 100644 share/frontend/impattern/old/oldpatterns/52.png create mode 100644 share/frontend/impattern/old/oldpatterns/53.png create mode 100644 share/frontend/impattern/old/oldpatterns/54.png create mode 100644 share/frontend/impattern/old/oldpatterns/55.png create mode 100644 share/frontend/impattern/old/oldpatterns/56.png create mode 100644 share/frontend/impattern/old/oldpatterns/57.png create mode 100644 share/frontend/impattern/old/oldpatterns/58.png create mode 100644 share/frontend/impattern/old/oldpatterns/59.png create mode 100644 share/frontend/impattern/old/oldpatterns/6.png create mode 100644 share/frontend/impattern/old/oldpatterns/60.png create mode 100644 share/frontend/impattern/old/oldpatterns/61.png create mode 100644 share/frontend/impattern/old/oldpatterns/62.png create mode 100644 share/frontend/impattern/old/oldpatterns/63.png create mode 100644 share/frontend/impattern/old/oldpatterns/64.png create mode 100644 share/frontend/impattern/old/oldpatterns/65.png create mode 100644 share/frontend/impattern/old/oldpatterns/66.png create mode 100644 share/frontend/impattern/old/oldpatterns/67.png create mode 100644 share/frontend/impattern/old/oldpatterns/68.png create mode 100644 share/frontend/impattern/old/oldpatterns/69.png create mode 100644 share/frontend/impattern/old/oldpatterns/7.png create mode 100644 share/frontend/impattern/old/oldpatterns/70.png create mode 100644 share/frontend/impattern/old/oldpatterns/71.png create mode 100644 share/frontend/impattern/old/oldpatterns/72.png create mode 100644 share/frontend/impattern/old/oldpatterns/73.png create mode 100644 share/frontend/impattern/old/oldpatterns/74.png create mode 100644 share/frontend/impattern/old/oldpatterns/75.png create mode 100644 share/frontend/impattern/old/oldpatterns/76.png create mode 100644 share/frontend/impattern/old/oldpatterns/77.png create mode 100644 share/frontend/impattern/old/oldpatterns/78.png create mode 100644 share/frontend/impattern/old/oldpatterns/79.png create mode 100644 share/frontend/impattern/old/oldpatterns/8.png create mode 100644 share/frontend/impattern/old/oldpatterns/80.png create mode 100644 share/frontend/impattern/old/oldpatterns/81.png create mode 100644 share/frontend/impattern/old/oldpatterns/82.png create mode 100644 share/frontend/impattern/old/oldpatterns/83.png create mode 100644 share/frontend/impattern/old/oldpatterns/84.png create mode 100644 share/frontend/impattern/old/oldpatterns/85.png create mode 100644 share/frontend/impattern/old/oldpatterns/86.png create mode 100644 share/frontend/impattern/old/oldpatterns/87.png create mode 100644 share/frontend/impattern/old/oldpatterns/88.png create mode 100644 share/frontend/impattern/old/oldpatterns/89.png create mode 100644 share/frontend/impattern/old/oldpatterns/9.png create mode 100644 share/frontend/impattern/old/oldpatterns/90.png create mode 100644 share/frontend/impattern/old/oldpatterns/91.png create mode 100644 share/frontend/impattern/old/oldpatterns/92.png create mode 100644 share/frontend/impattern/old/oldpatterns/93.png create mode 100644 share/frontend/impattern/old/oldpatterns/94.png create mode 100644 share/frontend/impattern/old/oldpatterns/95.png create mode 100644 share/frontend/impattern/old/oldpatterns/96.png create mode 100644 share/frontend/impattern/old/oldpatterns/a0.png create mode 100644 share/frontend/impattern/old/oldpatterns/a1.png create mode 100644 share/frontend/impattern/old/oldpatterns/a10.png create mode 100644 share/frontend/impattern/old/oldpatterns/a11.png create mode 100644 share/frontend/impattern/old/oldpatterns/a12.png create mode 100644 share/frontend/impattern/old/oldpatterns/a13.png create mode 100644 share/frontend/impattern/old/oldpatterns/a14.png create mode 100644 share/frontend/impattern/old/oldpatterns/a15.png create mode 100644 share/frontend/impattern/old/oldpatterns/a16.png create mode 100644 share/frontend/impattern/old/oldpatterns/a17.png create mode 100644 share/frontend/impattern/old/oldpatterns/a18.png create mode 100644 share/frontend/impattern/old/oldpatterns/a19.png create mode 100644 share/frontend/impattern/old/oldpatterns/a2.png create mode 100644 share/frontend/impattern/old/oldpatterns/a20.png create mode 100644 share/frontend/impattern/old/oldpatterns/a21.png create mode 100644 share/frontend/impattern/old/oldpatterns/a22.png create mode 100644 share/frontend/impattern/old/oldpatterns/a23.png create mode 100644 share/frontend/impattern/old/oldpatterns/a24.png create mode 100644 share/frontend/impattern/old/oldpatterns/a25.png create mode 100644 share/frontend/impattern/old/oldpatterns/a26.png create mode 100644 share/frontend/impattern/old/oldpatterns/a27.png create mode 100644 share/frontend/impattern/old/oldpatterns/a28.png create mode 100644 share/frontend/impattern/old/oldpatterns/a29.png create mode 100644 share/frontend/impattern/old/oldpatterns/a3.png create mode 100644 share/frontend/impattern/old/oldpatterns/a30.png create mode 100644 share/frontend/impattern/old/oldpatterns/a31.png create mode 100644 share/frontend/impattern/old/oldpatterns/a32.png create mode 100644 share/frontend/impattern/old/oldpatterns/a33.png create mode 100644 share/frontend/impattern/old/oldpatterns/a34.png create mode 100644 share/frontend/impattern/old/oldpatterns/a35.png create mode 100644 share/frontend/impattern/old/oldpatterns/a36.png create mode 100644 share/frontend/impattern/old/oldpatterns/a37.png create mode 100644 share/frontend/impattern/old/oldpatterns/a38.png create mode 100644 share/frontend/impattern/old/oldpatterns/a39.png create mode 100644 share/frontend/impattern/old/oldpatterns/a4.png create mode 100644 share/frontend/impattern/old/oldpatterns/a40.png create mode 100644 share/frontend/impattern/old/oldpatterns/a41.png create mode 100644 share/frontend/impattern/old/oldpatterns/a5.png create mode 100644 share/frontend/impattern/old/oldpatterns/a6.png create mode 100644 share/frontend/impattern/old/oldpatterns/a7.png create mode 100644 share/frontend/impattern/old/oldpatterns/a8.png create mode 100644 share/frontend/impattern/old/oldpatterns/a9.png create mode 100644 share/frontend/impattern/other_script.py create mode 100644 share/frontend/impattern/patterns/1.png create mode 100644 share/frontend/impattern/patterns/10.png create mode 100644 share/frontend/impattern/patterns/11.png create mode 100644 share/frontend/impattern/patterns/12.png create mode 100644 share/frontend/impattern/patterns/13.png create mode 100644 share/frontend/impattern/patterns/14.png create mode 100644 share/frontend/impattern/patterns/15.png create mode 100644 share/frontend/impattern/patterns/16.png create mode 100644 share/frontend/impattern/patterns/17.png create mode 100644 share/frontend/impattern/patterns/18.png create mode 100644 share/frontend/impattern/patterns/19.png create mode 100644 share/frontend/impattern/patterns/2.png create mode 100644 share/frontend/impattern/patterns/20.png create mode 100644 share/frontend/impattern/patterns/21.png create mode 100644 share/frontend/impattern/patterns/22.png create mode 100644 share/frontend/impattern/patterns/23.png create mode 100644 share/frontend/impattern/patterns/24.png create mode 100644 share/frontend/impattern/patterns/25.png create mode 100644 share/frontend/impattern/patterns/26.png create mode 100644 share/frontend/impattern/patterns/27.png create mode 100644 share/frontend/impattern/patterns/28.png create mode 100644 share/frontend/impattern/patterns/29.png create mode 100644 share/frontend/impattern/patterns/3.png create mode 100644 share/frontend/impattern/patterns/30.png create mode 100644 share/frontend/impattern/patterns/31.png create mode 100644 share/frontend/impattern/patterns/32.png create mode 100644 share/frontend/impattern/patterns/33.png create mode 100644 share/frontend/impattern/patterns/34.png create mode 100644 share/frontend/impattern/patterns/35.png create mode 100644 share/frontend/impattern/patterns/36.png create mode 100644 share/frontend/impattern/patterns/37.png create mode 100644 share/frontend/impattern/patterns/38.png create mode 100644 share/frontend/impattern/patterns/39.png create mode 100644 share/frontend/impattern/patterns/4.png create mode 100644 share/frontend/impattern/patterns/40.png create mode 100644 share/frontend/impattern/patterns/41.png create mode 100644 share/frontend/impattern/patterns/42.png create mode 100644 share/frontend/impattern/patterns/43.png create mode 100644 share/frontend/impattern/patterns/44.png create mode 100644 share/frontend/impattern/patterns/45.png create mode 100644 share/frontend/impattern/patterns/46.png create mode 100644 share/frontend/impattern/patterns/47.png create mode 100644 share/frontend/impattern/patterns/48.png create mode 100644 share/frontend/impattern/patterns/49.png create mode 100644 share/frontend/impattern/patterns/5.png create mode 100644 share/frontend/impattern/patterns/50.png create mode 100644 share/frontend/impattern/patterns/51.png create mode 100644 share/frontend/impattern/patterns/52.png create mode 100644 share/frontend/impattern/patterns/53.png create mode 100644 share/frontend/impattern/patterns/54.png create mode 100644 share/frontend/impattern/patterns/55.png create mode 100644 share/frontend/impattern/patterns/56.png create mode 100644 share/frontend/impattern/patterns/57.png create mode 100644 share/frontend/impattern/patterns/58.png create mode 100644 share/frontend/impattern/patterns/59.png create mode 100644 share/frontend/impattern/patterns/6.png create mode 100644 share/frontend/impattern/patterns/60.png create mode 100644 share/frontend/impattern/patterns/61.png create mode 100644 share/frontend/impattern/patterns/62.png create mode 100644 share/frontend/impattern/patterns/63.png create mode 100644 share/frontend/impattern/patterns/64.png create mode 100644 share/frontend/impattern/patterns/65.png create mode 100644 share/frontend/impattern/patterns/66.png create mode 100644 share/frontend/impattern/patterns/67.png create mode 100644 share/frontend/impattern/patterns/68.png create mode 100644 share/frontend/impattern/patterns/69.png create mode 100644 share/frontend/impattern/patterns/7.png create mode 100644 share/frontend/impattern/patterns/70.png create mode 100644 share/frontend/impattern/patterns/71.png create mode 100644 share/frontend/impattern/patterns/72.png create mode 100644 share/frontend/impattern/patterns/73.png create mode 100644 share/frontend/impattern/patterns/74.png create mode 100644 share/frontend/impattern/patterns/75.png create mode 100644 share/frontend/impattern/patterns/76.png create mode 100644 share/frontend/impattern/patterns/77.png create mode 100644 share/frontend/impattern/patterns/78.png create mode 100644 share/frontend/impattern/patterns/79.png create mode 100644 share/frontend/impattern/patterns/8.png create mode 100644 share/frontend/impattern/patterns/80.png create mode 100644 share/frontend/impattern/patterns/81.png create mode 100644 share/frontend/impattern/patterns/82.png create mode 100644 share/frontend/impattern/patterns/83.png create mode 100644 share/frontend/impattern/patterns/84.png create mode 100644 share/frontend/impattern/patterns/85.png create mode 100644 share/frontend/impattern/patterns/86.png create mode 100644 share/frontend/impattern/patterns/87.png create mode 100644 share/frontend/impattern/patterns/88.png create mode 100644 share/frontend/impattern/patterns/89.png create mode 100644 share/frontend/impattern/patterns/9.png create mode 100644 share/frontend/impattern/patterns/90.png create mode 100644 share/frontend/impattern/patterns/91.png create mode 100644 share/frontend/impattern/patterns/92.png create mode 100644 share/frontend/impattern/patterns/93.png create mode 100644 share/frontend/impattern/patterns/94.png create mode 100644 share/frontend/impattern/patterns/95.png create mode 100644 share/frontend/impattern/patterns/96.png create mode 100644 share/frontend/impattern/patterns/a0.png create mode 100644 share/frontend/impattern/patterns/a1.png create mode 100644 share/frontend/impattern/patterns/a10.png create mode 100644 share/frontend/impattern/patterns/a11.png create mode 100644 share/frontend/impattern/patterns/a12.png create mode 100644 share/frontend/impattern/patterns/a13.png create mode 100644 share/frontend/impattern/patterns/a14.png create mode 100644 share/frontend/impattern/patterns/a15.png create mode 100644 share/frontend/impattern/patterns/a16.png create mode 100644 share/frontend/impattern/patterns/a17.png create mode 100644 share/frontend/impattern/patterns/a18.png create mode 100644 share/frontend/impattern/patterns/a19.png create mode 100644 share/frontend/impattern/patterns/a2.png create mode 100644 share/frontend/impattern/patterns/a20.png create mode 100644 share/frontend/impattern/patterns/a21.png create mode 100644 share/frontend/impattern/patterns/a22.png create mode 100644 share/frontend/impattern/patterns/a23.png create mode 100644 share/frontend/impattern/patterns/a24.png create mode 100644 share/frontend/impattern/patterns/a25.png create mode 100644 share/frontend/impattern/patterns/a26.png create mode 100644 share/frontend/impattern/patterns/a27.png create mode 100644 share/frontend/impattern/patterns/a28.png create mode 100644 share/frontend/impattern/patterns/a29.png create mode 100644 share/frontend/impattern/patterns/a3.png create mode 100644 share/frontend/impattern/patterns/a30.png create mode 100644 share/frontend/impattern/patterns/a31.png create mode 100644 share/frontend/impattern/patterns/a32.png create mode 100644 share/frontend/impattern/patterns/a33.png create mode 100644 share/frontend/impattern/patterns/a34.png create mode 100644 share/frontend/impattern/patterns/a35.png create mode 100644 share/frontend/impattern/patterns/a36.png create mode 100644 share/frontend/impattern/patterns/a37.png create mode 100644 share/frontend/impattern/patterns/a38.png create mode 100644 share/frontend/impattern/patterns/a39.png create mode 100644 share/frontend/impattern/patterns/a4.png create mode 100644 share/frontend/impattern/patterns/a40.png create mode 100644 share/frontend/impattern/patterns/a41.png create mode 100644 share/frontend/impattern/patterns/a5.png create mode 100644 share/frontend/impattern/patterns/a6.png create mode 100644 share/frontend/impattern/patterns/a7.png create mode 100644 share/frontend/impattern/patterns/a8.png create mode 100644 share/frontend/impattern/patterns/a9.png create mode 100644 share/frontend/impattern/semi_patterns/1.png create mode 100644 share/frontend/impattern/semi_patterns/10.png create mode 100644 share/frontend/impattern/semi_patterns/11.png create mode 100644 share/frontend/impattern/semi_patterns/12.png create mode 100644 share/frontend/impattern/semi_patterns/13.png create mode 100644 share/frontend/impattern/semi_patterns/14.png create mode 100644 share/frontend/impattern/semi_patterns/15.png create mode 100644 share/frontend/impattern/semi_patterns/16.png create mode 100644 share/frontend/impattern/semi_patterns/17.png create mode 100644 share/frontend/impattern/semi_patterns/18.png create mode 100644 share/frontend/impattern/semi_patterns/19.png create mode 100644 share/frontend/impattern/semi_patterns/2.png create mode 100644 share/frontend/impattern/semi_patterns/20.png create mode 100644 share/frontend/impattern/semi_patterns/21.png create mode 100644 share/frontend/impattern/semi_patterns/22.png create mode 100644 share/frontend/impattern/semi_patterns/23.png create mode 100644 share/frontend/impattern/semi_patterns/24.png create mode 100644 share/frontend/impattern/semi_patterns/25.png create mode 100644 share/frontend/impattern/semi_patterns/26.png create mode 100644 share/frontend/impattern/semi_patterns/27.png create mode 100644 share/frontend/impattern/semi_patterns/28.png create mode 100644 share/frontend/impattern/semi_patterns/29.png create mode 100644 share/frontend/impattern/semi_patterns/3.png create mode 100644 share/frontend/impattern/semi_patterns/30.png create mode 100644 share/frontend/impattern/semi_patterns/31.png create mode 100644 share/frontend/impattern/semi_patterns/32.png create mode 100644 share/frontend/impattern/semi_patterns/33.png create mode 100644 share/frontend/impattern/semi_patterns/34.png create mode 100644 share/frontend/impattern/semi_patterns/35.png create mode 100644 share/frontend/impattern/semi_patterns/36.png create mode 100644 share/frontend/impattern/semi_patterns/37.png create mode 100644 share/frontend/impattern/semi_patterns/38.png create mode 100644 share/frontend/impattern/semi_patterns/39.png create mode 100644 share/frontend/impattern/semi_patterns/4.png create mode 100644 share/frontend/impattern/semi_patterns/40.png create mode 100644 share/frontend/impattern/semi_patterns/41.png create mode 100644 share/frontend/impattern/semi_patterns/42.png create mode 100644 share/frontend/impattern/semi_patterns/43.png create mode 100644 share/frontend/impattern/semi_patterns/44.png create mode 100644 share/frontend/impattern/semi_patterns/45.png create mode 100644 share/frontend/impattern/semi_patterns/46.png create mode 100644 share/frontend/impattern/semi_patterns/47.png create mode 100644 share/frontend/impattern/semi_patterns/48.png create mode 100644 share/frontend/impattern/semi_patterns/49.png create mode 100644 share/frontend/impattern/semi_patterns/5.png create mode 100644 share/frontend/impattern/semi_patterns/50.png create mode 100644 share/frontend/impattern/semi_patterns/51.png create mode 100644 share/frontend/impattern/semi_patterns/52.png create mode 100644 share/frontend/impattern/semi_patterns/53.png create mode 100644 share/frontend/impattern/semi_patterns/54.png create mode 100644 share/frontend/impattern/semi_patterns/55.png create mode 100644 share/frontend/impattern/semi_patterns/56.png create mode 100644 share/frontend/impattern/semi_patterns/57.png create mode 100644 share/frontend/impattern/semi_patterns/58.png create mode 100644 share/frontend/impattern/semi_patterns/59.png create mode 100644 share/frontend/impattern/semi_patterns/6.png create mode 100644 share/frontend/impattern/semi_patterns/60.png create mode 100644 share/frontend/impattern/semi_patterns/61.png create mode 100644 share/frontend/impattern/semi_patterns/62.png create mode 100644 share/frontend/impattern/semi_patterns/63.png create mode 100644 share/frontend/impattern/semi_patterns/64.png create mode 100644 share/frontend/impattern/semi_patterns/65.png create mode 100644 share/frontend/impattern/semi_patterns/66.png create mode 100644 share/frontend/impattern/semi_patterns/67.png create mode 100644 share/frontend/impattern/semi_patterns/68.png create mode 100644 share/frontend/impattern/semi_patterns/69.png create mode 100644 share/frontend/impattern/semi_patterns/7.png create mode 100644 share/frontend/impattern/semi_patterns/70.png create mode 100644 share/frontend/impattern/semi_patterns/71.png create mode 100644 share/frontend/impattern/semi_patterns/72.png create mode 100644 share/frontend/impattern/semi_patterns/73.png create mode 100644 share/frontend/impattern/semi_patterns/74.png create mode 100644 share/frontend/impattern/semi_patterns/75.png create mode 100644 share/frontend/impattern/semi_patterns/76.png create mode 100644 share/frontend/impattern/semi_patterns/77.png create mode 100644 share/frontend/impattern/semi_patterns/78.png create mode 100644 share/frontend/impattern/semi_patterns/79.png create mode 100644 share/frontend/impattern/semi_patterns/8.png create mode 100644 share/frontend/impattern/semi_patterns/80.png create mode 100644 share/frontend/impattern/semi_patterns/81.png create mode 100644 share/frontend/impattern/semi_patterns/82.png create mode 100644 share/frontend/impattern/semi_patterns/83.png create mode 100644 share/frontend/impattern/semi_patterns/84.png create mode 100644 share/frontend/impattern/semi_patterns/85.png create mode 100644 share/frontend/impattern/semi_patterns/86.png create mode 100644 share/frontend/impattern/semi_patterns/87.png create mode 100644 share/frontend/impattern/semi_patterns/88.png create mode 100644 share/frontend/impattern/semi_patterns/89.png create mode 100644 share/frontend/impattern/semi_patterns/9.png create mode 100644 share/frontend/impattern/semi_patterns/90.png create mode 100644 share/frontend/impattern/semi_patterns/91.png create mode 100644 share/frontend/impattern/semi_patterns/92.png create mode 100644 share/frontend/impattern/semi_patterns/93.png create mode 100644 share/frontend/impattern/semi_patterns/94.png create mode 100644 share/frontend/impattern/semi_patterns/95.png create mode 100644 share/frontend/impattern/semi_patterns/96.png create mode 100644 share/frontend/impattern/semi_patterns/a0.png create mode 100644 share/frontend/impattern/semi_patterns/a1.png create mode 100644 share/frontend/impattern/semi_patterns/a10.png create mode 100644 share/frontend/impattern/semi_patterns/a11.png create mode 100644 share/frontend/impattern/semi_patterns/a12.png create mode 100644 share/frontend/impattern/semi_patterns/a13.png create mode 100644 share/frontend/impattern/semi_patterns/a14.png create mode 100644 share/frontend/impattern/semi_patterns/a15.png create mode 100644 share/frontend/impattern/semi_patterns/a16.png create mode 100644 share/frontend/impattern/semi_patterns/a17.png create mode 100644 share/frontend/impattern/semi_patterns/a18.png create mode 100644 share/frontend/impattern/semi_patterns/a19.png create mode 100644 share/frontend/impattern/semi_patterns/a2.png create mode 100644 share/frontend/impattern/semi_patterns/a20.png create mode 100644 share/frontend/impattern/semi_patterns/a21.png create mode 100644 share/frontend/impattern/semi_patterns/a22.png create mode 100644 share/frontend/impattern/semi_patterns/a23.png create mode 100644 share/frontend/impattern/semi_patterns/a24.png create mode 100644 share/frontend/impattern/semi_patterns/a25.png create mode 100644 share/frontend/impattern/semi_patterns/a26.png create mode 100644 share/frontend/impattern/semi_patterns/a27.png create mode 100644 share/frontend/impattern/semi_patterns/a28.png create mode 100644 share/frontend/impattern/semi_patterns/a29.png create mode 100644 share/frontend/impattern/semi_patterns/a3.png create mode 100644 share/frontend/impattern/semi_patterns/a30.png create mode 100644 share/frontend/impattern/semi_patterns/a31.png create mode 100644 share/frontend/impattern/semi_patterns/a32.png create mode 100644 share/frontend/impattern/semi_patterns/a33.png create mode 100644 share/frontend/impattern/semi_patterns/a34.png create mode 100644 share/frontend/impattern/semi_patterns/a35.png create mode 100644 share/frontend/impattern/semi_patterns/a36.png create mode 100644 share/frontend/impattern/semi_patterns/a37.png create mode 100644 share/frontend/impattern/semi_patterns/a38.png create mode 100644 share/frontend/impattern/semi_patterns/a39.png create mode 100644 share/frontend/impattern/semi_patterns/a4.png create mode 100644 share/frontend/impattern/semi_patterns/a40.png create mode 100644 share/frontend/impattern/semi_patterns/a41.png create mode 100644 share/frontend/impattern/semi_patterns/a5.png create mode 100644 share/frontend/impattern/semi_patterns/a6.png create mode 100644 share/frontend/impattern/semi_patterns/a7.png create mode 100644 share/frontend/impattern/semi_patterns/a8.png create mode 100644 share/frontend/impattern/semi_patterns/a9.png create mode 100644 share/frontend/impattern/sketch.html create mode 100644 share/frontend/impattern/test.gif (limited to 'share/frontend/impattern') diff --git a/share/frontend/impattern/app.pl b/share/frontend/impattern/app.pl new file mode 100644 index 0000000..b1bfc3c --- /dev/null +++ b/share/frontend/impattern/app.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +use Dancer2; +use Data::Dumper; +set public => './'; + +get '/download/*.*' => sub { + my ($file, $ext) = splat; + # do something with $file.$ext here +}; + +get qr{/img/([\w\.\-_]+)} => sub { + my ($filename) = splat; + send_file sprintf("/img/%s", $filename); +}; +get qr{/patterns/([\w\.\-_]+)} => sub { + my ($filename) = splat; + send_file sprintf("/patterns/%s", $filename); +}; +get qr{/css/([\w\.\-_]+)} => sub { + my ($filename) = splat; + send_file sprintf("/css/%s", $filename); +}; +get qr{/js/([\w\.\-_]+)} => sub { + my ($filename) = splat; + send_file sprintf("/js/%s", $filename); +}; +get qr{/fonts/([\w\.\-_]+)} => sub { + my ($filename) = splat; + send_file sprintf("/fonts/%s", $filename); +}; +get '/' => sub { + send_file ("index.html"); +}; +dance; diff --git a/share/frontend/impattern/css/main.css b/share/frontend/impattern/css/main.css new file mode 100644 index 0000000..de2a782 --- /dev/null +++ b/share/frontend/impattern/css/main.css @@ -0,0 +1,101 @@ +html,body{ + min-height: 100%; +} +body{ +padding-top:5px; +font-family: 'Roboto', sans-serif; + position: relative; +} +.title{ + font-family: 'Orienta', sans-serif; + font-size:3em; + text-shadow: 2px 4px 3px rgba(153,153,153,0.3); + color: #1C1C1C; +} +#impattern{ + text-align:center; + display:inline-block; +} +#submit_wrapper{ + padding-top:30px; +} + +#choose_your_image{ + margin-left: -10px; + margin-bottom: 15px; +} +.image_input{ + min-width:300px; + +} + +#submit{ + font-size:30px; + +} + +#sample + { + display:inline-block; + border-style: outset; + border-color: gray; + border-width: 5px; + height:100px; + } +table.dithertable { + border-width: 5px; + border-spacing: 3px; + border-style: outset; + border-color: gray; + border-collapse: separate; + background-color: whitesmoke; +} +table.dithertable th { + border-width: medium; + padding: 2px; + border-style: ridge; + border-color: gray; + background-color: rgb(255, 255, 240); + -moz-border-radius: ; +} +table.dithertable td { + border-width: 3px; + padding: 2px; + border-style: ridge; + border-color: gray; + background-color: rgb(255, 255, 240); +// -moz-border-radius: ; + background-color:white; +} +.patterns + { + width:10px; + height:10px; +//border-color:#99aacc; border-style:ridge; +//border-width:3px 3px 6px 3px; + cursor:pointer; + } +#dithertable + { + width:100%; + display:inline-block; + } +tr + { + height:40px; + } +.dontshowme{ + display: none; +} +#acknowledgments{ + position: absolute; + font-size: 10px; + float: right; + bottom:1%; +} +#acknowledgments > a{ + color: gray; +} +#acknowledgments > a:active{ + color: gray; +} diff --git a/share/frontend/impattern/css/normalize.css b/share/frontend/impattern/css/normalize.css new file mode 100644 index 0000000..458eea1 --- /dev/null +++ b/share/frontend/impattern/css/normalize.css @@ -0,0 +1,427 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/share/frontend/impattern/css/overlay.css b/share/frontend/impattern/css/overlay.css new file mode 100644 index 0000000..796ad62 --- /dev/null +++ b/share/frontend/impattern/css/overlay.css @@ -0,0 +1,43 @@ +#draw_protector{ + height: 100%; + width: 100%; + position:absolute; + top: 0; + left: 0; + z-index:101; + display: none; +} +#overlay{ + position:absolute; + height:100%; + width:100%; + top:0; + left:0; + background: rgba(245,245,245,0.8); + z-index: 100; + display: none; +} +#overlay > .close{ + position: absolute; + padding: 10px; + top: 10px; + left: 10px; + border: 1px solid gray; + background: white; + cursor: pointer; + z-index: 102; +} +#final-image > img{ + max-width:550px; + max-height:550px; +} +#overlay > .content{ + top: 10px; + left: 150px; + padding: 10px; + border: 1px solid gray; + background: white; + position: absolute; + z-index: 102; +} + diff --git a/share/frontend/impattern/css/result.css b/share/frontend/impattern/css/result.css new file mode 100644 index 0000000..00567aa --- /dev/null +++ b/share/frontend/impattern/css/result.css @@ -0,0 +1,3 @@ +#links > input{ + width:100%; +} diff --git a/share/frontend/impattern/css/sketch.css b/share/frontend/impattern/css/sketch.css new file mode 100644 index 0000000..84c00a0 --- /dev/null +++ b/share/frontend/impattern/css/sketch.css @@ -0,0 +1,45 @@ +#draw{ + display:none; +} + +#canvas_wrapper{ +// position:absolute; + display: inline-block; +white-space: no-wrap; +word-wrap: break-word; +-webkit-user-select: none; +-moz-user-select: none; +user-select: none; +// pointer-events: none; + +} +.canvas_cell{ + border: 1px solid silver; + display: inline-block; + width: 1em; + height: 1em; +} +.canvas_row{ +// position: absolute; +} + +.brush_tools{ + margin:5px; + padding:5px; + display: inline-block; + background: whitesmoke; + border: 1px solid gray; + cursor: pointer; +} +#drawing_finished{ + padding:5px; + margin-top:10px; + text-transform:bold; + display:block; + width:100%; +} +#brush{ + background:gray; + color: white; + border: 1px solid black; +} diff --git a/share/frontend/impattern/css/unsemantic-grid-responsive.css b/share/frontend/impattern/css/unsemantic-grid-responsive.css new file mode 100644 index 0000000..929efe7 --- /dev/null +++ b/share/frontend/impattern/css/unsemantic-grid-responsive.css @@ -0,0 +1,1403 @@ +/* ============================================ */ +/* This file has a mobile-to-desktop breakpoint */ +/* ============================================ */ +@media (max-width: 400px) { + @-ms-viewport { + width: 320px; + } +} +.clear { + clear: both; + display: block; + overflow: hidden; + visibility: hidden; + width: 0; + height: 0; +} + +.grid-container:before, .grid-5:before, .mobile-grid-5:before, .grid-10:before, .mobile-grid-10:before, .grid-15:before, .mobile-grid-15:before, .grid-20:before, .mobile-grid-20:before, .grid-25:before, .mobile-grid-25:before, .grid-30:before, .mobile-grid-30:before, .grid-35:before, .mobile-grid-35:before, .grid-40:before, .mobile-grid-40:before, .grid-45:before, .mobile-grid-45:before, .grid-50:before, .mobile-grid-50:before, .grid-55:before, .mobile-grid-55:before, .grid-60:before, .mobile-grid-60:before, .grid-65:before, .mobile-grid-65:before, .grid-70:before, .mobile-grid-70:before, .grid-75:before, .mobile-grid-75:before, .grid-80:before, .mobile-grid-80:before, .grid-85:before, .mobile-grid-85:before, .grid-90:before, .mobile-grid-90:before, .grid-95:before, .mobile-grid-95:before, .grid-100:before, .mobile-grid-100:before, .grid-33:before, .mobile-grid-33:before, .grid-66:before, .mobile-grid-66:before, .clearfix:before, +.grid-container:after, +.grid-5:after, +.mobile-grid-5:after, +.grid-10:after, +.mobile-grid-10:after, +.grid-15:after, +.mobile-grid-15:after, +.grid-20:after, +.mobile-grid-20:after, +.grid-25:after, +.mobile-grid-25:after, +.grid-30:after, +.mobile-grid-30:after, +.grid-35:after, +.mobile-grid-35:after, +.grid-40:after, +.mobile-grid-40:after, +.grid-45:after, +.mobile-grid-45:after, +.grid-50:after, +.mobile-grid-50:after, +.grid-55:after, +.mobile-grid-55:after, +.grid-60:after, +.mobile-grid-60:after, +.grid-65:after, +.mobile-grid-65:after, +.grid-70:after, +.mobile-grid-70:after, +.grid-75:after, +.mobile-grid-75:after, +.grid-80:after, +.mobile-grid-80:after, +.grid-85:after, +.mobile-grid-85:after, +.grid-90:after, +.mobile-grid-90:after, +.grid-95:after, +.mobile-grid-95:after, +.grid-100:after, +.mobile-grid-100:after, +.grid-33:after, +.mobile-grid-33:after, +.grid-66:after, +.mobile-grid-66:after, +.clearfix:after { + content: "."; + display: block; + overflow: hidden; + visibility: hidden; + font-size: 0; + line-height: 0; + width: 0; + height: 0; +} + +.grid-container:after, .grid-5:after, .mobile-grid-5:after, .grid-10:after, .mobile-grid-10:after, .grid-15:after, .mobile-grid-15:after, .grid-20:after, .mobile-grid-20:after, .grid-25:after, .mobile-grid-25:after, .grid-30:after, .mobile-grid-30:after, .grid-35:after, .mobile-grid-35:after, .grid-40:after, .mobile-grid-40:after, .grid-45:after, .mobile-grid-45:after, .grid-50:after, .mobile-grid-50:after, .grid-55:after, .mobile-grid-55:after, .grid-60:after, .mobile-grid-60:after, .grid-65:after, .mobile-grid-65:after, .grid-70:after, .mobile-grid-70:after, .grid-75:after, .mobile-grid-75:after, .grid-80:after, .mobile-grid-80:after, .grid-85:after, .mobile-grid-85:after, .grid-90:after, .mobile-grid-90:after, .grid-95:after, .mobile-grid-95:after, .grid-100:after, .mobile-grid-100:after, .grid-33:after, .mobile-grid-33:after, .grid-66:after, .mobile-grid-66:after, .clearfix:after { + clear: both; +} + +.grid-container, .grid-5, .mobile-grid-5, .grid-10, .mobile-grid-10, .grid-15, .mobile-grid-15, .grid-20, .mobile-grid-20, .grid-25, .mobile-grid-25, .grid-30, .mobile-grid-30, .grid-35, .mobile-grid-35, .grid-40, .mobile-grid-40, .grid-45, .mobile-grid-45, .grid-50, .mobile-grid-50, .grid-55, .mobile-grid-55, .grid-60, .mobile-grid-60, .grid-65, .mobile-grid-65, .grid-70, .mobile-grid-70, .grid-75, .mobile-grid-75, .grid-80, .mobile-grid-80, .grid-85, .mobile-grid-85, .grid-90, .mobile-grid-90, .grid-95, .mobile-grid-95, .grid-100, .mobile-grid-100, .grid-33, .mobile-grid-33, .grid-66, .mobile-grid-66, .clearfix { + /* */ + *zoom: 1; + /* */ +} + +.grid-container { + margin-left: auto; + margin-right: auto; + max-width: 1200px; + padding-left: 10px; + padding-right: 10px; +} + +.grid-5, .mobile-grid-5, .grid-10, .mobile-grid-10, .grid-15, .mobile-grid-15, .grid-20, .mobile-grid-20, .grid-25, .mobile-grid-25, .grid-30, .mobile-grid-30, .grid-35, .mobile-grid-35, .grid-40, .mobile-grid-40, .grid-45, .mobile-grid-45, .grid-50, .mobile-grid-50, .grid-55, .mobile-grid-55, .grid-60, .mobile-grid-60, .grid-65, .mobile-grid-65, .grid-70, .mobile-grid-70, .grid-75, .mobile-grid-75, .grid-80, .mobile-grid-80, .grid-85, .mobile-grid-85, .grid-90, .mobile-grid-90, .grid-95, .mobile-grid-95, .grid-100, .mobile-grid-100, .grid-33, .mobile-grid-33, .grid-66, .mobile-grid-66 { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding-left: 10px; + padding-right: 10px; + /* */ + *padding-left: 0; + *padding-right: 0; + /* */ +} +.grid-5 > *, .mobile-grid-5 > *, .grid-10 > *, .mobile-grid-10 > *, .grid-15 > *, .mobile-grid-15 > *, .grid-20 > *, .mobile-grid-20 > *, .grid-25 > *, .mobile-grid-25 > *, .grid-30 > *, .mobile-grid-30 > *, .grid-35 > *, .mobile-grid-35 > *, .grid-40 > *, .mobile-grid-40 > *, .grid-45 > *, .mobile-grid-45 > *, .grid-50 > *, .mobile-grid-50 > *, .grid-55 > *, .mobile-grid-55 > *, .grid-60 > *, .mobile-grid-60 > *, .grid-65 > *, .mobile-grid-65 > *, .grid-70 > *, .mobile-grid-70 > *, .grid-75 > *, .mobile-grid-75 > *, .grid-80 > *, .mobile-grid-80 > *, .grid-85 > *, .mobile-grid-85 > *, .grid-90 > *, .mobile-grid-90 > *, .grid-95 > *, .mobile-grid-95 > *, .grid-100 > *, .mobile-grid-100 > *, .grid-33 > *, .mobile-grid-33 > *, .grid-66 > *, .mobile-grid-66 > * { + /* */ + *margin-left: "expression((!this.className.match(/grid-[1-9]/) && this.currentStyle.display === " block " && this.currentStyle.width === " auto ') && "10px")'; + *margin-right: "expression((!this.className.match(/grid-[1-9]/) && this.currentStyle.display === " block " && this.currentStyle.width === " auto ') && "10px")'; + /* */ +} + +.grid-parent { + padding-left: 0; + padding-right: 0; +} + +@media (max-width: 767px) { + .mobile-push-5, .mobile-pull-5, .mobile-push-10, .mobile-pull-10, .mobile-push-15, .mobile-pull-15, .mobile-push-20, .mobile-pull-20, .mobile-push-25, .mobile-pull-25, .mobile-push-30, .mobile-pull-30, .mobile-push-35, .mobile-pull-35, .mobile-push-40, .mobile-pull-40, .mobile-push-45, .mobile-pull-45, .mobile-push-50, .mobile-pull-50, .mobile-push-55, .mobile-pull-55, .mobile-push-60, .mobile-pull-60, .mobile-push-65, .mobile-pull-65, .mobile-push-70, .mobile-pull-70, .mobile-push-75, .mobile-pull-75, .mobile-push-80, .mobile-pull-80, .mobile-push-85, .mobile-pull-85, .mobile-push-90, .mobile-pull-90, .mobile-push-95, .mobile-pull-95, .mobile-push-33, .mobile-pull-33, .mobile-push-66, .mobile-pull-66 { + position: relative; + } + + .hide-on-mobile { + display: none !important; + } + + .mobile-grid-5 { + float: left; + width: 5%; + /* */ + *width: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-5 { + margin-left: 5%; + } + + .mobile-suffix-5 { + margin-right: 5%; + } + + .mobile-push-5 { + left: 5%; + /* */ + *left: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-5 { + left: -5%; + /* */ + *left: expression(Math.floor(-0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-10 { + float: left; + width: 10%; + /* */ + *width: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-10 { + margin-left: 10%; + } + + .mobile-suffix-10 { + margin-right: 10%; + } + + .mobile-push-10 { + left: 10%; + /* */ + *left: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-10 { + left: -10%; + /* */ + *left: expression(Math.floor(-0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-15 { + float: left; + width: 15%; + /* */ + *width: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-15 { + margin-left: 15%; + } + + .mobile-suffix-15 { + margin-right: 15%; + } + + .mobile-push-15 { + left: 15%; + /* */ + *left: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-15 { + left: -15%; + /* */ + *left: expression(Math.floor(-0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-20 { + float: left; + width: 20%; + /* */ + *width: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-20 { + margin-left: 20%; + } + + .mobile-suffix-20 { + margin-right: 20%; + } + + .mobile-push-20 { + left: 20%; + /* */ + *left: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-20 { + left: -20%; + /* */ + *left: expression(Math.floor(-0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-25 { + float: left; + width: 25%; + /* */ + *width: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-25 { + margin-left: 25%; + } + + .mobile-suffix-25 { + margin-right: 25%; + } + + .mobile-push-25 { + left: 25%; + /* */ + *left: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-25 { + left: -25%; + /* */ + *left: expression(Math.floor(-0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-30 { + float: left; + width: 30%; + /* */ + *width: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-30 { + margin-left: 30%; + } + + .mobile-suffix-30 { + margin-right: 30%; + } + + .mobile-push-30 { + left: 30%; + /* */ + *left: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-30 { + left: -30%; + /* */ + *left: expression(Math.floor(-0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-35 { + float: left; + width: 35%; + /* */ + *width: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-35 { + margin-left: 35%; + } + + .mobile-suffix-35 { + margin-right: 35%; + } + + .mobile-push-35 { + left: 35%; + /* */ + *left: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-35 { + left: -35%; + /* */ + *left: expression(Math.floor(-0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-40 { + float: left; + width: 40%; + /* */ + *width: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-40 { + margin-left: 40%; + } + + .mobile-suffix-40 { + margin-right: 40%; + } + + .mobile-push-40 { + left: 40%; + /* */ + *left: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-40 { + left: -40%; + /* */ + *left: expression(Math.floor(-0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-45 { + float: left; + width: 45%; + /* */ + *width: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-45 { + margin-left: 45%; + } + + .mobile-suffix-45 { + margin-right: 45%; + } + + .mobile-push-45 { + left: 45%; + /* */ + *left: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-45 { + left: -45%; + /* */ + *left: expression(Math.floor(-0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-50 { + float: left; + width: 50%; + /* */ + *width: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-50 { + margin-left: 50%; + } + + .mobile-suffix-50 { + margin-right: 50%; + } + + .mobile-push-50 { + left: 50%; + /* */ + *left: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-50 { + left: -50%; + /* */ + *left: expression(Math.floor(-0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-55 { + float: left; + width: 55%; + /* */ + *width: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-55 { + margin-left: 55%; + } + + .mobile-suffix-55 { + margin-right: 55%; + } + + .mobile-push-55 { + left: 55%; + /* */ + *left: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-55 { + left: -55%; + /* */ + *left: expression(Math.floor(-0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-60 { + float: left; + width: 60%; + /* */ + *width: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-60 { + margin-left: 60%; + } + + .mobile-suffix-60 { + margin-right: 60%; + } + + .mobile-push-60 { + left: 60%; + /* */ + *left: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-60 { + left: -60%; + /* */ + *left: expression(Math.floor(-0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-65 { + float: left; + width: 65%; + /* */ + *width: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-65 { + margin-left: 65%; + } + + .mobile-suffix-65 { + margin-right: 65%; + } + + .mobile-push-65 { + left: 65%; + /* */ + *left: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-65 { + left: -65%; + /* */ + *left: expression(Math.floor(-0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-70 { + float: left; + width: 70%; + /* */ + *width: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-70 { + margin-left: 70%; + } + + .mobile-suffix-70 { + margin-right: 70%; + } + + .mobile-push-70 { + left: 70%; + /* */ + *left: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-70 { + left: -70%; + /* */ + *left: expression(Math.floor(-0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-75 { + float: left; + width: 75%; + /* */ + *width: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-75 { + margin-left: 75%; + } + + .mobile-suffix-75 { + margin-right: 75%; + } + + .mobile-push-75 { + left: 75%; + /* */ + *left: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-75 { + left: -75%; + /* */ + *left: expression(Math.floor(-0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-80 { + float: left; + width: 80%; + /* */ + *width: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-80 { + margin-left: 80%; + } + + .mobile-suffix-80 { + margin-right: 80%; + } + + .mobile-push-80 { + left: 80%; + /* */ + *left: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-80 { + left: -80%; + /* */ + *left: expression(Math.floor(-0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-85 { + float: left; + width: 85%; + /* */ + *width: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-85 { + margin-left: 85%; + } + + .mobile-suffix-85 { + margin-right: 85%; + } + + .mobile-push-85 { + left: 85%; + /* */ + *left: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-85 { + left: -85%; + /* */ + *left: expression(Math.floor(-0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-90 { + float: left; + width: 90%; + /* */ + *width: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-90 { + margin-left: 90%; + } + + .mobile-suffix-90 { + margin-right: 90%; + } + + .mobile-push-90 { + left: 90%; + /* */ + *left: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-90 { + left: -90%; + /* */ + *left: expression(Math.floor(-0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-95 { + float: left; + width: 95%; + /* */ + *width: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-95 { + margin-left: 95%; + } + + .mobile-suffix-95 { + margin-right: 95%; + } + + .mobile-push-95 { + left: 95%; + /* */ + *left: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-95 { + left: -95%; + /* */ + *left: expression(Math.floor(-0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-33 { + float: left; + width: 33.33333%; + /* */ + *width: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-33 { + margin-left: 33.33333%; + } + + .mobile-suffix-33 { + margin-right: 33.33333%; + } + + .mobile-push-33 { + left: 33.33333%; + /* */ + *left: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-33 { + left: -33.33333%; + /* */ + *left: expression(Math.floor(-0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-66 { + float: left; + width: 66.66667%; + /* */ + *width: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-prefix-66 { + margin-left: 66.66667%; + } + + .mobile-suffix-66 { + margin-right: 66.66667%; + } + + .mobile-push-66 { + left: 66.66667%; + /* */ + *left: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-pull-66 { + left: -66.66667%; + /* */ + *left: expression(Math.floor(-0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .mobile-grid-100 { + clear: both; + width: 100%; + } +} +@media (min-width: 768px) { + .push-5, .pull-5, .push-10, .pull-10, .push-15, .pull-15, .push-20, .pull-20, .push-25, .pull-25, .push-30, .pull-30, .push-35, .pull-35, .push-40, .pull-40, .push-45, .pull-45, .push-50, .pull-50, .push-55, .pull-55, .push-60, .pull-60, .push-65, .pull-65, .push-70, .pull-70, .push-75, .pull-75, .push-80, .pull-80, .push-85, .pull-85, .push-90, .pull-90, .push-95, .pull-95, .push-33, .pull-33, .push-66, .pull-66 { + position: relative; + } + + .hide-on-desktop { + display: none !important; + } + + .grid-5 { + float: left; + width: 5%; + /* */ + *width: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-5 { + margin-left: 5%; + } + + .suffix-5 { + margin-right: 5%; + } + + .push-5 { + left: 5%; + /* */ + *left: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-5 { + left: -5%; + /* */ + *left: expression(Math.floor(-0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-10 { + float: left; + width: 10%; + /* */ + *width: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-10 { + margin-left: 10%; + } + + .suffix-10 { + margin-right: 10%; + } + + .push-10 { + left: 10%; + /* */ + *left: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-10 { + left: -10%; + /* */ + *left: expression(Math.floor(-0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-15 { + float: left; + width: 15%; + /* */ + *width: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-15 { + margin-left: 15%; + } + + .suffix-15 { + margin-right: 15%; + } + + .push-15 { + left: 15%; + /* */ + *left: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-15 { + left: -15%; + /* */ + *left: expression(Math.floor(-0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-20 { + float: left; + width: 20%; + /* */ + *width: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-20 { + margin-left: 20%; + } + + .suffix-20 { + margin-right: 20%; + } + + .push-20 { + left: 20%; + /* */ + *left: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-20 { + left: -20%; + /* */ + *left: expression(Math.floor(-0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-25 { + float: left; + width: 25%; + /* */ + *width: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-25 { + margin-left: 25%; + } + + .suffix-25 { + margin-right: 25%; + } + + .push-25 { + left: 25%; + /* */ + *left: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-25 { + left: -25%; + /* */ + *left: expression(Math.floor(-0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-30 { + float: left; + width: 30%; + /* */ + *width: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-30 { + margin-left: 30%; + } + + .suffix-30 { + margin-right: 30%; + } + + .push-30 { + left: 30%; + /* */ + *left: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-30 { + left: -30%; + /* */ + *left: expression(Math.floor(-0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-35 { + float: left; + width: 35%; + /* */ + *width: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-35 { + margin-left: 35%; + } + + .suffix-35 { + margin-right: 35%; + } + + .push-35 { + left: 35%; + /* */ + *left: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-35 { + left: -35%; + /* */ + *left: expression(Math.floor(-0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-40 { + float: left; + width: 40%; + /* */ + *width: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-40 { + margin-left: 40%; + } + + .suffix-40 { + margin-right: 40%; + } + + .push-40 { + left: 40%; + /* */ + *left: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-40 { + left: -40%; + /* */ + *left: expression(Math.floor(-0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-45 { + float: left; + width: 45%; + /* */ + *width: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-45 { + margin-left: 45%; + } + + .suffix-45 { + margin-right: 45%; + } + + .push-45 { + left: 45%; + /* */ + *left: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-45 { + left: -45%; + /* */ + *left: expression(Math.floor(-0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-50 { + float: left; + width: 50%; + /* */ + *width: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-50 { + margin-left: 50%; + } + + .suffix-50 { + margin-right: 50%; + } + + .push-50 { + left: 50%; + /* */ + *left: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-50 { + left: -50%; + /* */ + *left: expression(Math.floor(-0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-55 { + float: left; + width: 55%; + /* */ + *width: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-55 { + margin-left: 55%; + } + + .suffix-55 { + margin-right: 55%; + } + + .push-55 { + left: 55%; + /* */ + *left: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-55 { + left: -55%; + /* */ + *left: expression(Math.floor(-0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-60 { + float: left; + width: 60%; + /* */ + *width: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-60 { + margin-left: 60%; + } + + .suffix-60 { + margin-right: 60%; + } + + .push-60 { + left: 60%; + /* */ + *left: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-60 { + left: -60%; + /* */ + *left: expression(Math.floor(-0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-65 { + float: left; + width: 65%; + /* */ + *width: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-65 { + margin-left: 65%; + } + + .suffix-65 { + margin-right: 65%; + } + + .push-65 { + left: 65%; + /* */ + *left: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-65 { + left: -65%; + /* */ + *left: expression(Math.floor(-0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-70 { + float: left; + width: 70%; + /* */ + *width: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-70 { + margin-left: 70%; + } + + .suffix-70 { + margin-right: 70%; + } + + .push-70 { + left: 70%; + /* */ + *left: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-70 { + left: -70%; + /* */ + *left: expression(Math.floor(-0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-75 { + float: left; + width: 75%; + /* */ + *width: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-75 { + margin-left: 75%; + } + + .suffix-75 { + margin-right: 75%; + } + + .push-75 { + left: 75%; + /* */ + *left: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-75 { + left: -75%; + /* */ + *left: expression(Math.floor(-0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-80 { + float: left; + width: 80%; + /* */ + *width: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-80 { + margin-left: 80%; + } + + .suffix-80 { + margin-right: 80%; + } + + .push-80 { + left: 80%; + /* */ + *left: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-80 { + left: -80%; + /* */ + *left: expression(Math.floor(-0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-85 { + float: left; + width: 85%; + /* */ + *width: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-85 { + margin-left: 85%; + } + + .suffix-85 { + margin-right: 85%; + } + + .push-85 { + left: 85%; + /* */ + *left: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-85 { + left: -85%; + /* */ + *left: expression(Math.floor(-0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-90 { + float: left; + width: 90%; + /* */ + *width: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-90 { + margin-left: 90%; + } + + .suffix-90 { + margin-right: 90%; + } + + .push-90 { + left: 90%; + /* */ + *left: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-90 { + left: -90%; + /* */ + *left: expression(Math.floor(-0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-95 { + float: left; + width: 95%; + /* */ + *width: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-95 { + margin-left: 95%; + } + + .suffix-95 { + margin-right: 95%; + } + + .push-95 { + left: 95%; + /* */ + *left: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-95 { + left: -95%; + /* */ + *left: expression(Math.floor(-0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-33 { + float: left; + width: 33.33333%; + /* */ + *width: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-33 { + margin-left: 33.33333%; + } + + .suffix-33 { + margin-right: 33.33333%; + } + + .push-33 { + left: 33.33333%; + /* */ + *left: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-33 { + left: -33.33333%; + /* */ + *left: expression(Math.floor(-0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-66 { + float: left; + width: 66.66667%; + /* */ + *width: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .prefix-66 { + margin-left: 66.66667%; + } + + .suffix-66 { + margin-right: 66.66667%; + } + + .push-66 { + left: 66.66667%; + /* */ + *left: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .pull-66 { + left: -66.66667%; + /* */ + *left: expression(Math.floor(-0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); + /* */ + } + + .grid-100 { + clear: both; + width: 100%; + } +} diff --git a/share/frontend/impattern/img/brush.png b/share/frontend/impattern/img/brush.png new file mode 100644 index 0000000..72fe926 Binary files /dev/null and b/share/frontend/impattern/img/brush.png differ diff --git a/share/frontend/impattern/img/eraser.png b/share/frontend/impattern/img/eraser.png new file mode 100644 index 0000000..564949e Binary files /dev/null and b/share/frontend/impattern/img/eraser.png differ diff --git a/share/frontend/impattern/img/impattern.png b/share/frontend/impattern/img/impattern.png new file mode 100644 index 0000000..0f33419 Binary files /dev/null and b/share/frontend/impattern/img/impattern.png differ diff --git a/share/frontend/impattern/img/loading.gif b/share/frontend/impattern/img/loading.gif new file mode 100644 index 0000000..207b5d5 Binary files /dev/null and b/share/frontend/impattern/img/loading.gif differ diff --git a/share/frontend/impattern/img/logo.gif b/share/frontend/impattern/img/logo.gif new file mode 100644 index 0000000..6cf5742 Binary files /dev/null and b/share/frontend/impattern/img/logo.gif differ diff --git a/share/frontend/impattern/impattern.html b/share/frontend/impattern/impattern.html new file mode 100644 index 0000000..bf26446 --- /dev/null +++ b/share/frontend/impattern/impattern.html @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  
+ +
+testing testing tesitng +
+ +
  +
+Image to overlay: + + + + + + + diff --git a/share/frontend/impattern/index.html b/share/frontend/impattern/index.html new file mode 100755 index 0000000..b26ded5 --- /dev/null +++ b/share/frontend/impattern/index.html @@ -0,0 +1,340 @@ + + + + + + + + + +imPattern + + + +
+ +
+ +
+
+
+
+
+
+ FIRST: Choose your pattern: +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  
+
+
+
+ OR: Create your Own pattern... +
+
+
+
+NEXT: Choose your image: +
+
+Image Url: +
+
+ Photoblaster Username (optional): + + +
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
CLOSE
+
+ +
+
Draw an image below. +
(Each square will be 1 sq. pixel)
+
+
+
+ + + + + + + +
+ COLUMNS +
+ ROWS +
+ +
+
Brush
+
Eraser
+
+ Show grid? + + +
+ +
+
Your Result:
+ + +
+
+
+ + + + + + + + + +
site by pepper...thanks to jules (http://asdf.us/ascii) and timb (superpaint...RIP)
+ + + diff --git a/share/frontend/impattern/js/display_result.js b/share/frontend/impattern/js/display_result.js new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/share/frontend/impattern/js/display_result.js @@ -0,0 +1 @@ + diff --git a/share/frontend/impattern/js/inputs.js b/share/frontend/impattern/js/inputs.js new file mode 100644 index 0000000..69cd2d3 --- /dev/null +++ b/share/frontend/impattern/js/inputs.js @@ -0,0 +1,26 @@ +$('.patterns').attr("current_pattern", ""); +$('.patterns').click(function(){ + window.custom_pattern = ""; + $('.patterns').css({'border-color':'gray', + '-moz-box-shadow': 'none', + '-webkit-box-shadow':'none', + 'box-shadow': 'none' + }); + $(this).css({'border-color':'#EE0000', + '-moz-box-shadow': '0px 0px 9px 3px firebrick', + '-webkit-box-shadow':'0px 0px 9px 3px firebrick', + 'box-shadow': '0px 0px 9px 3px firebrick' + }) + + selected_pattern = /url\((.+)\)$/.exec($(this).css("background-image"))[1]; + preview_controller.from_image(selected_pattern) + $('.patterns').attr("current_pattern", selected_pattern); + }); +$("input.image_input").attr("clicked", false); +$("input.image_input").click(function(){ + if(! $(this).clicked){ + $(this).attr("value", ""); + $(this).attr("clicked",true); + } +}) + diff --git a/share/frontend/impattern/js/jquery.min.js b/share/frontend/impattern/js/jquery.min.js new file mode 100644 index 0000000..b2ac174 --- /dev/null +++ b/share/frontend/impattern/js/jquery.min.js @@ -0,0 +1,18 @@ +/*! + * jQuery JavaScript Library v1.6.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu May 12 15:04:36 2011 -0400 + */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!cj[a]){var b=f("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),c.body.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write("");b=cl.createElement(a),cl.body.appendChild(b),d=f.css(b,"display"),c.body.removeChild(ck)}cj[a]=d}return cj[a]}function cu(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function ct(){cq=b}function cs(){setTimeout(ct,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g=0===c})}function W(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function O(a,b){return(a&&a!=="*"?a+".":"")+b.replace(A,"`").replace(B,"&")}function N(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function L(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function F(){return!0}function E(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function H(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(H,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=d.userAgent,x,y,z,A=Object.prototype.toString,B=Object.prototype.hasOwnProperty,C=Array.prototype.push,D=Array.prototype.slice,E=String.prototype.trim,F=Array.prototype.indexOf,G={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.1",length:0,size:function(){return this.length},toArray:function(){return D.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?C.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(D.apply(this,arguments),"slice",D.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:C,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!y){y=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",z,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",z),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&H()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):G[A.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!B.call(a,"constructor")&&!B.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||B.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};f=c.createElement("select"),g=f.appendChild(c.createElement("option")),h=a.getElementsByTagName("input")[0],j={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},h.checked=!0,j.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,j.optDisabled=!g.disabled;try{delete a.test}catch(s){j.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function b(){j.noCloneEvent=!1,a.detachEvent("onclick",b)}),a.cloneNode(!0).fireEvent("onclick")),h=c.createElement("input"),h.value="t",h.setAttribute("type","radio"),j.radioValue=h.value==="t",h.setAttribute("checked","checked"),a.appendChild(h),k=c.createDocumentFragment(),k.appendChild(a.firstChild),j.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",l=c.createElement("body"),m={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};for(q in m)l.style[q]=m[q];l.appendChild(a),b.insertBefore(l,b.firstChild),j.appendChecked=h.checked,j.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,j.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",j.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",n=a.getElementsByTagName("td"),r=n[0].offsetHeight===0,n[0].style.display="",n[1].style.display="none",j.reliableHiddenOffsets=r&&n[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(i=c.createElement("div"),i.style.width="0",i.style.marginRight="0",a.appendChild(i),j.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(i,null)||{marginRight:0}).marginRight,10)||0)===0),l.innerHTML="",b.removeChild(l);if(a.attachEvent)for(q in{submit:1,change:1,focusin:1})p="on"+q,r=p in a,r||(a.setAttribute(p,"return;"),r=typeof a[p]=="function"),j[q+"Bubbles"]=r;return j}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;return(e.value||"").replace(p,"")}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);c=j&&f.attrFix[c]||c,i=f.attrHooks[c],i||(!t.test(c)||typeof d!="boolean"&&d!==b&&d.toLowerCase()!==c.toLowerCase()?v&&(f.nodeName(a,"form")||u.test(c))&&(i=v):i=w);if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j)return i.get(a,c);h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}},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(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);c=i&&f.propFix[c]||c,h=f.propHooks[c];return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return a[f.propFix[c]||c]?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=b),a.setAttribute(c,c.toLowerCase()));return c}},f.attrHooks.value={get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return a.value},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=Object.prototype.hasOwnProperty,y=/\.(.*)$/,z=/^(?:textarea|input|select)$/i,A=/\./g,B=/ /g,C=/[^\w\s.|`]/g,D=function(a){return a.replace(C,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=E;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=E);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),D).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem +)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},K=function(c){var d=c.target,e,g;if(!!z.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=J(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:K,beforedeactivate:K,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&K.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&K.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",J(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in I)f.event.add(this,c+".specialChange",I[c]);return z.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return z.test(this.nodeName)}},I=f.event.special.change.filters,I.focus=I.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=U.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(W(c[0])||W(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=T.call(arguments);P.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!V[a]?f.unique(e):e,(this.length>1||R.test(d))&&Q.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y=/ jQuery\d+="(?:\d+|null)"/g,Z=/^\s+/,$=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,_=/<([\w:]+)/,ba=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument|| +b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/)<[^<]*)*<\/script>/gi,bP=/^(?:select|textarea)/i,bQ=/\s+/,bR=/([?&])_=[^&]*/,bS=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bT=f.fn.load,bU={},bV={},bW,bX;try{bW=e.href}catch(bY){bW=c.createElement("a"),bW.href="",bW=bW.href}bX=bS.exec(bW.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bT)return bT.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bO,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bP.test(this.nodeName)||bJ.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bG,"\r\n")}}):{name:b.name,value:c.replace(bG,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bW,isLocal:bK.test(bX[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bZ(bU),ajaxTransport:bZ(bV),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?ca(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=cb(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bI.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bH,"").replace(bM,bX[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bQ),d.crossDomain==null&&(r=bS.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bX[1]&&r[2]==bX[2]&&(r[3]||(r[1]==="http:"?80:443))==(bX[3]||(bX[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bU,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bL.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bN.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bR,"$1_="+x);d.url=y+(y===d.url?(bN.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bV,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bE,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq,cr=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){return this[0]?parseFloat(f.css(this[0],d,"padding")):null},f.fn["outer"+c]=function(a){return this[0]?parseFloat(f.css(this[0],d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/share/frontend/impattern/js/overlay.js b/share/frontend/impattern/js/overlay.js new file mode 100644 index 0000000..49a70d1 --- /dev/null +++ b/share/frontend/impattern/js/overlay.js @@ -0,0 +1,19 @@ +$("#overlay > .close").click(function(){ + $("#overlay").hide(); +}); +$('document').ready(function(){ + $("#overlay").click( function(){ + if( event.target == this ){ + $("#overlay").hide(); + return false; + } + }); +}) +function show_finished_image(image_url){ + $("#overlay").show(); + $("#draw_protector").hide(); + $('#final_image > img').attr("src", image_url); + $('#links > input').attr("value", image_url); + $("#final_image").show(); +} + diff --git a/share/frontend/impattern/js/preview.js b/share/frontend/impattern/js/preview.js new file mode 100644 index 0000000..0800308 --- /dev/null +++ b/share/frontend/impattern/js/preview.js @@ -0,0 +1,47 @@ +function Preview(){ + var that = this; + this.preview_div = document.querySelectorAll('#sample')[0]; +// this.canvas = document.querySelectorAll('canvas')[0] +// this.ctx = this.canvas.getContext('2d'); + this.pat = "" + this._fill_preview = function(pat){ + this.preview_div.style.background = 'url('+pat+')' + } +//{{{ +// this._fill_preview = function(pat){ +// that.ctx.fillStyle = that.ctx.createPattern(pat, "repeat") +// that.ctx.fillRect( +// 0, 0, +// that.canvas.width, +// that.canvas.height +// ) +// } +// }}} + this.from_matrix = function(data){ + var pat = document.createElement("canvas"); + pat.height = data.height + pat.width = data.width + var pat_ctx = pat.getContext('2d') + for (var h = 0; h< data.height; h++){ + for (var i = 0; i < data.width; i++){ + if (parseInt(data.matrix[h][i])){ + pat_ctx.fillRect(i, h, 1, 1) + }else{ + pat_ctx.clearRect(i, h, 1, 1) + } + } + } + + that._fill_preview(pat.toDataURL()) + } + this.from_image = function(url){ + var pat = document.createElement("img"); + pat.src = url + pat.onload = function(){ + that._fill_preview(pat.src) + } + } +} +$(document).ready(function(){ + window.preview_controller = new Preview() +}) diff --git a/share/frontend/impattern/js/sketch.js b/share/frontend/impattern/js/sketch.js new file mode 100644 index 0000000..ec78489 --- /dev/null +++ b/share/frontend/impattern/js/sketch.js @@ -0,0 +1,219 @@ +//dragging event + +var COLUMNS_MAX = 20; +var ROWS_MAX = 20; +var isDragging = false; +$("body").mousedown(function() { + $(window).mousemove(function() { + isDragging = true; + $(window).unbind("mousemove"); + }); +}).mouseup(function() { + var wasDragging = isDragging; + isDragging = false; + $(window).unbind("mousemove"); + if (!wasDragging) { //was clicking + } +}); + +var c; + +window.active_tool = "brush"; +var brush_tools; + + + +function BrushTools(){ + var brushtools = this; + this.brush = $("#brush"); + this.eraser = $("#eraser"); + this.brush_tools = $(".brush_tools"); + this.active_css = { + "border" : "1px solid black", + "background" : "gray", + "color" : "white", + }, + this.inactive_css = { + "border" : "1px solid gray", + "background" : "whitesmoke", + "color" : "black", + }; + this.activate = function(elem){ + $(elem).css(this.active_css); + window.active_tool = $(elem).attr("id"); + }; + this.deactivate = function(elem){ + $(elem).css(this.inactive_css); + }; +// this.cursors = { +// "brush" : "img/brush.png", +// "eraser" : "img/eraser.png", +// }; + this.brush_tools.click(function(){ + var that = this; + window.active_tool = $(this).attr("id"); + brushtools.activate(that); + brushtools.brush_tools.each(function(){ + if(this != that){ + brushtools.deactivate(this); + } + }); +// $("#canvas_wrapper").css( +// "cursor" , "url("+brushtools.cursors[window.active_tool]+")" +// ) + }); +} + + + + +function GridCanvas(){ + var gridcanvas = this; + this.rows = 10; + this.cols = 10; + this.current_rows = []; + this.container = $("#canvas_wrapper"); + this.paint = function(elem){ + $(elem).attr("painted", "1"); + $(elem).css("background", "black"); + }; + this.erase = function(elem){ + $(elem).attr("painted", "0"); + $(elem).css("background", "white"); + }; + this.initialize = function(cols, rows){ + this.container.html(""); + this.rows = (rows > 0) ? rows : 1; + this.cols = (cols > 0) ? cols : 1; + if (this.rows > ROWS_MAX){ + this.rows = ROWS_MAX; + } + if (this.cols > COLUMNS_MAX){ + this.cols = COLUMNS_MAX; + } + this.cols = cols; + for (var i = 0; i< this.rows; i++){ + var row = document.createElement("div"); + $(row).attr("id", "row_"+i) + $(row).addClass("canvas_row") + for (var j = 0; j< this.cols; j++){ + var cell = document.createElement("span"); + $(cell).addClass("canvas_cell") + $(cell).attr("painted", "0") + $(cell).addClass("column_"+j) + $(cell).html(" ") + $(cell).click(function(){ + if (window.active_tool == 'brush'){ + gridcanvas.paint(this); + }else if(window.active_tool == 'eraser'){ + gridcanvas.erase(this); + } + }); + $(cell).mouseover(function(){ + if (isDragging){ + if (window.active_tool == 'brush'){ + gridcanvas.paint(this); + }else if(window.active_tool == 'eraser'){ + gridcanvas.erase(this); + } + } + }); + $(row).append(cell) + } + this.container.append(row) + } + } + this.toggleGrid = function(){ + if ($("#show_grid").prop("checked")){ + $(".canvas_cell").css("border","1px solid silver"); + }else{ + $(".canvas_cell").css("border","none"); + } + } + this.serialize = function(){ + var matrix = []; + for (var i = 0; i < this.rows; i++){ + var row_storage = []; + $("#row_"+i+"> span").each(function(){ + row_storage.push($(this).attr("painted")); + }); + matrix.push(row_storage); + } + return { + "matrix" : matrix, + "width" : this.cols, + "height" : this.rows, + } + } +} +$("#cols").change(function(){ + var cols = $(this).val() + c.initialize(cols, c.rows); +}); +$("#rows").change(function(){ + var rows = $(this).val() + c.initialize(c.cols, rows); +}); + +$('document').ready(function(){ + $("#create_your_own").click(function(){ + event.preventDefault(); + + $("#draw_protector").show(); + $("#overlay > .close").html("CANCEL"); + $("#overlay").show(); + $("#draw").show(); + $("#final_image").hide(); + }); + $("#overlay > .close").click(function(){ + $("#draw").hide(); + }); + + c = new GridCanvas() + brush_tools = new BrushTools(); + c.initialize($("#cols").val(), $("#rows").val()); + $("#show_grid").change(function(){ + c.toggleGrid(); + }); + $("#drawing_finished").click(function(){ + + window.custom_pattern = c.serialize(); + preview_controller.from_matrix(window.custom_pattern) + $('.patterns').attr("current_pattern", ""); + $('#drawing_finished').prop("disabled", false); + $('#drawing_finished').html("DONE"); + $("#draw_protector").css("background", "none"); + $("#draw").hide(); + $("#overlay").hide(); + console.log(window.custom_pattern) + }); + +}); +window.custom_pattern = ""; + +$('#drawing_finished').click(function(){ +// $("#draw_protector").css("background", "url(img/loading.gif)"); +// $(this).prop("disabled", true); +// $(this).html("Workin'..."); +// $.ajax({ +// type: "POST", +// url: NEW_PATTERN_URL, +// data: { json : JSON.stringify(c.serialize()) }, +// }).done(function( msg ) { +// $('#drawing_finished').prop("disabled", false); +// $('#drawing_finished').html("DONE"); +// $("#draw_protector").css("background", "none"); +// var error = msg.match(/ERR/ig); +// if (error){ +// alert( "There was an error processing your request "); +// return +// } +// $("#draw").hide(); +// $("#overlay").hide(); +// var parts = msg.split("\n") +// window.custom_pattern = "http://i.asdf.us/patterns/"+parts[0] +// $('#sample').css("background", "url("+window.custom_pattern+")"); +// }) + +}); + diff --git a/share/frontend/impattern/js/urls.js b/share/frontend/impattern/js/urls.js new file mode 100644 index 0000000..3ba94ce --- /dev/null +++ b/share/frontend/impattern/js/urls.js @@ -0,0 +1,3 @@ +var PROCESS_URL = '/im/api/impattern' +//var PATTERNS_URL = '/cgi-bin/im/getpatterns' +//var NEW_PATTERN_URL = '/cgi-bin/im/newpattern' diff --git a/share/frontend/impattern/js/username.js b/share/frontend/impattern/js/username.js new file mode 100644 index 0000000..eb89ed0 --- /dev/null +++ b/share/frontend/impattern/js/username.js @@ -0,0 +1,30 @@ +$(document).ready(function(){ + var name = get_name_from_cookie() + $("#username").val(name) +}); + +function get_name_from_cookie() + { + if (document.cookie) + { + var cookies = document.cookie.split(";") + for (i in cookies) + { + var cookie = cookies[i].split("=") + if (cookie[0].indexOf("imname") !== -1) + { + if (cookie[1] !== 'false' && cookie[1] !== 'undefined' && cookie[1].length) + { + return cookie[1] + } + } + } + } + return "" +}; + +function update_username(username){ + if (username.length > 0){ + document.cookie = "imname="+username+";path=/;domain=.asdf.us;max-age=1086400" + } +} diff --git a/share/frontend/impattern/makePattern.py b/share/frontend/impattern/makePattern.py new file mode 100755 index 0000000..98d298b --- /dev/null +++ b/share/frontend/impattern/makePattern.py @@ -0,0 +1,111 @@ +#!/usr/bin/python2.7 + +import sys +import cgi +from os import getpid, path +from subprocess import call, Popen, PIPE +import time + +MAIN_DIRECTORY = "" +BIN_CONVERT = "convert" +BIN_IDENTIFY = "identify" +BIN_COMPOSITE = "composite" +ACCEPTABLE_FILE_TYPES = [".png", ".jpg", ".gif", ".jpeg"] + +def usage(): + sys.stderr.write("$>makePattern.py [ input_file ] [ pattern_file ] [ username ]"); + +def now(): + return str(int(time.time())) + +def image_dimensions_and_test(filename): + ident = Popen([BIN_IDENTIFY, filename], stdout=PIPE).communicate()[0] + partz = ident.split(" ") + filetype = "."+partz[1] + size = partz[6] + if filetype.lower() not in ACCEPTABLE_FILE_TYPES: + error("file was not an image") + return partz[2].split("x") + +def error(s): + " returns an error and exits the program " + print("ERROR: "+s) + exit(1) + +def hexdir(filename): + " creates a two-letter directory name " + return sha1(filename.encode()).hexdigest()[:2] +#repage command convert original.png -resize 425x92 -repage 425x92+0+0 new.png + +class Pattern: + + def __init__(self): + self.nametag = "imPattern"; + self.pid = str(getpid()) + self.pattern_file = ""; + self.original_file = ""; + self.username = ""; + self.commands = []; + + def makeResultFilename(self): + file_base, extension = path.splitext(self.original_file) + if len(file_base) > self.MAX_NAME_LENGTH: + file_base = file_base[0:self.MAX_NAME_LENGTH] + return "%s_%s_%s%s%s" % (file_base, self.username, self.nametag, now(), extension) + + #first step + def makeCanvas(self): + call([BIN_CONVERT,"-size",self.dimensions[0]+"x"+self.dimensions[1],"canvas:transparent", self.canvas_file]) + + #second step use the Canvas as a background + def makeMask(self): + #tile the pattern pattern on the canvas + command = [BIN_COMPOSITE,"-tile", self.pattern_file, self.canvas_file, self.mask_file]; + call(command) + self.commands.append(command) + #fuse the tiled file to create a mask + #convert thebg.gif -compose Dst_In null: thefile.gif -matte -layers composite new.gif + command = [BIN_CONVERT, self.mask_file, "-compose", "Dst_In", "null:", self.original_file, "-matte", "-layers", "composite", self.mask_file] + call(command) + + #cleanup + call(["rm", self.canvas_file]) + + #third step + def fuseMask(self, fuse_mode="Pin_Light"): + call([BIN_CONVERT, self.mask_file, "null:", self.original_file, "-matte", "-compose", fuse_mode, "-layers", "composite", self.result_file]) + call(["rm", self.mask_file]) + + def main(self, input_file_path, pattern_file, username=""): + self.pattern_file = pattern_file; + self.original_file = input_file_path; + self.username = username; + self.MAX_NAME_LENGTH = 10; + + self.image_format = self.original_file.split(".")[-1] + self.dimensions = "" + try: + self.dimensions = image_dimensions_and_test(self.original_file); + except Exception as e: + sys.stderr.write(str(e)); + error("Unable to determine dimensions") + self.canvas_file = self.pid+"blank_canvas.png"; + self.makeCanvas(); + self.mask_file = self.pid+"mask_file"+"."+self.image_format; + self.makeMask(); + self.result_file = self.makeResultFilename(); + self.fuseMask(); + +if __name__ == "__main__": + p = Pattern(); + if len(sys.argv) < 2 or len(sys.argv) > 3: + usage(); + sys.exit(0); + input_file_path = sys.argv[1] + pattern_file = sys.argv[2] + username = ""; +# username = sys.argv[3] + print input_file_path; + print pattern_file; + print username; + p.main(input_file_path, pattern_file, username); diff --git a/share/frontend/impattern/myjson.json b/share/frontend/impattern/myjson.json new file mode 100644 index 0000000..ac685e7 --- /dev/null +++ b/share/frontend/impattern/myjson.json @@ -0,0 +1 @@ +{"matrix":[["0","0","0","0","0","0","0","0","0","0"],["0","0","0","1","1","0","0","0","0","0"],["0","0","1","1","0","0","0","0","0","0"],["0","0","1","1","1","1","0","0","0","0"],["0","1","1","0","0","0","0","0","0","0"],["1","0","0","0","0","0","0","0","0","0"],["1","1","1","1","1","1","1","1","1","1"],["0","0","0","0","0","1","1","0","0","1"],["0","0","0","0","0","0","1","0","1","1"],["0","0","0","0","0","0","0","1","1","0"]],"width":"10","height":"10"} diff --git a/share/frontend/impattern/newimagefromjson.py b/share/frontend/impattern/newimagefromjson.py new file mode 100644 index 0000000..5f62bd1 --- /dev/null +++ b/share/frontend/impattern/newimagefromjson.py @@ -0,0 +1,26 @@ +#!/usr/bin/python2.7 +import simplejson as json +from PIL import Image +import sys + +f = open("myjson.json", 'r'); +myjson = f.read(); +f.close(); + +specs = json.loads(myjson); +img = Image.new('RGBA', (int(specs['width']), int(specs['height']))); + +def boolToColor(boolean): + if boolean: + return (0,0,0,255); + else: + return (255,255,255,0) + +pixels = img.load(); +#for i in range(0, 9, 2): +# dosomething(i) +for i in range(0, len(specs['matrix'])): + for j in range(0, len(specs['matrix'][i])): + pixels[j,i] = boolToColor(int(specs['matrix'][i][j])); + +img.save("myimage.png", "PNG") diff --git a/share/frontend/impattern/old/bottle.py b/share/frontend/impattern/old/bottle.py new file mode 100644 index 0000000..40a858d --- /dev/null +++ b/share/frontend/impattern/old/bottle.py @@ -0,0 +1,3605 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Bottle is a fast and simple micro-framework for small web applications. It +offers request dispatching (Routes) with url parameter support, templates, +a built-in HTTP Server and adapters for many third party WSGI/HTTP-server and +template engines - all in a single file and with no dependencies other than the +Python Standard Library. + +Homepage and documentation: http://bottlepy.org/ + +Copyright (c) 2012, Marcel Hellkamp. +License: MIT (see LICENSE for details) +""" + +from __future__ import with_statement + +__author__ = 'Marcel Hellkamp' +__version__ = '0.12-dev' +__license__ = 'MIT' + +# The gevent server adapter needs to patch some modules before they are imported +# This is why we parse the commandline parameters here but handle them later +if __name__ == '__main__': + from optparse import OptionParser + _cmd_parser = OptionParser(usage="usage: %prog [options] package.module:app") + _opt = _cmd_parser.add_option + _opt("--version", action="store_true", help="show version number.") + _opt("-b", "--bind", metavar="ADDRESS", help="bind socket to ADDRESS.") + _opt("-s", "--server", default='wsgiref', help="use SERVER as backend.") + _opt("-p", "--plugin", action="append", help="install additional plugin/s.") + _opt("--debug", action="store_true", help="start server in debug mode.") + _opt("--reload", action="store_true", help="auto-reload on file changes.") + _cmd_options, _cmd_args = _cmd_parser.parse_args() + if _cmd_options.server and _cmd_options.server.startswith('gevent'): + import gevent.monkey; gevent.monkey.patch_all() + +import base64, cgi, email.utils, functools, hmac, imp, itertools, mimetypes,\ + os, re, subprocess, sys, tempfile, threading, time, warnings + +from datetime import date as datedate, datetime, timedelta +from tempfile import TemporaryFile +from traceback import format_exc, print_exc +from inspect import getargspec + +try: from simplejson import dumps as json_dumps, loads as json_lds +except ImportError: # pragma: no cover + try: from json import dumps as json_dumps, loads as json_lds + except ImportError: + try: from django.utils.simplejson import dumps as json_dumps, loads as json_lds + except ImportError: + def json_dumps(data): + raise ImportError("JSON support requires Python 2.6 or simplejson.") + json_lds = json_dumps + + + +# We now try to fix 2.5/2.6/3.1/3.2 incompatibilities. +# It ain't pretty but it works... Sorry for the mess. + +py = sys.version_info +py3k = py >= (3, 0, 0) +py25 = py < (2, 6, 0) +py31 = (3, 1, 0) <= py < (3, 2, 0) + +# Workaround for the missing "as" keyword in py3k. +def _e(): return sys.exc_info()[1] + +# Workaround for the "print is a keyword/function" Python 2/3 dilemma +# and a fallback for mod_wsgi (resticts stdout/err attribute access) +try: + _stdout, _stderr = sys.stdout.write, sys.stderr.write +except IOError: + _stdout = lambda x: sys.stdout.write(x) + _stderr = lambda x: sys.stderr.write(x) + +# Lots of stdlib and builtin differences. +if py3k: + import http.client as httplib + import _thread as thread + from urllib.parse import urljoin, SplitResult as UrlSplitResult + from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote + urlunquote = functools.partial(urlunquote, encoding='latin1') + from http.cookies import SimpleCookie + from collections import MutableMapping as DictMixin + import pickle + from io import BytesIO + from configparser import ConfigParser + basestring = str + unicode = str + json_loads = lambda s: json_lds(touni(s)) + callable = lambda x: hasattr(x, '__call__') + imap = map + def _raise(*a): raise a[0](a[1]).with_traceback(a[2]) +else: # 2.x + import httplib + import thread + from urlparse import urljoin, SplitResult as UrlSplitResult + from urllib import urlencode, quote as urlquote, unquote as urlunquote + from Cookie import SimpleCookie + from itertools import imap + import cPickle as pickle + from StringIO import StringIO as BytesIO + from ConfigParser import SafeConfigParser as ConfigParser + if py25: + msg = "Python 2.5 support may be dropped in future versions of Bottle." + warnings.warn(msg, DeprecationWarning) + from UserDict import DictMixin + def next(it): return it.next() + bytes = str + else: # 2.6, 2.7 + from collections import MutableMapping as DictMixin + json_loads = json_lds + eval(compile('def _raise(*a): raise a[0], a[1], a[2]', '', 'exec')) + +# Some helpers for string/byte handling +def tob(s, enc='utf8'): + return s.encode(enc) if isinstance(s, unicode) else bytes(s) +def touni(s, enc='utf8', err='strict'): + return s.decode(enc, err) if isinstance(s, bytes) else unicode(s) +tonat = touni if py3k else tob + +# 3.2 fixes cgi.FieldStorage to accept bytes (which makes a lot of sense). +# 3.1 needs a workaround. +if py31: + from io import TextIOWrapper + class NCTextIOWrapper(TextIOWrapper): + def close(self): pass # Keep wrapped buffer open. + + +# A bug in functools causes it to break if the wrapper is an instance method +def update_wrapper(wrapper, wrapped, *a, **ka): + try: functools.update_wrapper(wrapper, wrapped, *a, **ka) + except AttributeError: pass + + + +# These helpers are used at module level and need to be defined first. +# And yes, I know PEP-8, but sometimes a lower-case classname makes more sense. + +def depr(message, hard=False): + warnings.warn(message, DeprecationWarning, stacklevel=3) + +def makelist(data): # This is just to handy + if isinstance(data, (tuple, list, set, dict)): return list(data) + elif data: return [data] + else: return [] + + +class DictProperty(object): + ''' Property that maps to a key in a local dict-like attribute. ''' + def __init__(self, attr, key=None, read_only=False): + self.attr, self.key, self.read_only = attr, key, read_only + + def __call__(self, func): + functools.update_wrapper(self, func, updated=[]) + self.getter, self.key = func, self.key or func.__name__ + return self + + def __get__(self, obj, cls): + if obj is None: return self + key, storage = self.key, getattr(obj, self.attr) + if key not in storage: storage[key] = self.getter(obj) + return storage[key] + + def __set__(self, obj, value): + if self.read_only: raise AttributeError("Read-Only property.") + getattr(obj, self.attr)[self.key] = value + + def __delete__(self, obj): + if self.read_only: raise AttributeError("Read-Only property.") + del getattr(obj, self.attr)[self.key] + + +class cached_property(object): + ''' A property that is only computed once per instance and then replaces + itself with an ordinary attribute. Deleting the attribute resets the + property. ''' + + def __init__(self, func): + self.__doc__ = getattr(func, '__doc__') + self.func = func + + def __get__(self, obj, cls): + if obj is None: return self + value = obj.__dict__[self.func.__name__] = self.func(obj) + return value + + +class lazy_attribute(object): + ''' A property that caches itself to the class object. ''' + def __init__(self, func): + functools.update_wrapper(self, func, updated=[]) + self.getter = func + + def __get__(self, obj, cls): + value = self.getter(cls) + setattr(cls, self.__name__, value) + return value + + + + + + +############################################################################### +# Exceptions and Events ######################################################## +############################################################################### + + +class BottleException(Exception): + """ A base class for exceptions used by bottle. """ + pass + + + + + + +############################################################################### +# Routing ###################################################################### +############################################################################### + + +class RouteError(BottleException): + """ This is a base class for all routing related exceptions """ + + +class RouteReset(BottleException): + """ If raised by a plugin or request handler, the route is reset and all + plugins are re-applied. """ + +class RouterUnknownModeError(RouteError): pass + + +class RouteSyntaxError(RouteError): + """ The route parser found something not supported by this router. """ + + +class RouteBuildError(RouteError): + """ The route could not be built. """ + + +def _re_flatten(p): + ''' Turn all capturing groups in a regular expression pattern into + non-capturing groups. ''' + if '(' not in p: return p + return re.sub(r'(\\*)(\(\?P<[^>]+>|\((?!\?))', + lambda m: m.group(0) if len(m.group(1)) % 2 else m.group(1) + '(?:', p) + + +class Router(object): + ''' A Router is an ordered collection of route->target pairs. It is used to + efficiently match WSGI requests against a number of routes and return + the first target that satisfies the request. The target may be anything, + usually a string, ID or callable object. A route consists of a path-rule + and a HTTP method. + + The path-rule is either a static path (e.g. `/contact`) or a dynamic + path that contains wildcards (e.g. `/wiki/`). The wildcard syntax + and details on the matching order are described in docs:`routing`. + ''' + + default_pattern = '[^/]+' + default_filter = 're' + + #: The current CPython regexp implementation does not allow more + #: than 99 matching groups per regular expression. + _MAX_GROUPS_PER_PATTERN = 99 + + def __init__(self, strict=False): + self.rules = [] # All rules in order + self._groups = {} # index of regexes to find them in dyna_routes + self.builder = {} # Data structure for the url builder + self.static = {} # Search structure for static routes + self.dyna_routes = {} + self.dyna_regexes = {} # Search structure for dynamic routes + #: If true, static routes are no longer checked first. + self.strict_order = strict + self.filters = { + 're': lambda conf: + (_re_flatten(conf or self.default_pattern), None, None), + 'int': lambda conf: (r'-?\d+', int, lambda x: str(int(x))), + 'float': lambda conf: (r'-?[\d.]+', float, lambda x: str(float(x))), + 'path': lambda conf: (r'.+?', None, None)} + + def add_filter(self, name, func): + ''' Add a filter. The provided function is called with the configuration + string as parameter and must return a (regexp, to_python, to_url) tuple. + The first element is a string, the last two are callables or None. ''' + self.filters[name] = func + + rule_syntax = re.compile('(\\\\*)'\ + '(?:(?::([a-zA-Z_][a-zA-Z_0-9]*)?()(?:#(.*?)#)?)'\ + '|(?:<([a-zA-Z_][a-zA-Z_0-9]*)?(?::([a-zA-Z_]*)'\ + '(?::((?:\\\\.|[^\\\\>]+)+)?)?)?>))') + + def _itertokens(self, rule): + offset, prefix = 0, '' + for match in self.rule_syntax.finditer(rule): + prefix += rule[offset:match.start()] + g = match.groups() + if len(g[0])%2: # Escaped wildcard + prefix += match.group(0)[len(g[0]):] + offset = match.end() + continue + if prefix: + yield prefix, None, None + name, filtr, conf = g[4:7] if g[2] is None else g[1:4] + yield name, filtr or 'default', conf or None + offset, prefix = match.end(), '' + if offset <= len(rule) or prefix: + yield prefix+rule[offset:], None, None + + def add(self, rule, method, target, name=None): + ''' Add a new rule or replace the target for an existing rule. ''' + anons = 0 # Number of anonymous wildcards found + keys = [] # Names of keys + pattern = '' # Regular expression pattern with named groups + filters = [] # Lists of wildcard input filters + builder = [] # Data structure for the URL builder + is_static = True + + for key, mode, conf in self._itertokens(rule): + if mode: + is_static = False + if mode == 'default': mode = self.default_filter + mask, in_filter, out_filter = self.filters[mode](conf) + if not key: + pattern += '(?:%s)' % mask + key = 'anon%d' % anons + anons += 1 + else: + pattern += '(?P<%s>%s)' % (key, mask) + keys.append(key) + if in_filter: filters.append((key, in_filter)) + builder.append((key, out_filter or str)) + elif key: + pattern += re.escape(key) + builder.append((None, key)) + + self.builder[rule] = builder + if name: self.builder[name] = builder + + if is_static and not self.strict_order: + self.static.setdefault(method, {}) + self.static[method][self.build(rule)] = (target, None) + return + + try: + re_pattern = re.compile('^(%s)$' % pattern) + re_match = re_pattern.match + except re.error: + raise RouteSyntaxError("Could not add Route: %s (%s)" % (rule, _e())) + + if filters: + def getargs(path): + url_args = re_match(path).groupdict() + for name, wildcard_filter in filters: + try: + url_args[name] = wildcard_filter(url_args[name]) + except ValueError: + raise HTTPError(400, 'Path has wrong format.') + return url_args + elif re_pattern.groupindex: + def getargs(path): + return re_match(path).groupdict() + else: + getargs = None + + flatpat = _re_flatten(pattern) + whole_rule = (rule, flatpat, target, getargs) + + if (flatpat, method) in self._groups: + if DEBUG: + msg = 'Route <%s %s> overwrites a previously defined route' + warnings.warn(msg % (method, rule), RuntimeWarning) + self.dyna_routes[method][self._groups[flatpat, method]] = whole_rule + else: + self.dyna_routes.setdefault(method, []).append(whole_rule) + self._groups[flatpat, method] = len(self.dyna_routes[method]) - 1 + + self._compile(method) + + def _compile(self, method): + all_rules = self.dyna_routes[method] + comborules = self.dyna_regexes[method] = [] + maxgroups = self._MAX_GROUPS_PER_PATTERN + for x in range(0, len(all_rules), maxgroups): + some = all_rules[x:x+maxgroups] + combined = (flatpat for (_, flatpat, _, _) in some) + combined = '|'.join('(^%s$)' % flatpat for flatpat in combined) + combined = re.compile(combined).match + rules = [(target, getargs) for (_, _, target, getargs) in some] + comborules.append((combined, rules)) + + def build(self, _name, *anons, **query): + ''' Build an URL by filling the wildcards in a rule. ''' + builder = self.builder.get(_name) + if not builder: raise RouteBuildError("No route with that name.", _name) + try: + for i, value in enumerate(anons): query['anon%d'%i] = value + url = ''.join([f(query.pop(n)) if n else f for (n,f) in builder]) + return url if not query else url+'?'+urlencode(query) + except KeyError: + raise RouteBuildError('Missing URL argument: %r' % _e().args[0]) + + def match(self, environ): + ''' Return a (target, url_agrs) tuple or raise HTTPError(400/404/405). ''' + verb = environ['REQUEST_METHOD'].upper() + path = environ['PATH_INFO'] or '/' + target = None + methods = [verb, 'GET', 'ANY'] if verb == 'HEAD' else [verb, 'ANY'] + + for method in methods: + if method in self.static and path in self.static[method]: + target, getargs = self.static[method][path] + return target, getargs(path) if getargs else {} + elif method in self.dyna_regexes: + for combined, rules in self.dyna_regexes[method]: + match = combined(path) + if match: + target, getargs = rules[match.lastindex - 1] + return target, getargs(path) if getargs else {} + + # No matching route found. Collect alternative methods for 405 response + allowed = set([]) + nocheck = set(methods) + for method in set(self.static) - nocheck: + if path in self.static[method]: + allowed.add(verb) + for method in set(self.dyna_regexes) - allowed - nocheck: + for combined, rules in self.dyna_regexes[method]: + match = combined(path) + if match: + allowed.add(method) + if allowed: + allow_header = ",".join(sorted(allowed)) + raise HTTPError(405, "Method not allowed.", Allow=allow_header) + + # No matching route and no alternative method found. We give up + raise HTTPError(404, "Not found: " + repr(path)) + + + + + + +class Route(object): + ''' This class wraps a route callback along with route specific metadata and + configuration and applies Plugins on demand. It is also responsible for + turing an URL path rule into a regular expression usable by the Router. + ''' + + def __init__(self, app, rule, method, callback, name=None, + plugins=None, skiplist=None, **config): + #: The application this route is installed to. + self.app = app + #: The path-rule string (e.g. ``/wiki/:page``). + self.rule = rule + #: The HTTP method as a string (e.g. ``GET``). + self.method = method + #: The original callback with no plugins applied. Useful for introspection. + self.callback = callback + #: The name of the route (if specified) or ``None``. + self.name = name or None + #: A list of route-specific plugins (see :meth:`Bottle.route`). + self.plugins = plugins or [] + #: A list of plugins to not apply to this route (see :meth:`Bottle.route`). + self.skiplist = skiplist or [] + #: Additional keyword arguments passed to the :meth:`Bottle.route` + #: decorator are stored in this dictionary. Used for route-specific + #: plugin configuration and meta-data. + self.config = ConfigDict().load_dict(config) + + def __call__(self, *a, **ka): + depr("Some APIs changed to return Route() instances instead of"\ + " callables. Make sure to use the Route.call method and not to"\ + " call Route instances directly.") + return self.call(*a, **ka) + + @cached_property + def call(self): + ''' The route callback with all plugins applied. This property is + created on demand and then cached to speed up subsequent requests.''' + return self._make_callback() + + def reset(self): + ''' Forget any cached values. The next time :attr:`call` is accessed, + all plugins are re-applied. ''' + self.__dict__.pop('call', None) + + def prepare(self): + ''' Do all on-demand work immediately (useful for debugging).''' + self.call + + @property + def _context(self): + depr('Switch to Plugin API v2 and access the Route object directly.') + return dict(rule=self.rule, method=self.method, callback=self.callback, + name=self.name, app=self.app, config=self.config, + apply=self.plugins, skip=self.skiplist) + + def all_plugins(self): + ''' Yield all Plugins affecting this route. ''' + unique = set() + for p in reversed(self.app.plugins + self.plugins): + if True in self.skiplist: break + name = getattr(p, 'name', False) + if name and (name in self.skiplist or name in unique): continue + if p in self.skiplist or type(p) in self.skiplist: continue + if name: unique.add(name) + yield p + + def _make_callback(self): + callback = self.callback + for plugin in self.all_plugins(): + try: + if hasattr(plugin, 'apply'): + api = getattr(plugin, 'api', 1) + context = self if api > 1 else self._context + callback = plugin.apply(callback, context) + else: + callback = plugin(callback) + except RouteReset: # Try again with changed configuration. + return self._make_callback() + if not callback is self.callback: + update_wrapper(callback, self.callback) + return callback + + def get_undecorated_callback(self): + ''' Return the callback. If the callback is a decorated function, try to + recover the original function. ''' + func = self.callback + func = getattr(func, '__func__' if py3k else 'im_func', func) + closure_attr = '__closure__' if py3k else 'func_closure' + while hasattr(func, closure_attr) and getattr(func, closure_attr): + func = getattr(func, closure_attr)[0].cell_contents + return func + + def get_callback_args(self): + ''' Return a list of argument names the callback (most likely) accepts + as keyword arguments. If the callback is a decorated function, try + to recover the original function before inspection. ''' + return getargspec(self.get_undecorated_callback())[0] + + def get_config(key, default=None): + ''' Lookup a config field and return its value, first checking the + route.config, then route.app.config.''' + for conf in (self.config, self.app.conifg): + if key in conf: return conf[key] + return default + + def __repr__(self): + cb = self.get_undecorated_callback() + return '<%s %r %r>' % (self.method, self.rule, cb) + + + + + + +############################################################################### +# Application Object ########################################################### +############################################################################### + + +class Bottle(object): + """ Each Bottle object represents a single, distinct web application and + consists of routes, callbacks, plugins, resources and configuration. + Instances are callable WSGI applications. + + :param catchall: If true (default), handle all exceptions. Turn off to + let debugging middleware handle exceptions. + """ + + def __init__(self, catchall=True, autojson=True): + + #: A :class:`ConfigDict` for app specific configuration. + self.config = ConfigDict() + self.config._on_change = functools.partial(self.trigger_hook, 'config') + self.config.meta_set('autojson', 'validate', bool) + self.config.meta_set('catchall', 'validate', bool) + self.config['catchall'] = catchall + self.config['autojson'] = autojson + + #: A :class:`ResourceManager` for application files + self.resources = ResourceManager() + + self.routes = [] # List of installed :class:`Route` instances. + self.router = Router() # Maps requests to :class:`Route` instances. + self.error_handler = {} + + # Core plugins + self.plugins = [] # List of installed plugins. + if self.config['autojson']: + self.install(JSONPlugin()) + self.install(TemplatePlugin()) + + #: If true, most exceptions are caught and returned as :exc:`HTTPError` + catchall = DictProperty('config', 'catchall') + + __hook_names = 'before_request', 'after_request', 'app_reset', 'config' + __hook_reversed = 'after_request' + + @cached_property + def _hooks(self): + return dict((name, []) for name in self.__hook_names) + + def add_hook(self, name, func): + ''' Attach a callback to a hook. Three hooks are currently implemented: + + before_request + Executed once before each request. The request context is + available, but no routing has happened yet. + after_request + Executed once after each request regardless of its outcome. + app_reset + Called whenever :meth:`Bottle.reset` is called. + ''' + if name in self.__hook_reversed: + self._hooks[name].insert(0, func) + else: + self._hooks[name].append(func) + + def remove_hook(self, name, func): + ''' Remove a callback from a hook. ''' + if name in self._hooks and func in self._hooks[name]: + self._hooks[name].remove(func) + return True + + def trigger_hook(self, __name, *args, **kwargs): + ''' Trigger a hook and return a list of results. ''' + return [hook(*args, **kwargs) for hook in self._hooks[__name][:]] + + def hook(self, name): + """ Return a decorator that attaches a callback to a hook. See + :meth:`add_hook` for details.""" + def decorator(func): + self.add_hook(name, func) + return func + return decorator + + def mount(self, prefix, app, **options): + ''' Mount an application (:class:`Bottle` or plain WSGI) to a specific + URL prefix. Example:: + + root_app.mount('/admin/', admin_app) + + :param prefix: path prefix or `mount-point`. If it ends in a slash, + that slash is mandatory. + :param app: an instance of :class:`Bottle` or a WSGI application. + + All other parameters are passed to the underlying :meth:`route` call. + ''' + if isinstance(app, basestring): + depr('Parameter order of Bottle.mount() changed.', True) # 0.10 + + segments = [p for p in prefix.split('/') if p] + if not segments: raise ValueError('Empty path prefix.') + path_depth = len(segments) + + def mountpoint_wrapper(): + try: + request.path_shift(path_depth) + rs = HTTPResponse([]) + def start_response(status, headerlist, exc_info=None): + if exc_info: + try: + _raise(*exc_info) + finally: + exc_info = None + rs.status = status + for name, value in headerlist: rs.add_header(name, value) + return rs.body.append + body = app(request.environ, start_response) + if body and rs.body: body = itertools.chain(rs.body, body) + rs.body = body or rs.body + return rs + finally: + request.path_shift(-path_depth) + + options.setdefault('skip', True) + options.setdefault('method', 'ANY') + options.setdefault('mountpoint', {'prefix': prefix, 'target': app}) + options['callback'] = mountpoint_wrapper + + self.route('/%s/<:re:.*>' % '/'.join(segments), **options) + if not prefix.endswith('/'): + self.route('/' + '/'.join(segments), **options) + + def merge(self, routes): + ''' Merge the routes of another :class:`Bottle` application or a list of + :class:`Route` objects into this application. The routes keep their + 'owner', meaning that the :data:`Route.app` attribute is not + changed. ''' + if isinstance(routes, Bottle): + routes = routes.routes + for route in routes: + self.add_route(route) + + def install(self, plugin): + ''' Add a plugin to the list of plugins and prepare it for being + applied to all routes of this application. A plugin may be a simple + decorator or an object that implements the :class:`Plugin` API. + ''' + if hasattr(plugin, 'setup'): plugin.setup(self) + if not callable(plugin) and not hasattr(plugin, 'apply'): + raise TypeError("Plugins must be callable or implement .apply()") + self.plugins.append(plugin) + self.reset() + return plugin + + def uninstall(self, plugin): + ''' Uninstall plugins. Pass an instance to remove a specific plugin, a type + object to remove all plugins that match that type, a string to remove + all plugins with a matching ``name`` attribute or ``True`` to remove all + plugins. Return the list of removed plugins. ''' + removed, remove = [], plugin + for i, plugin in list(enumerate(self.plugins))[::-1]: + if remove is True or remove is plugin or remove is type(plugin) \ + or getattr(plugin, 'name', True) == remove: + removed.append(plugin) + del self.plugins[i] + if hasattr(plugin, 'close'): plugin.close() + if removed: self.reset() + return removed + + def reset(self, route=None): + ''' Reset all routes (force plugins to be re-applied) and clear all + caches. If an ID or route object is given, only that specific route + is affected. ''' + if route is None: routes = self.routes + elif isinstance(route, Route): routes = [route] + else: routes = [self.routes[route]] + for route in routes: route.reset() + if DEBUG: + for route in routes: route.prepare() + self.trigger_hook('app_reset') + + def close(self): + ''' Close the application and all installed plugins. ''' + for plugin in self.plugins: + if hasattr(plugin, 'close'): plugin.close() + self.stopped = True + + def run(self, **kwargs): + ''' Calls :func:`run` with the same parameters. ''' + run(self, **kwargs) + + def match(self, environ): + """ Search for a matching route and return a (:class:`Route` , urlargs) + tuple. The second value is a dictionary with parameters extracted + from the URL. Raise :exc:`HTTPError` (404/405) on a non-match.""" + return self.router.match(environ) + + def get_url(self, routename, **kargs): + """ Return a string that matches a named route """ + scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/' + location = self.router.build(routename, **kargs).lstrip('/') + return urljoin(urljoin('/', scriptname), location) + + def add_route(self, route): + ''' Add a route object, but do not change the :data:`Route.app` + attribute.''' + self.routes.append(route) + self.router.add(route.rule, route.method, route, name=route.name) + if DEBUG: route.prepare() + + def route(self, path=None, method='GET', callback=None, name=None, + apply=None, skip=None, **config): + """ A decorator to bind a function to a request URL. Example:: + + @app.route('/hello/:name') + def hello(name): + return 'Hello %s' % name + + The ``:name`` part is a wildcard. See :class:`Router` for syntax + details. + + :param path: Request path or a list of paths to listen to. If no + path is specified, it is automatically generated from the + signature of the function. + :param method: HTTP method (`GET`, `POST`, `PUT`, ...) or a list of + methods to listen to. (default: `GET`) + :param callback: An optional shortcut to avoid the decorator + syntax. ``route(..., callback=func)`` equals ``route(...)(func)`` + :param name: The name for this route. (default: None) + :param apply: A decorator or plugin or a list of plugins. These are + applied to the route callback in addition to installed plugins. + :param skip: A list of plugins, plugin classes or names. Matching + plugins are not installed to this route. ``True`` skips all. + + Any additional keyword arguments are stored as route-specific + configuration and passed to plugins (see :meth:`Plugin.apply`). + """ + if callable(path): path, callback = None, path + plugins = makelist(apply) + skiplist = makelist(skip) + def decorator(callback): + # TODO: Documentation and tests + if isinstance(callback, basestring): callback = load(callback) + for rule in makelist(path) or yieldroutes(callback): + for verb in makelist(method): + verb = verb.upper() + route = Route(self, rule, verb, callback, name=name, + plugins=plugins, skiplist=skiplist, **config) + self.add_route(route) + return callback + return decorator(callback) if callback else decorator + + def get(self, path=None, method='GET', **options): + """ Equals :meth:`route`. """ + return self.route(path, method, **options) + + def post(self, path=None, method='POST', **options): + """ Equals :meth:`route` with a ``POST`` method parameter. """ + return self.route(path, method, **options) + + def put(self, path=None, method='PUT', **options): + """ Equals :meth:`route` with a ``PUT`` method parameter. """ + return self.route(path, method, **options) + + def delete(self, path=None, method='DELETE', **options): + """ Equals :meth:`route` with a ``DELETE`` method parameter. """ + return self.route(path, method, **options) + + def error(self, code=500): + """ Decorator: Register an output handler for a HTTP error code""" + def wrapper(handler): + self.error_handler[int(code)] = handler + return handler + return wrapper + + def handle(self, path, method='GET'): + """ (deprecated) Execute the first matching route callback and return + the result. :exc:`HTTPResponse` exceptions are caught and returned. + If :attr:`Bottle.catchall` is true, other exceptions are caught as + well and returned as :exc:`HTTPError` instances (500). + """ + depr("This method will change semantics in 0.10. Try to avoid it.") + if isinstance(path, dict): + return self._handle(path) + return self._handle({'PATH_INFO': path, 'REQUEST_METHOD': method.upper()}) + + def default_error_handler(self, res): + return tob(template(ERROR_PAGE_TEMPLATE, e=res)) + + def _handle(self, environ): + try: + environ['bottle.app'] = self + request.bind(environ) + response.bind() + + try: + self.trigger_hook('before_request') + route, args = self.router.match(environ) + environ['route.handle'] = route + environ['bottle.route'] = route + environ['route.url_args'] = args + return route.call(**args) + finally: + self.trigger_hook('after_request') + + except HTTPResponse: + return _e() + except RouteReset: + route.reset() + return self._handle(environ) + except (KeyboardInterrupt, SystemExit, MemoryError): + raise + except Exception: + if not self.catchall: raise + stacktrace = format_exc() + environ['wsgi.errors'].write(stacktrace) + return HTTPError(500, "Internal Server Error", _e(), stacktrace) + + def _cast(self, out, peek=None): + """ Try to convert the parameter into something WSGI compatible and set + correct HTTP headers when possible. + Support: False, str, unicode, dict, HTTPResponse, HTTPError, file-like, + iterable of strings and iterable of unicodes + """ + + # Empty output is done here + if not out: + if 'Content-Length' not in response: + response['Content-Length'] = 0 + return [] + # Join lists of byte or unicode strings. Mixed lists are NOT supported + if isinstance(out, (tuple, list))\ + and isinstance(out[0], (bytes, unicode)): + out = out[0][0:0].join(out) # b'abc'[0:0] -> b'' + # Encode unicode strings + if isinstance(out, unicode): + out = out.encode(response.charset) + # Byte Strings are just returned + if isinstance(out, bytes): + if 'Content-Length' not in response: + response['Content-Length'] = len(out) + return [out] + # HTTPError or HTTPException (recursive, because they may wrap anything) + # TODO: Handle these explicitly in handle() or make them iterable. + if isinstance(out, HTTPError): + out.apply(response) + out = self.error_handler.get(out.status_code, self.default_error_handler)(out) + return self._cast(out) + if isinstance(out, HTTPResponse): + out.apply(response) + return self._cast(out.body) + + # File-like objects. + if hasattr(out, 'read'): + if 'wsgi.file_wrapper' in request.environ: + return request.environ['wsgi.file_wrapper'](out) + elif hasattr(out, 'close') or not hasattr(out, '__iter__'): + return WSGIFileWrapper(out) + + # Handle Iterables. We peek into them to detect their inner type. + try: + iout = iter(out) + first = next(iout) + while not first: + first = next(iout) + except StopIteration: + return self._cast('') + except HTTPResponse: + first = _e() + except (KeyboardInterrupt, SystemExit, MemoryError): + raise + except Exception: + if not self.catchall: raise + first = HTTPError(500, 'Unhandled exception', _e(), format_exc()) + + # These are the inner types allowed in iterator or generator objects. + if isinstance(first, HTTPResponse): + return self._cast(first) + elif isinstance(first, bytes): + new_iter = itertools.chain([first], iout) + elif isinstance(first, unicode): + encoder = lambda x: x.encode(response.charset) + new_iter = imap(encoder, itertools.chain([first], iout)) + else: + msg = 'Unsupported response type: %s' % type(first) + return self._cast(HTTPError(500, msg)) + if hasattr(out, 'close'): + new_iter = _closeiter(new_iter, out.close) + return new_iter + + def wsgi(self, environ, start_response): + """ The bottle WSGI-interface. """ + try: + out = self._cast(self._handle(environ)) + # rfc2616 section 4.3 + if response._status_code in (100, 101, 204, 304)\ + or environ['REQUEST_METHOD'] == 'HEAD': + if hasattr(out, 'close'): out.close() + out = [] + start_response(response._status_line, response.headerlist) + return out + except (KeyboardInterrupt, SystemExit, MemoryError): + raise + except Exception: + if not self.catchall: raise + err = '

Critical error while processing request: %s

' \ + % html_escape(environ.get('PATH_INFO', '/')) + if DEBUG: + err += '

Error:

\n
\n%s\n
\n' \ + '

Traceback:

\n
\n%s\n
\n' \ + % (html_escape(repr(_e())), html_escape(format_exc())) + environ['wsgi.errors'].write(err) + headers = [('Content-Type', 'text/html; charset=UTF-8')] + start_response('500 INTERNAL SERVER ERROR', headers, sys.exc_info()) + return [tob(err)] + + def __call__(self, environ, start_response): + ''' Each instance of :class:'Bottle' is a WSGI application. ''' + return self.wsgi(environ, start_response) + + + + + + +############################################################################### +# HTTP and WSGI Tools ########################################################## +############################################################################### + +class BaseRequest(object): + """ A wrapper for WSGI environment dictionaries that adds a lot of + convenient access methods and properties. Most of them are read-only. + + Adding new attributes to a request actually adds them to the environ + dictionary (as 'bottle.request.ext.'). This is the recommended + way to store and access request-specific data. + """ + + __slots__ = ('environ') + + #: Maximum size of memory buffer for :attr:`body` in bytes. + MEMFILE_MAX = 102400 + #: Maximum number pr GET or POST parameters per request + MAX_PARAMS = 100 + + def __init__(self, environ=None): + """ Wrap a WSGI environ dictionary. """ + #: The wrapped WSGI environ dictionary. This is the only real attribute. + #: All other attributes actually are read-only properties. + self.environ = {} if environ is None else environ + self.environ['bottle.request'] = self + + @DictProperty('environ', 'bottle.app', read_only=True) + def app(self): + ''' Bottle application handling this request. ''' + raise RuntimeError('This request is not connected to an application.') + + @DictProperty('environ', 'bottle.route', read_only=True) + def route(self): + """ The bottle :class:`Route` object that matches this request. """ + raise RuntimeError('This request is not connected to a route.') + + @DictProperty('environ', 'route.url_args', read_only=True) + def url_args(self): + """ The arguments extracted from the URL. """ + raise RuntimeError('This request is not connected to a route.') + + @property + def path(self): + ''' The value of ``PATH_INFO`` with exactly one prefixed slash (to fix + broken clients and avoid the "empty path" edge case). ''' + return '/' + self.environ.get('PATH_INFO','').lstrip('/') + + @property + def method(self): + ''' The ``REQUEST_METHOD`` value as an uppercase string. ''' + return self.environ.get('REQUEST_METHOD', 'GET').upper() + + @DictProperty('environ', 'bottle.request.headers', read_only=True) + def headers(self): + ''' A :class:`WSGIHeaderDict` that provides case-insensitive access to + HTTP request headers. ''' + return WSGIHeaderDict(self.environ) + + def get_header(self, name, default=None): + ''' Return the value of a request header, or a given default value. ''' + return self.headers.get(name, default) + + @DictProperty('environ', 'bottle.request.cookies', read_only=True) + def cookies(self): + """ Cookies parsed into a :class:`FormsDict`. Signed cookies are NOT + decoded. Use :meth:`get_cookie` if you expect signed cookies. """ + cookies = SimpleCookie(self.environ.get('HTTP_COOKIE','')).values() + if len(cookies) > self.MAX_PARAMS: + raise HTTPError(413, 'Too many cookies') + return FormsDict((c.key, c.value) for c in cookies) + + def get_cookie(self, key, default=None, secret=None): + """ Return the content of a cookie. To read a `Signed Cookie`, the + `secret` must match the one used to create the cookie (see + :meth:`BaseResponse.set_cookie`). If anything goes wrong (missing + cookie or wrong signature), return a default value. """ + value = self.cookies.get(key) + if secret and value: + dec = cookie_decode(value, secret) # (key, value) tuple or None + return dec[1] if dec and dec[0] == key else default + return value or default + + @DictProperty('environ', 'bottle.request.query', read_only=True) + def query(self): + ''' The :attr:`query_string` parsed into a :class:`FormsDict`. These + values are sometimes called "URL arguments" or "GET parameters", but + not to be confused with "URL wildcards" as they are provided by the + :class:`Router`. ''' + get = self.environ['bottle.get'] = FormsDict() + pairs = _parse_qsl(self.environ.get('QUERY_STRING', '')) + if len(pairs) > self.MAX_PARAMS: + raise HTTPError(413, 'Too many parameters') + for key, value in pairs: + get[key] = value + return get + + @DictProperty('environ', 'bottle.request.forms', read_only=True) + def forms(self): + """ Form values parsed from an `url-encoded` or `multipart/form-data` + encoded POST or PUT request body. The result is returned as a + :class:`FormsDict`. All keys and values are strings. File uploads + are stored separately in :attr:`files`. """ + forms = FormsDict() + for name, item in self.POST.allitems(): + if not isinstance(item, FileUpload): + forms[name] = item + return forms + + @DictProperty('environ', 'bottle.request.params', read_only=True) + def params(self): + """ A :class:`FormsDict` with the combined values of :attr:`query` and + :attr:`forms`. File uploads are stored in :attr:`files`. """ + params = FormsDict() + for key, value in self.query.allitems(): + params[key] = value + for key, value in self.forms.allitems(): + params[key] = value + return params + + @DictProperty('environ', 'bottle.request.files', read_only=True) + def files(self): + """ File uploads parsed from `multipart/form-data` encoded POST or PUT + request body. The values are instances of :class:`FileUpload`. + + """ + files = FormsDict() + for name, item in self.POST.allitems(): + if isinstance(item, FileUpload): + files[name] = item + return files + + @DictProperty('environ', 'bottle.request.json', read_only=True) + def json(self): + ''' If the ``Content-Type`` header is ``application/json``, this + property holds the parsed content of the request body. Only requests + smaller than :attr:`MEMFILE_MAX` are processed to avoid memory + exhaustion. ''' + if 'application/json' in self.environ.get('CONTENT_TYPE', ''): + return json_loads(self._get_body_string()) + return None + + @DictProperty('environ', 'bottle.request.body', read_only=True) + def _body(self): + maxread = max(0, self.content_length) + stream = self.environ['wsgi.input'] + body = BytesIO() if maxread < self.MEMFILE_MAX else TemporaryFile(mode='w+b') + while maxread > 0: + part = stream.read(min(maxread, self.MEMFILE_MAX)) + if not part: break + body.write(part) + maxread -= len(part) + self.environ['wsgi.input'] = body + body.seek(0) + return body + + def _get_body_string(self): + ''' read body until content-length or MEMFILE_MAX into a string. Raise + HTTPError(413) on requests that are to large. ''' + clen = self.content_length + if clen > self.MEMFILE_MAX: + raise HTTPError(413, 'Request to large') + if clen < 0: clen = self.MEMFILE_MAX + 1 + data = self.body.read(clen) + if len(data) > self.MEMFILE_MAX: # Fail fast + raise HTTPError(413, 'Request to large') + return data + + @property + def body(self): + """ The HTTP request body as a seek-able file-like object. Depending on + :attr:`MEMFILE_MAX`, this is either a temporary file or a + :class:`io.BytesIO` instance. Accessing this property for the first + time reads and replaces the ``wsgi.input`` environ variable. + Subsequent accesses just do a `seek(0)` on the file object. """ + self._body.seek(0) + return self._body + + #: An alias for :attr:`query`. + GET = query + + @DictProperty('environ', 'bottle.request.post', read_only=True) + def POST(self): + """ The values of :attr:`forms` and :attr:`files` combined into a single + :class:`FormsDict`. Values are either strings (form values) or + instances of :class:`cgi.FieldStorage` (file uploads). + """ + post = FormsDict() + # We default to application/x-www-form-urlencoded for everything that + # is not multipart and take the fast path (also: 3.1 workaround) + if not self.content_type.startswith('multipart/'): + pairs = _parse_qsl(tonat(self._get_body_string(), 'latin1')) + if len(pairs) > self.MAX_PARAMS: + raise HTTPError(413, 'Too many parameters') + for key, value in pairs: + post[key] = value + return post + + safe_env = {'QUERY_STRING':''} # Build a safe environment for cgi + for key in ('REQUEST_METHOD', 'CONTENT_TYPE', 'CONTENT_LENGTH'): + if key in self.environ: safe_env[key] = self.environ[key] + args = dict(fp=self.body, environ=safe_env, keep_blank_values=True) + if py31: + args['fp'] = NCTextIOWrapper(args['fp'], encoding='latin1', + newline='\n') + elif py3k: + args['encoding'] = 'latin1' + data = cgi.FieldStorage(**args) + data = data.list or [] + if len(data) > self.MAX_PARAMS: + raise HTTPError(413, 'Too many parameters') + for item in data: + if item.filename: + post[item.name] = FileUpload(item.file, item.name, + item.filename, item.headers) + else: + post[item.name] = item.value + return post + + @property + def COOKIES(self): + ''' Alias for :attr:`cookies` (deprecated). ''' + depr('BaseRequest.COOKIES was renamed to BaseRequest.cookies (lowercase).') + return self.cookies + + @property + def url(self): + """ The full request URI including hostname and scheme. If your app + lives behind a reverse proxy or load balancer and you get confusing + results, make sure that the ``X-Forwarded-Host`` header is set + correctly. """ + return self.urlparts.geturl() + + @DictProperty('environ', 'bottle.request.urlparts', read_only=True) + def urlparts(self): + ''' The :attr:`url` string as an :class:`urlparse.SplitResult` tuple. + The tuple contains (scheme, host, path, query_string and fragment), + but the fragment is always empty because it is not visible to the + server. ''' + env = self.environ + http = env.get('HTTP_X_FORWARDED_PROTO') or env.get('wsgi.url_scheme', 'http') + host = env.get('HTTP_X_FORWARDED_HOST') or env.get('HTTP_HOST') + if not host: + # HTTP 1.1 requires a Host-header. This is for HTTP/1.0 clients. + host = env.get('SERVER_NAME', '127.0.0.1') + port = env.get('SERVER_PORT') + if port and port != ('80' if http == 'http' else '443'): + host += ':' + port + path = urlquote(self.fullpath) + return UrlSplitResult(http, host, path, env.get('QUERY_STRING'), '') + + @property + def fullpath(self): + """ Request path including :attr:`script_name` (if present). """ + return urljoin(self.script_name, self.path.lstrip('/')) + + @property + def query_string(self): + """ The raw :attr:`query` part of the URL (everything in between ``?`` + and ``#``) as a string. """ + return self.environ.get('QUERY_STRING', '') + + @property + def script_name(self): + ''' The initial portion of the URL's `path` that was removed by a higher + level (server or routing middleware) before the application was + called. This script path is returned with leading and tailing + slashes. ''' + script_name = self.environ.get('SCRIPT_NAME', '').strip('/') + return '/' + script_name + '/' if script_name else '/' + + def path_shift(self, shift=1): + ''' Shift path segments from :attr:`path` to :attr:`script_name` and + vice versa. + + :param shift: The number of path segments to shift. May be negative + to change the shift direction. (default: 1) + ''' + script = self.environ.get('SCRIPT_NAME','/') + self['SCRIPT_NAME'], self['PATH_INFO'] = path_shift(script, self.path, shift) + + @property + def content_length(self): + ''' The request body length as an integer. The client is responsible to + set this header. Otherwise, the real length of the body is unknown + and -1 is returned. In this case, :attr:`body` will be empty. ''' + return int(self.environ.get('CONTENT_LENGTH') or -1) + + @property + def content_type(self): + ''' The Content-Type header as a lowercase-string (default: empty). ''' + return self.environ.get('CONTENT_TYPE', '').lower() + + @property + def is_xhr(self): + ''' True if the request was triggered by a XMLHttpRequest. This only + works with JavaScript libraries that support the `X-Requested-With` + header (most of the popular libraries do). ''' + requested_with = self.environ.get('HTTP_X_REQUESTED_WITH','') + return requested_with.lower() == 'xmlhttprequest' + + @property + def is_ajax(self): + ''' Alias for :attr:`is_xhr`. "Ajax" is not the right term. ''' + return self.is_xhr + + @property + def auth(self): + """ HTTP authentication data as a (user, password) tuple. This + implementation currently supports basic (not digest) authentication + only. If the authentication happened at a higher level (e.g. in the + front web-server or a middleware), the password field is None, but + the user field is looked up from the ``REMOTE_USER`` environ + variable. On any errors, None is returned. """ + basic = parse_auth(self.environ.get('HTTP_AUTHORIZATION','')) + if basic: return basic + ruser = self.environ.get('REMOTE_USER') + if ruser: return (ruser, None) + return None + + @property + def remote_route(self): + """ A list of all IPs that were involved in this request, starting with + the client IP and followed by zero or more proxies. This does only + work if all proxies support the ```X-Forwarded-For`` header. Note + that this information can be forged by malicious clients. """ + proxy = self.environ.get('HTTP_X_FORWARDED_FOR') + if proxy: return [ip.strip() for ip in proxy.split(',')] + remote = self.environ.get('REMOTE_ADDR') + return [remote] if remote else [] + + @property + def remote_addr(self): + """ The client IP as a string. Note that this information can be forged + by malicious clients. """ + route = self.remote_route + return route[0] if route else None + + def copy(self): + """ Return a new :class:`Request` with a shallow :attr:`environ` copy. """ + return Request(self.environ.copy()) + + def get(self, value, default=None): return self.environ.get(value, default) + def __getitem__(self, key): return self.environ[key] + def __delitem__(self, key): self[key] = ""; del(self.environ[key]) + def __iter__(self): return iter(self.environ) + def __len__(self): return len(self.environ) + def keys(self): return self.environ.keys() + def __setitem__(self, key, value): + """ Change an environ value and clear all caches that depend on it. """ + + if self.environ.get('bottle.request.readonly'): + raise KeyError('The environ dictionary is read-only.') + + self.environ[key] = value + todelete = () + + if key == 'wsgi.input': + todelete = ('body', 'forms', 'files', 'params', 'post', 'json') + elif key == 'QUERY_STRING': + todelete = ('query', 'params') + elif key.startswith('HTTP_'): + todelete = ('headers', 'cookies') + + for key in todelete: + self.environ.pop('bottle.request.'+key, None) + + def __repr__(self): + return '<%s: %s %s>' % (self.__class__.__name__, self.method, self.url) + + def __getattr__(self, name): + ''' Search in self.environ for additional user defined attributes. ''' + try: + var = self.environ['bottle.request.ext.%s'%name] + return var.__get__(self) if hasattr(var, '__get__') else var + except KeyError: + raise AttributeError('Attribute %r not defined.' % name) + + def __setattr__(self, name, value): + if name == 'environ': return object.__setattr__(self, name, value) + self.environ['bottle.request.ext.%s'%name] = value + + + + +def _hkey(s): + return s.title().replace('_','-') + + +class HeaderProperty(object): + def __init__(self, name, reader=None, writer=str, default=''): + self.name, self.default = name, default + self.reader, self.writer = reader, writer + self.__doc__ = 'Current value of the %r header.' % name.title() + + def __get__(self, obj, cls): + if obj is None: return self + value = obj.headers.get(self.name, self.default) + return self.reader(value) if self.reader else value + + def __set__(self, obj, value): + obj.headers[self.name] = self.writer(value) + + def __delete__(self, obj): + del obj.headers[self.name] + + +class BaseResponse(object): + """ Storage class for a response body as well as headers and cookies. + + This class does support dict-like case-insensitive item-access to + headers, but is NOT a dict. Most notably, iterating over a response + yields parts of the body and not the headers. + + :param body: The response body as one of the supported types. + :param status: Either an HTTP status code (e.g. 200) or a status line + including the reason phrase (e.g. '200 OK'). + :param headers: A dictionary or a list of name-value pairs. + + Additional keyword arguments are added to the list of headers. + Underscores in the header name are replaced with dashes. + """ + + default_status = 200 + default_content_type = 'text/html; charset=UTF-8' + + # Header blacklist for specific response codes + # (rfc2616 section 10.2.3 and 10.3.5) + bad_headers = { + 204: set(('Content-Type',)), + 304: set(('Allow', 'Content-Encoding', 'Content-Language', + 'Content-Length', 'Content-Range', 'Content-Type', + 'Content-Md5', 'Last-Modified'))} + + def __init__(self, body='', status=None, headers=None, **more_headers): + self._cookies = None + self._headers = {} + self.body = body + self.status = status or self.default_status + if headers: + if isinstance(headers, dict): + headers = headers.items() + for name, value in headers: + self.add_header(name, value) + if more_headers: + for name, value in more_headers.items(): + self.add_header(name, value) + + def copy(self, cls=None): + ''' Returns a copy of self. ''' + cls = cls or BaseResponse + assert issubclass(cls, BaseResponse) + copy = cls() + copy.status = self.status + copy._headers = dict((k, v[:]) for (k, v) in self._headers.items()) + copy.COOKIES.load(self.COOKIES.output()) + return copy + + def __iter__(self): + return iter(self.body) + + def close(self): + if hasattr(self.body, 'close'): + self.body.close() + + @property + def status_line(self): + ''' The HTTP status line as a string (e.g. ``404 Not Found``).''' + return self._status_line + + @property + def status_code(self): + ''' The HTTP status code as an integer (e.g. 404).''' + return self._status_code + + def _set_status(self, status): + if isinstance(status, int): + code, status = status, _HTTP_STATUS_LINES.get(status) + elif ' ' in status: + status = status.strip() + code = int(status.split()[0]) + else: + raise ValueError('String status line without a reason phrase.') + if not 100 <= code <= 999: raise ValueError('Status code out of range.') + self._status_code = code + self._status_line = str(status or ('%d Unknown' % code)) + + def _get_status(self): + return self._status_line + + status = property(_get_status, _set_status, None, + ''' A writeable property to change the HTTP response status. It accepts + either a numeric code (100-999) or a string with a custom reason + phrase (e.g. "404 Brain not found"). Both :data:`status_line` and + :data:`status_code` are updated accordingly. The return value is + always a status string. ''') + del _get_status, _set_status + + @property + def headers(self): + ''' An instance of :class:`HeaderDict`, a case-insensitive dict-like + view on the response headers. ''' + hdict = HeaderDict() + hdict.dict = self._headers + return hdict + + def __contains__(self, name): return _hkey(name) in self._headers + def __delitem__(self, name): del self._headers[_hkey(name)] + def __getitem__(self, name): return self._headers[_hkey(name)][-1] + def __setitem__(self, name, value): self._headers[_hkey(name)] = [str(value)] + + def get_header(self, name, default=None): + ''' Return the value of a previously defined header. If there is no + header with that name, return a default value. ''' + return self._headers.get(_hkey(name), [default])[-1] + + def set_header(self, name, value): + ''' Create a new response header, replacing any previously defined + headers with the same name. ''' + self._headers[_hkey(name)] = [str(value)] + + def add_header(self, name, value): + ''' Add an additional response header, not removing duplicates. ''' + self._headers.setdefault(_hkey(name), []).append(str(value)) + + def iter_headers(self): + ''' Yield (header, value) tuples, skipping headers that are not + allowed with the current response status code. ''' + return self.headerlist + + def wsgiheader(self): + depr('The wsgiheader method is deprecated. See headerlist.') #0.10 + return self.headerlist + + @property + def headerlist(self): + ''' WSGI conform list of (header, value) tuples. ''' + out = [] + headers = list(self._headers.items()) + if 'Content-Type' not in self._headers: + headers.append(('Content-Type', [self.default_content_type])) + if self._status_code in self.bad_headers: + bad_headers = self.bad_headers[self._status_code] + headers = [h for h in headers if h[0] not in bad_headers] + out += [(name, val) for name, vals in headers for val in vals] + if self._cookies: + for c in self._cookies.values(): + out.append(('Set-Cookie', c.OutputString())) + return out + + content_type = HeaderProperty('Content-Type') + content_length = HeaderProperty('Content-Length', reader=int) + expires = HeaderProperty('Expires', + reader=lambda x: datetime.utcfromtimestamp(parse_date(x)), + writer=lambda x: http_date(x)) + + @property + def charset(self, default='UTF-8'): + """ Return the charset specified in the content-type header (default: utf8). """ + if 'charset=' in self.content_type: + return self.content_type.split('charset=')[-1].split(';')[0].strip() + return default + + @property + def COOKIES(self): + """ A dict-like SimpleCookie instance. This should not be used directly. + See :meth:`set_cookie`. """ + depr('The COOKIES dict is deprecated. Use `set_cookie()` instead.') # 0.10 + if not self._cookies: + self._cookies = SimpleCookie() + return self._cookies + + def set_cookie(self, name, value, secret=None, **options): + ''' Create a new cookie or replace an old one. If the `secret` parameter is + set, create a `Signed Cookie` (described below). + + :param name: the name of the cookie. + :param value: the value of the cookie. + :param secret: a signature key required for signed cookies. + + Additionally, this method accepts all RFC 2109 attributes that are + supported by :class:`cookie.Morsel`, including: + + :param max_age: maximum age in seconds. (default: None) + :param expires: a datetime object or UNIX timestamp. (default: None) + :param domain: the domain that is allowed to read the cookie. + (default: current domain) + :param path: limits the cookie to a given path (default: current path) + :param secure: limit the cookie to HTTPS connections (default: off). + :param httponly: prevents client-side javascript to read this cookie + (default: off, requires Python 2.6 or newer). + + If neither `expires` nor `max_age` is set (default), the cookie will + expire at the end of the browser session (as soon as the browser + window is closed). + + Signed cookies may store any pickle-able object and are + cryptographically signed to prevent manipulation. Keep in mind that + cookies are limited to 4kb in most browsers. + + Warning: Signed cookies are not encrypted (the client can still see + the content) and not copy-protected (the client can restore an old + cookie). The main intention is to make pickling and unpickling + save, not to store secret information at client side. + ''' + if not self._cookies: + self._cookies = SimpleCookie() + + if secret: + value = touni(cookie_encode((name, value), secret)) + elif not isinstance(value, basestring): + raise TypeError('Secret key missing for non-string Cookie.') + + if len(value) > 4096: raise ValueError('Cookie value to long.') + self._cookies[name] = value + + for key, value in options.items(): + if key == 'max_age': + if isinstance(value, timedelta): + value = value.seconds + value.days * 24 * 3600 + if key == 'expires': + if isinstance(value, (datedate, datetime)): + value = value.timetuple() + elif isinstance(value, (int, float)): + value = time.gmtime(value) + value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value) + self._cookies[name][key.replace('_', '-')] = value + + def delete_cookie(self, key, **kwargs): + ''' Delete a cookie. Be sure to use the same `domain` and `path` + settings as used to create the cookie. ''' + kwargs['max_age'] = -1 + kwargs['expires'] = 0 + self.set_cookie(key, '', **kwargs) + + def __repr__(self): + out = '' + for name, value in self.headerlist: + out += '%s: %s\n' % (name.title(), value.strip()) + return out + +#: Thread-local storage for :class:`LocalRequest` and :class:`LocalResponse` +#: attributes. +_lctx = threading.local() + +def local_property(name): + def fget(self): + try: + return getattr(_lctx, name) + except AttributeError: + raise RuntimeError("Request context not initialized.") + def fset(self, value): setattr(_lctx, name, value) + def fdel(self): delattr(_lctx, name) + return property(fget, fset, fdel, + 'Thread-local property stored in :data:`_lctx.%s`' % name) + + +class LocalRequest(BaseRequest): + ''' A thread-local subclass of :class:`BaseRequest` with a different + set of attribues for each thread. There is usually only one global + instance of this class (:data:`request`). If accessed during a + request/response cycle, this instance always refers to the *current* + request (even on a multithreaded server). ''' + bind = BaseRequest.__init__ + environ = local_property('request_environ') + + +class LocalResponse(BaseResponse): + ''' A thread-local subclass of :class:`BaseResponse` with a different + set of attribues for each thread. There is usually only one global + instance of this class (:data:`response`). Its attributes are used + to build the HTTP response at the end of the request/response cycle. + ''' + bind = BaseResponse.__init__ + _status_line = local_property('response_status_line') + _status_code = local_property('response_status_code') + _cookies = local_property('response_cookies') + _headers = local_property('response_headers') + body = local_property('response_body') + + +Request = BaseRequest +Response = BaseResponse + + +class HTTPResponse(Response, BottleException): + def __init__(self, body='', status=None, headers=None, + header=None, **more_headers): + if header or 'output' in more_headers: + depr('Call signature changed (for the better). See BaseResponse') + if header: more_headers.update(header) + if 'output' in more_headers: body = more_headers.pop('output') + super(HTTPResponse, self).__init__(body, status, headers, **more_headers) + + def apply(self, response): + response._status_code = self._status_code + response._status_line = self._status_line + response._headers = self._headers + response._cookies = self._cookies + response.body = self.body + + def _output(self, value=None): + depr('Use HTTPResponse.body instead of HTTPResponse.output') + if value is None: return self.body + self.body = value + + output = property(_output, _output, doc='Alias for .body') + + +class HTTPError(HTTPResponse): + default_status = 500 + def __init__(self, status=None, body=None, exception=None, traceback=None, + **options): + self.exception = exception + self.traceback = traceback + super(HTTPError, self).__init__(body, status, **options) + + + + + +############################################################################### +# Plugins ###################################################################### +############################################################################### + +class PluginError(BottleException): pass + + +class JSONPlugin(object): + name = 'json' + api = 2 + + def __init__(self, json_dumps=json_dumps): + self.json_dumps = json_dumps + + def apply(self, callback, route): + dumps = self.json_dumps + if not dumps: return callback + def wrapper(*a, **ka): + try: + rv = callback(*a, **ka) + except HTTPError: + rv = _e() + + if isinstance(rv, dict): + #Attempt to serialize, raises exception on failure + json_response = dumps(rv) + #Set content type only if serialization succesful + response.content_type = 'application/json' + return json_response + elif isinstance(rv, HTTPResponse) and isinstance(rv.body, dict): + rv.body = dumps(rv.body) + rv.content_type = 'application/json' + return rv + + return wrapper + + +class TemplatePlugin(object): + ''' This plugin applies the :func:`view` decorator to all routes with a + `template` config parameter. If the parameter is a tuple, the second + element must be a dict with additional options (e.g. `template_engine`) + or default variables for the template. ''' + name = 'template' + api = 2 + + def apply(self, callback, route): + conf = route.config.get('template') + if isinstance(conf, (tuple, list)) and len(conf) == 2: + return view(conf[0], **conf[1])(callback) + elif isinstance(conf, str): + return view(conf)(callback) + else: + return callback + + +#: Not a plugin, but part of the plugin API. TODO: Find a better place. +class _ImportRedirect(object): + def __init__(self, name, impmask): + ''' Create a virtual package that redirects imports (see PEP 302). ''' + self.name = name + self.impmask = impmask + self.module = sys.modules.setdefault(name, imp.new_module(name)) + self.module.__dict__.update({'__file__': __file__, '__path__': [], + '__all__': [], '__loader__': self}) + sys.meta_path.append(self) + + def find_module(self, fullname, path=None): + if '.' not in fullname: return + packname, modname = fullname.rsplit('.', 1) + if packname != self.name: return + return self + + def load_module(self, fullname): + if fullname in sys.modules: return sys.modules[fullname] + packname, modname = fullname.rsplit('.', 1) + realname = self.impmask % modname + __import__(realname) + module = sys.modules[fullname] = sys.modules[realname] + setattr(self.module, modname, module) + module.__loader__ = self + return module + + + + + + +############################################################################### +# Common Utilities ############################################################# +############################################################################### + + +class MultiDict(DictMixin): + """ This dict stores multiple values per key, but behaves exactly like a + normal dict in that it returns only the newest value for any given key. + There are special methods available to access the full list of values. + """ + + def __init__(self, *a, **k): + self.dict = dict((k, [v]) for (k, v) in dict(*a, **k).items()) + + def __len__(self): return len(self.dict) + def __iter__(self): return iter(self.dict) + def __contains__(self, key): return key in self.dict + def __delitem__(self, key): del self.dict[key] + def __getitem__(self, key): return self.dict[key][-1] + def __setitem__(self, key, value): self.append(key, value) + def keys(self): return self.dict.keys() + + if py3k: + def values(self): return (v[-1] for v in self.dict.values()) + def items(self): return ((k, v[-1]) for k, v in self.dict.items()) + def allitems(self): + return ((k, v) for k, vl in self.dict.items() for v in vl) + iterkeys = keys + itervalues = values + iteritems = items + iterallitems = allitems + + else: + def values(self): return [v[-1] for v in self.dict.values()] + def items(self): return [(k, v[-1]) for k, v in self.dict.items()] + def iterkeys(self): return self.dict.iterkeys() + def itervalues(self): return (v[-1] for v in self.dict.itervalues()) + def iteritems(self): + return ((k, v[-1]) for k, v in self.dict.iteritems()) + def iterallitems(self): + return ((k, v) for k, vl in self.dict.iteritems() for v in vl) + def allitems(self): + return [(k, v) for k, vl in self.dict.iteritems() for v in vl] + + def get(self, key, default=None, index=-1, type=None): + ''' Return the most recent value for a key. + + :param default: The default value to be returned if the key is not + present or the type conversion fails. + :param index: An index for the list of available values. + :param type: If defined, this callable is used to cast the value + into a specific type. Exception are suppressed and result in + the default value to be returned. + ''' + try: + val = self.dict[key][index] + return type(val) if type else val + except Exception: + pass + return default + + def append(self, key, value): + ''' Add a new value to the list of values for this key. ''' + self.dict.setdefault(key, []).append(value) + + def replace(self, key, value): + ''' Replace the list of values with a single value. ''' + self.dict[key] = [value] + + def getall(self, key): + ''' Return a (possibly empty) list of values for a key. ''' + return self.dict.get(key) or [] + + #: Aliases for WTForms to mimic other multi-dict APIs (Django) + getone = get + getlist = getall + + +class FormsDict(MultiDict): + ''' This :class:`MultiDict` subclass is used to store request form data. + Additionally to the normal dict-like item access methods (which return + unmodified data as native strings), this container also supports + attribute-like access to its values. Attributes are automatically de- + or recoded to match :attr:`input_encoding` (default: 'utf8'). Missing + attributes default to an empty string. ''' + + #: Encoding used for attribute values. + input_encoding = 'utf8' + #: If true (default), unicode strings are first encoded with `latin1` + #: and then decoded to match :attr:`input_encoding`. + recode_unicode = True + + def _fix(self, s, encoding=None): + if isinstance(s, unicode) and self.recode_unicode: # Python 3 WSGI + s = s.encode('latin1') + if isinstance(s, bytes): # Python 2 WSGI + return s.decode(encoding or self.input_encoding) + return s + + def decode(self, encoding=None): + ''' Returns a copy with all keys and values de- or recoded to match + :attr:`input_encoding`. Some libraries (e.g. WTForms) want a + unicode dictionary. ''' + copy = FormsDict() + enc = copy.input_encoding = encoding or self.input_encoding + copy.recode_unicode = False + for key, value in self.allitems(): + copy.append(self._fix(key, enc), self._fix(value, enc)) + return copy + + def getunicode(self, name, default=None, encoding=None): + ''' Return the value as a unicode string, or the default. ''' + try: + return self._fix(self[name], encoding) + except (UnicodeError, KeyError): + return default + + def __getattr__(self, name, default=unicode()): + # Without this guard, pickle generates a cryptic TypeError: + if name.startswith('__') and name.endswith('__'): + return super(FormsDict, self).__getattr__(name) + return self.getunicode(name, default=default) + + +class HeaderDict(MultiDict): + """ A case-insensitive version of :class:`MultiDict` that defaults to + replace the old value instead of appending it. """ + + def __init__(self, *a, **ka): + self.dict = {} + if a or ka: self.update(*a, **ka) + + def __contains__(self, key): return _hkey(key) in self.dict + def __delitem__(self, key): del self.dict[_hkey(key)] + def __getitem__(self, key): return self.dict[_hkey(key)][-1] + def __setitem__(self, key, value): self.dict[_hkey(key)] = [str(value)] + def append(self, key, value): + self.dict.setdefault(_hkey(key), []).append(str(value)) + def replace(self, key, value): self.dict[_hkey(key)] = [str(value)] + def getall(self, key): return self.dict.get(_hkey(key)) or [] + def get(self, key, default=None, index=-1): + return MultiDict.get(self, _hkey(key), default, index) + def filter(self, names): + for name in [_hkey(n) for n in names]: + if name in self.dict: + del self.dict[name] + + +class WSGIHeaderDict(DictMixin): + ''' This dict-like class wraps a WSGI environ dict and provides convenient + access to HTTP_* fields. Keys and values are native strings + (2.x bytes or 3.x unicode) and keys are case-insensitive. If the WSGI + environment contains non-native string values, these are de- or encoded + using a lossless 'latin1' character set. + + The API will remain stable even on changes to the relevant PEPs. + Currently PEP 333, 444 and 3333 are supported. (PEP 444 is the only one + that uses non-native strings.) + ''' + #: List of keys that do not have a ``HTTP_`` prefix. + cgikeys = ('CONTENT_TYPE', 'CONTENT_LENGTH') + + def __init__(self, environ): + self.environ = environ + + def _ekey(self, key): + ''' Translate header field name to CGI/WSGI environ key. ''' + key = key.replace('-','_').upper() + if key in self.cgikeys: + return key + return 'HTTP_' + key + + def raw(self, key, default=None): + ''' Return the header value as is (may be bytes or unicode). ''' + return self.environ.get(self._ekey(key), default) + + def __getitem__(self, key): + return tonat(self.environ[self._ekey(key)], 'latin1') + + def __setitem__(self, key, value): + raise TypeError("%s is read-only." % self.__class__) + + def __delitem__(self, key): + raise TypeError("%s is read-only." % self.__class__) + + def __iter__(self): + for key in self.environ: + if key[:5] == 'HTTP_': + yield key[5:].replace('_', '-').title() + elif key in self.cgikeys: + yield key.replace('_', '-').title() + + def keys(self): return [x for x in self] + def __len__(self): return len(self.keys()) + def __contains__(self, key): return self._ekey(key) in self.environ + + + +class ConfigDict(dict): + ''' A dict-like configuration storage with additional support for + namespaces, validators, meta-data, on_change listeners and more. + ''' + + __slots__ = ('_meta', '_on_change') + + def __init__(self, *a, **ka): + self._meta = {} + self._on_change = lambda name, value: None + if a or ka: + depr('Constructor does no longer accept parameters.') + self.update(*a, **ka) + + def load_config(self, filename): + ''' Load values from an *.ini style config file. + + If the config file contains sections, their names are used as + namespaces for the values within. The two special sections + ``DEFAULT`` and ``bottle`` refer to the root namespace (no prefix). + ''' + conf = ConfigParser() + conf.read(filename) + for section in conf.sections(): + for key, value in conf.items(section): + if section not in ('DEFAULT', 'bottle'): + key = section + '.' + key + self[key] = value + return self + + def load_dict(self, source, namespace=''): + ''' Load values from a dictionary structure. Nesting can be used to + represent namespaces. + + >>> c.load_dict({'some': {'namespace': {'key': 'value'} } }) + {'some.namespace.key': 'value'} + ''' + for key, value in source.items(): + if isinstance(key, str): + nskey = (namespace + '.' + key).strip('.') + if isinstance(value, dict): + self.load_dict(value, namespace=nskey) + else: + self[nskey] = value + else: + raise TypeError('Key has type %r (not a string)' % type(key)) + return self + + def update(self, *a, **ka): + ''' If the first parameter is a string, all keys are prefixed with this + namespace. Apart from that it works just as the usual dict.update(). + Example: ``update('some.namespace', key='value')`` ''' + prefix = '' + if a and isinstance(a[0], str): + prefix = a[0].strip('.') + '.' + a = a[1:] + for key, value in dict(*a, **ka).items(): + self[prefix+key] = value + + def setdefault(self, key, value): + if key not in self: + self[key] = value + + def __setitem__(self, key, value): + if not isinstance(key, str): + raise TypeError('Key has type %r (not a string)' % type(key)) + value = self.meta_get(key, 'filter', lambda x: x)(value) + if key in self and self[key] is value: + return + self._on_change(key, value) + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + self._on_change(key, None) + dict.__delitem__(self, key) + + def meta_get(self, key, metafield, default=None): + ''' Return the value of a meta field for a key. ''' + return self._meta.get(key, {}).get(metafield, default) + + def meta_set(self, key, metafield, value): + ''' Set the meta field for a key to a new value. This triggers the + on-change handler for existing keys. ''' + self._meta.setdefault(key, {})[metafield] = value + if key in self: + self[key] = self[key] + + def meta_list(self, key): + ''' Return an iterable of meta field names defined for a key. ''' + return self._meta.get(key, {}).keys() + + # Deprecated ConfigDict features + def __getattr__(self, key): + depr('Attribute access is deprecated.') #0.12 + if key not in self and key[0].isupper(): + self[key] = ConfigDict() + return self.get(key) + + def __setattr__(self, key, value): + if key in self.__slots__: + return dict.__setattr__(self, key, value) + depr('Attribute assignment is deprecated.') #0.12 + if hasattr(dict, key): + raise AttributeError('Read-only attribute.') + if key in self and self[key] and isinstance(self[key], ConfigDict): + raise AttributeError('Non-empty namespace attribute.') + self[key] = value + + def __delattr__(self, key): + if key in self: del self[key] + + def __call__(self, *a, **ka): + depr('Calling ConfDict is deprecated. Use the update() method.') #0.12 + self.update(*a, **ka) + return self + + + +class AppStack(list): + """ A stack-like list. Calling it returns the head of the stack. """ + + def __call__(self): + """ Return the current default application. """ + return self[-1] + + def push(self, value=None): + """ Add a new :class:`Bottle` instance to the stack """ + if not isinstance(value, Bottle): + value = Bottle() + self.append(value) + return value + + +class WSGIFileWrapper(object): + + def __init__(self, fp, buffer_size=1024*64): + self.fp, self.buffer_size = fp, buffer_size + for attr in ('fileno', 'close', 'read', 'readlines', 'tell', 'seek'): + if hasattr(fp, attr): setattr(self, attr, getattr(fp, attr)) + + def __iter__(self): + buff, read = self.buffer_size, self.read + while True: + part = read(buff) + if not part: return + yield part + + +class _closeiter(object): + ''' This only exists to be able to attach a .close method to iterators that + do not support attribute assignment (most of itertools). ''' + + def __init__(self, iterator, close=None): + self.iterator = iterator + self.close_callbacks = makelist(close) + + def __iter__(self): + return iter(self.iterator) + + def close(self): + for func in self.close_callbacks: + func() + + +class ResourceManager(object): + ''' This class manages a list of search paths and helps to find and open + application-bound resources (files). + + :param base: default value for :meth:`add_path` calls. + :param opener: callable used to open resources. + :param cachemode: controls which lookups are cached. One of 'all', + 'found' or 'none'. + ''' + + def __init__(self, base='./', opener=open, cachemode='all'): + self.opener = open + self.base = base + self.cachemode = cachemode + + #: A list of search paths. See :meth:`add_path` for details. + self.path = [] + #: A cache for resolved paths. ``res.cache.clear()`` clears the cache. + self.cache = {} + + def add_path(self, path, base=None, index=None, create=False): + ''' Add a new path to the list of search paths. Return False if the + path does not exist. + + :param path: The new search path. Relative paths are turned into + an absolute and normalized form. If the path looks like a file + (not ending in `/`), the filename is stripped off. + :param base: Path used to absolutize relative search paths. + Defaults to :attr:`base` which defaults to ``os.getcwd()``. + :param index: Position within the list of search paths. Defaults + to last index (appends to the list). + + The `base` parameter makes it easy to reference files installed + along with a python module or package:: + + res.add_path('./resources/', __file__) + ''' + base = os.path.abspath(os.path.dirname(base or self.base)) + path = os.path.abspath(os.path.join(base, os.path.dirname(path))) + path += os.sep + if path in self.path: + self.path.remove(path) + if create and not os.path.isdir(path): + os.makedirs(path) + if index is None: + self.path.append(path) + else: + self.path.insert(index, path) + self.cache.clear() + return os.path.exists(path) + + def __iter__(self): + ''' Iterate over all existing files in all registered paths. ''' + search = self.path[:] + while search: + path = search.pop() + if not os.path.isdir(path): continue + for name in os.listdir(path): + full = os.path.join(path, name) + if os.path.isdir(full): search.append(full) + else: yield full + + def lookup(self, name): + ''' Search for a resource and return an absolute file path, or `None`. + + The :attr:`path` list is searched in order. The first match is + returend. Symlinks are followed. The result is cached to speed up + future lookups. ''' + if name not in self.cache or DEBUG: + for path in self.path: + fpath = os.path.join(path, name) + if os.path.isfile(fpath): + if self.cachemode in ('all', 'found'): + self.cache[name] = fpath + return fpath + if self.cachemode == 'all': + self.cache[name] = None + return self.cache[name] + + def open(self, name, mode='r', *args, **kwargs): + ''' Find a resource and return a file object, or raise IOError. ''' + fname = self.lookup(name) + if not fname: raise IOError("Resource %r not found." % name) + return self.opener(fname, mode=mode, *args, **kwargs) + + +class FileUpload(object): + + def __init__(self, fileobj, name, filename, headers=None): + ''' Wrapper for file uploads. ''' + #: Open file(-like) object (BytesIO buffer or temporary file) + self.file = fileobj + #: Name of the upload form field + self.name = name + #: Raw filename as sent by the client (may contain unsafe characters) + self.raw_filename = filename + #: A :class:`HeaderDict` with additional headers (e.g. content-type) + self.headers = HeaderDict(headers) if headers else HeaderDict() + + content_type = HeaderProperty('Content-Type') + content_length = HeaderProperty('Content-Length', reader=int, default=-1) + + @cached_property + def filename(self): + ''' Name of the file on the client file system, but normalized to ensure + file system compatibility (lowercase, no whitespace, no path + separators, no unsafe characters, ASCII only). An empty filename + is returned as 'empty'. + ''' + from unicodedata import normalize #TODO: Module level import? + fname = self.raw_filename + if isinstance(fname, unicode): + fname = normalize('NFKD', fname).encode('ASCII', 'ignore') + fname = fname.decode('ASCII', 'ignore') + fname = os.path.basename(fname.replace('\\', os.path.sep)) + fname = re.sub(r'[^a-zA-Z0-9-_.\s]', '', fname).strip().lower() + fname = re.sub(r'[-\s]+', '-', fname.strip('.').strip()) + return fname or 'empty' + + def _copy_file(self, fp, chunk_size=2**16): + read, write, offset = self.file.read, fp.write, self.file.tell() + while 1: + buf = read(chunk_size) + if not buf: break + write(buf) + self.file.seek(offset) + + def save(self, destination, overwrite=False, chunk_size=2**16): + ''' Save file to disk or copy its content to an open file(-like) object. + If *destination* is a directory, :attr:`filename` is added to the + path. Existing files are not overwritten by default (IOError). + + :param destination: File path, directory or file(-like) object. + :param overwrite: If True, replace existing files. (default: False) + :param chunk_size: Bytes to read at a time. (default: 64kb) + ''' + if isinstance(destination, basestring): # Except file-likes here + if os.path.isdir(destination): + destination = os.path.join(destination, self.filename) + if not overwrite and os.path.exists(destination): + raise IOError('File exists.') + with open(destination, 'wb') as fp: + self._copy_file(fp, chunk_size) + else: + self._copy_file(destination, chunk_size) + + + + + + +############################################################################### +# Application Helper ########################################################### +############################################################################### + + +def abort(code=500, text='Unknown Error: Application stopped.'): + """ Aborts execution and causes a HTTP error. """ + raise HTTPError(code, text) + + +def redirect(url, code=None): + """ Aborts execution and causes a 303 or 302 redirect, depending on + the HTTP protocol version. """ + if not code: + code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302 + res = response.copy(cls=HTTPResponse) + res.status = code + res.body = "" + res.set_header('Location', urljoin(request.url, url)) + raise res + + +def _file_iter_range(fp, offset, bytes, maxread=1024*1024): + ''' Yield chunks from a range in a file. No chunk is bigger than maxread.''' + fp.seek(offset) + while bytes > 0: + part = fp.read(min(bytes, maxread)) + if not part: break + bytes -= len(part) + yield part + + +def static_file(filename, root, mimetype='auto', download=False, charset='UTF-8'): + """ Open a file in a safe way and return :exc:`HTTPResponse` with status + code 200, 305, 401 or 404. The ``Content-Type``, ``Content-Encoding``, + ``Content-Length`` and ``Last-Modified`` headers are set if possible. + Special support for ``If-Modified-Since``, ``Range`` and ``HEAD`` + requests. + + :param filename: Name or path of the file to send. + :param root: Root path for file lookups. Should be an absolute directory + path. + :param mimetype: Defines the content-type header (default: guess from + file extension) + :param download: If True, ask the browser to open a `Save as...` dialog + instead of opening the file with the associated program. You can + specify a custom filename as a string. If not specified, the + original filename is used (default: False). + :param charset: The charset to use for files with a ``text/*`` + mime-type. (default: UTF-8) + """ + + root = os.path.abspath(root) + os.sep + filename = os.path.abspath(os.path.join(root, filename.strip('/\\'))) + headers = dict() + + if not filename.startswith(root): + return HTTPError(403, "Access denied.") + if not os.path.exists(filename) or not os.path.isfile(filename): + return HTTPError(404, "File does not exist.") + if not os.access(filename, os.R_OK): + return HTTPError(403, "You do not have permission to access this file.") + + if mimetype == 'auto': + mimetype, encoding = mimetypes.guess_type(filename) + if encoding: headers['Content-Encoding'] = encoding + + if mimetype: + if mimetype[:5] == 'text/' and charset and 'charset' not in mimetype: + mimetype += '; charset=%s' % charset + headers['Content-Type'] = mimetype + + if download: + download = os.path.basename(filename if download == True else download) + headers['Content-Disposition'] = 'attachment; filename="%s"' % download + + stats = os.stat(filename) + headers['Content-Length'] = clen = stats.st_size + lm = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(stats.st_mtime)) + headers['Last-Modified'] = lm + + ims = request.environ.get('HTTP_IF_MODIFIED_SINCE') + if ims: + ims = parse_date(ims.split(";")[0].strip()) + if ims is not None and ims >= int(stats.st_mtime): + headers['Date'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()) + return HTTPResponse(status=304, **headers) + + body = '' if request.method == 'HEAD' else open(filename, 'rb') + + headers["Accept-Ranges"] = "bytes" + ranges = request.environ.get('HTTP_RANGE') + if 'HTTP_RANGE' in request.environ: + ranges = list(parse_range_header(request.environ['HTTP_RANGE'], clen)) + if not ranges: + return HTTPError(416, "Requested Range Not Satisfiable") + offset, end = ranges[0] + headers["Content-Range"] = "bytes %d-%d/%d" % (offset, end-1, clen) + headers["Content-Length"] = str(end-offset) + if body: body = _file_iter_range(body, offset, end-offset) + return HTTPResponse(body, status=206, **headers) + return HTTPResponse(body, **headers) + + + + + + +############################################################################### +# HTTP Utilities and MISC (TODO) ############################################### +############################################################################### + + +def debug(mode=True): + """ Change the debug level. + There is only one debug level supported at the moment.""" + global DEBUG + if mode: warnings.simplefilter('default') + DEBUG = bool(mode) + +def http_date(value): + if isinstance(value, (datedate, datetime)): + value = value.utctimetuple() + elif isinstance(value, (int, float)): + value = time.gmtime(value) + if not isinstance(value, basestring): + value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value) + return value + +def parse_date(ims): + """ Parse rfc1123, rfc850 and asctime timestamps and return UTC epoch. """ + try: + ts = email.utils.parsedate_tz(ims) + return time.mktime(ts[:8] + (0,)) - (ts[9] or 0) - time.timezone + except (TypeError, ValueError, IndexError, OverflowError): + return None + +def parse_auth(header): + """ Parse rfc2617 HTTP authentication header string (basic) and return (user,pass) tuple or None""" + try: + method, data = header.split(None, 1) + if method.lower() == 'basic': + user, pwd = touni(base64.b64decode(tob(data))).split(':',1) + return user, pwd + except (KeyError, ValueError): + return None + +def parse_range_header(header, maxlen=0): + ''' Yield (start, end) ranges parsed from a HTTP Range header. Skip + unsatisfiable ranges. The end index is non-inclusive.''' + if not header or header[:6] != 'bytes=': return + ranges = [r.split('-', 1) for r in header[6:].split(',') if '-' in r] + for start, end in ranges: + try: + if not start: # bytes=-100 -> last 100 bytes + start, end = max(0, maxlen-int(end)), maxlen + elif not end: # bytes=100- -> all but the first 99 bytes + start, end = int(start), maxlen + else: # bytes=100-200 -> bytes 100-200 (inclusive) + start, end = int(start), min(int(end)+1, maxlen) + if 0 <= start < end <= maxlen: + yield start, end + except ValueError: + pass + +def _parse_qsl(qs): + r = [] + for pair in qs.replace(';','&').split('&'): + if not pair: continue + nv = pair.split('=', 1) + if len(nv) != 2: nv.append('') + key = urlunquote(nv[0].replace('+', ' ')) + value = urlunquote(nv[1].replace('+', ' ')) + r.append((key, value)) + return r + +def _lscmp(a, b): + ''' Compares two strings in a cryptographically safe way: + Runtime is not affected by length of common prefix. ''' + return not sum(0 if x==y else 1 for x, y in zip(a, b)) and len(a) == len(b) + + +def cookie_encode(data, key): + ''' Encode and sign a pickle-able object. Return a (byte) string ''' + msg = base64.b64encode(pickle.dumps(data, -1)) + sig = base64.b64encode(hmac.new(tob(key), msg).digest()) + return tob('!') + sig + tob('?') + msg + + +def cookie_decode(data, key): + ''' Verify and decode an encoded string. Return an object or None.''' + data = tob(data) + if cookie_is_encoded(data): + sig, msg = data.split(tob('?'), 1) + if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(key), msg).digest())): + return pickle.loads(base64.b64decode(msg)) + return None + + +def cookie_is_encoded(data): + ''' Return True if the argument looks like a encoded cookie.''' + return bool(data.startswith(tob('!')) and tob('?') in data) + + +def html_escape(string): + ''' Escape HTML special characters ``&<>`` and quotes ``'"``. ''' + return string.replace('&','&').replace('<','<').replace('>','>')\ + .replace('"','"').replace("'",''') + + +def html_quote(string): + ''' Escape and quote a string to be used as an HTTP attribute.''' + return '"%s"' % html_escape(string).replace('\n','%#10;')\ + .replace('\r',' ').replace('\t',' ') + + +def yieldroutes(func): + """ Return a generator for routes that match the signature (name, args) + of the func parameter. This may yield more than one route if the function + takes optional keyword arguments. The output is best described by example:: + + a() -> '/a' + b(x, y) -> '/b//' + c(x, y=5) -> '/c/' and '/c//' + d(x=5, y=6) -> '/d' and '/d/' and '/d//' + """ + path = '/' + func.__name__.replace('__','/').lstrip('/') + spec = getargspec(func) + argc = len(spec[0]) - len(spec[3] or []) + path += ('/<%s>' * argc) % tuple(spec[0][:argc]) + yield path + for arg in spec[0][argc:]: + path += '/<%s>' % arg + yield path + + +def path_shift(script_name, path_info, shift=1): + ''' Shift path fragments from PATH_INFO to SCRIPT_NAME and vice versa. + + :return: The modified paths. + :param script_name: The SCRIPT_NAME path. + :param script_name: The PATH_INFO path. + :param shift: The number of path fragments to shift. May be negative to + change the shift direction. (default: 1) + ''' + if shift == 0: return script_name, path_info + pathlist = path_info.strip('/').split('/') + scriptlist = script_name.strip('/').split('/') + if pathlist and pathlist[0] == '': pathlist = [] + if scriptlist and scriptlist[0] == '': scriptlist = [] + if shift > 0 and shift <= len(pathlist): + moved = pathlist[:shift] + scriptlist = scriptlist + moved + pathlist = pathlist[shift:] + elif shift < 0 and shift >= -len(scriptlist): + moved = scriptlist[shift:] + pathlist = moved + pathlist + scriptlist = scriptlist[:shift] + else: + empty = 'SCRIPT_NAME' if shift < 0 else 'PATH_INFO' + raise AssertionError("Cannot shift. Nothing left from %s" % empty) + new_script_name = '/' + '/'.join(scriptlist) + new_path_info = '/' + '/'.join(pathlist) + if path_info.endswith('/') and pathlist: new_path_info += '/' + return new_script_name, new_path_info + + +def auth_basic(check, realm="private", text="Access denied"): + ''' Callback decorator to require HTTP auth (basic). + TODO: Add route(check_auth=...) parameter. ''' + def decorator(func): + def wrapper(*a, **ka): + user, password = request.auth or (None, None) + if user is None or not check(user, password): + err = HTTPError(401, text) + err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm) + return err + return func(*a, **ka) + return wrapper + return decorator + + +# Shortcuts for common Bottle methods. +# They all refer to the current default application. + +def make_default_app_wrapper(name): + ''' Return a callable that relays calls to the current default app. ''' + @functools.wraps(getattr(Bottle, name)) + def wrapper(*a, **ka): + return getattr(app(), name)(*a, **ka) + return wrapper + +route = make_default_app_wrapper('route') +get = make_default_app_wrapper('get') +post = make_default_app_wrapper('post') +put = make_default_app_wrapper('put') +delete = make_default_app_wrapper('delete') +error = make_default_app_wrapper('error') +mount = make_default_app_wrapper('mount') +hook = make_default_app_wrapper('hook') +install = make_default_app_wrapper('install') +uninstall = make_default_app_wrapper('uninstall') +url = make_default_app_wrapper('get_url') + + + + + + + +############################################################################### +# Server Adapter ############################################################### +############################################################################### + + +class ServerAdapter(object): + quiet = False + def __init__(self, host='127.0.0.1', port=8080, **options): + self.options = options + self.host = host + self.port = int(port) + + def run(self, handler): # pragma: no cover + pass + + def __repr__(self): + args = ', '.join(['%s=%s'%(k,repr(v)) for k, v in self.options.items()]) + return "%s(%s)" % (self.__class__.__name__, args) + + +class CGIServer(ServerAdapter): + quiet = True + def run(self, handler): # pragma: no cover + from wsgiref.handlers import CGIHandler + def fixed_environ(environ, start_response): + environ.setdefault('PATH_INFO', '') + return handler(environ, start_response) + CGIHandler().run(fixed_environ) + + +class FlupFCGIServer(ServerAdapter): + def run(self, handler): # pragma: no cover + import flup.server.fcgi + self.options.setdefault('bindAddress', (self.host, self.port)) + flup.server.fcgi.WSGIServer(handler, **self.options).run() + + +class WSGIRefServer(ServerAdapter): + def run(self, app): # pragma: no cover + from wsgiref.simple_server import WSGIRequestHandler, WSGIServer + from wsgiref.simple_server import make_server + import socket + + class FixedHandler(WSGIRequestHandler): + def address_string(self): # Prevent reverse DNS lookups please. + return self.client_address[0] + def log_request(*args, **kw): + if not self.quiet: + return WSGIRequestHandler.log_request(*args, **kw) + + handler_cls = self.options.get('handler_class', FixedHandler) + server_cls = self.options.get('server_class', WSGIServer) + + if ':' in self.host: # Fix wsgiref for IPv6 addresses. + if getattr(server_cls, 'address_family') == socket.AF_INET: + class server_cls(server_cls): + address_family = socket.AF_INET6 + + srv = make_server(self.host, self.port, app, server_cls, handler_cls) + srv.serve_forever() + + +class CherryPyServer(ServerAdapter): + def run(self, handler): # pragma: no cover + from cherrypy import wsgiserver + self.options['bind_addr'] = (self.host, self.port) + self.options['wsgi_app'] = handler + server = wsgiserver.CherryPyWSGIServer(**self.options) + try: + server.start() + finally: + server.stop() + + +class WaitressServer(ServerAdapter): + def run(self, handler): + from waitress import serve + serve(handler, host=self.host, port=self.port) + + +class PasteServer(ServerAdapter): + def run(self, handler): # pragma: no cover + from paste import httpserver + from paste.translogger import TransLogger + handler = TransLogger(handler, setup_console_handler=(not self.quiet)) + httpserver.serve(handler, host=self.host, port=str(self.port), + **self.options) + + +class MeinheldServer(ServerAdapter): + def run(self, handler): + from meinheld import server + server.listen((self.host, self.port)) + server.run(handler) + + +class FapwsServer(ServerAdapter): + """ Extremely fast webserver using libev. See http://www.fapws.org/ """ + def run(self, handler): # pragma: no cover + import fapws._evwsgi as evwsgi + from fapws import base, config + port = self.port + if float(config.SERVER_IDENT[-2:]) > 0.4: + # fapws3 silently changed its API in 0.5 + port = str(port) + evwsgi.start(self.host, port) + # fapws3 never releases the GIL. Complain upstream. I tried. No luck. + if 'BOTTLE_CHILD' in os.environ and not self.quiet: + _stderr("WARNING: Auto-reloading does not work with Fapws3.\n") + _stderr(" (Fapws3 breaks python thread support)\n") + evwsgi.set_base_module(base) + def app(environ, start_response): + environ['wsgi.multiprocess'] = False + return handler(environ, start_response) + evwsgi.wsgi_cb(('', app)) + evwsgi.run() + + +class TornadoServer(ServerAdapter): + """ The super hyped asynchronous server by facebook. Untested. """ + def run(self, handler): # pragma: no cover + import tornado.wsgi, tornado.httpserver, tornado.ioloop + container = tornado.wsgi.WSGIContainer(handler) + server = tornado.httpserver.HTTPServer(container) + server.listen(port=self.port,address=self.host) + tornado.ioloop.IOLoop.instance().start() + + +class AppEngineServer(ServerAdapter): + """ Adapter for Google App Engine. """ + quiet = True + def run(self, handler): + from google.appengine.ext.webapp import util + # A main() function in the handler script enables 'App Caching'. + # Lets makes sure it is there. This _really_ improves performance. + module = sys.modules.get('__main__') + if module and not hasattr(module, 'main'): + module.main = lambda: util.run_wsgi_app(handler) + util.run_wsgi_app(handler) + + +class TwistedServer(ServerAdapter): + """ Untested. """ + def run(self, handler): + from twisted.web import server, wsgi + from twisted.python.threadpool import ThreadPool + from twisted.internet import reactor + thread_pool = ThreadPool() + thread_pool.start() + reactor.addSystemEventTrigger('after', 'shutdown', thread_pool.stop) + factory = server.Site(wsgi.WSGIResource(reactor, thread_pool, handler)) + reactor.listenTCP(self.port, factory, interface=self.host) + reactor.run() + + +class DieselServer(ServerAdapter): + """ Untested. """ + def run(self, handler): + from diesel.protocols.wsgi import WSGIApplication + app = WSGIApplication(handler, port=self.port) + app.run() + + +class GeventServer(ServerAdapter): + """ Untested. Options: + + * `fast` (default: False) uses libevent's http server, but has some + issues: No streaming, no pipelining, no SSL. + * See gevent.wsgi.WSGIServer() documentation for more options. + """ + def run(self, handler): + from gevent import wsgi, pywsgi, local + if not isinstance(_lctx, local.local): + msg = "Bottle requires gevent.monkey.patch_all() (before import)" + raise RuntimeError(msg) + if not self.options.pop('fast', None): wsgi = pywsgi + self.options['log'] = None if self.quiet else 'default' + address = (self.host, self.port) + wsgi.WSGIServer(address, handler, **self.options).serve_forever() + + +class GunicornServer(ServerAdapter): + """ Untested. See http://gunicorn.org/configure.html for options. """ + def run(self, handler): + from gunicorn.app.base import Application + + config = {'bind': "%s:%d" % (self.host, int(self.port))} + config.update(self.options) + + class GunicornApplication(Application): + def init(self, parser, opts, args): + return config + + def load(self): + return handler + + GunicornApplication().run() + + +class EventletServer(ServerAdapter): + """ Untested """ + def run(self, handler): + from eventlet import wsgi, listen + try: + wsgi.server(listen((self.host, self.port)), handler, + log_output=(not self.quiet)) + except TypeError: + # Fallback, if we have old version of eventlet + wsgi.server(listen((self.host, self.port)), handler) + + +class RocketServer(ServerAdapter): + """ Untested. """ + def run(self, handler): + from rocket import Rocket + server = Rocket((self.host, self.port), 'wsgi', { 'wsgi_app' : handler }) + server.start() + + +class BjoernServer(ServerAdapter): + """ Fast server written in C: https://github.com/jonashaag/bjoern """ + def run(self, handler): + from bjoern import run + run(handler, self.host, self.port) + + +class AutoServer(ServerAdapter): + """ Untested. """ + adapters = [WaitressServer, PasteServer, TwistedServer, CherryPyServer, WSGIRefServer] + def run(self, handler): + for sa in self.adapters: + try: + return sa(self.host, self.port, **self.options).run(handler) + except ImportError: + pass + +server_names = { + 'cgi': CGIServer, + 'flup': FlupFCGIServer, + 'wsgiref': WSGIRefServer, + 'waitress': WaitressServer, + 'cherrypy': CherryPyServer, + 'paste': PasteServer, + 'fapws3': FapwsServer, + 'tornado': TornadoServer, + 'gae': AppEngineServer, + 'twisted': TwistedServer, + 'diesel': DieselServer, + 'meinheld': MeinheldServer, + 'gunicorn': GunicornServer, + 'eventlet': EventletServer, + 'gevent': GeventServer, + 'rocket': RocketServer, + 'bjoern' : BjoernServer, + 'auto': AutoServer, +} + + + + + + +############################################################################### +# Application Control ########################################################## +############################################################################### + + +def load(target, **namespace): + """ Import a module or fetch an object from a module. + + * ``package.module`` returns `module` as a module object. + * ``pack.mod:name`` returns the module variable `name` from `pack.mod`. + * ``pack.mod:func()`` calls `pack.mod.func()` and returns the result. + + The last form accepts not only function calls, but any type of + expression. Keyword arguments passed to this function are available as + local variables. Example: ``import_string('re:compile(x)', x='[a-z]')`` + """ + module, target = target.split(":", 1) if ':' in target else (target, None) + if module not in sys.modules: __import__(module) + if not target: return sys.modules[module] + if target.isalnum(): return getattr(sys.modules[module], target) + package_name = module.split('.')[0] + namespace[package_name] = sys.modules[package_name] + return eval('%s.%s' % (module, target), namespace) + + +def load_app(target): + """ Load a bottle application from a module and make sure that the import + does not affect the current default application, but returns a separate + application object. See :func:`load` for the target parameter. """ + global NORUN; NORUN, nr_old = True, NORUN + try: + tmp = default_app.push() # Create a new "default application" + rv = load(target) # Import the target module + return rv if callable(rv) else tmp + finally: + default_app.remove(tmp) # Remove the temporary added default application + NORUN = nr_old + +_debug = debug +def run(app=None, server='wsgiref', host='127.0.0.1', port=8080, + interval=1, reloader=False, quiet=False, plugins=None, + debug=None, **kargs): + """ Start a server instance. This method blocks until the server terminates. + + :param app: WSGI application or target string supported by + :func:`load_app`. (default: :func:`default_app`) + :param server: Server adapter to use. See :data:`server_names` keys + for valid names or pass a :class:`ServerAdapter` subclass. + (default: `wsgiref`) + :param host: Server address to bind to. Pass ``0.0.0.0`` to listens on + all interfaces including the external one. (default: 127.0.0.1) + :param port: Server port to bind to. Values below 1024 require root + privileges. (default: 8080) + :param reloader: Start auto-reloading server? (default: False) + :param interval: Auto-reloader interval in seconds (default: 1) + :param quiet: Suppress output to stdout and stderr? (default: False) + :param options: Options passed to the server adapter. + """ + if NORUN: return + if reloader and not os.environ.get('BOTTLE_CHILD'): + try: + lockfile = None + fd, lockfile = tempfile.mkstemp(prefix='bottle.', suffix='.lock') + os.close(fd) # We only need this file to exist. We never write to it + while os.path.exists(lockfile): + args = [sys.executable] + sys.argv + environ = os.environ.copy() + environ['BOTTLE_CHILD'] = 'true' + environ['BOTTLE_LOCKFILE'] = lockfile + p = subprocess.Popen(args, env=environ) + while p.poll() is None: # Busy wait... + os.utime(lockfile, None) # I am alive! + time.sleep(interval) + if p.poll() != 3: + if os.path.exists(lockfile): os.unlink(lockfile) + sys.exit(p.poll()) + except KeyboardInterrupt: + pass + finally: + if os.path.exists(lockfile): + os.unlink(lockfile) + return + + try: + if debug is not None: _debug(debug) + app = app or default_app() + if isinstance(app, basestring): + app = load_app(app) + if not callable(app): + raise ValueError("Application is not callable: %r" % app) + + for plugin in plugins or []: + app.install(plugin) + + if server in server_names: + server = server_names.get(server) + if isinstance(server, basestring): + server = load(server) + if isinstance(server, type): + server = server(host=host, port=port, **kargs) + if not isinstance(server, ServerAdapter): + raise ValueError("Unknown or unsupported server: %r" % server) + + server.quiet = server.quiet or quiet + if not server.quiet: + _stderr("Bottle v%s server starting up (using %s)...\n" % (__version__, repr(server))) + _stderr("Listening on http://%s:%d/\n" % (server.host, server.port)) + _stderr("Hit Ctrl-C to quit.\n\n") + + if reloader: + lockfile = os.environ.get('BOTTLE_LOCKFILE') + bgcheck = FileCheckerThread(lockfile, interval) + with bgcheck: + server.run(app) + if bgcheck.status == 'reload': + sys.exit(3) + else: + server.run(app) + except KeyboardInterrupt: + pass + except (SystemExit, MemoryError): + raise + except: + if not reloader: raise + if not getattr(server, 'quiet', quiet): + print_exc() + time.sleep(interval) + sys.exit(3) + + + +class FileCheckerThread(threading.Thread): + ''' Interrupt main-thread as soon as a changed module file is detected, + the lockfile gets deleted or gets to old. ''' + + def __init__(self, lockfile, interval): + threading.Thread.__init__(self) + self.lockfile, self.interval = lockfile, interval + #: Is one of 'reload', 'error' or 'exit' + self.status = None + + def run(self): + exists = os.path.exists + mtime = lambda path: os.stat(path).st_mtime + files = dict() + + for module in list(sys.modules.values()): + path = getattr(module, '__file__', '') + if path[-4:] in ('.pyo', '.pyc'): path = path[:-1] + if path and exists(path): files[path] = mtime(path) + + while not self.status: + if not exists(self.lockfile)\ + or mtime(self.lockfile) < time.time() - self.interval - 5: + self.status = 'error' + thread.interrupt_main() + for path, lmtime in list(files.items()): + if not exists(path) or mtime(path) > lmtime: + self.status = 'reload' + thread.interrupt_main() + break + time.sleep(self.interval) + + def __enter__(self): + self.start() + + def __exit__(self, exc_type, exc_val, exc_tb): + if not self.status: self.status = 'exit' # silent exit + self.join() + return exc_type is not None and issubclass(exc_type, KeyboardInterrupt) + + + + + +############################################################################### +# Template Adapters ############################################################ +############################################################################### + + +class TemplateError(HTTPError): + def __init__(self, message): + HTTPError.__init__(self, 500, message) + + +class BaseTemplate(object): + """ Base class and minimal API for template adapters """ + extensions = ['tpl','html','thtml','stpl'] + settings = {} #used in prepare() + defaults = {} #used in render() + + def __init__(self, source=None, name=None, lookup=[], encoding='utf8', **settings): + """ Create a new template. + If the source parameter (str or buffer) is missing, the name argument + is used to guess a template filename. Subclasses can assume that + self.source and/or self.filename are set. Both are strings. + The lookup, encoding and settings parameters are stored as instance + variables. + The lookup parameter stores a list containing directory paths. + The encoding parameter should be used to decode byte strings or files. + The settings parameter contains a dict for engine-specific settings. + """ + self.name = name + self.source = source.read() if hasattr(source, 'read') else source + self.filename = source.filename if hasattr(source, 'filename') else None + self.lookup = [os.path.abspath(x) for x in lookup] + self.encoding = encoding + self.settings = self.settings.copy() # Copy from class variable + self.settings.update(settings) # Apply + if not self.source and self.name: + self.filename = self.search(self.name, self.lookup) + if not self.filename: + raise TemplateError('Template %s not found.' % repr(name)) + if not self.source and not self.filename: + raise TemplateError('No template specified.') + self.prepare(**self.settings) + + @classmethod + def search(cls, name, lookup=[]): + """ Search name in all directories specified in lookup. + First without, then with common extensions. Return first hit. """ + if not lookup: + depr('The template lookup path list should not be empty.') + lookup = ['.'] + + if os.path.isabs(name) and os.path.isfile(name): + depr('Absolute template path names are deprecated.') + return os.path.abspath(name) + + for spath in lookup: + spath = os.path.abspath(spath) + os.sep + fname = os.path.abspath(os.path.join(spath, name)) + if not fname.startswith(spath): continue + if os.path.isfile(fname): return fname + for ext in cls.extensions: + if os.path.isfile('%s.%s' % (fname, ext)): + return '%s.%s' % (fname, ext) + + @classmethod + def global_config(cls, key, *args): + ''' This reads or sets the global settings stored in class.settings. ''' + if args: + cls.settings = cls.settings.copy() # Make settings local to class + cls.settings[key] = args[0] + else: + return cls.settings[key] + + def prepare(self, **options): + """ Run preparations (parsing, caching, ...). + It should be possible to call this again to refresh a template or to + update settings. + """ + raise NotImplementedError + + def render(self, *args, **kwargs): + """ Render the template with the specified local variables and return + a single byte or unicode string. If it is a byte string, the encoding + must match self.encoding. This method must be thread-safe! + Local variables may be provided in dictionaries (args) + or directly, as keywords (kwargs). + """ + raise NotImplementedError + + +class MakoTemplate(BaseTemplate): + def prepare(self, **options): + from mako.template import Template + from mako.lookup import TemplateLookup + options.update({'input_encoding':self.encoding}) + options.setdefault('format_exceptions', bool(DEBUG)) + lookup = TemplateLookup(directories=self.lookup, **options) + if self.source: + self.tpl = Template(self.source, lookup=lookup, **options) + else: + self.tpl = Template(uri=self.name, filename=self.filename, lookup=lookup, **options) + + def render(self, *args, **kwargs): + for dictarg in args: kwargs.update(dictarg) + _defaults = self.defaults.copy() + _defaults.update(kwargs) + return self.tpl.render(**_defaults) + + +class CheetahTemplate(BaseTemplate): + def prepare(self, **options): + from Cheetah.Template import Template + self.context = threading.local() + self.context.vars = {} + options['searchList'] = [self.context.vars] + if self.source: + self.tpl = Template(source=self.source, **options) + else: + self.tpl = Template(file=self.filename, **options) + + def render(self, *args, **kwargs): + for dictarg in args: kwargs.update(dictarg) + self.context.vars.update(self.defaults) + self.context.vars.update(kwargs) + out = str(self.tpl) + self.context.vars.clear() + return out + + +class Jinja2Template(BaseTemplate): + def prepare(self, filters=None, tests=None, **kwargs): + from jinja2 import Environment, FunctionLoader + if 'prefix' in kwargs: # TODO: to be removed after a while + raise RuntimeError('The keyword argument `prefix` has been removed. ' + 'Use the full jinja2 environment name line_statement_prefix instead.') + self.env = Environment(loader=FunctionLoader(self.loader), **kwargs) + if filters: self.env.filters.update(filters) + if tests: self.env.tests.update(tests) + if self.source: + self.tpl = self.env.from_string(self.source) + else: + self.tpl = self.env.get_template(self.filename) + + def render(self, *args, **kwargs): + for dictarg in args: kwargs.update(dictarg) + _defaults = self.defaults.copy() + _defaults.update(kwargs) + return self.tpl.render(**_defaults) + + def loader(self, name): + fname = self.search(name, self.lookup) + if not fname: return + with open(fname, "rb") as f: + return f.read().decode(self.encoding) + + +class SimpleTemplate(BaseTemplate): + + def prepare(self, escape_func=html_escape, noescape=False, syntax=None, **ka): + self.cache = {} + enc = self.encoding + self._str = lambda x: touni(x, enc) + self._escape = lambda x: escape_func(touni(x, enc)) + self.syntax = syntax + if noescape: + self._str, self._escape = self._escape, self._str + + @cached_property + def co(self): + return compile(self.code, self.filename or '', 'exec') + + @cached_property + def code(self): + source = self.source or open(self.filename, 'rb').read() + try: + source, encoding = touni(source), 'utf8' + except UnicodeError: + depr('Template encodings other than utf8 are no longer supported.') + source, encoding = touni(source, 'latin1'), 'latin1' + parser = StplParser(source, encoding=encoding, syntax=self.syntax) + code = parser.translate() + self.encoding = parser.encoding + return code + + def _rebase(self, _env, _name=None, **kwargs): + if _name is None: + depr('Rebase function called without arguments.' + ' You were probably looking for {{base}}?', True) + _env['_rebase'] = (_name, kwargs) + + def _include(self, _env, _name=None, **kwargs): + if _name is None: + depr('Rebase function called without arguments.' + ' You were probably looking for {{base}}?', True) + env = _env.copy() + env.update(kwargs) + if _name not in self.cache: + self.cache[_name] = self.__class__(name=_name, lookup=self.lookup) + return self.cache[_name].execute(env['_stdout'], env) + + def execute(self, _stdout, kwargs): + env = self.defaults.copy() + env.update(kwargs) + env.update({'_stdout': _stdout, '_printlist': _stdout.extend, + 'include': functools.partial(self._include, env), + 'rebase': functools.partial(self._rebase, env), '_rebase': None, + '_str': self._str, '_escape': self._escape, 'get': env.get, + 'setdefault': env.setdefault, 'defined': env.__contains__ }) + eval(self.co, env) + if env.get('_rebase'): + subtpl, rargs = env.pop('_rebase') + rargs['base'] = ''.join(_stdout) #copy stdout + del _stdout[:] # clear stdout + return self._include(env, subtpl, **rargs) + return env + + def render(self, *args, **kwargs): + """ Render the template using keyword arguments as local variables. """ + env = {}; stdout = [] + for dictarg in args: env.update(dictarg) + env.update(kwargs) + self.execute(stdout, env) + return ''.join(stdout) + + +class StplSyntaxError(TemplateError): pass + + +class StplParser(object): + ''' Parser for stpl templates. ''' + _re_cache = {} #: Cache for compiled re patterns + # This huge pile of voodoo magic splits python code into 8 different tokens. + # 1: All kinds of python strings (trust me, it works) + _re_tok = '((?m)[urbURB]?(?:\'\'(?!\')|""(?!")|\'{6}|"{6}' \ + '|\'(?:[^\\\\\']|\\\\.)+?\'|"(?:[^\\\\"]|\\\\.)+?"' \ + '|\'{3}(?:[^\\\\]|\\\\.|\\n)+?\'{3}' \ + '|"{3}(?:[^\\\\]|\\\\.|\\n)+?"{3}))' + _re_inl = _re_tok.replace('|\\n','') # We re-use this string pattern later + # 2: Comments (until end of line, but not the newline itself) + _re_tok += '|(#.*)' + # 3,4: Keywords that start or continue a python block (only start of line) + _re_tok += '|^([ \\t]*(?:if|for|while|with|try|def|class)\\b)' \ + '|^([ \\t]*(?:elif|else|except|finally)\\b)' + # 5: Our special 'end' keyword (but only if it stands alone) + _re_tok += '|((?:^|;)[ \\t]*end[ \\t]*(?=(?:%(block_close)s[ \\t]*)?\\r?$|;|#))' + # 6: A customizable end-of-code-block template token (only end of line) + _re_tok += '|(%(block_close)s[ \\t]*(?=$))' + # 7: And finally, a single newline. The 8th token is 'everything else' + _re_tok += '|(\\r?\\n)' + # Match the start tokens of code areas in a template + _re_split = '(?m)^[ \t]*(\\\\?)((%(line_start)s)|(%(block_start)s))(%%?)' + # Match inline statements (may contain python strings) + _re_inl = '%%(inline_start)s((?:%s|[^\'"\n]*?)+)%%(inline_end)s' % _re_inl + + default_syntax = '<% %> % {{ }}' + + def __init__(self, source, syntax=None, encoding='utf8'): + self.source, self.encoding = touni(source, encoding), encoding + self.set_syntax(syntax or self.default_syntax) + self.code_buffer, self.text_buffer = [], [] + self.lineno, self.offset = 1, 0 + self.indent, self.indent_mod = 0, 0 + + def get_syntax(self): + ''' Tokens as a space separated string (default: <% %> % {{ }}) ''' + return self._syntax + + def set_syntax(self, syntax): + self._syntax = syntax + self._tokens = syntax.split() + if not syntax in self._re_cache: + names = 'block_start block_close line_start inline_start inline_end' + etokens = map(re.escape, self._tokens) + pattern_vars = dict(zip(names.split(), etokens)) + patterns = (self._re_split, self._re_tok, self._re_inl) + patterns = [re.compile(p%pattern_vars) for p in patterns] + self._re_cache[syntax] = patterns + self.re_split, self.re_tok, self.re_inl = self._re_cache[syntax] + + syntax = property(get_syntax, set_syntax) + + def translate(self): + if self.offset: raise RuntimeError('Parser is a one time instance.') + while True: + m = self.re_split.search(self.source[self.offset:]) + if m: + text = self.source[self.offset:self.offset+m.start()] + self.text_buffer.append(text) + self.offset += m.end() + if m.group(1): # New escape syntax + line, sep, _ = self.source[self.offset:].partition('\n') + self.text_buffer.append(m.group(2)+m.group(5)+line+sep) + self.offset += len(line+sep)+1 + continue + elif m.group(5): # Old escape syntax + depr('Escape code lines with a backslash.') + line, sep, _ = self.source[self.offset:].partition('\n') + self.text_buffer.append(m.group(2)+line+sep) + self.offset += len(line+sep)+1 + continue + self.flush_text() + self.read_code(multiline=bool(m.group(4))) + else: break + self.text_buffer.append(self.source[self.offset:]) + self.flush_text() + return ''.join(self.code_buffer) + + def read_code(self, multiline): + code_line, comment, start_line = '', '', self.lineno + while True: + m = self.re_tok.search(self.source[self.offset:]) + if not m: + code_line += self.source[self.offset:] + self.offset = len(self.source) + self.write_code(code_line.strip(), comment) + return + code_line += self.source[self.offset:self.offset+m.start()] + self.offset += m.end() + _str, _com, _blk1, _blk2, _end, _cend, _nl = m.groups() + if _str: # Python string + code_line += _str + elif _com: # Python comment (up to EOL) + comment = _com + if multiline and _com.strip().endswith(self._tokens[1]): + multiline = False # Allow end-of-block in comments + elif _blk1: # Start-block keyword (if/for/while/def/try/...) + code_line, self.indent_mod = _blk1, -1 + self.indent += 1 + elif _blk2: # Continue-block keyword (else/elif/except/...) + code_line, self.indent_mod = _blk2, -1 + elif _end: # The non-standard 'end'-keyword (ends a block) + self.indent -= 1 + elif _cend: # The end-code-block template token (usually '%>') + if multiline: multiline = False + else: code_line += _cend + else: # \n + self.write_code(code_line.strip(), comment) + self.lineno += 1 + code_line, comment, self.indent_mod = '', '', 0 + if not multiline: + break + + def flush_text(self): + text = ''.join(self.text_buffer) + del self.text_buffer[:] + if not text: return + parts, pos, nl = [], 0, '\\\n'+' '*self.indent + for m in self.re_inl.finditer(text): + prefix, pos = text[pos:m.start()], m.end() + if prefix: + parts.append(nl.join(map(repr, prefix.splitlines(True)))) + if prefix.endswith('\n'): parts[-1] += nl + parts.append(self.process_inline(m.group(1).strip())) + if pos < len(text): + prefix = text[pos:] + lines = prefix.splitlines(True) + if lines[-1].endswith('\\\\\n'): lines[-1] = lines[-1][:-3] + parts.append(nl.join(map(repr, lines))) + code = '_printlist((%s,))' % ', '.join(parts) + self.lineno += code.count('\n')+1 + self.write_code(code) + + def process_inline(self, chunk): + if chunk[0] == '!': return '_str(%s)' % chunk[1:] + return '_escape(%s)' % chunk + + def write_code(self, line, comment=''): + line, comment = self.fix_backward_compatibility(line, comment) + code = ' ' * (self.indent+self.indent_mod) + code += line.lstrip() + comment + '\n' + self.code_buffer.append(code) + + def fix_backward_compatibility(self, line, comment): + parts = line.strip().split(None, 2) + if parts and parts[0] in ('include', 'rebase'): + depr('The include and rebase keywords are functions now.') + if len(parts) == 1: return "_printlist([base])", comment + elif len(parts) == 2: return "_=%s(%r)" % tuple(parts), comment + else: return "_=%s(%r, %s)" % tuple(parts), comment + if self.lineno <= 2 and not line.strip() and 'coding' in comment: + m = re.match(r"#.*coding[:=]\s*([-\w.]+)", comment) + if m: + depr('PEP263 encoding strings in templates are deprecated.') + enc = m.group(1) + self.source = self.source.encode(self.encoding).decode(enc) + self.encoding = enc + return line, comment.replace('coding','coding*') + return line, comment + + +def template(*args, **kwargs): + ''' + Get a rendered template as a string iterator. + You can use a name, a filename or a template string as first parameter. + Template rendering arguments can be passed as dictionaries + or directly (as keyword arguments). + ''' + tpl = args[0] if args else None + adapter = kwargs.pop('template_adapter', SimpleTemplate) + lookup = kwargs.pop('template_lookup', TEMPLATE_PATH) + tplid = (id(lookup), tpl) + if tplid not in TEMPLATES or DEBUG: + settings = kwargs.pop('template_settings', {}) + if isinstance(tpl, adapter): + TEMPLATES[tplid] = tpl + if settings: TEMPLATES[tplid].prepare(**settings) + elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl: + TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings) + else: + TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings) + if not TEMPLATES[tplid]: + abort(500, 'Template (%s) not found' % tpl) + for dictarg in args[1:]: kwargs.update(dictarg) + return TEMPLATES[tplid].render(kwargs) + +mako_template = functools.partial(template, template_adapter=MakoTemplate) +cheetah_template = functools.partial(template, template_adapter=CheetahTemplate) +jinja2_template = functools.partial(template, template_adapter=Jinja2Template) + + +def view(tpl_name, **defaults): + ''' Decorator: renders a template for a handler. + The handler can control its behavior like that: + + - return a dict of template vars to fill out the template + - return something other than a dict and the view decorator will not + process the template, but return the handler result as is. + This includes returning a HTTPResponse(dict) to get, + for instance, JSON with autojson or other castfilters. + ''' + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + result = func(*args, **kwargs) + if isinstance(result, (dict, DictMixin)): + tplvars = defaults.copy() + tplvars.update(result) + return template(tpl_name, **tplvars) + elif result is None: + return template(tpl_name, defaults) + return result + return wrapper + return decorator + +mako_view = functools.partial(view, template_adapter=MakoTemplate) +cheetah_view = functools.partial(view, template_adapter=CheetahTemplate) +jinja2_view = functools.partial(view, template_adapter=Jinja2Template) + + + + + + +############################################################################### +# Constants and Globals ######################################################## +############################################################################### + + +TEMPLATE_PATH = ['./', './views/'] +TEMPLATES = {} +DEBUG = False +NORUN = False # If set, run() does nothing. Used by load_app() + +#: A dict to map HTTP status codes (e.g. 404) to phrases (e.g. 'Not Found') +HTTP_CODES = httplib.responses +HTTP_CODES[418] = "I'm a teapot" # RFC 2324 +HTTP_CODES[428] = "Precondition Required" +HTTP_CODES[429] = "Too Many Requests" +HTTP_CODES[431] = "Request Header Fields Too Large" +HTTP_CODES[511] = "Network Authentication Required" +_HTTP_STATUS_LINES = dict((k, '%d %s'%(k,v)) for (k,v) in HTTP_CODES.items()) + +#: The default template used for error pages. Override with @error() +ERROR_PAGE_TEMPLATE = """ +%%try: + %%from %s import DEBUG, HTTP_CODES, request, touni + + + + Error: {{e.status}} + + + +

Error: {{e.status}}

+

Sorry, the requested URL {{repr(request.url)}} + caused an error:

+
{{e.body}}
+ %%if DEBUG and e.exception: +

Exception:

+
{{repr(e.exception)}}
+ %%end + %%if DEBUG and e.traceback: +

Traceback:

+
{{e.traceback}}
+ %%end + + +%%except ImportError: + ImportError: Could not generate the error page. Please add bottle to + the import path. +%%end +""" % __name__ + +#: A thread-safe instance of :class:`LocalRequest`. If accessed from within a +#: request callback, this instance always refers to the *current* request +#: (even on a multithreaded server). +request = LocalRequest() + +#: A thread-safe instance of :class:`LocalResponse`. It is used to change the +#: HTTP response for the *current* request. +response = LocalResponse() + +#: A thread-safe namespace. Not used by Bottle. +local = threading.local() + +# Initialize app stack (create first empty Bottle app) +# BC: 0.6.4 and needed for run() +app = default_app = AppStack() +app.push() + +#: A virtual package that redirects import statements. +#: Example: ``import bottle.ext.sqlite`` actually imports `bottle_sqlite`. +ext = _ImportRedirect('bottle.ext' if __name__ == '__main__' else __name__+".ext", 'bottle_%s').module + +if __name__ == '__main__': + opt, args, parser = _cmd_options, _cmd_args, _cmd_parser + if opt.version: + _stdout('Bottle %s\n'%__version__) + sys.exit(0) + if not args: + parser.print_help() + _stderr('\nError: No application specified.\n') + sys.exit(1) + + sys.path.insert(0, '.') + sys.modules.setdefault('bottle', sys.modules['__main__']) + + host, port = (opt.bind or 'localhost'), 8080 + if ':' in host and host.rfind(']') < host.rfind(':'): + host, port = host.rsplit(':', 1) + host = host.strip('[]') + + run(args[0], host=host, port=int(port), server=opt.server, + reloader=opt.reload, plugins=opt.plugin, debug=opt.debug) + + + + +# THE END diff --git a/share/frontend/impattern/old/index.html.old b/share/frontend/impattern/old/index.html.old new file mode 100644 index 0000000..fbb5850 --- /dev/null +++ b/share/frontend/impattern/old/index.html.old @@ -0,0 +1,305 @@ + + + + + + + +
+ +
+ +
+Step 1: Choose your dither +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  
+ + +
  +
+ +
+Image to overlay: +Or Upload +
+ + +
+
+ + + + + + + + + diff --git a/share/frontend/impattern/old/oldpatterns/1.png b/share/frontend/impattern/old/oldpatterns/1.png new file mode 100644 index 0000000..a0aeccb Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/1.png differ diff --git a/share/frontend/impattern/old/oldpatterns/10.png b/share/frontend/impattern/old/oldpatterns/10.png new file mode 100644 index 0000000..3865589 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/10.png differ diff --git a/share/frontend/impattern/old/oldpatterns/11.png b/share/frontend/impattern/old/oldpatterns/11.png new file mode 100644 index 0000000..2a8ca34 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/11.png differ diff --git a/share/frontend/impattern/old/oldpatterns/12.png b/share/frontend/impattern/old/oldpatterns/12.png new file mode 100644 index 0000000..4adb35f Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/12.png differ diff --git a/share/frontend/impattern/old/oldpatterns/13.png b/share/frontend/impattern/old/oldpatterns/13.png new file mode 100644 index 0000000..48e9362 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/13.png differ diff --git a/share/frontend/impattern/old/oldpatterns/14.png b/share/frontend/impattern/old/oldpatterns/14.png new file mode 100644 index 0000000..867b0a9 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/14.png differ diff --git a/share/frontend/impattern/old/oldpatterns/15.png b/share/frontend/impattern/old/oldpatterns/15.png new file mode 100644 index 0000000..f37be5a Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/15.png differ diff --git a/share/frontend/impattern/old/oldpatterns/16.png b/share/frontend/impattern/old/oldpatterns/16.png new file mode 100644 index 0000000..7994ced Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/16.png differ diff --git a/share/frontend/impattern/old/oldpatterns/17.png b/share/frontend/impattern/old/oldpatterns/17.png new file mode 100644 index 0000000..9ffa444 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/17.png differ diff --git a/share/frontend/impattern/old/oldpatterns/18.png b/share/frontend/impattern/old/oldpatterns/18.png new file mode 100644 index 0000000..2522e8d Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/18.png differ diff --git a/share/frontend/impattern/old/oldpatterns/19.png b/share/frontend/impattern/old/oldpatterns/19.png new file mode 100644 index 0000000..5b4ac7a Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/19.png differ diff --git a/share/frontend/impattern/old/oldpatterns/2.png b/share/frontend/impattern/old/oldpatterns/2.png new file mode 100644 index 0000000..a6aa256 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/2.png differ diff --git a/share/frontend/impattern/old/oldpatterns/20.png b/share/frontend/impattern/old/oldpatterns/20.png new file mode 100644 index 0000000..57a82c1 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/20.png differ diff --git a/share/frontend/impattern/old/oldpatterns/21.png b/share/frontend/impattern/old/oldpatterns/21.png new file mode 100644 index 0000000..2b671c7 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/21.png differ diff --git a/share/frontend/impattern/old/oldpatterns/22.png b/share/frontend/impattern/old/oldpatterns/22.png new file mode 100644 index 0000000..d28f071 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/22.png differ diff --git a/share/frontend/impattern/old/oldpatterns/23.png b/share/frontend/impattern/old/oldpatterns/23.png new file mode 100644 index 0000000..052cf6f Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/23.png differ diff --git a/share/frontend/impattern/old/oldpatterns/24.png b/share/frontend/impattern/old/oldpatterns/24.png new file mode 100644 index 0000000..4bee000 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/24.png differ diff --git a/share/frontend/impattern/old/oldpatterns/25.png b/share/frontend/impattern/old/oldpatterns/25.png new file mode 100644 index 0000000..cbd1097 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/25.png differ diff --git a/share/frontend/impattern/old/oldpatterns/26.png b/share/frontend/impattern/old/oldpatterns/26.png new file mode 100644 index 0000000..5fc32f4 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/26.png differ diff --git a/share/frontend/impattern/old/oldpatterns/27.png b/share/frontend/impattern/old/oldpatterns/27.png new file mode 100644 index 0000000..18ce493 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/27.png differ diff --git a/share/frontend/impattern/old/oldpatterns/28.png b/share/frontend/impattern/old/oldpatterns/28.png new file mode 100644 index 0000000..5924c44 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/28.png differ diff --git a/share/frontend/impattern/old/oldpatterns/29.png b/share/frontend/impattern/old/oldpatterns/29.png new file mode 100644 index 0000000..16fc2a5 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/29.png differ diff --git a/share/frontend/impattern/old/oldpatterns/3.png b/share/frontend/impattern/old/oldpatterns/3.png new file mode 100644 index 0000000..8c3d334 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/3.png differ diff --git a/share/frontend/impattern/old/oldpatterns/30.png b/share/frontend/impattern/old/oldpatterns/30.png new file mode 100644 index 0000000..50c8289 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/30.png differ diff --git a/share/frontend/impattern/old/oldpatterns/31.png b/share/frontend/impattern/old/oldpatterns/31.png new file mode 100644 index 0000000..3dd944e Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/31.png differ diff --git a/share/frontend/impattern/old/oldpatterns/32.png b/share/frontend/impattern/old/oldpatterns/32.png new file mode 100644 index 0000000..79aeb84 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/32.png differ diff --git a/share/frontend/impattern/old/oldpatterns/33.png b/share/frontend/impattern/old/oldpatterns/33.png new file mode 100644 index 0000000..55def42 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/33.png differ diff --git a/share/frontend/impattern/old/oldpatterns/34.png b/share/frontend/impattern/old/oldpatterns/34.png new file mode 100644 index 0000000..f7616ea Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/34.png differ diff --git a/share/frontend/impattern/old/oldpatterns/35.png b/share/frontend/impattern/old/oldpatterns/35.png new file mode 100644 index 0000000..3ecbaaf Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/35.png differ diff --git a/share/frontend/impattern/old/oldpatterns/36.png b/share/frontend/impattern/old/oldpatterns/36.png new file mode 100644 index 0000000..0243cf7 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/36.png differ diff --git a/share/frontend/impattern/old/oldpatterns/37.png b/share/frontend/impattern/old/oldpatterns/37.png new file mode 100644 index 0000000..012ed79 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/37.png differ diff --git a/share/frontend/impattern/old/oldpatterns/38.png b/share/frontend/impattern/old/oldpatterns/38.png new file mode 100644 index 0000000..9aa54b7 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/38.png differ diff --git a/share/frontend/impattern/old/oldpatterns/39.png b/share/frontend/impattern/old/oldpatterns/39.png new file mode 100644 index 0000000..e98ec53 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/39.png differ diff --git a/share/frontend/impattern/old/oldpatterns/4.png b/share/frontend/impattern/old/oldpatterns/4.png new file mode 100644 index 0000000..473e6e7 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/4.png differ diff --git a/share/frontend/impattern/old/oldpatterns/40.png b/share/frontend/impattern/old/oldpatterns/40.png new file mode 100644 index 0000000..d7d7cba Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/40.png differ diff --git a/share/frontend/impattern/old/oldpatterns/41.png b/share/frontend/impattern/old/oldpatterns/41.png new file mode 100644 index 0000000..5d15dd7 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/41.png differ diff --git a/share/frontend/impattern/old/oldpatterns/42.png b/share/frontend/impattern/old/oldpatterns/42.png new file mode 100644 index 0000000..dedbfe2 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/42.png differ diff --git a/share/frontend/impattern/old/oldpatterns/43.png b/share/frontend/impattern/old/oldpatterns/43.png new file mode 100644 index 0000000..dd690d6 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/43.png differ diff --git a/share/frontend/impattern/old/oldpatterns/44.png b/share/frontend/impattern/old/oldpatterns/44.png new file mode 100644 index 0000000..12afc85 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/44.png differ diff --git a/share/frontend/impattern/old/oldpatterns/45.png b/share/frontend/impattern/old/oldpatterns/45.png new file mode 100644 index 0000000..972933b Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/45.png differ diff --git a/share/frontend/impattern/old/oldpatterns/46.png b/share/frontend/impattern/old/oldpatterns/46.png new file mode 100644 index 0000000..857ef06 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/46.png differ diff --git a/share/frontend/impattern/old/oldpatterns/47.png b/share/frontend/impattern/old/oldpatterns/47.png new file mode 100644 index 0000000..4002e54 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/47.png differ diff --git a/share/frontend/impattern/old/oldpatterns/48.png b/share/frontend/impattern/old/oldpatterns/48.png new file mode 100644 index 0000000..ff785ed Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/48.png differ diff --git a/share/frontend/impattern/old/oldpatterns/49.png b/share/frontend/impattern/old/oldpatterns/49.png new file mode 100644 index 0000000..1a8525f Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/49.png differ diff --git a/share/frontend/impattern/old/oldpatterns/5.png b/share/frontend/impattern/old/oldpatterns/5.png new file mode 100644 index 0000000..7bd6619 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/5.png differ diff --git a/share/frontend/impattern/old/oldpatterns/50.png b/share/frontend/impattern/old/oldpatterns/50.png new file mode 100644 index 0000000..f32d908 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/50.png differ diff --git a/share/frontend/impattern/old/oldpatterns/51.png b/share/frontend/impattern/old/oldpatterns/51.png new file mode 100644 index 0000000..20dc9ca Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/51.png differ diff --git a/share/frontend/impattern/old/oldpatterns/52.png b/share/frontend/impattern/old/oldpatterns/52.png new file mode 100644 index 0000000..0e097fa Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/52.png differ diff --git a/share/frontend/impattern/old/oldpatterns/53.png b/share/frontend/impattern/old/oldpatterns/53.png new file mode 100644 index 0000000..eec7951 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/53.png differ diff --git a/share/frontend/impattern/old/oldpatterns/54.png b/share/frontend/impattern/old/oldpatterns/54.png new file mode 100644 index 0000000..e23a862 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/54.png differ diff --git a/share/frontend/impattern/old/oldpatterns/55.png b/share/frontend/impattern/old/oldpatterns/55.png new file mode 100644 index 0000000..d908a85 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/55.png differ diff --git a/share/frontend/impattern/old/oldpatterns/56.png b/share/frontend/impattern/old/oldpatterns/56.png new file mode 100644 index 0000000..330b589 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/56.png differ diff --git a/share/frontend/impattern/old/oldpatterns/57.png b/share/frontend/impattern/old/oldpatterns/57.png new file mode 100644 index 0000000..d9587f3 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/57.png differ diff --git a/share/frontend/impattern/old/oldpatterns/58.png b/share/frontend/impattern/old/oldpatterns/58.png new file mode 100644 index 0000000..0ccfba0 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/58.png differ diff --git a/share/frontend/impattern/old/oldpatterns/59.png b/share/frontend/impattern/old/oldpatterns/59.png new file mode 100644 index 0000000..673a3b7 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/59.png differ diff --git a/share/frontend/impattern/old/oldpatterns/6.png b/share/frontend/impattern/old/oldpatterns/6.png new file mode 100644 index 0000000..a3b8272 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/6.png differ diff --git a/share/frontend/impattern/old/oldpatterns/60.png b/share/frontend/impattern/old/oldpatterns/60.png new file mode 100644 index 0000000..e8ea7a6 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/60.png differ diff --git a/share/frontend/impattern/old/oldpatterns/61.png b/share/frontend/impattern/old/oldpatterns/61.png new file mode 100644 index 0000000..4a8f42c Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/61.png differ diff --git a/share/frontend/impattern/old/oldpatterns/62.png b/share/frontend/impattern/old/oldpatterns/62.png new file mode 100644 index 0000000..491e211 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/62.png differ diff --git a/share/frontend/impattern/old/oldpatterns/63.png b/share/frontend/impattern/old/oldpatterns/63.png new file mode 100644 index 0000000..456203e Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/63.png differ diff --git a/share/frontend/impattern/old/oldpatterns/64.png b/share/frontend/impattern/old/oldpatterns/64.png new file mode 100644 index 0000000..363c9e1 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/64.png differ diff --git a/share/frontend/impattern/old/oldpatterns/65.png b/share/frontend/impattern/old/oldpatterns/65.png new file mode 100644 index 0000000..40b3ab0 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/65.png differ diff --git a/share/frontend/impattern/old/oldpatterns/66.png b/share/frontend/impattern/old/oldpatterns/66.png new file mode 100644 index 0000000..4c46c0d Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/66.png differ diff --git a/share/frontend/impattern/old/oldpatterns/67.png b/share/frontend/impattern/old/oldpatterns/67.png new file mode 100644 index 0000000..62f44fa Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/67.png differ diff --git a/share/frontend/impattern/old/oldpatterns/68.png b/share/frontend/impattern/old/oldpatterns/68.png new file mode 100644 index 0000000..32bd5bc Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/68.png differ diff --git a/share/frontend/impattern/old/oldpatterns/69.png b/share/frontend/impattern/old/oldpatterns/69.png new file mode 100644 index 0000000..35b5d56 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/69.png differ diff --git a/share/frontend/impattern/old/oldpatterns/7.png b/share/frontend/impattern/old/oldpatterns/7.png new file mode 100644 index 0000000..3e01636 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/7.png differ diff --git a/share/frontend/impattern/old/oldpatterns/70.png b/share/frontend/impattern/old/oldpatterns/70.png new file mode 100644 index 0000000..a6771e5 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/70.png differ diff --git a/share/frontend/impattern/old/oldpatterns/71.png b/share/frontend/impattern/old/oldpatterns/71.png new file mode 100644 index 0000000..649c43f Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/71.png differ diff --git a/share/frontend/impattern/old/oldpatterns/72.png b/share/frontend/impattern/old/oldpatterns/72.png new file mode 100644 index 0000000..d51cde8 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/72.png differ diff --git a/share/frontend/impattern/old/oldpatterns/73.png b/share/frontend/impattern/old/oldpatterns/73.png new file mode 100644 index 0000000..79d7585 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/73.png differ diff --git a/share/frontend/impattern/old/oldpatterns/74.png b/share/frontend/impattern/old/oldpatterns/74.png new file mode 100644 index 0000000..9e91e73 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/74.png differ diff --git a/share/frontend/impattern/old/oldpatterns/75.png b/share/frontend/impattern/old/oldpatterns/75.png new file mode 100644 index 0000000..8702a1e Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/75.png differ diff --git a/share/frontend/impattern/old/oldpatterns/76.png b/share/frontend/impattern/old/oldpatterns/76.png new file mode 100644 index 0000000..618f42a Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/76.png differ diff --git a/share/frontend/impattern/old/oldpatterns/77.png b/share/frontend/impattern/old/oldpatterns/77.png new file mode 100644 index 0000000..a2b5966 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/77.png differ diff --git a/share/frontend/impattern/old/oldpatterns/78.png b/share/frontend/impattern/old/oldpatterns/78.png new file mode 100644 index 0000000..82867f8 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/78.png differ diff --git a/share/frontend/impattern/old/oldpatterns/79.png b/share/frontend/impattern/old/oldpatterns/79.png new file mode 100644 index 0000000..3bbd78d Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/79.png differ diff --git a/share/frontend/impattern/old/oldpatterns/8.png b/share/frontend/impattern/old/oldpatterns/8.png new file mode 100644 index 0000000..73f4d43 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/8.png differ diff --git a/share/frontend/impattern/old/oldpatterns/80.png b/share/frontend/impattern/old/oldpatterns/80.png new file mode 100644 index 0000000..810fba6 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/80.png differ diff --git a/share/frontend/impattern/old/oldpatterns/81.png b/share/frontend/impattern/old/oldpatterns/81.png new file mode 100644 index 0000000..92fa744 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/81.png differ diff --git a/share/frontend/impattern/old/oldpatterns/82.png b/share/frontend/impattern/old/oldpatterns/82.png new file mode 100644 index 0000000..bc30bcf Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/82.png differ diff --git a/share/frontend/impattern/old/oldpatterns/83.png b/share/frontend/impattern/old/oldpatterns/83.png new file mode 100644 index 0000000..caddb63 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/83.png differ diff --git a/share/frontend/impattern/old/oldpatterns/84.png b/share/frontend/impattern/old/oldpatterns/84.png new file mode 100644 index 0000000..4176f9a Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/84.png differ diff --git a/share/frontend/impattern/old/oldpatterns/85.png b/share/frontend/impattern/old/oldpatterns/85.png new file mode 100644 index 0000000..8215f71 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/85.png differ diff --git a/share/frontend/impattern/old/oldpatterns/86.png b/share/frontend/impattern/old/oldpatterns/86.png new file mode 100644 index 0000000..c85e4f7 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/86.png differ diff --git a/share/frontend/impattern/old/oldpatterns/87.png b/share/frontend/impattern/old/oldpatterns/87.png new file mode 100644 index 0000000..2933559 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/87.png differ diff --git a/share/frontend/impattern/old/oldpatterns/88.png b/share/frontend/impattern/old/oldpatterns/88.png new file mode 100644 index 0000000..7793e19 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/88.png differ diff --git a/share/frontend/impattern/old/oldpatterns/89.png b/share/frontend/impattern/old/oldpatterns/89.png new file mode 100644 index 0000000..1523885 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/89.png differ diff --git a/share/frontend/impattern/old/oldpatterns/9.png b/share/frontend/impattern/old/oldpatterns/9.png new file mode 100644 index 0000000..6741ffd Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/9.png differ diff --git a/share/frontend/impattern/old/oldpatterns/90.png b/share/frontend/impattern/old/oldpatterns/90.png new file mode 100644 index 0000000..e001830 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/90.png differ diff --git a/share/frontend/impattern/old/oldpatterns/91.png b/share/frontend/impattern/old/oldpatterns/91.png new file mode 100644 index 0000000..e6e87f0 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/91.png differ diff --git a/share/frontend/impattern/old/oldpatterns/92.png b/share/frontend/impattern/old/oldpatterns/92.png new file mode 100644 index 0000000..30f150d Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/92.png differ diff --git a/share/frontend/impattern/old/oldpatterns/93.png b/share/frontend/impattern/old/oldpatterns/93.png new file mode 100644 index 0000000..fb1c648 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/93.png differ diff --git a/share/frontend/impattern/old/oldpatterns/94.png b/share/frontend/impattern/old/oldpatterns/94.png new file mode 100644 index 0000000..171a461 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/94.png differ diff --git a/share/frontend/impattern/old/oldpatterns/95.png b/share/frontend/impattern/old/oldpatterns/95.png new file mode 100644 index 0000000..27f0f06 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/95.png differ diff --git a/share/frontend/impattern/old/oldpatterns/96.png b/share/frontend/impattern/old/oldpatterns/96.png new file mode 100644 index 0000000..11114ec Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/96.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a0.png b/share/frontend/impattern/old/oldpatterns/a0.png new file mode 100644 index 0000000..5fb0b18 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a0.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a1.png b/share/frontend/impattern/old/oldpatterns/a1.png new file mode 100644 index 0000000..cab1780 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a1.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a10.png b/share/frontend/impattern/old/oldpatterns/a10.png new file mode 100644 index 0000000..193ff24 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a10.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a11.png b/share/frontend/impattern/old/oldpatterns/a11.png new file mode 100644 index 0000000..a211a04 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a11.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a12.png b/share/frontend/impattern/old/oldpatterns/a12.png new file mode 100644 index 0000000..0c493b9 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a12.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a13.png b/share/frontend/impattern/old/oldpatterns/a13.png new file mode 100644 index 0000000..bfa653c Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a13.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a14.png b/share/frontend/impattern/old/oldpatterns/a14.png new file mode 100644 index 0000000..10d7b13 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a14.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a15.png b/share/frontend/impattern/old/oldpatterns/a15.png new file mode 100644 index 0000000..2381078 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a15.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a16.png b/share/frontend/impattern/old/oldpatterns/a16.png new file mode 100644 index 0000000..9636ee5 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a16.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a17.png b/share/frontend/impattern/old/oldpatterns/a17.png new file mode 100644 index 0000000..9bc91db Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a17.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a18.png b/share/frontend/impattern/old/oldpatterns/a18.png new file mode 100644 index 0000000..a2e2928 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a18.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a19.png b/share/frontend/impattern/old/oldpatterns/a19.png new file mode 100644 index 0000000..7d45270 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a19.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a2.png b/share/frontend/impattern/old/oldpatterns/a2.png new file mode 100644 index 0000000..7d9c7d9 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a2.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a20.png b/share/frontend/impattern/old/oldpatterns/a20.png new file mode 100644 index 0000000..f670cf5 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a20.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a21.png b/share/frontend/impattern/old/oldpatterns/a21.png new file mode 100644 index 0000000..14aac9b Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a21.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a22.png b/share/frontend/impattern/old/oldpatterns/a22.png new file mode 100644 index 0000000..e9f8a43 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a22.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a23.png b/share/frontend/impattern/old/oldpatterns/a23.png new file mode 100644 index 0000000..bbdaa29 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a23.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a24.png b/share/frontend/impattern/old/oldpatterns/a24.png new file mode 100644 index 0000000..0746ced Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a24.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a25.png b/share/frontend/impattern/old/oldpatterns/a25.png new file mode 100644 index 0000000..2f23bdd Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a25.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a26.png b/share/frontend/impattern/old/oldpatterns/a26.png new file mode 100644 index 0000000..0e21976 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a26.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a27.png b/share/frontend/impattern/old/oldpatterns/a27.png new file mode 100644 index 0000000..0c11122 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a27.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a28.png b/share/frontend/impattern/old/oldpatterns/a28.png new file mode 100644 index 0000000..4469d65 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a28.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a29.png b/share/frontend/impattern/old/oldpatterns/a29.png new file mode 100644 index 0000000..e956157 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a29.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a3.png b/share/frontend/impattern/old/oldpatterns/a3.png new file mode 100644 index 0000000..41cd44f Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a3.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a30.png b/share/frontend/impattern/old/oldpatterns/a30.png new file mode 100644 index 0000000..9058a6d Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a30.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a31.png b/share/frontend/impattern/old/oldpatterns/a31.png new file mode 100644 index 0000000..6692715 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a31.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a32.png b/share/frontend/impattern/old/oldpatterns/a32.png new file mode 100644 index 0000000..daf16c1 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a32.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a33.png b/share/frontend/impattern/old/oldpatterns/a33.png new file mode 100644 index 0000000..b3cee15 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a33.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a34.png b/share/frontend/impattern/old/oldpatterns/a34.png new file mode 100644 index 0000000..0557dae Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a34.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a35.png b/share/frontend/impattern/old/oldpatterns/a35.png new file mode 100644 index 0000000..66d88c9 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a35.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a36.png b/share/frontend/impattern/old/oldpatterns/a36.png new file mode 100644 index 0000000..7abb51b Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a36.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a37.png b/share/frontend/impattern/old/oldpatterns/a37.png new file mode 100644 index 0000000..f30a1ce Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a37.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a38.png b/share/frontend/impattern/old/oldpatterns/a38.png new file mode 100644 index 0000000..3e03424 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a38.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a39.png b/share/frontend/impattern/old/oldpatterns/a39.png new file mode 100644 index 0000000..a802ae0 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a39.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a4.png b/share/frontend/impattern/old/oldpatterns/a4.png new file mode 100644 index 0000000..943ecac Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a4.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a40.png b/share/frontend/impattern/old/oldpatterns/a40.png new file mode 100644 index 0000000..7e3f149 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a40.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a41.png b/share/frontend/impattern/old/oldpatterns/a41.png new file mode 100644 index 0000000..95a7558 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a41.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a5.png b/share/frontend/impattern/old/oldpatterns/a5.png new file mode 100644 index 0000000..c0d0801 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a5.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a6.png b/share/frontend/impattern/old/oldpatterns/a6.png new file mode 100644 index 0000000..414ebb4 Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a6.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a7.png b/share/frontend/impattern/old/oldpatterns/a7.png new file mode 100644 index 0000000..e93e21f Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a7.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a8.png b/share/frontend/impattern/old/oldpatterns/a8.png new file mode 100644 index 0000000..8fa69bb Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a8.png differ diff --git a/share/frontend/impattern/old/oldpatterns/a9.png b/share/frontend/impattern/old/oldpatterns/a9.png new file mode 100644 index 0000000..98c81ad Binary files /dev/null and b/share/frontend/impattern/old/oldpatterns/a9.png differ diff --git a/share/frontend/impattern/other_script.py b/share/frontend/impattern/other_script.py new file mode 100644 index 0000000..a057646 --- /dev/null +++ b/share/frontend/impattern/other_script.py @@ -0,0 +1,90 @@ +#!/usr/bin/python + +import downloader +import filenamer +import inventnamer +import fieldstorager +import hexdirer +import cgi +from subprocess import Popen, PIPE +import os +import sys + +print "Content-Type: text/html" +print +print "" + +nametag = "imDither" + +MAIN_DIRECTORY = "" +#BIN_CONVERT = "/usr/bin/convert" +#BIN_IDENTIFY = "/usr/bin/identify" +#BIN_COMPOSITE = "/usr/bin/composite" +BIN_CONVERT = "convert" +BIN_IDENTIFY = "identify" +BIN_COMPOSITE = "composite" + +PARAM_LIST = "theurl thedither username format" + +form = cgi.FieldStorage() +newvalues = fieldstorager.fieldstorage(PARAM_LIST, form) +thekeys = PARAM_LIST.split() +for key in thekeys: + globals()[key] = newvalues[key] + +if username == None: + username = "" + +################################### +### TEST WITH VALUES HERE +theurl = "http://asdf.us/im/10/friedeggstresstoy_1321140711_1322282769_pepper.gif" +thedither = "1.png" +username = "pepper" +format = "png" +################################### +if format == None: + format = "png" + +class Dither: + def file_size (self, file): + return os.stat(file)[6] + def identify(self, thefile): + ident = Popen([BIN_IDENTIFY, thefile], stdout=PIPE).communicate()[0] + partz = ident.split(" ") + return partz[2].split("x") + def makeCanvas(self, dimensions, thefile): + os.system(BIN_CONVERT+" -size "+self.dimensions[0]+"x"+self.dimensions[1]+" canvas:transparent "+thefile) + def makeMask(self, themask, thedither, thebackground): + os.system(BIN_COMPOSITE+" -tile "+thedither+" "+thebackground+" "+themask) + #convert thebg.gif -compose Dst_In null: thefile.gif -matte -layers composite new.gif + os.system(BIN_CONVERT+" "+themask+" -compose Dst_In null: "+self.mainfile+" -matte -layers composite "+themask) + # os.system("rm "+thebackground) + def fuseMask(self, themask, theimage): + os.system(BIN_COMPOSITE+" "+theimage+" -compose Pin_Light "+themask+" "+theimage) + # os.system("rm "+themask) + def __init__(self, theurl, thedither, username): + self.mainfile = filenamer.filename(theurl, "imDither", username) + filepaths = hexdirer.hexdir() + self.privatepath = filepaths[0] + self.publicpath = filepaths[1] + self.privatepath = "" # + downloader.download(theurl, self.mainfile, self.privatepath) + parts = self.mainfile.split('.') + print parts + if "gif" in parts[-1]: + canvastype = "gif" + else: + canvastype = "png" + self.canvasfile = inventnamer.inventname(canvastype, "canvasfile") + self.dimensions = self.identify(self.mainfile) + self.makeCanvas(self.dimensions, self.canvasfile) + self.theMask = inventnamer.inventname(canvastype, "maskfile") + self.makeMask(self.theMask, thedither, self.canvasfile) + self.fuseMask(self.theMask, self.mainfile) + #self.mainfile = self.mainfile.replace(, do something with s3) + print self.mainfile + print self.file_size(self.mainfile) + print 'width: '+self.dimensions[0]+'px' + print 'height: '+self.dimensions[1]+'px' +daddy = Dither(theurl, thedither, username) + diff --git a/share/frontend/impattern/patterns/1.png b/share/frontend/impattern/patterns/1.png new file mode 100644 index 0000000..0ff9c9b Binary files /dev/null and b/share/frontend/impattern/patterns/1.png differ diff --git a/share/frontend/impattern/patterns/10.png b/share/frontend/impattern/patterns/10.png new file mode 100644 index 0000000..8b7c149 Binary files /dev/null and b/share/frontend/impattern/patterns/10.png differ diff --git a/share/frontend/impattern/patterns/11.png b/share/frontend/impattern/patterns/11.png new file mode 100644 index 0000000..d83822f Binary files /dev/null and b/share/frontend/impattern/patterns/11.png differ diff --git a/share/frontend/impattern/patterns/12.png b/share/frontend/impattern/patterns/12.png new file mode 100644 index 0000000..1a0fbae Binary files /dev/null and b/share/frontend/impattern/patterns/12.png differ diff --git a/share/frontend/impattern/patterns/13.png b/share/frontend/impattern/patterns/13.png new file mode 100644 index 0000000..162d259 Binary files /dev/null and b/share/frontend/impattern/patterns/13.png differ diff --git a/share/frontend/impattern/patterns/14.png b/share/frontend/impattern/patterns/14.png new file mode 100644 index 0000000..888f852 Binary files /dev/null and b/share/frontend/impattern/patterns/14.png differ diff --git a/share/frontend/impattern/patterns/15.png b/share/frontend/impattern/patterns/15.png new file mode 100644 index 0000000..c118abd Binary files /dev/null and b/share/frontend/impattern/patterns/15.png differ diff --git a/share/frontend/impattern/patterns/16.png b/share/frontend/impattern/patterns/16.png new file mode 100644 index 0000000..99a8498 Binary files /dev/null and b/share/frontend/impattern/patterns/16.png differ diff --git a/share/frontend/impattern/patterns/17.png b/share/frontend/impattern/patterns/17.png new file mode 100644 index 0000000..3b2dc1a Binary files /dev/null and b/share/frontend/impattern/patterns/17.png differ diff --git a/share/frontend/impattern/patterns/18.png b/share/frontend/impattern/patterns/18.png new file mode 100644 index 0000000..6c88fcc Binary files /dev/null and b/share/frontend/impattern/patterns/18.png differ diff --git a/share/frontend/impattern/patterns/19.png b/share/frontend/impattern/patterns/19.png new file mode 100644 index 0000000..343d10c Binary files /dev/null and b/share/frontend/impattern/patterns/19.png differ diff --git a/share/frontend/impattern/patterns/2.png b/share/frontend/impattern/patterns/2.png new file mode 100644 index 0000000..db8b278 Binary files /dev/null and b/share/frontend/impattern/patterns/2.png differ diff --git a/share/frontend/impattern/patterns/20.png b/share/frontend/impattern/patterns/20.png new file mode 100644 index 0000000..b151802 Binary files /dev/null and b/share/frontend/impattern/patterns/20.png differ diff --git a/share/frontend/impattern/patterns/21.png b/share/frontend/impattern/patterns/21.png new file mode 100644 index 0000000..a4dd846 Binary files /dev/null and b/share/frontend/impattern/patterns/21.png differ diff --git a/share/frontend/impattern/patterns/22.png b/share/frontend/impattern/patterns/22.png new file mode 100644 index 0000000..549a7f3 Binary files /dev/null and b/share/frontend/impattern/patterns/22.png differ diff --git a/share/frontend/impattern/patterns/23.png b/share/frontend/impattern/patterns/23.png new file mode 100644 index 0000000..5a3e921 Binary files /dev/null and b/share/frontend/impattern/patterns/23.png differ diff --git a/share/frontend/impattern/patterns/24.png b/share/frontend/impattern/patterns/24.png new file mode 100644 index 0000000..d1786f4 Binary files /dev/null and b/share/frontend/impattern/patterns/24.png differ diff --git a/share/frontend/impattern/patterns/25.png b/share/frontend/impattern/patterns/25.png new file mode 100644 index 0000000..9916934 Binary files /dev/null and b/share/frontend/impattern/patterns/25.png differ diff --git a/share/frontend/impattern/patterns/26.png b/share/frontend/impattern/patterns/26.png new file mode 100644 index 0000000..b24b4ad Binary files /dev/null and b/share/frontend/impattern/patterns/26.png differ diff --git a/share/frontend/impattern/patterns/27.png b/share/frontend/impattern/patterns/27.png new file mode 100644 index 0000000..b06d0ff Binary files /dev/null and b/share/frontend/impattern/patterns/27.png differ diff --git a/share/frontend/impattern/patterns/28.png b/share/frontend/impattern/patterns/28.png new file mode 100644 index 0000000..e3cdf2c Binary files /dev/null and b/share/frontend/impattern/patterns/28.png differ diff --git a/share/frontend/impattern/patterns/29.png b/share/frontend/impattern/patterns/29.png new file mode 100644 index 0000000..04adbdb Binary files /dev/null and b/share/frontend/impattern/patterns/29.png differ diff --git a/share/frontend/impattern/patterns/3.png b/share/frontend/impattern/patterns/3.png new file mode 100644 index 0000000..e5a8bfc Binary files /dev/null and b/share/frontend/impattern/patterns/3.png differ diff --git a/share/frontend/impattern/patterns/30.png b/share/frontend/impattern/patterns/30.png new file mode 100644 index 0000000..963dec8 Binary files /dev/null and b/share/frontend/impattern/patterns/30.png differ diff --git a/share/frontend/impattern/patterns/31.png b/share/frontend/impattern/patterns/31.png new file mode 100644 index 0000000..ca882f1 Binary files /dev/null and b/share/frontend/impattern/patterns/31.png differ diff --git a/share/frontend/impattern/patterns/32.png b/share/frontend/impattern/patterns/32.png new file mode 100644 index 0000000..16613b9 Binary files /dev/null and b/share/frontend/impattern/patterns/32.png differ diff --git a/share/frontend/impattern/patterns/33.png b/share/frontend/impattern/patterns/33.png new file mode 100644 index 0000000..0f9407e Binary files /dev/null and b/share/frontend/impattern/patterns/33.png differ diff --git a/share/frontend/impattern/patterns/34.png b/share/frontend/impattern/patterns/34.png new file mode 100644 index 0000000..f74cfde Binary files /dev/null and b/share/frontend/impattern/patterns/34.png differ diff --git a/share/frontend/impattern/patterns/35.png b/share/frontend/impattern/patterns/35.png new file mode 100644 index 0000000..863e55e Binary files /dev/null and b/share/frontend/impattern/patterns/35.png differ diff --git a/share/frontend/impattern/patterns/36.png b/share/frontend/impattern/patterns/36.png new file mode 100644 index 0000000..90ae4fd Binary files /dev/null and b/share/frontend/impattern/patterns/36.png differ diff --git a/share/frontend/impattern/patterns/37.png b/share/frontend/impattern/patterns/37.png new file mode 100644 index 0000000..b89436a Binary files /dev/null and b/share/frontend/impattern/patterns/37.png differ diff --git a/share/frontend/impattern/patterns/38.png b/share/frontend/impattern/patterns/38.png new file mode 100644 index 0000000..4ac8558 Binary files /dev/null and b/share/frontend/impattern/patterns/38.png differ diff --git a/share/frontend/impattern/patterns/39.png b/share/frontend/impattern/patterns/39.png new file mode 100644 index 0000000..d05f50d Binary files /dev/null and b/share/frontend/impattern/patterns/39.png differ diff --git a/share/frontend/impattern/patterns/4.png b/share/frontend/impattern/patterns/4.png new file mode 100644 index 0000000..a89724c Binary files /dev/null and b/share/frontend/impattern/patterns/4.png differ diff --git a/share/frontend/impattern/patterns/40.png b/share/frontend/impattern/patterns/40.png new file mode 100644 index 0000000..58d9757 Binary files /dev/null and b/share/frontend/impattern/patterns/40.png differ diff --git a/share/frontend/impattern/patterns/41.png b/share/frontend/impattern/patterns/41.png new file mode 100644 index 0000000..84c5723 Binary files /dev/null and b/share/frontend/impattern/patterns/41.png differ diff --git a/share/frontend/impattern/patterns/42.png b/share/frontend/impattern/patterns/42.png new file mode 100644 index 0000000..d633b3f Binary files /dev/null and b/share/frontend/impattern/patterns/42.png differ diff --git a/share/frontend/impattern/patterns/43.png b/share/frontend/impattern/patterns/43.png new file mode 100644 index 0000000..a515475 Binary files /dev/null and b/share/frontend/impattern/patterns/43.png differ diff --git a/share/frontend/impattern/patterns/44.png b/share/frontend/impattern/patterns/44.png new file mode 100644 index 0000000..de7cb2b Binary files /dev/null and b/share/frontend/impattern/patterns/44.png differ diff --git a/share/frontend/impattern/patterns/45.png b/share/frontend/impattern/patterns/45.png new file mode 100644 index 0000000..794c466 Binary files /dev/null and b/share/frontend/impattern/patterns/45.png differ diff --git a/share/frontend/impattern/patterns/46.png b/share/frontend/impattern/patterns/46.png new file mode 100644 index 0000000..79e6720 Binary files /dev/null and b/share/frontend/impattern/patterns/46.png differ diff --git a/share/frontend/impattern/patterns/47.png b/share/frontend/impattern/patterns/47.png new file mode 100644 index 0000000..553201d Binary files /dev/null and b/share/frontend/impattern/patterns/47.png differ diff --git a/share/frontend/impattern/patterns/48.png b/share/frontend/impattern/patterns/48.png new file mode 100644 index 0000000..36e284e Binary files /dev/null and b/share/frontend/impattern/patterns/48.png differ diff --git a/share/frontend/impattern/patterns/49.png b/share/frontend/impattern/patterns/49.png new file mode 100644 index 0000000..fd30432 Binary files /dev/null and b/share/frontend/impattern/patterns/49.png differ diff --git a/share/frontend/impattern/patterns/5.png b/share/frontend/impattern/patterns/5.png new file mode 100644 index 0000000..cebb2e1 Binary files /dev/null and b/share/frontend/impattern/patterns/5.png differ diff --git a/share/frontend/impattern/patterns/50.png b/share/frontend/impattern/patterns/50.png new file mode 100644 index 0000000..bc884e8 Binary files /dev/null and b/share/frontend/impattern/patterns/50.png differ diff --git a/share/frontend/impattern/patterns/51.png b/share/frontend/impattern/patterns/51.png new file mode 100644 index 0000000..6a2c0fa Binary files /dev/null and b/share/frontend/impattern/patterns/51.png differ diff --git a/share/frontend/impattern/patterns/52.png b/share/frontend/impattern/patterns/52.png new file mode 100644 index 0000000..3af3ed9 Binary files /dev/null and b/share/frontend/impattern/patterns/52.png differ diff --git a/share/frontend/impattern/patterns/53.png b/share/frontend/impattern/patterns/53.png new file mode 100644 index 0000000..bf84248 Binary files /dev/null and b/share/frontend/impattern/patterns/53.png differ diff --git a/share/frontend/impattern/patterns/54.png b/share/frontend/impattern/patterns/54.png new file mode 100644 index 0000000..8a2229f Binary files /dev/null and b/share/frontend/impattern/patterns/54.png differ diff --git a/share/frontend/impattern/patterns/55.png b/share/frontend/impattern/patterns/55.png new file mode 100644 index 0000000..3d88454 Binary files /dev/null and b/share/frontend/impattern/patterns/55.png differ diff --git a/share/frontend/impattern/patterns/56.png b/share/frontend/impattern/patterns/56.png new file mode 100644 index 0000000..fefbe1e Binary files /dev/null and b/share/frontend/impattern/patterns/56.png differ diff --git a/share/frontend/impattern/patterns/57.png b/share/frontend/impattern/patterns/57.png new file mode 100644 index 0000000..f6f5dd8 Binary files /dev/null and b/share/frontend/impattern/patterns/57.png differ diff --git a/share/frontend/impattern/patterns/58.png b/share/frontend/impattern/patterns/58.png new file mode 100644 index 0000000..9816629 Binary files /dev/null and b/share/frontend/impattern/patterns/58.png differ diff --git a/share/frontend/impattern/patterns/59.png b/share/frontend/impattern/patterns/59.png new file mode 100644 index 0000000..ea4be4a Binary files /dev/null and b/share/frontend/impattern/patterns/59.png differ diff --git a/share/frontend/impattern/patterns/6.png b/share/frontend/impattern/patterns/6.png new file mode 100644 index 0000000..fe8bbdf Binary files /dev/null and b/share/frontend/impattern/patterns/6.png differ diff --git a/share/frontend/impattern/patterns/60.png b/share/frontend/impattern/patterns/60.png new file mode 100644 index 0000000..0144486 Binary files /dev/null and b/share/frontend/impattern/patterns/60.png differ diff --git a/share/frontend/impattern/patterns/61.png b/share/frontend/impattern/patterns/61.png new file mode 100644 index 0000000..49795ba Binary files /dev/null and b/share/frontend/impattern/patterns/61.png differ diff --git a/share/frontend/impattern/patterns/62.png b/share/frontend/impattern/patterns/62.png new file mode 100644 index 0000000..bdee3df Binary files /dev/null and b/share/frontend/impattern/patterns/62.png differ diff --git a/share/frontend/impattern/patterns/63.png b/share/frontend/impattern/patterns/63.png new file mode 100644 index 0000000..27b42bd Binary files /dev/null and b/share/frontend/impattern/patterns/63.png differ diff --git a/share/frontend/impattern/patterns/64.png b/share/frontend/impattern/patterns/64.png new file mode 100644 index 0000000..8424055 Binary files /dev/null and b/share/frontend/impattern/patterns/64.png differ diff --git a/share/frontend/impattern/patterns/65.png b/share/frontend/impattern/patterns/65.png new file mode 100644 index 0000000..fec3e1a Binary files /dev/null and b/share/frontend/impattern/patterns/65.png differ diff --git a/share/frontend/impattern/patterns/66.png b/share/frontend/impattern/patterns/66.png new file mode 100644 index 0000000..612e95d Binary files /dev/null and b/share/frontend/impattern/patterns/66.png differ diff --git a/share/frontend/impattern/patterns/67.png b/share/frontend/impattern/patterns/67.png new file mode 100644 index 0000000..f419c07 Binary files /dev/null and b/share/frontend/impattern/patterns/67.png differ diff --git a/share/frontend/impattern/patterns/68.png b/share/frontend/impattern/patterns/68.png new file mode 100644 index 0000000..7341240 Binary files /dev/null and b/share/frontend/impattern/patterns/68.png differ diff --git a/share/frontend/impattern/patterns/69.png b/share/frontend/impattern/patterns/69.png new file mode 100644 index 0000000..0a45292 Binary files /dev/null and b/share/frontend/impattern/patterns/69.png differ diff --git a/share/frontend/impattern/patterns/7.png b/share/frontend/impattern/patterns/7.png new file mode 100644 index 0000000..f841ca6 Binary files /dev/null and b/share/frontend/impattern/patterns/7.png differ diff --git a/share/frontend/impattern/patterns/70.png b/share/frontend/impattern/patterns/70.png new file mode 100644 index 0000000..8480de3 Binary files /dev/null and b/share/frontend/impattern/patterns/70.png differ diff --git a/share/frontend/impattern/patterns/71.png b/share/frontend/impattern/patterns/71.png new file mode 100644 index 0000000..7ca4d72 Binary files /dev/null and b/share/frontend/impattern/patterns/71.png differ diff --git a/share/frontend/impattern/patterns/72.png b/share/frontend/impattern/patterns/72.png new file mode 100644 index 0000000..1a3da86 Binary files /dev/null and b/share/frontend/impattern/patterns/72.png differ diff --git a/share/frontend/impattern/patterns/73.png b/share/frontend/impattern/patterns/73.png new file mode 100644 index 0000000..52c5334 Binary files /dev/null and b/share/frontend/impattern/patterns/73.png differ diff --git a/share/frontend/impattern/patterns/74.png b/share/frontend/impattern/patterns/74.png new file mode 100644 index 0000000..4e3c915 Binary files /dev/null and b/share/frontend/impattern/patterns/74.png differ diff --git a/share/frontend/impattern/patterns/75.png b/share/frontend/impattern/patterns/75.png new file mode 100644 index 0000000..094dd47 Binary files /dev/null and b/share/frontend/impattern/patterns/75.png differ diff --git a/share/frontend/impattern/patterns/76.png b/share/frontend/impattern/patterns/76.png new file mode 100644 index 0000000..dd10449 Binary files /dev/null and b/share/frontend/impattern/patterns/76.png differ diff --git a/share/frontend/impattern/patterns/77.png b/share/frontend/impattern/patterns/77.png new file mode 100644 index 0000000..73c8b00 Binary files /dev/null and b/share/frontend/impattern/patterns/77.png differ diff --git a/share/frontend/impattern/patterns/78.png b/share/frontend/impattern/patterns/78.png new file mode 100644 index 0000000..ba1d28a Binary files /dev/null and b/share/frontend/impattern/patterns/78.png differ diff --git a/share/frontend/impattern/patterns/79.png b/share/frontend/impattern/patterns/79.png new file mode 100644 index 0000000..22de399 Binary files /dev/null and b/share/frontend/impattern/patterns/79.png differ diff --git a/share/frontend/impattern/patterns/8.png b/share/frontend/impattern/patterns/8.png new file mode 100644 index 0000000..4941c17 Binary files /dev/null and b/share/frontend/impattern/patterns/8.png differ diff --git a/share/frontend/impattern/patterns/80.png b/share/frontend/impattern/patterns/80.png new file mode 100644 index 0000000..5b6c87a Binary files /dev/null and b/share/frontend/impattern/patterns/80.png differ diff --git a/share/frontend/impattern/patterns/81.png b/share/frontend/impattern/patterns/81.png new file mode 100644 index 0000000..26fa933 Binary files /dev/null and b/share/frontend/impattern/patterns/81.png differ diff --git a/share/frontend/impattern/patterns/82.png b/share/frontend/impattern/patterns/82.png new file mode 100644 index 0000000..2bfcc05 Binary files /dev/null and b/share/frontend/impattern/patterns/82.png differ diff --git a/share/frontend/impattern/patterns/83.png b/share/frontend/impattern/patterns/83.png new file mode 100644 index 0000000..7cf3918 Binary files /dev/null and b/share/frontend/impattern/patterns/83.png differ diff --git a/share/frontend/impattern/patterns/84.png b/share/frontend/impattern/patterns/84.png new file mode 100644 index 0000000..5d8e74d Binary files /dev/null and b/share/frontend/impattern/patterns/84.png differ diff --git a/share/frontend/impattern/patterns/85.png b/share/frontend/impattern/patterns/85.png new file mode 100644 index 0000000..be68806 Binary files /dev/null and b/share/frontend/impattern/patterns/85.png differ diff --git a/share/frontend/impattern/patterns/86.png b/share/frontend/impattern/patterns/86.png new file mode 100644 index 0000000..d039020 Binary files /dev/null and b/share/frontend/impattern/patterns/86.png differ diff --git a/share/frontend/impattern/patterns/87.png b/share/frontend/impattern/patterns/87.png new file mode 100644 index 0000000..ddc2689 Binary files /dev/null and b/share/frontend/impattern/patterns/87.png differ diff --git a/share/frontend/impattern/patterns/88.png b/share/frontend/impattern/patterns/88.png new file mode 100644 index 0000000..929c103 Binary files /dev/null and b/share/frontend/impattern/patterns/88.png differ diff --git a/share/frontend/impattern/patterns/89.png b/share/frontend/impattern/patterns/89.png new file mode 100644 index 0000000..4ff3225 Binary files /dev/null and b/share/frontend/impattern/patterns/89.png differ diff --git a/share/frontend/impattern/patterns/9.png b/share/frontend/impattern/patterns/9.png new file mode 100644 index 0000000..7910721 Binary files /dev/null and b/share/frontend/impattern/patterns/9.png differ diff --git a/share/frontend/impattern/patterns/90.png b/share/frontend/impattern/patterns/90.png new file mode 100644 index 0000000..04259e9 Binary files /dev/null and b/share/frontend/impattern/patterns/90.png differ diff --git a/share/frontend/impattern/patterns/91.png b/share/frontend/impattern/patterns/91.png new file mode 100644 index 0000000..039af04 Binary files /dev/null and b/share/frontend/impattern/patterns/91.png differ diff --git a/share/frontend/impattern/patterns/92.png b/share/frontend/impattern/patterns/92.png new file mode 100644 index 0000000..7a4d348 Binary files /dev/null and b/share/frontend/impattern/patterns/92.png differ diff --git a/share/frontend/impattern/patterns/93.png b/share/frontend/impattern/patterns/93.png new file mode 100644 index 0000000..511fee3 Binary files /dev/null and b/share/frontend/impattern/patterns/93.png differ diff --git a/share/frontend/impattern/patterns/94.png b/share/frontend/impattern/patterns/94.png new file mode 100644 index 0000000..449c73a Binary files /dev/null and b/share/frontend/impattern/patterns/94.png differ diff --git a/share/frontend/impattern/patterns/95.png b/share/frontend/impattern/patterns/95.png new file mode 100644 index 0000000..70548f8 Binary files /dev/null and b/share/frontend/impattern/patterns/95.png differ diff --git a/share/frontend/impattern/patterns/96.png b/share/frontend/impattern/patterns/96.png new file mode 100644 index 0000000..0de8efe Binary files /dev/null and b/share/frontend/impattern/patterns/96.png differ diff --git a/share/frontend/impattern/patterns/a0.png b/share/frontend/impattern/patterns/a0.png new file mode 100644 index 0000000..9606e48 Binary files /dev/null and b/share/frontend/impattern/patterns/a0.png differ diff --git a/share/frontend/impattern/patterns/a1.png b/share/frontend/impattern/patterns/a1.png new file mode 100644 index 0000000..2dd534d Binary files /dev/null and b/share/frontend/impattern/patterns/a1.png differ diff --git a/share/frontend/impattern/patterns/a10.png b/share/frontend/impattern/patterns/a10.png new file mode 100644 index 0000000..e950ad0 Binary files /dev/null and b/share/frontend/impattern/patterns/a10.png differ diff --git a/share/frontend/impattern/patterns/a11.png b/share/frontend/impattern/patterns/a11.png new file mode 100644 index 0000000..9c52699 Binary files /dev/null and b/share/frontend/impattern/patterns/a11.png differ diff --git a/share/frontend/impattern/patterns/a12.png b/share/frontend/impattern/patterns/a12.png new file mode 100644 index 0000000..3b80e68 Binary files /dev/null and b/share/frontend/impattern/patterns/a12.png differ diff --git a/share/frontend/impattern/patterns/a13.png b/share/frontend/impattern/patterns/a13.png new file mode 100644 index 0000000..094cb6f Binary files /dev/null and b/share/frontend/impattern/patterns/a13.png differ diff --git a/share/frontend/impattern/patterns/a14.png b/share/frontend/impattern/patterns/a14.png new file mode 100644 index 0000000..d3046c5 Binary files /dev/null and b/share/frontend/impattern/patterns/a14.png differ diff --git a/share/frontend/impattern/patterns/a15.png b/share/frontend/impattern/patterns/a15.png new file mode 100644 index 0000000..3096a81 Binary files /dev/null and b/share/frontend/impattern/patterns/a15.png differ diff --git a/share/frontend/impattern/patterns/a16.png b/share/frontend/impattern/patterns/a16.png new file mode 100644 index 0000000..bb6affb Binary files /dev/null and b/share/frontend/impattern/patterns/a16.png differ diff --git a/share/frontend/impattern/patterns/a17.png b/share/frontend/impattern/patterns/a17.png new file mode 100644 index 0000000..2c259e6 Binary files /dev/null and b/share/frontend/impattern/patterns/a17.png differ diff --git a/share/frontend/impattern/patterns/a18.png b/share/frontend/impattern/patterns/a18.png new file mode 100644 index 0000000..301d419 Binary files /dev/null and b/share/frontend/impattern/patterns/a18.png differ diff --git a/share/frontend/impattern/patterns/a19.png b/share/frontend/impattern/patterns/a19.png new file mode 100644 index 0000000..431345f Binary files /dev/null and b/share/frontend/impattern/patterns/a19.png differ diff --git a/share/frontend/impattern/patterns/a2.png b/share/frontend/impattern/patterns/a2.png new file mode 100644 index 0000000..5c26a6e Binary files /dev/null and b/share/frontend/impattern/patterns/a2.png differ diff --git a/share/frontend/impattern/patterns/a20.png b/share/frontend/impattern/patterns/a20.png new file mode 100644 index 0000000..5cc7f26 Binary files /dev/null and b/share/frontend/impattern/patterns/a20.png differ diff --git a/share/frontend/impattern/patterns/a21.png b/share/frontend/impattern/patterns/a21.png new file mode 100644 index 0000000..8980947 Binary files /dev/null and b/share/frontend/impattern/patterns/a21.png differ diff --git a/share/frontend/impattern/patterns/a22.png b/share/frontend/impattern/patterns/a22.png new file mode 100644 index 0000000..cafcace Binary files /dev/null and b/share/frontend/impattern/patterns/a22.png differ diff --git a/share/frontend/impattern/patterns/a23.png b/share/frontend/impattern/patterns/a23.png new file mode 100644 index 0000000..5fdf851 Binary files /dev/null and b/share/frontend/impattern/patterns/a23.png differ diff --git a/share/frontend/impattern/patterns/a24.png b/share/frontend/impattern/patterns/a24.png new file mode 100644 index 0000000..64c9e02 Binary files /dev/null and b/share/frontend/impattern/patterns/a24.png differ diff --git a/share/frontend/impattern/patterns/a25.png b/share/frontend/impattern/patterns/a25.png new file mode 100644 index 0000000..bab6cd6 Binary files /dev/null and b/share/frontend/impattern/patterns/a25.png differ diff --git a/share/frontend/impattern/patterns/a26.png b/share/frontend/impattern/patterns/a26.png new file mode 100644 index 0000000..fb32ff0 Binary files /dev/null and b/share/frontend/impattern/patterns/a26.png differ diff --git a/share/frontend/impattern/patterns/a27.png b/share/frontend/impattern/patterns/a27.png new file mode 100644 index 0000000..d0a8821 Binary files /dev/null and b/share/frontend/impattern/patterns/a27.png differ diff --git a/share/frontend/impattern/patterns/a28.png b/share/frontend/impattern/patterns/a28.png new file mode 100644 index 0000000..220a847 Binary files /dev/null and b/share/frontend/impattern/patterns/a28.png differ diff --git a/share/frontend/impattern/patterns/a29.png b/share/frontend/impattern/patterns/a29.png new file mode 100644 index 0000000..dc36d31 Binary files /dev/null and b/share/frontend/impattern/patterns/a29.png differ diff --git a/share/frontend/impattern/patterns/a3.png b/share/frontend/impattern/patterns/a3.png new file mode 100644 index 0000000..dd045ec Binary files /dev/null and b/share/frontend/impattern/patterns/a3.png differ diff --git a/share/frontend/impattern/patterns/a30.png b/share/frontend/impattern/patterns/a30.png new file mode 100644 index 0000000..f7ea372 Binary files /dev/null and b/share/frontend/impattern/patterns/a30.png differ diff --git a/share/frontend/impattern/patterns/a31.png b/share/frontend/impattern/patterns/a31.png new file mode 100644 index 0000000..e04391a Binary files /dev/null and b/share/frontend/impattern/patterns/a31.png differ diff --git a/share/frontend/impattern/patterns/a32.png b/share/frontend/impattern/patterns/a32.png new file mode 100644 index 0000000..022b3fc Binary files /dev/null and b/share/frontend/impattern/patterns/a32.png differ diff --git a/share/frontend/impattern/patterns/a33.png b/share/frontend/impattern/patterns/a33.png new file mode 100644 index 0000000..200c2d6 Binary files /dev/null and b/share/frontend/impattern/patterns/a33.png differ diff --git a/share/frontend/impattern/patterns/a34.png b/share/frontend/impattern/patterns/a34.png new file mode 100644 index 0000000..e5d0ddb Binary files /dev/null and b/share/frontend/impattern/patterns/a34.png differ diff --git a/share/frontend/impattern/patterns/a35.png b/share/frontend/impattern/patterns/a35.png new file mode 100644 index 0000000..e334627 Binary files /dev/null and b/share/frontend/impattern/patterns/a35.png differ diff --git a/share/frontend/impattern/patterns/a36.png b/share/frontend/impattern/patterns/a36.png new file mode 100644 index 0000000..b7e8233 Binary files /dev/null and b/share/frontend/impattern/patterns/a36.png differ diff --git a/share/frontend/impattern/patterns/a37.png b/share/frontend/impattern/patterns/a37.png new file mode 100644 index 0000000..da715d2 Binary files /dev/null and b/share/frontend/impattern/patterns/a37.png differ diff --git a/share/frontend/impattern/patterns/a38.png b/share/frontend/impattern/patterns/a38.png new file mode 100644 index 0000000..da1ca80 Binary files /dev/null and b/share/frontend/impattern/patterns/a38.png differ diff --git a/share/frontend/impattern/patterns/a39.png b/share/frontend/impattern/patterns/a39.png new file mode 100644 index 0000000..efb59a3 Binary files /dev/null and b/share/frontend/impattern/patterns/a39.png differ diff --git a/share/frontend/impattern/patterns/a4.png b/share/frontend/impattern/patterns/a4.png new file mode 100644 index 0000000..f9b0f25 Binary files /dev/null and b/share/frontend/impattern/patterns/a4.png differ diff --git a/share/frontend/impattern/patterns/a40.png b/share/frontend/impattern/patterns/a40.png new file mode 100644 index 0000000..8923c32 Binary files /dev/null and b/share/frontend/impattern/patterns/a40.png differ diff --git a/share/frontend/impattern/patterns/a41.png b/share/frontend/impattern/patterns/a41.png new file mode 100644 index 0000000..953e5ca Binary files /dev/null and b/share/frontend/impattern/patterns/a41.png differ diff --git a/share/frontend/impattern/patterns/a5.png b/share/frontend/impattern/patterns/a5.png new file mode 100644 index 0000000..293f3c0 Binary files /dev/null and b/share/frontend/impattern/patterns/a5.png differ diff --git a/share/frontend/impattern/patterns/a6.png b/share/frontend/impattern/patterns/a6.png new file mode 100644 index 0000000..7cd9ec7 Binary files /dev/null and b/share/frontend/impattern/patterns/a6.png differ diff --git a/share/frontend/impattern/patterns/a7.png b/share/frontend/impattern/patterns/a7.png new file mode 100644 index 0000000..c3d9c40 Binary files /dev/null and b/share/frontend/impattern/patterns/a7.png differ diff --git a/share/frontend/impattern/patterns/a8.png b/share/frontend/impattern/patterns/a8.png new file mode 100644 index 0000000..7c65020 Binary files /dev/null and b/share/frontend/impattern/patterns/a8.png differ diff --git a/share/frontend/impattern/patterns/a9.png b/share/frontend/impattern/patterns/a9.png new file mode 100644 index 0000000..699b370 Binary files /dev/null and b/share/frontend/impattern/patterns/a9.png differ diff --git a/share/frontend/impattern/semi_patterns/1.png b/share/frontend/impattern/semi_patterns/1.png new file mode 100644 index 0000000..a0aeccb Binary files /dev/null and b/share/frontend/impattern/semi_patterns/1.png differ diff --git a/share/frontend/impattern/semi_patterns/10.png b/share/frontend/impattern/semi_patterns/10.png new file mode 100644 index 0000000..3865589 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/10.png differ diff --git a/share/frontend/impattern/semi_patterns/11.png b/share/frontend/impattern/semi_patterns/11.png new file mode 100644 index 0000000..2a8ca34 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/11.png differ diff --git a/share/frontend/impattern/semi_patterns/12.png b/share/frontend/impattern/semi_patterns/12.png new file mode 100644 index 0000000..4adb35f Binary files /dev/null and b/share/frontend/impattern/semi_patterns/12.png differ diff --git a/share/frontend/impattern/semi_patterns/13.png b/share/frontend/impattern/semi_patterns/13.png new file mode 100644 index 0000000..48e9362 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/13.png differ diff --git a/share/frontend/impattern/semi_patterns/14.png b/share/frontend/impattern/semi_patterns/14.png new file mode 100644 index 0000000..867b0a9 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/14.png differ diff --git a/share/frontend/impattern/semi_patterns/15.png b/share/frontend/impattern/semi_patterns/15.png new file mode 100644 index 0000000..f37be5a Binary files /dev/null and b/share/frontend/impattern/semi_patterns/15.png differ diff --git a/share/frontend/impattern/semi_patterns/16.png b/share/frontend/impattern/semi_patterns/16.png new file mode 100644 index 0000000..7994ced Binary files /dev/null and b/share/frontend/impattern/semi_patterns/16.png differ diff --git a/share/frontend/impattern/semi_patterns/17.png b/share/frontend/impattern/semi_patterns/17.png new file mode 100644 index 0000000..9ffa444 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/17.png differ diff --git a/share/frontend/impattern/semi_patterns/18.png b/share/frontend/impattern/semi_patterns/18.png new file mode 100644 index 0000000..2522e8d Binary files /dev/null and b/share/frontend/impattern/semi_patterns/18.png differ diff --git a/share/frontend/impattern/semi_patterns/19.png b/share/frontend/impattern/semi_patterns/19.png new file mode 100644 index 0000000..5b4ac7a Binary files /dev/null and b/share/frontend/impattern/semi_patterns/19.png differ diff --git a/share/frontend/impattern/semi_patterns/2.png b/share/frontend/impattern/semi_patterns/2.png new file mode 100644 index 0000000..a6aa256 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/2.png differ diff --git a/share/frontend/impattern/semi_patterns/20.png b/share/frontend/impattern/semi_patterns/20.png new file mode 100644 index 0000000..57a82c1 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/20.png differ diff --git a/share/frontend/impattern/semi_patterns/21.png b/share/frontend/impattern/semi_patterns/21.png new file mode 100644 index 0000000..2b671c7 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/21.png differ diff --git a/share/frontend/impattern/semi_patterns/22.png b/share/frontend/impattern/semi_patterns/22.png new file mode 100644 index 0000000..d28f071 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/22.png differ diff --git a/share/frontend/impattern/semi_patterns/23.png b/share/frontend/impattern/semi_patterns/23.png new file mode 100644 index 0000000..052cf6f Binary files /dev/null and b/share/frontend/impattern/semi_patterns/23.png differ diff --git a/share/frontend/impattern/semi_patterns/24.png b/share/frontend/impattern/semi_patterns/24.png new file mode 100644 index 0000000..4bee000 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/24.png differ diff --git a/share/frontend/impattern/semi_patterns/25.png b/share/frontend/impattern/semi_patterns/25.png new file mode 100644 index 0000000..cbd1097 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/25.png differ diff --git a/share/frontend/impattern/semi_patterns/26.png b/share/frontend/impattern/semi_patterns/26.png new file mode 100644 index 0000000..5fc32f4 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/26.png differ diff --git a/share/frontend/impattern/semi_patterns/27.png b/share/frontend/impattern/semi_patterns/27.png new file mode 100644 index 0000000..18ce493 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/27.png differ diff --git a/share/frontend/impattern/semi_patterns/28.png b/share/frontend/impattern/semi_patterns/28.png new file mode 100644 index 0000000..5924c44 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/28.png differ diff --git a/share/frontend/impattern/semi_patterns/29.png b/share/frontend/impattern/semi_patterns/29.png new file mode 100644 index 0000000..16fc2a5 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/29.png differ diff --git a/share/frontend/impattern/semi_patterns/3.png b/share/frontend/impattern/semi_patterns/3.png new file mode 100644 index 0000000..8c3d334 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/3.png differ diff --git a/share/frontend/impattern/semi_patterns/30.png b/share/frontend/impattern/semi_patterns/30.png new file mode 100644 index 0000000..50c8289 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/30.png differ diff --git a/share/frontend/impattern/semi_patterns/31.png b/share/frontend/impattern/semi_patterns/31.png new file mode 100644 index 0000000..3dd944e Binary files /dev/null and b/share/frontend/impattern/semi_patterns/31.png differ diff --git a/share/frontend/impattern/semi_patterns/32.png b/share/frontend/impattern/semi_patterns/32.png new file mode 100644 index 0000000..79aeb84 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/32.png differ diff --git a/share/frontend/impattern/semi_patterns/33.png b/share/frontend/impattern/semi_patterns/33.png new file mode 100644 index 0000000..55def42 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/33.png differ diff --git a/share/frontend/impattern/semi_patterns/34.png b/share/frontend/impattern/semi_patterns/34.png new file mode 100644 index 0000000..f7616ea Binary files /dev/null and b/share/frontend/impattern/semi_patterns/34.png differ diff --git a/share/frontend/impattern/semi_patterns/35.png b/share/frontend/impattern/semi_patterns/35.png new file mode 100644 index 0000000..3ecbaaf Binary files /dev/null and b/share/frontend/impattern/semi_patterns/35.png differ diff --git a/share/frontend/impattern/semi_patterns/36.png b/share/frontend/impattern/semi_patterns/36.png new file mode 100644 index 0000000..0243cf7 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/36.png differ diff --git a/share/frontend/impattern/semi_patterns/37.png b/share/frontend/impattern/semi_patterns/37.png new file mode 100644 index 0000000..012ed79 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/37.png differ diff --git a/share/frontend/impattern/semi_patterns/38.png b/share/frontend/impattern/semi_patterns/38.png new file mode 100644 index 0000000..9aa54b7 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/38.png differ diff --git a/share/frontend/impattern/semi_patterns/39.png b/share/frontend/impattern/semi_patterns/39.png new file mode 100644 index 0000000..e98ec53 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/39.png differ diff --git a/share/frontend/impattern/semi_patterns/4.png b/share/frontend/impattern/semi_patterns/4.png new file mode 100644 index 0000000..473e6e7 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/4.png differ diff --git a/share/frontend/impattern/semi_patterns/40.png b/share/frontend/impattern/semi_patterns/40.png new file mode 100644 index 0000000..d7d7cba Binary files /dev/null and b/share/frontend/impattern/semi_patterns/40.png differ diff --git a/share/frontend/impattern/semi_patterns/41.png b/share/frontend/impattern/semi_patterns/41.png new file mode 100644 index 0000000..5d15dd7 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/41.png differ diff --git a/share/frontend/impattern/semi_patterns/42.png b/share/frontend/impattern/semi_patterns/42.png new file mode 100644 index 0000000..dedbfe2 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/42.png differ diff --git a/share/frontend/impattern/semi_patterns/43.png b/share/frontend/impattern/semi_patterns/43.png new file mode 100644 index 0000000..dd690d6 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/43.png differ diff --git a/share/frontend/impattern/semi_patterns/44.png b/share/frontend/impattern/semi_patterns/44.png new file mode 100644 index 0000000..12afc85 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/44.png differ diff --git a/share/frontend/impattern/semi_patterns/45.png b/share/frontend/impattern/semi_patterns/45.png new file mode 100644 index 0000000..972933b Binary files /dev/null and b/share/frontend/impattern/semi_patterns/45.png differ diff --git a/share/frontend/impattern/semi_patterns/46.png b/share/frontend/impattern/semi_patterns/46.png new file mode 100644 index 0000000..857ef06 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/46.png differ diff --git a/share/frontend/impattern/semi_patterns/47.png b/share/frontend/impattern/semi_patterns/47.png new file mode 100644 index 0000000..4002e54 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/47.png differ diff --git a/share/frontend/impattern/semi_patterns/48.png b/share/frontend/impattern/semi_patterns/48.png new file mode 100644 index 0000000..ff785ed Binary files /dev/null and b/share/frontend/impattern/semi_patterns/48.png differ diff --git a/share/frontend/impattern/semi_patterns/49.png b/share/frontend/impattern/semi_patterns/49.png new file mode 100644 index 0000000..1a8525f Binary files /dev/null and b/share/frontend/impattern/semi_patterns/49.png differ diff --git a/share/frontend/impattern/semi_patterns/5.png b/share/frontend/impattern/semi_patterns/5.png new file mode 100644 index 0000000..7bd6619 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/5.png differ diff --git a/share/frontend/impattern/semi_patterns/50.png b/share/frontend/impattern/semi_patterns/50.png new file mode 100644 index 0000000..f32d908 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/50.png differ diff --git a/share/frontend/impattern/semi_patterns/51.png b/share/frontend/impattern/semi_patterns/51.png new file mode 100644 index 0000000..20dc9ca Binary files /dev/null and b/share/frontend/impattern/semi_patterns/51.png differ diff --git a/share/frontend/impattern/semi_patterns/52.png b/share/frontend/impattern/semi_patterns/52.png new file mode 100644 index 0000000..0e097fa Binary files /dev/null and b/share/frontend/impattern/semi_patterns/52.png differ diff --git a/share/frontend/impattern/semi_patterns/53.png b/share/frontend/impattern/semi_patterns/53.png new file mode 100644 index 0000000..eec7951 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/53.png differ diff --git a/share/frontend/impattern/semi_patterns/54.png b/share/frontend/impattern/semi_patterns/54.png new file mode 100644 index 0000000..e23a862 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/54.png differ diff --git a/share/frontend/impattern/semi_patterns/55.png b/share/frontend/impattern/semi_patterns/55.png new file mode 100644 index 0000000..d908a85 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/55.png differ diff --git a/share/frontend/impattern/semi_patterns/56.png b/share/frontend/impattern/semi_patterns/56.png new file mode 100644 index 0000000..330b589 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/56.png differ diff --git a/share/frontend/impattern/semi_patterns/57.png b/share/frontend/impattern/semi_patterns/57.png new file mode 100644 index 0000000..d9587f3 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/57.png differ diff --git a/share/frontend/impattern/semi_patterns/58.png b/share/frontend/impattern/semi_patterns/58.png new file mode 100644 index 0000000..0ccfba0 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/58.png differ diff --git a/share/frontend/impattern/semi_patterns/59.png b/share/frontend/impattern/semi_patterns/59.png new file mode 100644 index 0000000..673a3b7 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/59.png differ diff --git a/share/frontend/impattern/semi_patterns/6.png b/share/frontend/impattern/semi_patterns/6.png new file mode 100644 index 0000000..a3b8272 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/6.png differ diff --git a/share/frontend/impattern/semi_patterns/60.png b/share/frontend/impattern/semi_patterns/60.png new file mode 100644 index 0000000..e8ea7a6 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/60.png differ diff --git a/share/frontend/impattern/semi_patterns/61.png b/share/frontend/impattern/semi_patterns/61.png new file mode 100644 index 0000000..4a8f42c Binary files /dev/null and b/share/frontend/impattern/semi_patterns/61.png differ diff --git a/share/frontend/impattern/semi_patterns/62.png b/share/frontend/impattern/semi_patterns/62.png new file mode 100644 index 0000000..491e211 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/62.png differ diff --git a/share/frontend/impattern/semi_patterns/63.png b/share/frontend/impattern/semi_patterns/63.png new file mode 100644 index 0000000..456203e Binary files /dev/null and b/share/frontend/impattern/semi_patterns/63.png differ diff --git a/share/frontend/impattern/semi_patterns/64.png b/share/frontend/impattern/semi_patterns/64.png new file mode 100644 index 0000000..363c9e1 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/64.png differ diff --git a/share/frontend/impattern/semi_patterns/65.png b/share/frontend/impattern/semi_patterns/65.png new file mode 100644 index 0000000..40b3ab0 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/65.png differ diff --git a/share/frontend/impattern/semi_patterns/66.png b/share/frontend/impattern/semi_patterns/66.png new file mode 100644 index 0000000..4c46c0d Binary files /dev/null and b/share/frontend/impattern/semi_patterns/66.png differ diff --git a/share/frontend/impattern/semi_patterns/67.png b/share/frontend/impattern/semi_patterns/67.png new file mode 100644 index 0000000..62f44fa Binary files /dev/null and b/share/frontend/impattern/semi_patterns/67.png differ diff --git a/share/frontend/impattern/semi_patterns/68.png b/share/frontend/impattern/semi_patterns/68.png new file mode 100644 index 0000000..32bd5bc Binary files /dev/null and b/share/frontend/impattern/semi_patterns/68.png differ diff --git a/share/frontend/impattern/semi_patterns/69.png b/share/frontend/impattern/semi_patterns/69.png new file mode 100644 index 0000000..35b5d56 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/69.png differ diff --git a/share/frontend/impattern/semi_patterns/7.png b/share/frontend/impattern/semi_patterns/7.png new file mode 100644 index 0000000..3e01636 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/7.png differ diff --git a/share/frontend/impattern/semi_patterns/70.png b/share/frontend/impattern/semi_patterns/70.png new file mode 100644 index 0000000..a6771e5 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/70.png differ diff --git a/share/frontend/impattern/semi_patterns/71.png b/share/frontend/impattern/semi_patterns/71.png new file mode 100644 index 0000000..649c43f Binary files /dev/null and b/share/frontend/impattern/semi_patterns/71.png differ diff --git a/share/frontend/impattern/semi_patterns/72.png b/share/frontend/impattern/semi_patterns/72.png new file mode 100644 index 0000000..d51cde8 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/72.png differ diff --git a/share/frontend/impattern/semi_patterns/73.png b/share/frontend/impattern/semi_patterns/73.png new file mode 100644 index 0000000..79d7585 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/73.png differ diff --git a/share/frontend/impattern/semi_patterns/74.png b/share/frontend/impattern/semi_patterns/74.png new file mode 100644 index 0000000..9e91e73 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/74.png differ diff --git a/share/frontend/impattern/semi_patterns/75.png b/share/frontend/impattern/semi_patterns/75.png new file mode 100644 index 0000000..8702a1e Binary files /dev/null and b/share/frontend/impattern/semi_patterns/75.png differ diff --git a/share/frontend/impattern/semi_patterns/76.png b/share/frontend/impattern/semi_patterns/76.png new file mode 100644 index 0000000..618f42a Binary files /dev/null and b/share/frontend/impattern/semi_patterns/76.png differ diff --git a/share/frontend/impattern/semi_patterns/77.png b/share/frontend/impattern/semi_patterns/77.png new file mode 100644 index 0000000..a2b5966 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/77.png differ diff --git a/share/frontend/impattern/semi_patterns/78.png b/share/frontend/impattern/semi_patterns/78.png new file mode 100644 index 0000000..82867f8 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/78.png differ diff --git a/share/frontend/impattern/semi_patterns/79.png b/share/frontend/impattern/semi_patterns/79.png new file mode 100644 index 0000000..3bbd78d Binary files /dev/null and b/share/frontend/impattern/semi_patterns/79.png differ diff --git a/share/frontend/impattern/semi_patterns/8.png b/share/frontend/impattern/semi_patterns/8.png new file mode 100644 index 0000000..73f4d43 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/8.png differ diff --git a/share/frontend/impattern/semi_patterns/80.png b/share/frontend/impattern/semi_patterns/80.png new file mode 100644 index 0000000..810fba6 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/80.png differ diff --git a/share/frontend/impattern/semi_patterns/81.png b/share/frontend/impattern/semi_patterns/81.png new file mode 100644 index 0000000..92fa744 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/81.png differ diff --git a/share/frontend/impattern/semi_patterns/82.png b/share/frontend/impattern/semi_patterns/82.png new file mode 100644 index 0000000..bc30bcf Binary files /dev/null and b/share/frontend/impattern/semi_patterns/82.png differ diff --git a/share/frontend/impattern/semi_patterns/83.png b/share/frontend/impattern/semi_patterns/83.png new file mode 100644 index 0000000..caddb63 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/83.png differ diff --git a/share/frontend/impattern/semi_patterns/84.png b/share/frontend/impattern/semi_patterns/84.png new file mode 100644 index 0000000..4176f9a Binary files /dev/null and b/share/frontend/impattern/semi_patterns/84.png differ diff --git a/share/frontend/impattern/semi_patterns/85.png b/share/frontend/impattern/semi_patterns/85.png new file mode 100644 index 0000000..8215f71 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/85.png differ diff --git a/share/frontend/impattern/semi_patterns/86.png b/share/frontend/impattern/semi_patterns/86.png new file mode 100644 index 0000000..c85e4f7 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/86.png differ diff --git a/share/frontend/impattern/semi_patterns/87.png b/share/frontend/impattern/semi_patterns/87.png new file mode 100644 index 0000000..2933559 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/87.png differ diff --git a/share/frontend/impattern/semi_patterns/88.png b/share/frontend/impattern/semi_patterns/88.png new file mode 100644 index 0000000..7793e19 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/88.png differ diff --git a/share/frontend/impattern/semi_patterns/89.png b/share/frontend/impattern/semi_patterns/89.png new file mode 100644 index 0000000..1523885 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/89.png differ diff --git a/share/frontend/impattern/semi_patterns/9.png b/share/frontend/impattern/semi_patterns/9.png new file mode 100644 index 0000000..6741ffd Binary files /dev/null and b/share/frontend/impattern/semi_patterns/9.png differ diff --git a/share/frontend/impattern/semi_patterns/90.png b/share/frontend/impattern/semi_patterns/90.png new file mode 100644 index 0000000..e001830 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/90.png differ diff --git a/share/frontend/impattern/semi_patterns/91.png b/share/frontend/impattern/semi_patterns/91.png new file mode 100644 index 0000000..e6e87f0 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/91.png differ diff --git a/share/frontend/impattern/semi_patterns/92.png b/share/frontend/impattern/semi_patterns/92.png new file mode 100644 index 0000000..30f150d Binary files /dev/null and b/share/frontend/impattern/semi_patterns/92.png differ diff --git a/share/frontend/impattern/semi_patterns/93.png b/share/frontend/impattern/semi_patterns/93.png new file mode 100644 index 0000000..fb1c648 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/93.png differ diff --git a/share/frontend/impattern/semi_patterns/94.png b/share/frontend/impattern/semi_patterns/94.png new file mode 100644 index 0000000..171a461 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/94.png differ diff --git a/share/frontend/impattern/semi_patterns/95.png b/share/frontend/impattern/semi_patterns/95.png new file mode 100644 index 0000000..27f0f06 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/95.png differ diff --git a/share/frontend/impattern/semi_patterns/96.png b/share/frontend/impattern/semi_patterns/96.png new file mode 100644 index 0000000..11114ec Binary files /dev/null and b/share/frontend/impattern/semi_patterns/96.png differ diff --git a/share/frontend/impattern/semi_patterns/a0.png b/share/frontend/impattern/semi_patterns/a0.png new file mode 100644 index 0000000..5fb0b18 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a0.png differ diff --git a/share/frontend/impattern/semi_patterns/a1.png b/share/frontend/impattern/semi_patterns/a1.png new file mode 100644 index 0000000..cab1780 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a1.png differ diff --git a/share/frontend/impattern/semi_patterns/a10.png b/share/frontend/impattern/semi_patterns/a10.png new file mode 100644 index 0000000..193ff24 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a10.png differ diff --git a/share/frontend/impattern/semi_patterns/a11.png b/share/frontend/impattern/semi_patterns/a11.png new file mode 100644 index 0000000..a211a04 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a11.png differ diff --git a/share/frontend/impattern/semi_patterns/a12.png b/share/frontend/impattern/semi_patterns/a12.png new file mode 100644 index 0000000..0c493b9 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a12.png differ diff --git a/share/frontend/impattern/semi_patterns/a13.png b/share/frontend/impattern/semi_patterns/a13.png new file mode 100644 index 0000000..bfa653c Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a13.png differ diff --git a/share/frontend/impattern/semi_patterns/a14.png b/share/frontend/impattern/semi_patterns/a14.png new file mode 100644 index 0000000..10d7b13 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a14.png differ diff --git a/share/frontend/impattern/semi_patterns/a15.png b/share/frontend/impattern/semi_patterns/a15.png new file mode 100644 index 0000000..2381078 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a15.png differ diff --git a/share/frontend/impattern/semi_patterns/a16.png b/share/frontend/impattern/semi_patterns/a16.png new file mode 100644 index 0000000..9636ee5 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a16.png differ diff --git a/share/frontend/impattern/semi_patterns/a17.png b/share/frontend/impattern/semi_patterns/a17.png new file mode 100644 index 0000000..9bc91db Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a17.png differ diff --git a/share/frontend/impattern/semi_patterns/a18.png b/share/frontend/impattern/semi_patterns/a18.png new file mode 100644 index 0000000..a2e2928 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a18.png differ diff --git a/share/frontend/impattern/semi_patterns/a19.png b/share/frontend/impattern/semi_patterns/a19.png new file mode 100644 index 0000000..7d45270 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a19.png differ diff --git a/share/frontend/impattern/semi_patterns/a2.png b/share/frontend/impattern/semi_patterns/a2.png new file mode 100644 index 0000000..7d9c7d9 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a2.png differ diff --git a/share/frontend/impattern/semi_patterns/a20.png b/share/frontend/impattern/semi_patterns/a20.png new file mode 100644 index 0000000..f670cf5 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a20.png differ diff --git a/share/frontend/impattern/semi_patterns/a21.png b/share/frontend/impattern/semi_patterns/a21.png new file mode 100644 index 0000000..14aac9b Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a21.png differ diff --git a/share/frontend/impattern/semi_patterns/a22.png b/share/frontend/impattern/semi_patterns/a22.png new file mode 100644 index 0000000..e9f8a43 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a22.png differ diff --git a/share/frontend/impattern/semi_patterns/a23.png b/share/frontend/impattern/semi_patterns/a23.png new file mode 100644 index 0000000..bbdaa29 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a23.png differ diff --git a/share/frontend/impattern/semi_patterns/a24.png b/share/frontend/impattern/semi_patterns/a24.png new file mode 100644 index 0000000..0746ced Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a24.png differ diff --git a/share/frontend/impattern/semi_patterns/a25.png b/share/frontend/impattern/semi_patterns/a25.png new file mode 100644 index 0000000..2f23bdd Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a25.png differ diff --git a/share/frontend/impattern/semi_patterns/a26.png b/share/frontend/impattern/semi_patterns/a26.png new file mode 100644 index 0000000..0e21976 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a26.png differ diff --git a/share/frontend/impattern/semi_patterns/a27.png b/share/frontend/impattern/semi_patterns/a27.png new file mode 100644 index 0000000..0c11122 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a27.png differ diff --git a/share/frontend/impattern/semi_patterns/a28.png b/share/frontend/impattern/semi_patterns/a28.png new file mode 100644 index 0000000..4469d65 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a28.png differ diff --git a/share/frontend/impattern/semi_patterns/a29.png b/share/frontend/impattern/semi_patterns/a29.png new file mode 100644 index 0000000..e956157 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a29.png differ diff --git a/share/frontend/impattern/semi_patterns/a3.png b/share/frontend/impattern/semi_patterns/a3.png new file mode 100644 index 0000000..41cd44f Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a3.png differ diff --git a/share/frontend/impattern/semi_patterns/a30.png b/share/frontend/impattern/semi_patterns/a30.png new file mode 100644 index 0000000..9058a6d Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a30.png differ diff --git a/share/frontend/impattern/semi_patterns/a31.png b/share/frontend/impattern/semi_patterns/a31.png new file mode 100644 index 0000000..6692715 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a31.png differ diff --git a/share/frontend/impattern/semi_patterns/a32.png b/share/frontend/impattern/semi_patterns/a32.png new file mode 100644 index 0000000..daf16c1 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a32.png differ diff --git a/share/frontend/impattern/semi_patterns/a33.png b/share/frontend/impattern/semi_patterns/a33.png new file mode 100644 index 0000000..b3cee15 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a33.png differ diff --git a/share/frontend/impattern/semi_patterns/a34.png b/share/frontend/impattern/semi_patterns/a34.png new file mode 100644 index 0000000..0557dae Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a34.png differ diff --git a/share/frontend/impattern/semi_patterns/a35.png b/share/frontend/impattern/semi_patterns/a35.png new file mode 100644 index 0000000..66d88c9 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a35.png differ diff --git a/share/frontend/impattern/semi_patterns/a36.png b/share/frontend/impattern/semi_patterns/a36.png new file mode 100644 index 0000000..7abb51b Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a36.png differ diff --git a/share/frontend/impattern/semi_patterns/a37.png b/share/frontend/impattern/semi_patterns/a37.png new file mode 100644 index 0000000..f30a1ce Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a37.png differ diff --git a/share/frontend/impattern/semi_patterns/a38.png b/share/frontend/impattern/semi_patterns/a38.png new file mode 100644 index 0000000..3e03424 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a38.png differ diff --git a/share/frontend/impattern/semi_patterns/a39.png b/share/frontend/impattern/semi_patterns/a39.png new file mode 100644 index 0000000..a802ae0 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a39.png differ diff --git a/share/frontend/impattern/semi_patterns/a4.png b/share/frontend/impattern/semi_patterns/a4.png new file mode 100644 index 0000000..943ecac Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a4.png differ diff --git a/share/frontend/impattern/semi_patterns/a40.png b/share/frontend/impattern/semi_patterns/a40.png new file mode 100644 index 0000000..7e3f149 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a40.png differ diff --git a/share/frontend/impattern/semi_patterns/a41.png b/share/frontend/impattern/semi_patterns/a41.png new file mode 100644 index 0000000..95a7558 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a41.png differ diff --git a/share/frontend/impattern/semi_patterns/a5.png b/share/frontend/impattern/semi_patterns/a5.png new file mode 100644 index 0000000..c0d0801 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a5.png differ diff --git a/share/frontend/impattern/semi_patterns/a6.png b/share/frontend/impattern/semi_patterns/a6.png new file mode 100644 index 0000000..414ebb4 Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a6.png differ diff --git a/share/frontend/impattern/semi_patterns/a7.png b/share/frontend/impattern/semi_patterns/a7.png new file mode 100644 index 0000000..e93e21f Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a7.png differ diff --git a/share/frontend/impattern/semi_patterns/a8.png b/share/frontend/impattern/semi_patterns/a8.png new file mode 100644 index 0000000..8fa69bb Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a8.png differ diff --git a/share/frontend/impattern/semi_patterns/a9.png b/share/frontend/impattern/semi_patterns/a9.png new file mode 100644 index 0000000..98c81ad Binary files /dev/null and b/share/frontend/impattern/semi_patterns/a9.png differ diff --git a/share/frontend/impattern/sketch.html b/share/frontend/impattern/sketch.html new file mode 100644 index 0000000..c519820 --- /dev/null +++ b/share/frontend/impattern/sketch.html @@ -0,0 +1,231 @@ + + + + + + + + +
+
+ + + + + + + +
+ ROWS +
+ COLS +
+ +
+
Brush
+
Eraser
+
+Show grid? + + + + + diff --git a/share/frontend/impattern/test.gif b/share/frontend/impattern/test.gif new file mode 100644 index 0000000..a9723d6 Binary files /dev/null and b/share/frontend/impattern/test.gif differ -- cgit v1.2.3-70-g09d2