From cc0ccb6024feb7fda197f336875435135c40336e Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Sat, 12 Dec 2015 10:00:06 +0000 Subject: [PATCH] add movielib --- movielib/.gitattributes | 5 + movielib/.gitignore | 2 + movielib/.htaccess | 16 + movielib/CHANGELOG.txt | 111 + movielib/LICENSE.txt | 674 ++ movielib/README.txt | 11 + movielib/admin.php | 681 ++ movielib/admin/css/font/archivonarrow.ttf | Bin 0 -> 128488 bytes movielib/admin/css/style.css | 47 + movielib/admin/img/delete.png | Bin 0 -> 3405 bytes movielib/admin/img/exist.png | Bin 0 -> 3343 bytes movielib/admin/img/hidden.png | Bin 0 -> 456 bytes movielib/admin/img/i_delete.png | Bin 0 -> 3196 bytes movielib/admin/img/i_fanart.png | Bin 0 -> 328 bytes movielib/admin/img/i_hidden.png | Bin 0 -> 341 bytes movielib/admin/img/i_poster.png | Bin 0 -> 364 bytes movielib/admin/img/i_trailer.png | Bin 0 -> 332 bytes movielib/admin/img/icon.ico | Bin 0 -> 894 bytes movielib/admin/img/link.png | Bin 0 -> 3144 bytes movielib/admin/img/movies.png | Bin 0 -> 3319 bytes movielib/admin/img/tvshows.png | Bin 0 -> 3756 bytes movielib/admin/img/visible.png | Bin 0 -> 454 bytes movielib/config.php | 482 + movielib/files.md5 | 1 + movielib/function.js.php | 410 + movielib/function.php | 780 ++ movielib/index.php | 910 ++ movielib/install.php | 186 + movielib/js/jquery-1.9.1.js | 9597 +++++++++++++++++ movielib/js/jquery.cycle.lite.js | 235 + movielib/js/jquery.script.js | 437 + movielib/js/video.js | 7101 ++++++++++++ movielib/lang/bg/lang.php | 239 + movielib/lang/bg/readme | 11 + movielib/lang/da/lang.php | 239 + movielib/lang/da/readme | 11 + movielib/lang/de/lang.php | 239 + movielib/lang/de/readme | 11 + movielib/lang/en/lang.php | 239 + movielib/lang/en/readme | 11 + movielib/lang/es/lang.php | 239 + movielib/lang/es/readme | 11 + movielib/lang/fr/lang.php | 239 + movielib/lang/fr/readme | 11 + movielib/lang/hr/lang.php | 239 + movielib/lang/hr/readme | 11 + movielib/lang/it/lang.php | 239 + movielib/lang/it/readme | 11 + movielib/lang/nl/lang.php | 240 + movielib/lang/nl/readme | 11 + movielib/lang/pl/lang.php | 239 + movielib/lang/pl/readme | 11 + movielib/lang/sk/lang.php | 239 + movielib/lang/sk/readme | 11 + movielib/lang/sr/lang.php | 239 + movielib/lang/sr/readme | 11 + movielib/login.php | 91 + movielib/sync.php | 114 + movielib/templates/default/css/font/vjs.eot | Bin 0 -> 3536 bytes movielib/templates/default/css/font/vjs.svg | 65 + movielib/templates/default/css/font/vjs.ttf | Bin 0 -> 3372 bytes movielib/templates/default/css/font/vjs.woff | Bin 0 -> 4228 bytes movielib/templates/default/css/style.css | 87 + movielib/templates/default/css/video.css | 767 ++ .../templates/default/css/view_bposter.css | 7 + .../templates/default/css/view_default.css | 49 + movielib/templates/default/css/view_list.css | 12 + .../templates/default/css/view_sposter.css | 7 + movielib/templates/default/episodes.tpl | 36 + movielib/templates/default/img/0.png | Bin 0 -> 1219 bytes movielib/templates/default/img/1.png | Bin 0 -> 959 bytes movielib/templates/default/img/2.png | Bin 0 -> 1142 bytes movielib/templates/default/img/3.png | Bin 0 -> 1251 bytes movielib/templates/default/img/4.png | Bin 0 -> 1127 bytes movielib/templates/default/img/5.png | Bin 0 -> 1208 bytes movielib/templates/default/img/6.png | Bin 0 -> 1228 bytes movielib/templates/default/img/7.png | Bin 0 -> 944 bytes movielib/templates/default/img/8.png | Bin 0 -> 1286 bytes movielib/templates/default/img/9.png | Bin 0 -> 1254 bytes movielib/templates/default/img/back.png | Bin 0 -> 1481 bytes movielib/templates/default/img/bg.jpg | Bin 0 -> 312953 bytes .../templates/default/img/bigstepback.png | Bin 0 -> 1321 bytes .../templates/default/img/bigstepforward.png | Bin 0 -> 1320 bytes movielib/templates/default/img/context.png | Bin 0 -> 1216 bytes movielib/templates/default/img/d_actor.jpg | Bin 0 -> 10798 bytes movielib/templates/default/img/d_poster.jpg | Bin 0 -> 7907 bytes .../templates/default/img/d_thumbnail.jpg | Bin 0 -> 8627 bytes movielib/templates/default/img/delete.png | Bin 0 -> 3405 bytes movielib/templates/default/img/down.png | Bin 0 -> 1349 bytes movielib/templates/default/img/download.png | Bin 0 -> 1365 bytes .../templates/default/img/flags/ac_aac.png | Bin 0 -> 3526 bytes .../templates/default/img/flags/ac_ac3.png | Bin 0 -> 3558 bytes .../templates/default/img/flags/ac_aif.png | Bin 0 -> 3481 bytes .../templates/default/img/flags/ac_dd.png | Bin 0 -> 3357 bytes .../templates/default/img/flags/ac_dts.png | Bin 0 -> 3549 bytes .../templates/default/img/flags/ac_flac.png | Bin 0 -> 3582 bytes .../templates/default/img/flags/ac_mp3.png | Bin 0 -> 3631 bytes .../templates/default/img/flags/ac_ogg.png | Bin 0 -> 3456 bytes .../templates/default/img/flags/ac_truehd.png | Bin 0 -> 3650 bytes .../templates/default/img/flags/ac_wma.png | Bin 0 -> 3749 bytes .../templates/default/img/flags/ach_1.png | Bin 0 -> 3469 bytes .../templates/default/img/flags/ach_2.png | Bin 0 -> 3476 bytes .../templates/default/img/flags/ach_6.png | Bin 0 -> 3358 bytes .../templates/default/img/flags/ach_8.png | Bin 0 -> 3418 bytes .../templates/default/img/flags/l_alb.png | Bin 0 -> 3361 bytes .../templates/default/img/flags/l_ces.png | Bin 0 -> 3349 bytes .../templates/default/img/flags/l_dan.png | Bin 0 -> 3367 bytes .../templates/default/img/flags/l_deu.png | Bin 0 -> 3308 bytes .../templates/default/img/flags/l_dut.png | Bin 0 -> 3343 bytes .../templates/default/img/flags/l_egy.png | Bin 0 -> 3317 bytes .../templates/default/img/flags/l_ell.png | Bin 0 -> 3392 bytes .../templates/default/img/flags/l_eng.png | Bin 0 -> 3373 bytes .../templates/default/img/flags/l_eng2.png | Bin 0 -> 3439 bytes .../templates/default/img/flags/l_est.png | Bin 0 -> 3305 bytes .../templates/default/img/flags/l_fin.png | Bin 0 -> 3398 bytes .../templates/default/img/flags/l_fra.png | Bin 0 -> 3336 bytes .../templates/default/img/flags/l_gle.png | Bin 0 -> 3342 bytes .../templates/default/img/flags/l_heb.png | Bin 0 -> 3420 bytes .../templates/default/img/flags/l_hun.png | Bin 0 -> 3339 bytes .../templates/default/img/flags/l_ind.png | Bin 0 -> 3354 bytes .../templates/default/img/flags/l_ira.png | Bin 0 -> 3382 bytes .../templates/default/img/flags/l_isl.png | Bin 0 -> 3386 bytes .../templates/default/img/flags/l_ita.png | Bin 0 -> 3331 bytes .../templates/default/img/flags/l_jpn.png | Bin 0 -> 3402 bytes .../templates/default/img/flags/l_kat.png | Bin 0 -> 3407 bytes .../templates/default/img/flags/l_khm.png | Bin 0 -> 3366 bytes .../templates/default/img/flags/l_kor.png | Bin 0 -> 3433 bytes .../templates/default/img/flags/l_mlt.png | Bin 0 -> 3378 bytes .../templates/default/img/flags/l_mol.png | Bin 0 -> 3354 bytes .../templates/default/img/flags/l_mon.png | Bin 0 -> 3365 bytes .../templates/default/img/flags/l_nep.png | Bin 0 -> 3457 bytes .../templates/default/img/flags/l_nno.png | Bin 0 -> 3375 bytes .../templates/default/img/flags/l_pol.png | Bin 0 -> 3328 bytes .../templates/default/img/flags/l_por.png | Bin 0 -> 3398 bytes .../templates/default/img/flags/l_ron.png | Bin 0 -> 3327 bytes .../templates/default/img/flags/l_rus.png | Bin 0 -> 3293 bytes .../templates/default/img/flags/l_slk.png | Bin 0 -> 3393 bytes .../templates/default/img/flags/l_slv.png | Bin 0 -> 3342 bytes .../templates/default/img/flags/l_spa.png | Bin 0 -> 3374 bytes .../templates/default/img/flags/l_srp.png | Bin 0 -> 3412 bytes .../templates/default/img/flags/l_swe.png | Bin 0 -> 3395 bytes .../templates/default/img/flags/l_tur.png | Bin 0 -> 3385 bytes .../templates/default/img/flags/l_ukr.png | Bin 0 -> 3353 bytes .../templates/default/img/flags/l_zho.png | Bin 0 -> 3308 bytes movielib/templates/default/img/flags/sub.png | Bin 0 -> 3238 bytes movielib/templates/default/img/flags/v_hd.png | Bin 0 -> 3307 bytes movielib/templates/default/img/flags/v_sd.png | Bin 0 -> 3325 bytes .../templates/default/img/flags/v_uhd.png | Bin 0 -> 3419 bytes .../templates/default/img/flags/vc_3ivx.png | Bin 0 -> 3853 bytes .../templates/default/img/flags/vc_avc.png | Bin 0 -> 3685 bytes .../templates/default/img/flags/vc_divx.png | Bin 0 -> 3851 bytes .../templates/default/img/flags/vc_flv.png | Bin 0 -> 3656 bytes .../templates/default/img/flags/vc_h264.png | Bin 0 -> 3839 bytes .../templates/default/img/flags/vc_hevc.png | Bin 0 -> 4050 bytes .../templates/default/img/flags/vc_mp4.png | Bin 0 -> 3792 bytes .../templates/default/img/flags/vc_mpeg.png | Bin 0 -> 3801 bytes .../templates/default/img/flags/vc_mpeg2.png | Bin 0 -> 3954 bytes .../templates/default/img/flags/vc_mpeg4.png | Bin 0 -> 3972 bytes .../templates/default/img/flags/vc_qt.png | Bin 0 -> 3962 bytes .../templates/default/img/flags/vc_wmv.png | Bin 0 -> 3947 bytes .../templates/default/img/flags/vc_xvid.png | Bin 0 -> 3800 bytes .../templates/default/img/flags/vres_0.png | Bin 0 -> 3470 bytes .../templates/default/img/flags/vres_1080.png | Bin 0 -> 3595 bytes .../templates/default/img/flags/vres_4096.png | Bin 0 -> 3704 bytes .../templates/default/img/flags/vres_480.png | Bin 0 -> 3609 bytes .../templates/default/img/flags/vres_576.png | Bin 0 -> 3523 bytes .../templates/default/img/flags/vres_720.png | Bin 0 -> 3521 bytes .../templates/default/img/flags/vres_768.png | Bin 0 -> 3552 bytes movielib/templates/default/img/icon.ico | Bin 0 -> 894 bytes movielib/templates/default/img/imdb.png | Bin 0 -> 1485 bytes movielib/templates/default/img/info.png | Bin 0 -> 1399 bytes movielib/templates/default/img/left.png | Bin 0 -> 1450 bytes movielib/templates/default/img/list.png | Bin 0 -> 1183 bytes movielib/templates/default/img/logo.jpg | Bin 0 -> 30455 bytes movielib/templates/default/img/pause.png | Bin 0 -> 1225 bytes movielib/templates/default/img/play.png | Bin 0 -> 1204 bytes movielib/templates/default/img/power.png | Bin 0 -> 1644 bytes movielib/templates/default/img/ribbon_new.png | Bin 0 -> 14577 bytes movielib/templates/default/img/right.png | Bin 0 -> 1417 bytes movielib/templates/default/img/select.png | Bin 0 -> 1523 bytes movielib/templates/default/img/space.png | Bin 0 -> 3411 bytes movielib/templates/default/img/star.png | Bin 0 -> 3180 bytes movielib/templates/default/img/star_g.png | Bin 0 -> 3171 bytes movielib/templates/default/img/star_h.png | Bin 0 -> 3241 bytes movielib/templates/default/img/stepback.png | Bin 0 -> 1227 bytes .../templates/default/img/stepforward.png | Bin 0 -> 1230 bytes movielib/templates/default/img/stop.png | Bin 0 -> 1109 bytes movielib/templates/default/img/sync.png | Bin 0 -> 1646 bytes movielib/templates/default/img/trailer.png | Bin 0 -> 4080 bytes movielib/templates/default/img/up.png | Bin 0 -> 1372 bytes movielib/templates/default/img/v_down.png | Bin 0 -> 1306 bytes movielib/templates/default/img/v_mute.png | Bin 0 -> 1430 bytes movielib/templates/default/img/v_up.png | Bin 0 -> 1360 bytes movielib/templates/default/img/watch.png | Bin 0 -> 1626 bytes movielib/templates/default/img/watched.png | Bin 0 -> 7315 bytes movielib/templates/default/img/xbmc_v.png | Bin 0 -> 2386 bytes movielib/templates/default/img/xbmc_vd.png | Bin 0 -> 1449 bytes movielib/templates/default/index.tpl | 160 + movielib/templates/default/view_bposter.tpl | 11 + movielib/templates/default/view_default.tpl | 115 + movielib/templates/default/view_list.tpl | 21 + movielib/templates/default/view_sposter.tpl | 11 + movielib/templates/white/css/font/vjs.eot | Bin 0 -> 3536 bytes movielib/templates/white/css/font/vjs.svg | 65 + movielib/templates/white/css/font/vjs.ttf | Bin 0 -> 3372 bytes movielib/templates/white/css/font/vjs.woff | Bin 0 -> 4228 bytes movielib/templates/white/css/style.css | 87 + movielib/templates/white/css/video.css | 767 ++ movielib/templates/white/css/view_bposter.css | 7 + movielib/templates/white/css/view_default.css | 49 + movielib/templates/white/css/view_list.css | 12 + movielib/templates/white/css/view_sposter.css | 7 + movielib/templates/white/episodes.tpl | 36 + movielib/templates/white/img/0.png | Bin 0 -> 1219 bytes movielib/templates/white/img/1.png | Bin 0 -> 959 bytes movielib/templates/white/img/2.png | Bin 0 -> 1142 bytes movielib/templates/white/img/3.png | Bin 0 -> 1251 bytes movielib/templates/white/img/4.png | Bin 0 -> 1127 bytes movielib/templates/white/img/5.png | Bin 0 -> 1208 bytes movielib/templates/white/img/6.png | Bin 0 -> 1228 bytes movielib/templates/white/img/7.png | Bin 0 -> 944 bytes movielib/templates/white/img/8.png | Bin 0 -> 1286 bytes movielib/templates/white/img/9.png | Bin 0 -> 1254 bytes movielib/templates/white/img/back.png | Bin 0 -> 1481 bytes movielib/templates/white/img/bg.jpg | Bin 0 -> 344799 bytes movielib/templates/white/img/bigstepback.png | Bin 0 -> 1321 bytes .../templates/white/img/bigstepforward.png | Bin 0 -> 1320 bytes movielib/templates/white/img/context.png | Bin 0 -> 1216 bytes movielib/templates/white/img/d_actor.jpg | Bin 0 -> 10798 bytes movielib/templates/white/img/d_poster.jpg | Bin 0 -> 7907 bytes movielib/templates/white/img/d_thumbnail.jpg | Bin 0 -> 8627 bytes movielib/templates/white/img/delete.png | Bin 0 -> 3405 bytes movielib/templates/white/img/down.png | Bin 0 -> 1349 bytes movielib/templates/white/img/download.png | Bin 0 -> 1365 bytes movielib/templates/white/img/flags/ac_aac.png | Bin 0 -> 3526 bytes movielib/templates/white/img/flags/ac_ac3.png | Bin 0 -> 3558 bytes movielib/templates/white/img/flags/ac_aif.png | Bin 0 -> 3481 bytes movielib/templates/white/img/flags/ac_dd.png | Bin 0 -> 3357 bytes movielib/templates/white/img/flags/ac_dts.png | Bin 0 -> 3549 bytes .../templates/white/img/flags/ac_flac.png | Bin 0 -> 3582 bytes movielib/templates/white/img/flags/ac_mp3.png | Bin 0 -> 3631 bytes movielib/templates/white/img/flags/ac_ogg.png | Bin 0 -> 3456 bytes .../templates/white/img/flags/ac_truehd.png | Bin 0 -> 3650 bytes movielib/templates/white/img/flags/ac_wma.png | Bin 0 -> 3749 bytes movielib/templates/white/img/flags/ach_1.png | Bin 0 -> 3469 bytes movielib/templates/white/img/flags/ach_2.png | Bin 0 -> 3476 bytes movielib/templates/white/img/flags/ach_6.png | Bin 0 -> 3358 bytes movielib/templates/white/img/flags/ach_8.png | Bin 0 -> 3418 bytes movielib/templates/white/img/flags/l_alb.png | Bin 0 -> 3361 bytes movielib/templates/white/img/flags/l_ces.png | Bin 0 -> 3349 bytes movielib/templates/white/img/flags/l_dan.png | Bin 0 -> 3367 bytes movielib/templates/white/img/flags/l_deu.png | Bin 0 -> 3308 bytes movielib/templates/white/img/flags/l_dut.png | Bin 0 -> 3343 bytes movielib/templates/white/img/flags/l_egy.png | Bin 0 -> 3317 bytes movielib/templates/white/img/flags/l_ell.png | Bin 0 -> 3392 bytes movielib/templates/white/img/flags/l_eng.png | Bin 0 -> 3373 bytes movielib/templates/white/img/flags/l_eng2.png | Bin 0 -> 3439 bytes movielib/templates/white/img/flags/l_est.png | Bin 0 -> 3305 bytes movielib/templates/white/img/flags/l_fin.png | Bin 0 -> 3398 bytes movielib/templates/white/img/flags/l_fra.png | Bin 0 -> 3336 bytes movielib/templates/white/img/flags/l_gle.png | Bin 0 -> 3342 bytes movielib/templates/white/img/flags/l_heb.png | Bin 0 -> 3420 bytes movielib/templates/white/img/flags/l_hun.png | Bin 0 -> 3339 bytes movielib/templates/white/img/flags/l_ind.png | Bin 0 -> 3354 bytes movielib/templates/white/img/flags/l_ira.png | Bin 0 -> 3382 bytes movielib/templates/white/img/flags/l_isl.png | Bin 0 -> 3386 bytes movielib/templates/white/img/flags/l_ita.png | Bin 0 -> 3331 bytes movielib/templates/white/img/flags/l_jpn.png | Bin 0 -> 3402 bytes movielib/templates/white/img/flags/l_kat.png | Bin 0 -> 3407 bytes movielib/templates/white/img/flags/l_khm.png | Bin 0 -> 3366 bytes movielib/templates/white/img/flags/l_kor.png | Bin 0 -> 3433 bytes movielib/templates/white/img/flags/l_mlt.png | Bin 0 -> 3378 bytes movielib/templates/white/img/flags/l_mol.png | Bin 0 -> 3354 bytes movielib/templates/white/img/flags/l_mon.png | Bin 0 -> 3365 bytes movielib/templates/white/img/flags/l_nep.png | Bin 0 -> 3457 bytes movielib/templates/white/img/flags/l_nno.png | Bin 0 -> 3375 bytes movielib/templates/white/img/flags/l_pol.png | Bin 0 -> 3328 bytes movielib/templates/white/img/flags/l_por.png | Bin 0 -> 3398 bytes movielib/templates/white/img/flags/l_ron.png | Bin 0 -> 3327 bytes movielib/templates/white/img/flags/l_rus.png | Bin 0 -> 3293 bytes movielib/templates/white/img/flags/l_slk.png | Bin 0 -> 3393 bytes movielib/templates/white/img/flags/l_slv.png | Bin 0 -> 3342 bytes movielib/templates/white/img/flags/l_spa.png | Bin 0 -> 3374 bytes movielib/templates/white/img/flags/l_srp.png | Bin 0 -> 3412 bytes movielib/templates/white/img/flags/l_swe.png | Bin 0 -> 3395 bytes movielib/templates/white/img/flags/l_tur.png | Bin 0 -> 3385 bytes movielib/templates/white/img/flags/l_ukr.png | Bin 0 -> 3353 bytes movielib/templates/white/img/flags/l_zho.png | Bin 0 -> 3308 bytes movielib/templates/white/img/flags/sub.png | Bin 0 -> 3238 bytes movielib/templates/white/img/flags/v_hd.png | Bin 0 -> 3307 bytes movielib/templates/white/img/flags/v_sd.png | Bin 0 -> 3325 bytes movielib/templates/white/img/flags/v_uhd.png | Bin 0 -> 3419 bytes .../templates/white/img/flags/vc_3ivx.png | Bin 0 -> 3853 bytes movielib/templates/white/img/flags/vc_avc.png | Bin 0 -> 3685 bytes .../templates/white/img/flags/vc_divx.png | Bin 0 -> 3851 bytes movielib/templates/white/img/flags/vc_flv.png | Bin 0 -> 3656 bytes .../templates/white/img/flags/vc_h264.png | Bin 0 -> 3839 bytes .../templates/white/img/flags/vc_hevc.png | Bin 0 -> 4050 bytes movielib/templates/white/img/flags/vc_mp4.png | Bin 0 -> 3792 bytes .../templates/white/img/flags/vc_mpeg.png | Bin 0 -> 3801 bytes .../templates/white/img/flags/vc_mpeg2.png | Bin 0 -> 3954 bytes .../templates/white/img/flags/vc_mpeg4.png | Bin 0 -> 3972 bytes movielib/templates/white/img/flags/vc_qt.png | Bin 0 -> 3962 bytes movielib/templates/white/img/flags/vc_wmv.png | Bin 0 -> 3947 bytes .../templates/white/img/flags/vc_xvid.png | Bin 0 -> 3800 bytes movielib/templates/white/img/flags/vres_0.png | Bin 0 -> 3470 bytes .../templates/white/img/flags/vres_1080.png | Bin 0 -> 3595 bytes .../templates/white/img/flags/vres_4096.png | Bin 0 -> 3704 bytes .../templates/white/img/flags/vres_480.png | Bin 0 -> 3609 bytes .../templates/white/img/flags/vres_576.png | Bin 0 -> 3523 bytes .../templates/white/img/flags/vres_720.png | Bin 0 -> 3521 bytes .../templates/white/img/flags/vres_768.png | Bin 0 -> 3552 bytes movielib/templates/white/img/icon.ico | Bin 0 -> 894 bytes movielib/templates/white/img/imdb.png | Bin 0 -> 1485 bytes movielib/templates/white/img/info.png | Bin 0 -> 1399 bytes movielib/templates/white/img/left.png | Bin 0 -> 1450 bytes movielib/templates/white/img/list.png | Bin 0 -> 1183 bytes movielib/templates/white/img/logo.jpg | Bin 0 -> 30455 bytes movielib/templates/white/img/pause.png | Bin 0 -> 1225 bytes movielib/templates/white/img/play.png | Bin 0 -> 1204 bytes movielib/templates/white/img/power.png | Bin 0 -> 1644 bytes movielib/templates/white/img/ribbon_new.png | Bin 0 -> 14577 bytes movielib/templates/white/img/right.png | Bin 0 -> 1417 bytes movielib/templates/white/img/select.png | Bin 0 -> 1523 bytes movielib/templates/white/img/space.png | Bin 0 -> 3346 bytes movielib/templates/white/img/star.png | Bin 0 -> 3180 bytes movielib/templates/white/img/star_g.png | Bin 0 -> 3171 bytes movielib/templates/white/img/star_h.png | Bin 0 -> 3241 bytes movielib/templates/white/img/stepback.png | Bin 0 -> 1227 bytes movielib/templates/white/img/stepforward.png | Bin 0 -> 1230 bytes movielib/templates/white/img/stop.png | Bin 0 -> 1109 bytes movielib/templates/white/img/sync.png | Bin 0 -> 1646 bytes movielib/templates/white/img/trailer.png | Bin 0 -> 4080 bytes movielib/templates/white/img/up.png | Bin 0 -> 1372 bytes movielib/templates/white/img/v_down.png | Bin 0 -> 1306 bytes movielib/templates/white/img/v_mute.png | Bin 0 -> 1430 bytes movielib/templates/white/img/v_up.png | Bin 0 -> 1360 bytes movielib/templates/white/img/watch.png | Bin 0 -> 1626 bytes movielib/templates/white/img/watched.png | Bin 0 -> 7315 bytes movielib/templates/white/img/xbmc_v.png | Bin 0 -> 2386 bytes movielib/templates/white/img/xbmc_vd.png | Bin 0 -> 1449 bytes movielib/templates/white/index.tpl | 160 + movielib/templates/white/view_bposter.tpl | 11 + movielib/templates/white/view_default.tpl | 115 + movielib/templates/white/view_list.tpl | 21 + movielib/templates/white/view_sposter.tpl | 11 + 346 files changed, 27588 insertions(+) create mode 100644 movielib/.gitattributes create mode 100644 movielib/.gitignore create mode 100644 movielib/.htaccess create mode 100644 movielib/CHANGELOG.txt create mode 100644 movielib/LICENSE.txt create mode 100644 movielib/README.txt create mode 100644 movielib/admin.php create mode 100644 movielib/admin/css/font/archivonarrow.ttf create mode 100644 movielib/admin/css/style.css create mode 100644 movielib/admin/img/delete.png create mode 100644 movielib/admin/img/exist.png create mode 100644 movielib/admin/img/hidden.png create mode 100644 movielib/admin/img/i_delete.png create mode 100644 movielib/admin/img/i_fanart.png create mode 100644 movielib/admin/img/i_hidden.png create mode 100644 movielib/admin/img/i_poster.png create mode 100644 movielib/admin/img/i_trailer.png create mode 100644 movielib/admin/img/icon.ico create mode 100644 movielib/admin/img/link.png create mode 100644 movielib/admin/img/movies.png create mode 100644 movielib/admin/img/tvshows.png create mode 100644 movielib/admin/img/visible.png create mode 100644 movielib/config.php create mode 100644 movielib/files.md5 create mode 100644 movielib/function.js.php create mode 100644 movielib/function.php create mode 100644 movielib/index.php create mode 100644 movielib/install.php create mode 100644 movielib/js/jquery-1.9.1.js create mode 100644 movielib/js/jquery.cycle.lite.js create mode 100644 movielib/js/jquery.script.js create mode 100644 movielib/js/video.js create mode 100644 movielib/lang/bg/lang.php create mode 100644 movielib/lang/bg/readme create mode 100644 movielib/lang/da/lang.php create mode 100644 movielib/lang/da/readme create mode 100644 movielib/lang/de/lang.php create mode 100644 movielib/lang/de/readme create mode 100644 movielib/lang/en/lang.php create mode 100644 movielib/lang/en/readme create mode 100644 movielib/lang/es/lang.php create mode 100644 movielib/lang/es/readme create mode 100644 movielib/lang/fr/lang.php create mode 100644 movielib/lang/fr/readme create mode 100644 movielib/lang/hr/lang.php create mode 100644 movielib/lang/hr/readme create mode 100644 movielib/lang/it/lang.php create mode 100644 movielib/lang/it/readme create mode 100644 movielib/lang/nl/lang.php create mode 100644 movielib/lang/nl/readme create mode 100644 movielib/lang/pl/lang.php create mode 100644 movielib/lang/pl/readme create mode 100644 movielib/lang/sk/lang.php create mode 100644 movielib/lang/sk/readme create mode 100644 movielib/lang/sr/lang.php create mode 100644 movielib/lang/sr/readme create mode 100644 movielib/login.php create mode 100644 movielib/sync.php create mode 100644 movielib/templates/default/css/font/vjs.eot create mode 100644 movielib/templates/default/css/font/vjs.svg create mode 100644 movielib/templates/default/css/font/vjs.ttf create mode 100644 movielib/templates/default/css/font/vjs.woff create mode 100644 movielib/templates/default/css/style.css create mode 100644 movielib/templates/default/css/video.css create mode 100644 movielib/templates/default/css/view_bposter.css create mode 100644 movielib/templates/default/css/view_default.css create mode 100644 movielib/templates/default/css/view_list.css create mode 100644 movielib/templates/default/css/view_sposter.css create mode 100644 movielib/templates/default/episodes.tpl create mode 100644 movielib/templates/default/img/0.png create mode 100644 movielib/templates/default/img/1.png create mode 100644 movielib/templates/default/img/2.png create mode 100644 movielib/templates/default/img/3.png create mode 100644 movielib/templates/default/img/4.png create mode 100644 movielib/templates/default/img/5.png create mode 100644 movielib/templates/default/img/6.png create mode 100644 movielib/templates/default/img/7.png create mode 100644 movielib/templates/default/img/8.png create mode 100644 movielib/templates/default/img/9.png create mode 100644 movielib/templates/default/img/back.png create mode 100644 movielib/templates/default/img/bg.jpg create mode 100644 movielib/templates/default/img/bigstepback.png create mode 100644 movielib/templates/default/img/bigstepforward.png create mode 100644 movielib/templates/default/img/context.png create mode 100644 movielib/templates/default/img/d_actor.jpg create mode 100644 movielib/templates/default/img/d_poster.jpg create mode 100644 movielib/templates/default/img/d_thumbnail.jpg create mode 100644 movielib/templates/default/img/delete.png create mode 100644 movielib/templates/default/img/down.png create mode 100644 movielib/templates/default/img/download.png create mode 100644 movielib/templates/default/img/flags/ac_aac.png create mode 100644 movielib/templates/default/img/flags/ac_ac3.png create mode 100644 movielib/templates/default/img/flags/ac_aif.png create mode 100644 movielib/templates/default/img/flags/ac_dd.png create mode 100644 movielib/templates/default/img/flags/ac_dts.png create mode 100644 movielib/templates/default/img/flags/ac_flac.png create mode 100644 movielib/templates/default/img/flags/ac_mp3.png create mode 100644 movielib/templates/default/img/flags/ac_ogg.png create mode 100644 movielib/templates/default/img/flags/ac_truehd.png create mode 100644 movielib/templates/default/img/flags/ac_wma.png create mode 100644 movielib/templates/default/img/flags/ach_1.png create mode 100644 movielib/templates/default/img/flags/ach_2.png create mode 100644 movielib/templates/default/img/flags/ach_6.png create mode 100644 movielib/templates/default/img/flags/ach_8.png create mode 100644 movielib/templates/default/img/flags/l_alb.png create mode 100644 movielib/templates/default/img/flags/l_ces.png create mode 100644 movielib/templates/default/img/flags/l_dan.png create mode 100644 movielib/templates/default/img/flags/l_deu.png create mode 100644 movielib/templates/default/img/flags/l_dut.png create mode 100644 movielib/templates/default/img/flags/l_egy.png create mode 100644 movielib/templates/default/img/flags/l_ell.png create mode 100644 movielib/templates/default/img/flags/l_eng.png create mode 100644 movielib/templates/default/img/flags/l_eng2.png create mode 100644 movielib/templates/default/img/flags/l_est.png create mode 100644 movielib/templates/default/img/flags/l_fin.png create mode 100644 movielib/templates/default/img/flags/l_fra.png create mode 100644 movielib/templates/default/img/flags/l_gle.png create mode 100644 movielib/templates/default/img/flags/l_heb.png create mode 100644 movielib/templates/default/img/flags/l_hun.png create mode 100644 movielib/templates/default/img/flags/l_ind.png create mode 100644 movielib/templates/default/img/flags/l_ira.png create mode 100644 movielib/templates/default/img/flags/l_isl.png create mode 100644 movielib/templates/default/img/flags/l_ita.png create mode 100644 movielib/templates/default/img/flags/l_jpn.png create mode 100644 movielib/templates/default/img/flags/l_kat.png create mode 100644 movielib/templates/default/img/flags/l_khm.png create mode 100644 movielib/templates/default/img/flags/l_kor.png create mode 100644 movielib/templates/default/img/flags/l_mlt.png create mode 100644 movielib/templates/default/img/flags/l_mol.png create mode 100644 movielib/templates/default/img/flags/l_mon.png create mode 100644 movielib/templates/default/img/flags/l_nep.png create mode 100644 movielib/templates/default/img/flags/l_nno.png create mode 100644 movielib/templates/default/img/flags/l_pol.png create mode 100644 movielib/templates/default/img/flags/l_por.png create mode 100644 movielib/templates/default/img/flags/l_ron.png create mode 100644 movielib/templates/default/img/flags/l_rus.png create mode 100644 movielib/templates/default/img/flags/l_slk.png create mode 100644 movielib/templates/default/img/flags/l_slv.png create mode 100644 movielib/templates/default/img/flags/l_spa.png create mode 100644 movielib/templates/default/img/flags/l_srp.png create mode 100644 movielib/templates/default/img/flags/l_swe.png create mode 100644 movielib/templates/default/img/flags/l_tur.png create mode 100644 movielib/templates/default/img/flags/l_ukr.png create mode 100644 movielib/templates/default/img/flags/l_zho.png create mode 100644 movielib/templates/default/img/flags/sub.png create mode 100644 movielib/templates/default/img/flags/v_hd.png create mode 100644 movielib/templates/default/img/flags/v_sd.png create mode 100644 movielib/templates/default/img/flags/v_uhd.png create mode 100644 movielib/templates/default/img/flags/vc_3ivx.png create mode 100644 movielib/templates/default/img/flags/vc_avc.png create mode 100644 movielib/templates/default/img/flags/vc_divx.png create mode 100644 movielib/templates/default/img/flags/vc_flv.png create mode 100644 movielib/templates/default/img/flags/vc_h264.png create mode 100644 movielib/templates/default/img/flags/vc_hevc.png create mode 100644 movielib/templates/default/img/flags/vc_mp4.png create mode 100644 movielib/templates/default/img/flags/vc_mpeg.png create mode 100644 movielib/templates/default/img/flags/vc_mpeg2.png create mode 100644 movielib/templates/default/img/flags/vc_mpeg4.png create mode 100644 movielib/templates/default/img/flags/vc_qt.png create mode 100644 movielib/templates/default/img/flags/vc_wmv.png create mode 100644 movielib/templates/default/img/flags/vc_xvid.png create mode 100644 movielib/templates/default/img/flags/vres_0.png create mode 100644 movielib/templates/default/img/flags/vres_1080.png create mode 100644 movielib/templates/default/img/flags/vres_4096.png create mode 100644 movielib/templates/default/img/flags/vres_480.png create mode 100644 movielib/templates/default/img/flags/vres_576.png create mode 100644 movielib/templates/default/img/flags/vres_720.png create mode 100644 movielib/templates/default/img/flags/vres_768.png create mode 100644 movielib/templates/default/img/icon.ico create mode 100644 movielib/templates/default/img/imdb.png create mode 100644 movielib/templates/default/img/info.png create mode 100644 movielib/templates/default/img/left.png create mode 100644 movielib/templates/default/img/list.png create mode 100644 movielib/templates/default/img/logo.jpg create mode 100644 movielib/templates/default/img/pause.png create mode 100644 movielib/templates/default/img/play.png create mode 100644 movielib/templates/default/img/power.png create mode 100644 movielib/templates/default/img/ribbon_new.png create mode 100644 movielib/templates/default/img/right.png create mode 100644 movielib/templates/default/img/select.png create mode 100644 movielib/templates/default/img/space.png create mode 100644 movielib/templates/default/img/star.png create mode 100644 movielib/templates/default/img/star_g.png create mode 100644 movielib/templates/default/img/star_h.png create mode 100644 movielib/templates/default/img/stepback.png create mode 100644 movielib/templates/default/img/stepforward.png create mode 100644 movielib/templates/default/img/stop.png create mode 100644 movielib/templates/default/img/sync.png create mode 100644 movielib/templates/default/img/trailer.png create mode 100644 movielib/templates/default/img/up.png create mode 100644 movielib/templates/default/img/v_down.png create mode 100644 movielib/templates/default/img/v_mute.png create mode 100644 movielib/templates/default/img/v_up.png create mode 100644 movielib/templates/default/img/watch.png create mode 100644 movielib/templates/default/img/watched.png create mode 100644 movielib/templates/default/img/xbmc_v.png create mode 100644 movielib/templates/default/img/xbmc_vd.png create mode 100644 movielib/templates/default/index.tpl create mode 100644 movielib/templates/default/view_bposter.tpl create mode 100644 movielib/templates/default/view_default.tpl create mode 100644 movielib/templates/default/view_list.tpl create mode 100644 movielib/templates/default/view_sposter.tpl create mode 100644 movielib/templates/white/css/font/vjs.eot create mode 100644 movielib/templates/white/css/font/vjs.svg create mode 100644 movielib/templates/white/css/font/vjs.ttf create mode 100644 movielib/templates/white/css/font/vjs.woff create mode 100644 movielib/templates/white/css/style.css create mode 100644 movielib/templates/white/css/video.css create mode 100644 movielib/templates/white/css/view_bposter.css create mode 100644 movielib/templates/white/css/view_default.css create mode 100644 movielib/templates/white/css/view_list.css create mode 100644 movielib/templates/white/css/view_sposter.css create mode 100644 movielib/templates/white/episodes.tpl create mode 100644 movielib/templates/white/img/0.png create mode 100644 movielib/templates/white/img/1.png create mode 100644 movielib/templates/white/img/2.png create mode 100644 movielib/templates/white/img/3.png create mode 100644 movielib/templates/white/img/4.png create mode 100644 movielib/templates/white/img/5.png create mode 100644 movielib/templates/white/img/6.png create mode 100644 movielib/templates/white/img/7.png create mode 100644 movielib/templates/white/img/8.png create mode 100644 movielib/templates/white/img/9.png create mode 100644 movielib/templates/white/img/back.png create mode 100644 movielib/templates/white/img/bg.jpg create mode 100644 movielib/templates/white/img/bigstepback.png create mode 100644 movielib/templates/white/img/bigstepforward.png create mode 100644 movielib/templates/white/img/context.png create mode 100644 movielib/templates/white/img/d_actor.jpg create mode 100644 movielib/templates/white/img/d_poster.jpg create mode 100644 movielib/templates/white/img/d_thumbnail.jpg create mode 100644 movielib/templates/white/img/delete.png create mode 100644 movielib/templates/white/img/down.png create mode 100644 movielib/templates/white/img/download.png create mode 100644 movielib/templates/white/img/flags/ac_aac.png create mode 100644 movielib/templates/white/img/flags/ac_ac3.png create mode 100644 movielib/templates/white/img/flags/ac_aif.png create mode 100644 movielib/templates/white/img/flags/ac_dd.png create mode 100644 movielib/templates/white/img/flags/ac_dts.png create mode 100644 movielib/templates/white/img/flags/ac_flac.png create mode 100644 movielib/templates/white/img/flags/ac_mp3.png create mode 100644 movielib/templates/white/img/flags/ac_ogg.png create mode 100644 movielib/templates/white/img/flags/ac_truehd.png create mode 100644 movielib/templates/white/img/flags/ac_wma.png create mode 100644 movielib/templates/white/img/flags/ach_1.png create mode 100644 movielib/templates/white/img/flags/ach_2.png create mode 100644 movielib/templates/white/img/flags/ach_6.png create mode 100644 movielib/templates/white/img/flags/ach_8.png create mode 100644 movielib/templates/white/img/flags/l_alb.png create mode 100644 movielib/templates/white/img/flags/l_ces.png create mode 100644 movielib/templates/white/img/flags/l_dan.png create mode 100644 movielib/templates/white/img/flags/l_deu.png create mode 100644 movielib/templates/white/img/flags/l_dut.png create mode 100644 movielib/templates/white/img/flags/l_egy.png create mode 100644 movielib/templates/white/img/flags/l_ell.png create mode 100644 movielib/templates/white/img/flags/l_eng.png create mode 100644 movielib/templates/white/img/flags/l_eng2.png create mode 100644 movielib/templates/white/img/flags/l_est.png create mode 100644 movielib/templates/white/img/flags/l_fin.png create mode 100644 movielib/templates/white/img/flags/l_fra.png create mode 100644 movielib/templates/white/img/flags/l_gle.png create mode 100644 movielib/templates/white/img/flags/l_heb.png create mode 100644 movielib/templates/white/img/flags/l_hun.png create mode 100644 movielib/templates/white/img/flags/l_ind.png create mode 100644 movielib/templates/white/img/flags/l_ira.png create mode 100644 movielib/templates/white/img/flags/l_isl.png create mode 100644 movielib/templates/white/img/flags/l_ita.png create mode 100644 movielib/templates/white/img/flags/l_jpn.png create mode 100644 movielib/templates/white/img/flags/l_kat.png create mode 100644 movielib/templates/white/img/flags/l_khm.png create mode 100644 movielib/templates/white/img/flags/l_kor.png create mode 100644 movielib/templates/white/img/flags/l_mlt.png create mode 100644 movielib/templates/white/img/flags/l_mol.png create mode 100644 movielib/templates/white/img/flags/l_mon.png create mode 100644 movielib/templates/white/img/flags/l_nep.png create mode 100644 movielib/templates/white/img/flags/l_nno.png create mode 100644 movielib/templates/white/img/flags/l_pol.png create mode 100644 movielib/templates/white/img/flags/l_por.png create mode 100644 movielib/templates/white/img/flags/l_ron.png create mode 100644 movielib/templates/white/img/flags/l_rus.png create mode 100644 movielib/templates/white/img/flags/l_slk.png create mode 100644 movielib/templates/white/img/flags/l_slv.png create mode 100644 movielib/templates/white/img/flags/l_spa.png create mode 100644 movielib/templates/white/img/flags/l_srp.png create mode 100644 movielib/templates/white/img/flags/l_swe.png create mode 100644 movielib/templates/white/img/flags/l_tur.png create mode 100644 movielib/templates/white/img/flags/l_ukr.png create mode 100644 movielib/templates/white/img/flags/l_zho.png create mode 100644 movielib/templates/white/img/flags/sub.png create mode 100644 movielib/templates/white/img/flags/v_hd.png create mode 100644 movielib/templates/white/img/flags/v_sd.png create mode 100644 movielib/templates/white/img/flags/v_uhd.png create mode 100644 movielib/templates/white/img/flags/vc_3ivx.png create mode 100644 movielib/templates/white/img/flags/vc_avc.png create mode 100644 movielib/templates/white/img/flags/vc_divx.png create mode 100644 movielib/templates/white/img/flags/vc_flv.png create mode 100644 movielib/templates/white/img/flags/vc_h264.png create mode 100644 movielib/templates/white/img/flags/vc_hevc.png create mode 100644 movielib/templates/white/img/flags/vc_mp4.png create mode 100644 movielib/templates/white/img/flags/vc_mpeg.png create mode 100644 movielib/templates/white/img/flags/vc_mpeg2.png create mode 100644 movielib/templates/white/img/flags/vc_mpeg4.png create mode 100644 movielib/templates/white/img/flags/vc_qt.png create mode 100644 movielib/templates/white/img/flags/vc_wmv.png create mode 100644 movielib/templates/white/img/flags/vc_xvid.png create mode 100644 movielib/templates/white/img/flags/vres_0.png create mode 100644 movielib/templates/white/img/flags/vres_1080.png create mode 100644 movielib/templates/white/img/flags/vres_4096.png create mode 100644 movielib/templates/white/img/flags/vres_480.png create mode 100644 movielib/templates/white/img/flags/vres_576.png create mode 100644 movielib/templates/white/img/flags/vres_720.png create mode 100644 movielib/templates/white/img/flags/vres_768.png create mode 100644 movielib/templates/white/img/icon.ico create mode 100644 movielib/templates/white/img/imdb.png create mode 100644 movielib/templates/white/img/info.png create mode 100644 movielib/templates/white/img/left.png create mode 100644 movielib/templates/white/img/list.png create mode 100644 movielib/templates/white/img/logo.jpg create mode 100644 movielib/templates/white/img/pause.png create mode 100644 movielib/templates/white/img/play.png create mode 100644 movielib/templates/white/img/power.png create mode 100644 movielib/templates/white/img/ribbon_new.png create mode 100644 movielib/templates/white/img/right.png create mode 100644 movielib/templates/white/img/select.png create mode 100644 movielib/templates/white/img/space.png create mode 100644 movielib/templates/white/img/star.png create mode 100644 movielib/templates/white/img/star_g.png create mode 100644 movielib/templates/white/img/star_h.png create mode 100644 movielib/templates/white/img/stepback.png create mode 100644 movielib/templates/white/img/stepforward.png create mode 100644 movielib/templates/white/img/stop.png create mode 100644 movielib/templates/white/img/sync.png create mode 100644 movielib/templates/white/img/trailer.png create mode 100644 movielib/templates/white/img/up.png create mode 100644 movielib/templates/white/img/v_down.png create mode 100644 movielib/templates/white/img/v_mute.png create mode 100644 movielib/templates/white/img/v_up.png create mode 100644 movielib/templates/white/img/watch.png create mode 100644 movielib/templates/white/img/watched.png create mode 100644 movielib/templates/white/img/xbmc_v.png create mode 100644 movielib/templates/white/img/xbmc_vd.png create mode 100644 movielib/templates/white/index.tpl create mode 100644 movielib/templates/white/view_bposter.tpl create mode 100644 movielib/templates/white/view_default.tpl create mode 100644 movielib/templates/white/view_list.tpl create mode 100644 movielib/templates/white/view_sposter.tpl diff --git a/movielib/.gitattributes b/movielib/.gitattributes new file mode 100644 index 0000000..6e4dec4 --- /dev/null +++ b/movielib/.gitattributes @@ -0,0 +1,5 @@ +* text eol=lf +*.ttf binary +*.png binary +*.jpg binary +*.ico binary \ No newline at end of file diff --git a/movielib/.gitignore b/movielib/.gitignore new file mode 100644 index 0000000..6a2aafe --- /dev/null +++ b/movielib/.gitignore @@ -0,0 +1,2 @@ +hash.py +/nbproject \ No newline at end of file diff --git a/movielib/.htaccess b/movielib/.htaccess new file mode 100644 index 0000000..c2b26b0 --- /dev/null +++ b/movielib/.htaccess @@ -0,0 +1,16 @@ + + + # Tell PHP that the mod_rewrite module is ENABLED. + SetEnv HTTP_MOD_REWRITE On + + RewriteEngine On + + RewriteRule ^index.html$ index.php + + RewriteRule ^(index,[^/]+)-([^/]+)$ $1=$2 [N] + RewriteRule ^(index,[^/]+),([^/]+)$ $1&$2 [N] + + RewriteRule ^index,([^/]+).html$ index.php?$1 + RewriteRule ^index,(.*)/([^/]+).html$ $1/index.php?$2 + + \ No newline at end of file diff --git a/movielib/CHANGELOG.txt b/movielib/CHANGELOG.txt new file mode 100644 index 0000000..569c88d --- /dev/null +++ b/movielib/CHANGELOG.txt @@ -0,0 +1,111 @@ +v. 2.8.1 +- fixed creating database indexes + +v. 2.8.0 +- fixed filter delete button +- fixed database tables +- added indexes to database +- added cleaning function +- separate image sync +- fixed filter links +- added delete button for each image in admin panel +- added playcount digit in default view +- added function to autosync webserver settings for control remote + +v. 2.7.3 +- add uhd flag +- add htaccess and mod rewrite +- option to set default sorting +- optin to set default watched status +- option to set hidden the select media header bar +- add imdb link + +v. 2.7.2 +- added sync episode thumbnail +- added new episodes view + +v. 2.7.1 +- added navigate buttons to remote +- added star rating +- added video new flag +- fixed audio and subs flag +- fixed deleting episodes when delete tvshow +- fixed banner +- fixed sync episodes +- added next, prev buttons for extrathumb view +- added cached actors in admin panel +- fixed facebook tags +- added facebook buttons + +v. 2.7.0 +- added extra thumbs +- added multi audio track +- added audio and subtitles language +- now movies info update when XBMC do some changes +- added actors to live search +- rewrite sync functions + +v. 2.6.1 +- added studio panel +- added studio flags +- added language: Spanish, Italian + +v. 2.6.0 +- added remote control XBMC +- added support for download video file +- added support for playing video directly +- added filter watched/unwatched + +v. 2.5.4 +- fixed install process +- added Danish language + +v. 2.5.3 +- added banner with last played movie or tvshow + +v. 2.5.2 +- added ability to hide movie or tvshow + +v. 2.5.1 +- fixed switching between views +- added banner support + +v. 2.5.0 +- added views + +v. 2.4.0 +- fixed sync images +- added TVshows +- added filter info + +v. 2.3.3 +- fixed default poster image in live search +- added checking files integrity +- added checking tables integrity (auto update to new versions) +- added checking if allow_url_fopen is enabled +- added support for movies set + +v. 2.3.2 +- fixed graphics for HD movies +- fixed create tables in install process + +v. 2.3.1 +- fixed sorting + +v. 2.3.0 +- added cast field +- added actors thumbnail +- added live search + +v. 2.2.0 +- language translation by Transifex +- rewrite creating cache function +- added trailer support +- added support for sync poster and fanart stored localy + +v. 2.1.0 +- added more filter options +- PA: possibility to manualy delete movie option + +v. 2.0.0 +- init new version \ No newline at end of file diff --git a/movielib/LICENSE.txt b/movielib/LICENSE.txt new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/movielib/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/movielib/README.txt b/movielib/README.txt new file mode 100644 index 0000000..eb6667e --- /dev/null +++ b/movielib/README.txt @@ -0,0 +1,11 @@ +The script automatically synchronizes and displays XBMC/Kodi library. + +Requirements: +- Server with Apache server, PHP 5, MySql 5 +- Addon "Movielib" for XBMC/Kodi https://raw.github.com/Regss/xbmc-regss-repository/master/repo/repository.regss/repository.regss-1.2.1.zip + +Default passwords: +Access to site: user +Access to admin panel: admin + +In Panel Admin section you need to generate token and put it to addon settings with URL to script. \ No newline at end of file diff --git a/movielib/admin.php b/movielib/admin.php new file mode 100644 index 0000000..09cdc5c --- /dev/null +++ b/movielib/admin.php @@ -0,0 +1,681 @@ +'; +} + +/* ###################### + * CHECK ADMIN PASSWORD # + */###################### +if (!isset($_SESSION['logged_admin']) or $_SESSION['logged_admin'] !== true) { + header('Location:login.php?login=admin'); + die('Cant\'t redirect to login.php'); +} + +/* ############# + * # CHECK DIR # + */############# +foreach ($dir_assoc as $dir) { + if (!file_exists($dir)) { + mkdir($dir); + } +} + +/* ############# + * # MAIN SITE # + */############# +$output_panel = ''; +if ($option == '') { + + // get version from db + $db_vers_sql = 'SELECT version FROM config'; + $db_vers_result = mysql_q($db_vers_sql); + $db_version_assoc = mysql_fetch_assoc($db_vers_result); + $db_version = $db_version_assoc['version']; + + // check tables if versions not match + if ($db_version !== $version or isset($_GET['tables'])) { + $output_panel_info.= create_table($mysql_tables, $mysql_indexes, $lang, $version, 0); + + // delete session var + $_SESSION = array(); + $_SESSION['logged_admin'] = true; + } + + // Watched + $overall_movies_sql = 'SELECT play_count, hide FROM movies'; + $overall_movies_result = mysql_q($overall_movies_sql); + $overall_movies_all = mysql_num_rows($overall_movies_result); + $overall_movies_watched = 0; + $overall_movies_hidden = 0; + while ($overall_movies = mysql_fetch_array($overall_movies_result)) { + if ($overall_movies['hide'] == 1) { + $overall_movies_hidden++; + } else { + if ($overall_movies['play_count'] > 0) { + $overall_movies_watched++; + } + } + } + $overall_movies_unwatched = $overall_movies_all - $overall_movies_watched; + + $overall_tvshows_sql = 'SELECT play_count, hide FROM tvshows'; + $overall_tvshows_result = mysql_q($overall_tvshows_sql); + $overall_tvshows_all = mysql_num_rows($overall_tvshows_result); + $overall_tvshows_watched = 0; + $overall_tvshows_hidden = 0; + while ($overall_tvshows = mysql_fetch_array($overall_tvshows_result)) { + if ($overall_tvshows['hide'] == 1) { + $overall_tvshows_hidden++; + } else { + if ($overall_tvshows['play_count'] > 0) { + $overall_tvshows_watched++; + } + } + } + $overall_tvshows_unwatched = $overall_tvshows_all - $overall_tvshows_watched; + + // Cached poster and fanarts + $cached_dir = scandir('cache/'); + $poster_cached = 0; + $fanart_cached = 0; + $exthumb_cached = 0; + foreach ($cached_dir as $val) { + if (preg_match_all('/_[0-9]+\.jpg/', $val, $res) == 1) { + $poster_cached++; + } + if (preg_match_all('/_[0-9]+_f\.jpg/', $val, $res) == 1) { + $fanart_cached++; + } + if (preg_match_all('/_[0-9]+_t[0-9]\.jpg/', $val, $res) == 1) { + $exthumb_cached++; + } + } + + // Cached actors + $cached_dir = scandir('cache/actors/'); + $actors_cached = 0; + foreach ($cached_dir as $val) { + if (preg_match_all('/[0-9a-z]{10}\.jpg/', $val, $res) == 1) { + $actors_cached++; + } + } + + // Directories + $output_dirs = ''; + foreach ($dir_assoc as $dir) { + if (file_exists($dir)) { + $output_dirs.= '' . $dir . '' . (file_exists($dir) ? '' . $lang['a_exists'] . '' : '' . $lang['a_not_exists'] . '') . ''; + } + } + + // MD5 files + $md5_file = 'files.md5'; + $output_md5 = ''; + $fp = fopen($md5_file, 'r'); + $data = fread($fp, filesize($md5_file)); + fclose($fp); + foreach (explode(';', $data) as $f) { + $file = explode(':', $f); + $output_md5.= '' . $file[0] . '' . (md5_file($file[0]) == $file[1] ? '' . $lang['a_match'] . '' : '' . $lang['a_mismatch'] . '') . ''; + } + + $output_panel = ' + + + + + + + + + + + + + + + + + + + + + + + + + + ' . $output_dirs . ' + + ' . $output_md5 . ' +
' . $lang['a_movies'] . '
' . $lang['a_all'] . '' . $overall_movies_all . '
' . $lang['a_watched'] . '' . $overall_movies_watched . '
' . $lang['a_unwatched'] . '' . $overall_movies_unwatched . '
' . $lang['a_hidden'] . '' . $overall_movies_hidden . '
' . $lang['a_tvshows'] . '
' . $lang['a_all'] . '' . $overall_tvshows_all . '
' . $lang['a_watched'] . '' . $overall_tvshows_watched . '
' . $lang['a_unwatched'] . '' . $overall_tvshows_unwatched . '
' . $lang['a_hidden'] . '' . $overall_tvshows_hidden . '
' . $lang['a_cache'] . '
' . $lang['a_cached_posters'] . '' . $poster_cached . '
' . $lang['a_cached_fanarts'] . '' . $fanart_cached . '
' . $lang['a_cached_actors'] . '' . $actors_cached . '
' . $lang['a_cached_exthumb'] . '' . $exthumb_cached . '
' . $lang['a_server_settings'] . '
GD' . (extension_loaded('gd') && function_exists('gd_info') ? '' . $lang['a_setting_on'] . '' : '' . $lang['a_setting_off'] . '') . '
CURL' . (function_exists('curl_version') ? '' . $lang['a_setting_on'] . '' : '' . $lang['a_setting_off'] . '') . '
MOD REWRITE' . (array_key_exists('HTTP_MOD_REWRITE', $_SERVER) ? '' . $lang['a_setting_on'] . '' : '' . $lang['a_setting_off'] . '') . '
ALLOW URL FOPEN' . (ini_get('allow_url_fopen') == 1 ? '' . $lang['a_setting_on'] . '' : '' . $lang['a_setting_off'] . '') . '
MAX EXECUTION TIME' . ini_get('max_execution_time') . '
UPLOAD MAX FILESIZE' . ini_get('upload_max_filesize') . '
POST MAX SIZE' . ini_get('post_max_size') . '
' . $lang['a_server_directories'] . '
' . $lang['a_files_md5'] . '
'; +} + +/* ######################### + * # MOVIE AND TVSHOW LIST # + */######################### +if ($option == 'movieslist' or $option == 'tvshowslist') { + if ($option == 'movieslist') { + $t = 'movies'; + $list_sql = 'SELECT id, title, trailer, play_count, hide FROM movies ORDER BY title'; + } else { + $t = 'tvshows'; + $list_sql = 'SELECT id, title, play_count, hide FROM tvshows ORDER BY title'; + } + + $list_result = mysql_q($list_sql); + $output_panel = ' + + + + + + + + + + + '; + $i = 0; + while ($list = mysql_fetch_array($list_result)) { + if (file_exists('cache/' . $t . '_' . $list['id'] . '.jpg')) { + $poster_exist = ''; + } else { + $poster_exist = ''; + } + if (file_exists('cache/' . $t . '_' . $list['id'] . '_f.jpg')) { + $fanart_exist = ''; + } else { + $fanart_exist = ''; + } + if ($t == 'movies' && stristr($list['trailer'], 'http://')) { + $trailer_link = ''; + } else { + $trailer_link = ''; + } + if ($list['hide'] == 1) { + $hide = ''; + } else { + $hide = ''; + } + $i++; + $output_panel.= ' + + + + + + + + + '; + } + $output_panel.= '
ID' . $lang['a_title'] . '
' . $i . '' . $list['id'] . '' . $list['title'] . '' . $poster_exist . '' . $fanart_exist . '' . $trailer_link . '' . $hide . '
' . $lang['a_delete_all'] . ''; +} + +// DELETE ALL +if ($option == 'delete_all_movies' or $option == 'delete_all_tvshows') { + if ($option == 'delete_all_movies') { + $truncate = array('movies', 'movies_country', 'movies_actor', 'movies_director', 'movies_genre', 'movies_stream', 'movies_studio'); + $reg_exp = '#^(movies)#'; + } else { + $truncate = array('tvshows', 'tvshows_actor', 'tvshows_genre', 'episodes', 'episodes_stream'); + $reg_exp = '#^(tvshows|episodes)#'; + } + foreach ($truncate as $t) { + $sql = 'TRUNCATE `' . $t . '`'; + mysql_q($sql); + } + $files = scandir('cache/'); + $files_to_remove = array(); + foreach($files as $file) { + $match = preg_match_all($reg_exp, $file); + if ($match > 0) { + $files_to_remove[] = $file; + } + } + remove_images($files_to_remove); +} + +/* ############ + * # SETTINGS # + */############ +if ($option == 'settings') { + + $output_lang = ''; + $output_theme = ''; + $output_select_media_header = ''; + $output_view = ''; + $output_panel_top = ''; + $output_panel_view = ''; + $output_watched_status = ''; + $output_show_playcount = ''; + $output_live_search = ''; + $output_live_search_max_res = ''; + $output_panel_overall = ''; + $output_panel_genre = ''; + $output_panel_year = ''; + $output_panel_country = ''; + $output_panel_set = ''; + $output_panel_studio = ''; + $output_show_fanart = ''; + $output_fadeout_fanart = ''; + $output_show_trailer = ''; + $output_show_facebook = ''; + $output_protect_site = ''; + $output_mod_rewrite = ''; + $output_per_page = ''; + $output_default_sort = ''; + $output_default_watch = ''; + $output_panel_top_limit = ''; + $output_xbmc_thumbs = ''; + $output_xbmc_posters = ''; + $output_xbmc_fanarts = ''; + $output_xbmc_exthumbs = ''; + $output_xbmc_exthumbs_q = ''; + $output_xbmc_auto_conf_remote = ''; + $output_xbmc_master = ''; + + // set language input + $option_language = scandir('lang/'); + foreach ($option_language as $val) { + if (file_exists('lang/' . $val . '/lang.php')) { + if (array_key_exists($val, $langs)) { + $lang_title = $langs[$val]; + } else { + $lang_title = $val; + } + $output_lang.= '' . $lang_title . ''; + } + } + + // set default sort + $sort_array = array( + 1 => $lang['i_title'], + 4 => $lang['i_rating'], + 5 => $lang['i_added'], + 7 => $lang['i_last_played'], + 8 => $lang['i_most_watched'] + ); + foreach ($sort_array as $key => $val) { + $output_default_sort.= '' . $val . ''; + } + + // set default watch + $watch_array = array( + 0 => $lang['i_all'], + 1 => $lang['i_watched'], + 2 => $lang['i_unwatched'] + ); + foreach ($watch_array as $key => $val) { + $output_default_watch.= '' . $val . ''; + } + + // set theme input + $option_theme = scandir('templates/'); + foreach ($option_theme as $val) { + if ($val !== '.' && $val !== '..') { + $output_theme.= '' . $val . ''; + } + } + + // set view input + foreach ($views as $key => $val) { + $output_view.= '' . $lang['a_' . $val] . ''; + } + + // extra thumbs size + $dimens = array('1920x1080', '1280x720', '853x480'); + foreach ($dimens as $val) { + $output_xbmc_exthumbs_q.= '' . $val . ''; + } + + $mode = array(0, 1); + foreach ($mode as $val) { + $output_panel_top.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_select_media_header.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_panel_view.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_watched_status.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_show_playcount.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_live_search.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_show_fanart.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_fadeout_fanart.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_show_trailer.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_show_facebook.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_protect_site.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_mod_rewrite.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_xbmc_thumbs.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_xbmc_posters.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_xbmc_fanarts.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_xbmc_exthumbs.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_xbmc_auto_conf_remote.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + $output_xbmc_master.= '' . ($val == 0 ? $lang['a_setting_off'] : $lang['a_setting_on']) . ''; + } + + $mode2 = array(0 => $lang['a_setting_off'], 1 => $lang['a_setting_on_expanded'], 2 => $lang['a_setting_on_collapsed']); + foreach ($mode2 as $key => $val) { + $output_panel_overall.= '' . $val . ''; + $output_panel_genre.= '' . $val . ''; + $output_panel_year.= '' . $val . ''; + $output_panel_country.= '' . $val . ''; + $output_panel_set.= '' . $val . ''; + $output_panel_studio.= '' . $val . ''; + } + + $quantity = array(5, 10, 20, 50, 100); + foreach ($quantity as $val) { + // set per page input + $output_per_page.= '' . $val . ''; + // set panel top limit + $output_panel_top_limit.= '' . $val . ''; + // set live search max res + $output_live_search_max_res.= '' . $val . ''; + } + + // output form + $output_panel.= ' +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
' . $lang['a_set_sync'] . '
' . $lang['a_xbmc_thumbs'] . ':
' . $lang['a_xbmc_posters'] . ':
' . $lang['a_xbmc_fanarts'] . ':
' . $lang['a_xbmc_exthumbs'] . ':
' . $lang['a_xbmc_exthumbs_q'] . ':
' . $lang['a_xbmc_auto_conf_remote'] . ':
' . $lang['a_xbmc_master'] . ':
' . $lang['a_set_main'] . '
' . $lang['a_site_name'] . ':
' . $lang['a_language'] . ':
' . $lang['a_theme'] . ':
' . $lang['a_select_media_header'] . ':
' . $lang['a_view'] . ':
' . $lang['a_per_page'] . ':
' . $lang['a_default_sort'] . ':
' . $lang['a_default_watch'] . ':
' . $lang['a_panel_top'] . ':
' . $lang['a_panel_view'] . ':
' . $lang['a_watched_status'] . ':
' . $lang['a_show_playcount'] . ':
' . $lang['a_live_search'] . ':
' . $lang['a_live_search_max_res'] . ':
' . $lang['a_show_fanart'] . ':
' . $lang['a_fadeout_fanart'] . ':
' . $lang['a_show_trailer'] . ':
' . $lang['a_show_facebook'] . ':
' . $lang['a_protect_site'] . ':
' . $lang['a_mod_rewrite'] . ':
' . $lang['a_set_panel_left'] . '
' . $lang['a_panel_overall'] . ':
' . $lang['a_panel_genre'] . ':
' . $lang['a_panel_year'] . ':
' . $lang['a_panel_country'] . ':
' . $lang['a_panel_set'] . ':
' . $lang['a_panel_studio'] . ':
' . $lang['a_set_panel_top'] . '
' . $lang['a_panel_top_time'] . ':
' . $lang['a_panel_top_limit'] . ':

+ +
'; +} + +// Saving settings +if ($option == 'settings_save' && isset($_POST) && count($_POST) > 10) { + $settings_array = array(); + $test = true; + foreach ($_POST as $key => $val) { + $settings_array[] = $key . ' = "' . $val . '"'; + if (strlen($val) == 0) { + $test = false; + break; + } + } + $settings_update_sql = 'UPDATE config SET ' . implode(', ', $settings_array); + + // delete session var + $_SESSION = array(); + $_SESSION['logged_admin'] = true; + if ($test) { + $settings_update_res = mysql_q($settings_update_sql); + $output_panel_info.= $lang['a_saved'] . '
'; + } else { + $output_panel_info.= $lang['a_not_saved'] . '
'; + } + reset_hash(); +} + +/* ################### + * # CHANGE PASSWORD # + */################### +if ($option == 'password') { + $output_panel.= ' +
+ + + + + + + +
' . $lang['a_user'] . '
' . $lang['a_new_password'] . '
' . $lang['a_new_password_re'] . '
' . $lang['a_admin'] . '
' . $lang['a_new_password'] . '
' . $lang['a_new_password_re'] . '

+ +
+ '; +} + +// Save password +if ($option == 'password_save') { + if (strlen($_POST['password']) > 0) { + if ($_POST['password'] == $_POST['password_re']) { + if (strlen($_POST['password']) > 3) { + $password_update_sql = 'UPDATE users SET password = "' . md5($_POST['password']) . '" WHERE login ="user"'; + mysql_q($password_update_sql); + $output_panel_info.= $lang['a_user_pass_changed'] . '
'; + } else { + $output_panel_info.= $lang['a_user_pass_min'] . '
'; + } + } else { + $output_panel_info.= $lang['a_user_pass_n_match'] . '
'; + } + } + + if (strlen($_POST['password_admin']) > 0) { + if ($_POST['password_admin'] == $_POST['password_admin_re']) { + if (strlen($_POST['password_admin']) > 3) { + $password_update_sql = 'UPDATE users SET password = "' . md5($_POST['password_admin']) . '" WHERE login ="admin"'; + mysql_q($password_update_sql); + $output_panel_info.= $lang['a_admin_pass_changed'] . '
'; + } else { + $output_panel_info.= $lang['a_admin_pass_min'] . '
'; + } + } else { + $output_panel_info.= $lang['a_admin_pass_n_match'] . '
'; + } + } +} +// check admin pass is not default +$pass_check_sql = 'SELECT * FROM users WHERE login = "admin"'; +$pass_check_result = mysql_q($pass_check_sql); +$pass_check = mysql_fetch_array($pass_check_result); +if ($pass_check['password'] == '21232f297a57a5a743894a0e4a801fc3') { + $output_panel_info.= $lang['a_pass_default'] . '
'; +} + +/* ######### + * # TOKEN # + */######### +if ($option == 'token') { + if (isset($_POST['new_token'])) { + $new_token = change_token(); + $output_panel_info.= $lang['a_token_changed'] . '
'; + } else { + $new_token = $setting['token']; + } + $output_panel.= ' + + +
Token:' . $new_token . '

+
+ + +
+ '; +} + +/* ########## + * # BANNER # + */########## +if ($option == 'banner') { + if (isset($_POST['banner'])) { + foreach ($_POST['banner'] as $val) { + if (!is_numeric($val)) { + if (!preg_match('/^[0-9abcdefABCDEF]{6}$/', $val)) { + $false = true; + break; + } + } + } + if (!isset($false)) { + $update_sql = 'UPDATE config SET `banner` = "' . banner2str($_POST['banner']) . '"'; + mysql_q($update_sql); + $_SESSION['banner'] = $setting['banner'] = banner2str($_POST['banner']); + $b = create_banner($lang, 'banner.jpg', banner2str($_POST['banner'])); + } else { + $output_panel_info.= $lang['a_error_form']; + } + } + + if (isset($_POST['reset'])) { + $b = create_banner($lang, 'banner.jpg', '0'); + $_SESSION['banner'] = $setting['banner'] = banner2str($b); + } + + $b = create_banner($lang, 'banner_v.jpg', $setting['banner']); + + $output_panel.= ''; + $output_panel.= ''; + $output_panel.= '

'; + $output_panel.= '

'; + $url = 'http://' . $_SERVER['SERVER_NAME'] . implode('/', array_slice(explode('/', $_SERVER['REQUEST_URI']), 0, -1)) . '/'; + $output_panel.= ''; +} + +/* ######## + * # XBMC # + */######## +if ($option == 'xbmc') { + $_SESSION = array(); + $_SESSION['logged_admin'] = true; + if ($setting['xbmc_auto_conf_remote'] == 1) { + $output_panel.= '

' . $lang['a_xbmc_auto_conf_enabled'] . '

'; + $d = 'disabled'; + } else { + $d = ''; + } + $output_panel.= ' +
+ + + + + + +
' . $lang['a_xbmc_settings'] . '
' . $lang['a_xbmc_host'] . '
' . $lang['a_xbmc_port'] . '
' . $lang['a_xbmc_login'] . '
' . $lang['a_xbmc_pass'] . '
+
' . $lang['a_xmbc_test'] . '
+ +
+ '; +} + +// Save connection +if ($option == 'xbmc_save') { + $xbmc_update_sql = 'UPDATE config SET + xbmc_host = "' . $_POST['xbmc_host'] . '", + xbmc_port = "' . $_POST['xbmc_port'] . '", + xbmc_login = "' . $_POST['xbmc_login'] . '", + xbmc_pass = "' . $_POST['xbmc_pass'] . '"'; + mysql_q($xbmc_update_sql); + $output_panel_info.= $lang['a_xbmc_saved'] . '
'; + $_SESSION = array(); + $_SESSION['logged_admin'] = true; +} + +/* ############## + * # PANEL INFO # + */############## +if ($output_panel_info !== '') { + $output_panel_info = '
' . $output_panel_info . '
'; +} +?> + + + + <?PHP echo $setting['site_name'] ?> - <?PHP echo $lang['a_html_admin_panel'] ?> + + + + + + + + + +
+
+ + + + + + + + + XBMC + +
+
+ +
+
+ + \ No newline at end of file diff --git a/movielib/admin/css/font/archivonarrow.ttf b/movielib/admin/css/font/archivonarrow.ttf new file mode 100644 index 0000000000000000000000000000000000000000..af3dfa7d348d4b479ac46570226efb5aaf718164 GIT binary patch literal 128488 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%0Aa2F|8Qd%*x_4QU98Iu*2={7<5~+(-RWXv#lJS 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 F`~^cIOCbON literal 0 HcmV?d00001 diff --git a/movielib/admin/css/style.css b/movielib/admin/css/style.css new file mode 100644 index 0000000..35ebc12 --- /dev/null +++ b/movielib/admin/css/style.css @@ -0,0 +1,47 @@ +@charset "utf-8"; + +body { background-color:#000; font-family:Arial, Helvetica, sans-serif; font-size:11px; color:#ddd; border:0px; padding:0px; margin:0px; outline:none; } +#background { position:fixed; top:0; left:0; z-index:-10; min-width:100%; min-height:100%; } +img { vertical-align:middle; border:0px; } + +a:link { color:#999; text-decoration:none; } +a:visited { color:#999; text-decoration:none; } +a:hover { color:#FFF; text-decoration:none; } +a:active { color:#FFF; text-decoration:none; } + +.bold { font-weight:bold; } +.orange { color:#ff7300; } +.red { color:#FF0000; } +.green { color:#0FE800; } +.animate { cursor:pointer; } +.center { text-align:center; } + +input, select { resize:none; background-color:#222; color:#dddddd; border:1px solid #000; font-size:11px; width:160px; height:20px; } +textarea { resize:none; background-color:#222; color:#dddddd; border:1px solid #000; font-size:11px; width:500px; height:18px; padding:5px; margin:10px; } +input:disabled, select:disabled, textarea:disabled { color:#888; } + +.panel_info { border:3px solid #00cc00; background-color:#66ff33; font-weight:bold; color:#000; padding:5px; } +.panel_error { border:3px solid #750000; background-color:#FF0000; font-weight:bold; color:#000; padding:5px; } + +.container { background-color:#111; border:1px solid #333; width:800px; overflow:hidden; margin:auto; padding-bottom:20px; padding-top:10px; opacity:0.9; } + +#panel_left { float:left; width:140px; margin-left:10px; margin-top:10px; } +#panel_right { text-align:center; float:right; width:630px; margin-right:10px; margin-top:10px; } + +.box { display:block; width:100px; font-weight:bold; border:1px solid #333; background-color:#000; margin:auto; margin-bottom:10px; padding:3px; padding-left:10px; padding-right:10px; text-align:center; cursor:pointer; } + +.table { border:1px solid #222; text-align:left; width:100%; margin-bottom:10px; } +.table td { background-color:#000; padding:2px 5px 2px 5px; } +.table img { display:block; margin:auto; } +.text_left { text-align:left; } +.text_right { text-align:right; } + +#banner { margin-top:5px; margin-bottom:20px; } +.ban{ width:50px; } + +/* INSTALL */ +.container_install { margin:auto; } +.container_install input, .container_install select { display:block; margin:auto; background-color:#222; color:#dddddd; border:1px solid #000; font-size:11px; width:160px; height:20px; } +.container_install textarea { display:block; width:600px; height:420px; background-color:#111; color:#fff; border:1px solid #333; margin:auto; margin-top:10px; margin-bottom:10px; resize:none; padding:10px; } +.title { width:300px; margin:auto; background-color:#111; border:1px solid #333; margin-top:20px; margin-bottom:20px; padding:10px; text-align:center; font-size:14px; font-weight:bold; } +.container_install table { margin:auto; border:1px solid #222; text-align:left; width:300px; margin-bottom:10px; margin-top:10px; } diff --git a/movielib/admin/img/delete.png b/movielib/admin/img/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..82764ad5274fda9759ed263c3314066db5f49b92 GIT binary patch literal 3405 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 literal 0 HcmV?d00001 diff --git a/movielib/admin/img/i_delete.png b/movielib/admin/img/i_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..8367baba2b75d6b92e6548c5b521f65c91a3e2ed GIT binary patch literal 3196 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 literal 0 HcmV?d00001 diff --git a/movielib/admin/img/i_hidden.png b/movielib/admin/img/i_hidden.png new file mode 100644 index 0000000000000000000000000000000000000000..64f152aebc68caa57b0f10283b83851f44da24b5 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$#=yX+Sd>!;vL>4nJ=qZCRW5rVYGN7PB zvPY0F14ET614BbI1H;e%K>8&EL#Y7+!>a@a2CEqi4C48d;*Yuk)!z1WaSW-rmGtNT ze|u&S5C-DIcP)GVGXiD*|4;e>lxSgxuv<!HMty3k t*$j!tK#Hx+y4+w+>uIq`w!C0hFf+UjZgpurW@HL7&(qb!;vL>4nJ=qZCRW5rVYGN7PB zvPY0F14ET614BbI1H;e%K>8&EL#Y7+!>a@a2CEqi4C48d;*Yuk)qe7HaSW-rmGtNT zfBVCCEqngYlvn^1X88X<=?74V`7%h15hBoX($K&FXb4z#kMZor#IJ&F|9ODGhlfXi zt>>^n7V|@>^q>FoN`>WokN;nFR}fm=?+|*Br+H;t_Hm%w!P-+25)vA2a$R0H=hOU& zosEp40(l|THp>*4fk4>IanH2JQy?m*T-eClV8G*YF@K70gbu5-fm2yS)4l8p9;4HN z4k|4zO!!;vL>4nJ=qZCRW5rVYGN7PB zvPY0F14ET614BbI1H;e%K>8&EL#Y7+!>a@a2CEqi4C48d;*Yuk)n4*+aSW-rmGtNT ze|u&S5C&prcP3?KpydDmNk2g1m+xBk{AWZ69G-iV=RXjf2MU1{wP?0z@3U_IXg_E3 zFAf)=^I$r=>?G2X9GJ?V8~l6k(U6he$m!IZz_YdS1H`aHSv*~V2I31WxM!<$vG~cZ z?l&+<@=)M5GB5zT6=aGNC;JT9Q=0!JJ2x>!D(`yDX(cw@ZI4u#{J}5G+tKH9%b^$hv;BtxVa%|3j3i23qX8NS3j3^P6 zATPt`?I5X|SOz z5W6rGUA-_rgNrc;0Rsf+aUjFV2&86CDMVYWI8C5j{ jgOMs!3ZejwTvm&&9>`DiMmHZ~V?hXmq9hjeLtY2~%}Z{J literal 0 HcmV?d00001 diff --git a/movielib/admin/img/link.png b/movielib/admin/img/link.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2cdd7656666ac5c8b584951346f68653fc0364 GIT binary patch literal 3144 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 literal 0 HcmV?d00001 diff --git a/movielib/config.php b/movielib/config.php new file mode 100644 index 0000000..b6ec00c --- /dev/null +++ b/movielib/config.php @@ -0,0 +1,482 @@ + 0, + 640 => 480, + 768 => 576, + 1280 => 720, + 1920 => 1080, + 3000 => 4096 +); + +// Video codec +$vtype_assoc['3ivx'] = array('3ivx', '3iv2', '3ivd'); +$vtype_assoc['avc'] = array('avc', 'avc1'); +$vtype_assoc['divx'] = array('divx', 'div1', 'div2', 'div3', 'div4', 'div5', 'div6'); +$vtype_assoc['flv'] = array('flv'); +$vtype_assoc['h264'] = array('h264', 'x264'); +$vtype_assoc['mp4'] = array('mp4'); +$vtype_assoc['mpeg'] = array('mpeg', 'pim1'); +$vtype_assoc['mpeg2'] = array('mpeg2', 'em2v', 'lmp2', 'mmes', 'mpeg-2'); +$vtype_assoc['mpeg4'] = array('mpeg4', 'dm4v', 'dx50', 'geox', 'm4s2', 'mpeg-4', 'nds', 'ndx', 'pvmm'); +$vtype_assoc['qt'] = array('qt', '8bps', 'advj', 'avrn', 'rle', 'rpza', 'smc', 'sv10', 'svq', 'zygo'); +$vtype_assoc['wmv'] = array('wmv', 'wma'); +$vtype_assoc['xvid'] = array('xvid', 'xvix'); +$vtype_assoc['hevc'] = array('h265', 'x265'); + +// Audio codec +$atype_assoc['aac'] = array('aac'); +$atype_assoc['ac3'] = array('ac3'); +$atype_assoc['aif'] = array('aif', 'aifc', 'aiff'); +$atype_assoc['dd'] = array('dd', 'dtshd', 'dtsma', 'dtshr'); +$atype_assoc['dts'] = array('dts', 'dca'); +$atype_assoc['flac'] = array('flac'); +$atype_assoc['mp3'] = array('mp3', 'mp2', 'mp1'); +$atype_assoc['ogg'] = array('ogg', 'a_vorbis', 'vorbis'); +$atype_assoc['truehd'] = array('truehd'); +$atype_assoc['wma'] = array('wma', 'wmav2', 'wmahd', 'wmapro'); + +// Audio channel +$achan_assoc = array( + '1' => '1', + '2' => '2', + '6' => '6', + '8' => '8' +); + +// Language +$langs = array( + 'bg' => 'Bulgarian', + 'cs' => 'Czech', + 'da' => 'Danish', + 'de' => 'German', + 'en' => 'English', + 'es' => 'Spanish', + 'fr' => 'French', + 'hu' => 'Hungarian', + 'it' => 'Italian', + 'nl' => 'Dutch', + 'no' => 'Norwegian', + 'pl' => 'Polish', + 'pt' => 'Portuguese', + 'ru' => 'Russian', + 'hr' => 'Croatian', + 'sk' => 'Slovak', + 'sr' => 'Serbian' +); + +// MimeType +$mimetype_assoc['video/mp4'] = array('mp4'); +$mimetype_assoc['video/ogg'] = array('ogg', 'ogv'); +$mimetype_assoc['video/webm'] = array('webm'); +$mimetype_assoc['video/flv'] = array('flv'); + +// tables +$mysql_tables['movies'] = array( + 'id' => 'int(6) NOT NULL PRIMARY KEY', + 'title' => 'varchar(100) DEFAULT ""', + 'plot' => 'varchar(5000) DEFAULT ""', + 'rating' => 'float DEFAULT NULL', + 'trailer' => 'varchar(255) DEFAULT ""', + 'runtime' => 'int(4) DEFAULT NULL', + 'originaltitle' => 'varchar(255) DEFAULT ""', + 'year' => 'int(4) DEFAULT NULL', + 'set' => 'varchar(255) DEFAULT ""', + 'file' => 'varchar(255) DEFAULT ""', + 'imdbid' => 'varchar(12) DEFAULT ""', + 'play_count' => 'int(10) DEFAULT 0', + 'last_played' => 'varchar(20) DEFAULT ""', + 'date_added' => 'varchar(20) DEFAULT ""', + 'hide' => 'int(1) DEFAULT 0', + 'hash' => 'varchar(32) DEFAULT ""' +); +$mysql_tables['tvshows'] = array( + 'id' => 'int(6) NOT NULL PRIMARY KEY', + 'title' => 'varchar(100) DEFAULT ""', + 'plot' => 'varchar(5000) DEFAULT ""', + 'rating' => 'float DEFAULT NULL', + 'originaltitle' => 'varchar(255) DEFAULT ""', + 'premiered' => 'varchar(20) DEFAULT ""', + 'play_count' => 'int(10) DEFAULT 0', + 'last_played' => 'varchar(20) DEFAULT ""', + 'date_added' => 'varchar(20) DEFAULT ""', + 'hide' => 'int(1) DEFAULT 0', + 'hash' => 'varchar(32) DEFAULT ""' +); +$mysql_tables['episodes'] = array( + 'id' => 'int(6) NOT NULL PRIMARY KEY', + 'title' => 'varchar(100) DEFAULT ""', + 'plot' => 'varchar(5000) DEFAULT ""', + 'episode' => 'int(6) NOT NULL', + 'season' => 'int(6) NOT NULL', + 'tvshow' => 'int(6) NOT NULL', + 'firstaired' => 'varchar(20) DEFAULT ""', + 'file' => 'varchar(255) DEFAULT ""', + 'play_count' => 'int(10) DEFAULT 0', + 'last_played' => 'varchar(20) DEFAULT ""', + 'date_added' => 'varchar(20) DEFAULT ""', + 'hash' => 'varchar(32) DEFAULT ""' +); +$mysql_tables['actor'] = array( + 'id' => 'int(6) NOT NULL AUTO_INCREMENT PRIMARY KEY', + 'actor' => 'varchar(255) NOT NULL' +); +$mysql_tables['movies_actor'] = array( + 'id' => 'int(6) NOT NULL', + 'actorid' => 'int(6) NOT NULL', + 'order' => 'int(2) NOT NULL' +); +$mysql_tables['tvshows_actor'] = array( + 'id' => 'int(6) NOT NULL', + 'actorid' => 'int(6) NOT NULL', + 'order' => 'int(2) NOT NULL' +); +$mysql_tables['genre'] = array( + 'id' => 'int(6) NOT NULL AUTO_INCREMENT PRIMARY KEY', + 'genre' => 'varchar(255) NOT NULL' +); +$mysql_tables['movies_genre'] = array( + 'id' => 'int(6) NOT NULL', + 'genreid' => 'int(6) NOT NULL' +); +$mysql_tables['tvshows_genre'] = array( + 'id' => 'int(6) NOT NULL', + 'genreid' => 'int(6) NOT NULL' +); +$mysql_tables['country'] = array( + 'id' => 'int(6) NOT NULL AUTO_INCREMENT PRIMARY KEY', + 'country' => 'varchar(255) NOT NULL' +); +$mysql_tables['movies_country'] = array( + 'id' => 'int(6) NOT NULL', + 'countryid' => 'int(6) NOT NULL' +); +$mysql_tables['studio'] = array( + 'id' => 'int(6) NOT NULL AUTO_INCREMENT PRIMARY KEY', + 'studio' => 'varchar(255) NOT NULL' +); +$mysql_tables['movies_studio'] = array( + 'id' => 'int(6) NOT NULL', + 'studioid' => 'int(6) NOT NULL' +); +$mysql_tables['director'] = array( + 'id' => 'int(6) NOT NULL AUTO_INCREMENT PRIMARY KEY', + 'director' => 'varchar(255) NOT NULL' +); +$mysql_tables['movies_director'] = array( + 'id' => 'int(6) NOT NULL', + 'directorid' => 'int(6) NOT NULL' +); +$mysql_tables['movies_stream'] = array( + 'id' => 'int(6) NOT NULL', + 'type' => 'varchar(1) NOT NULL', + 'v_codec' => 'varchar(255)', + 'v_aspect' => 'varchar(15)', + 'v_width' => 'int(11)', + 'v_height' => 'int(11)', + 'v_duration' => 'int(11)', + 'a_codec' => 'varchar(255)', + 'a_chan' => 'int(11)', + 'a_lang' => 'varchar(10)', + 's_lang' => 'varchar(10)' +); +$mysql_tables['episodes_stream'] = array( + 'id' => 'int(6) NOT NULL', + 'type' => 'varchar(1) NOT NULL', + 'v_codec' => 'varchar(255)', + 'v_aspect' => 'varchar(15)', + 'v_width' => 'int(11)', + 'v_height' => 'int(11)', + 'v_duration' => 'int(11)', + 'a_codec' => 'varchar(255)', + 'a_chan' => 'int(11)', + 'a_lang' => 'varchar(10)', + 's_lang' => 'varchar(10)' +); +$mysql_tables['config'] = array( + 'site_name' => 'varchar(30) DEFAULT "MovieLib"', + 'language' => 'varchar(2) DEFAULT "en"', + 'theme' => 'varchar(15) DEFAULT "default"', + 'select_media_header' => 'int(1) DEFAULT 0', + 'view' => 'int(1) DEFAULT 0', + 'per_page' => 'int(5) DEFAULT 50', + 'default_sort' => 'int(1) DEFAULT 1', + 'default_watch' => 'int(1) DEFAULT 0', + 'panel_top_limit' => 'int(5) DEFAULT 10', + 'panel_top_time' => 'int(5) DEFAULT 5', + 'panel_top' => 'int(1) DEFAULT 1', + 'panel_view' => 'int(1) DEFAULT 1', + 'watched_status' => 'int(1) DEFAULT 1', + 'show_playcount' => 'int(1) DEFAULT 1', + 'live_search' => 'int(1) DEFAULT 1', + 'live_search_max_res' => 'int(4) DEFAULT 10', + 'panel_overall' => 'int(1) DEFAULT 1', + 'panel_genre' => 'int(1) DEFAULT 1', + 'panel_year' => 'int(1) DEFAULT 1', + 'panel_country' => 'int(1) DEFAULT 1', + 'panel_set' => 'int(1) DEFAULT 1', + 'panel_studio' => 'int(1) DEFAULT 1', + 'show_fanart' => 'int(1) DEFAULT 1', + 'fadeout_fanart' => 'int(1) DEFAULT 0', + 'show_trailer' => 'int(1) DEFAULT 1', + 'show_facebook' => 'int(1) DEFAULT 1', + 'banner' => 'varchar(200) DEFAULT 0', + 'protect_site' => 'int(1) DEFAULT 0', + 'mod_rewrite' => 'int(1) DEFAULT 0', + 'token' => 'varchar(6) DEFAULT ""', + 'xbmc_thumbs' => 'int(1) DEFAULT 1', + 'xbmc_posters' => 'int(1) DEFAULT 1', + 'xbmc_fanarts' => 'int(1) DEFAULT 1', + 'xbmc_exthumbs' => 'int(1) DEFAULT 1', + 'xbmc_exthumbs_q' => 'varchar(10) DEFAULT "853x480"', + 'xbmc_auto_conf_remote' => 'int(1) DEFAULT 0', + 'xbmc_master' => 'int(1) DEFAULT 0', + 'xbmc_host' => 'varchar(30) DEFAULT ""', + 'xbmc_port' => 'varchar(5) DEFAULT ""', + 'xbmc_login' => 'varchar(30) DEFAULT ""', + 'xbmc_pass' => 'varchar(30) DEFAULT ""', + 'version' => 'varchar(6) DEFAULT "' . $version . '"' +); +$mysql_tables['users'] = array( + 'id' => 'int(2) NOT NULL PRIMARY KEY', + 'login' => 'varchar(5) DEFAULT NULL', + 'password' => 'varchar(32) DEFAULT NULL' +); +$mysql_tables['hash'] = array( + 'movies' => 'varchar(32) DEFAULT ""', + 'tvshows' => 'varchar(32) DEFAULT ""', + 'episodes' => 'varchar(32) DEFAULT ""', + 'images' => 'varchar(32) DEFAULT ""' +); + +// indexes +$mysql_indexes['actor'] = array('ix_actor'); +$mysql_indexes['country'] = array('ix_country'); +$mysql_indexes['director'] = array('ix_director'); +$mysql_indexes['genre'] = array('ix_genre'); +$mysql_indexes['studio'] = array('ix_studio'); + +$mysql_indexes['movies'] = array('ix_title', 'ix_rating', 'ix_runtime', 'ix_originaltitle', 'ix_year', 'ix_set', 'ix_play_count', 'ix_last_played', 'ix_date_added', 'ix_hide'); +$mysql_indexes['movies_actor'] = array('ix_id', 'ix_actorid', 'ix_order'); +$mysql_indexes['movies_country'] = array('ix_id', 'ix_countryid'); +$mysql_indexes['movies_director'] = array('ix_id', 'ix_directorid'); +$mysql_indexes['movies_genre'] = array('ix_id', 'ix_genreid'); +$mysql_indexes['movies_studio'] = array('ix_id', 'ix_studioid'); +$mysql_indexes['movies_stream'] = array('ix_id'); + +$mysql_indexes['tvshows'] = array('ix_title', 'ix_rating', 'ix_originaltitle', 'ix_premiered', 'ix_play_count', 'ix_last_played', 'ix_date_added', 'ix_hide'); +$mysql_indexes['tvshows_actor'] = array('ix_id', 'ix_actorid', 'ix_order'); +$mysql_indexes['tvshows_genre'] = array('ix_id', 'ix_genreid'); + +$mysql_indexes['episodes'] = array('ix_season', 'ix_tvshow'); +$mysql_indexes['episodes_stream'] = array('ix_id'); + +// views +$views = array('view_default', 'view_list', 'view_sposter', 'view_bposter'); + +//outputs +$item = array( + 'select_media', + 'view', + 'include_view', + 'sort', + 'watch', + 'url_delete_filter', + 'meta_title', + 'meta_img', + 'meta_url', + 'meta_desc', + 'meta_type', + 'facebook', + 'version', + 'panel_top', + 'panel_top_last_added', + 'panel_top_most_watched', + 'panel_top_last_played', + 'panel_top_top_rated', + 'overall_all', + 'overall_watched', + 'overall_unwatched', + 'panel_remote', + 'panel_genre', + 'panel_year', + 'panel_country', + 'panel_set', + 'panel_studio', + 'panel_live_search', + 'panel_sort', + 'panel_view', + 'panel_watch', + 'panel_nav', + 'panel_filter' +); +$item_desc = array( + 'mysql_table', + 'id', + 'video', + 'view', + 'include_view', + 'sort', + 'title', + 'originaltitle', + 'url_title', + 'file', + 'xbmc', + 'xbmc_episode', + 'watched_img', + 'playcount_img', + 'genre', + 'rating', + 'rating_star', + 'imdb_url', + 'actor', + 'plot', + 'year', + 'country', + 'runtime', + 'director', + 'set', + 'studio', + 'studio_art', + 'ribbon_new', + 'img_flag_v', + 'img_flag_a', + 'img_flag_s', + 'facebook_button', + 'extra_thumbs', + 'trailer_img', + 'trailer', + 'premiered', + 'seasons', + 'episodes', + 'episodes_plot', + 'fb_url' +); +$item_episode = array( + 'episode', + 'season', + 'season_title', + 'thumbnail', + 'file', + 'xbmc', + 'plot', + 'aired', + 'img_flag_v', + 'img_flag_a', + 'img_flag_s', + 'watched_img', + 'ribbon_new' +); + +// array for language audio and subs +$iso_lang = array( + 'ces' => array('ces', 'cze', 'czech'), + 'dan' => array('dan', 'danish'), + 'deu' => array('deu', 'ger', 'german', 'deutch'), + 'dut' => array('dut', 'nld', 'dutch'), + 'egy' => array('egy', 'egyptian'), + 'ell' => array('ell', 'gre', 'greek'), + 'eng' => array('eng', 'english'), + 'est' => array('est', 'estonian'), + 'fin' => array('fin', 'finnish'), + 'fra' => array('fra', 'fre', 'french'), + 'gle' => array('gle', 'irish'), + 'heb' => array('heb', 'hebrew'), + 'hun' => array('hun', 'hungarian'), + 'ind' => array('ind', 'indonesian'), + 'ira' => array('ira', 'iranian'), + 'isl' => array('isl', 'ice', 'icelandic'), + 'ita' => array('ita', 'italian'), + 'jpn' => array('jpn', 'japanese'), + 'kat' => array('kat', 'geo', 'georgian'), + 'khm' => array('khm', 'khmer'), + 'kor' => array('kor', 'korean'), + 'mlt' => array('mlt', 'maltese'), + 'mol' => array('mol'), + 'mon' => array('mon', 'mongolian'), + 'nep' => array('nep', 'nepali'), + 'nno' => array('nno', 'norwegian'), + 'pol' => array('pol', 'polish'), + 'por' => array('por', 'portuguese'), + 'ron' => array('ron', 'rum', 'romanian'), + 'rus' => array('rus', 'russian'), + 'slk' => array('slk', 'slo', 'slovak'), + 'slv' => array('slv', 'slovenian'), + 'spa' => array('spa', 'spanish'), + 'srp' => array('srp', 'serbian'), + 'swe' => array('swe', 'swedish'), + 'tur' => array('tur', 'turkish'), + 'ukr' => array('ukr', 'ukrainian'), + 'zho' => array('zho', 'chi', 'chinese') +); + +// array for language facebook buttons +$lang_fb_assoc = array( + 'sq' => 'sq_AL', + 'bg' => 'bg_BG', + 'cs' => 'cs_CZ', + 'da' => 'da_DK', + 'nl' => 'nl_NL', + 'en' => 'en_GB', + 'en' => 'en_US', + 'et' => 'et_EE', + 'fr' => 'fr_FR', + 'de' => 'de_DE', + 'el' => 'el_GR', + 'hu' => 'hu_HU', + 'it' => 'it_IT', + 'nb' => 'nb_NO', + 'pl' => 'pl_PL', + 'pt' => 'pt_PT', + 'ro' => 'ro_RO', + 'ru' => 'ru_RU', + 'sk' => 'sk_SK', + 'sl' => 'sl_SI', + 'es' => 'es_LA', + 'uk' => 'uk_UA' +); + +// JSON function +$json_f = array( + 'play' => array('p' => '', 'm' => 'Player.Open'), + 'stop' => array('p' => '"playerid": 1', 'm' => 'Player.Stop'), + 'pause' => array('p' => '"playerid": 1', 'm' => 'Player.PlayPause'), + 'v_up' => array('p' => '"action": "volumeup"', 'm' => 'Input.ExecuteAction'), + 'v_down' => array('p' => '"action": "volumedown"', 'm' => 'Input.ExecuteAction'), + 'playing' => array('p' => '"playerid": 1', 'm' => 'Player.GetItem') +); + +// Set var +$var = array( + 'id' => 0, + 'search' => '', + 'page' => 1, + 'token' => '', + 'option' => '', + 'filter' => '', + 'filterid' => '', + 'fb_link' => '' + ); +foreach ($var as $key => $val) { + if (isset($_GET[$key])) { + $$key = $_GET[$key]; + } else { + $$key = $val; + } +} + +?> \ No newline at end of file diff --git a/movielib/files.md5 b/movielib/files.md5 new file mode 100644 index 0000000..9fd425b --- /dev/null +++ b/movielib/files.md5 @@ -0,0 +1 @@ +admin.php:a08251fe59c1a6ec3e23d8c770642dc7;config.php:31e094f8c836d82ec2cb9516de141be2;function.js.php:3b55a87df8f482825fc93880a9ef4cd6;function.php:4d24cbbf9e91f0c5b837c013fc9ceba0;index.php:9a84dbe80d1bad4129601031d747acc2;login.php:a075317bff5dd423526595dd5997f2a2;sync.php:3d3ed8a0023587aa1bbc8e95ad1427f1;js/jquery-1.9.1.js:08c235d357750c657ac1db7d1cf656a9;js/jquery.cycle.lite.js:2ab8505038a95e0e5a913c65c163898c;js/jquery.script.js:366d6d350a1ef52b256f733fcf39f218;js/video.js:e7d1334eab76e6022f929b50f83e95d6 \ No newline at end of file diff --git a/movielib/function.js.php b/movielib/function.js.php new file mode 100644 index 0000000..da885ff --- /dev/null +++ b/movielib/function.js.php @@ -0,0 +1,410 @@ + (isset($setting['show_fanart']) ? $setting['show_fanart'] : ''), + 'fadeout_fanart' => (isset($setting['fadeout_fanart']) ? $setting['fadeout_fanart'] : ''), + 'panel_top_time' => (isset($setting['panel_top_time']) ? $setting['panel_top_time'] : ''), + 'theme' => (isset($setting['theme']) ? $setting['theme'] : '') + ); + echo json_encode($set_js); +} + +// save panel status +if ($option == 'panel') { + echo $_GET['id'] . ' - ' . $_GET['opt']; + $_SESSION[$_GET['id']] = $_GET['opt']; + $setting[$_GET['id']] = $_GET['opt']; +} + +// live search +if ($option == 'search') { + include('function.php'); + connect($mysql_ml); + $setting = get_settings(); + $output = ''; + + function search($table, $search_sql, $search_array, $a_href, $setting) { + $output = ''; + $search_res = mysql_q($search_sql); + if (mysql_num_rows($search_res) > 0) { + while($searched = mysql_fetch_assoc($search_res)) { + // thumb + if ($table == 'movies' or $table == 'tvshows') { + if (file_exists('cache/' . $table . '_' . $searched['id'] . '.jpg')) { + $searched['thumb'] = 'cache/' . $table . '_' . $searched['id'] . '.jpg'; + } else { + $searched['thumb'] = 'templates/' . $setting['theme'] . '/img/d_poster.jpg'; + } + } + if ($table == 'actor') { + if (file_exists('cache/actors/' . substr(md5($searched['actor']), 0, 10) . '.jpg')) { + $searched['thumb'] = 'cache/actors/' . substr(md5($searched['actor']), 0, 10) . '.jpg'; + } else { + $searched['thumb'] = 'templates/' . $setting['theme'] . '/img/d_actor.jpg'; + } + $searched['title'] = $searched['actor']; + } + // panels + foreach ($search_array as $val) { + $sel_sql = 'SELECT ' . $val . '.' . $val . ' FROM ' . $val . ', ' . $table . '_' . $val . ' WHERE ' . $val . '.id = ' . $table . '_' . $val . '.' . $val . 'id AND ' . $table . '_' . $val . '.id = "' . $searched['id'] . '"'; + $sel_res = mysql_q($sel_sql); + $out = array(); + while ($s = mysql_fetch_row($sel_res)) { + $out[] = $s[0]; + } + $searched[$val] = implode(' / ', $out); + } + $output.= ' + + + '; + } + } + return $output; + } + + if ($_GET['video'] == 'search_movies') { + $table = 'movies'; + $search_sql = 'SELECT id, title, rating, year, runtime, originaltitle, hide FROM ' . $table . ' WHERE (title LIKE "%' . $_GET['search'] . '%" OR originaltitle LIKE "%' . $_GET['search'] . '%") AND hide=0 LIMIT 0, ' . $setting['live_search_max_res']; + $search_array = array('director', 'genre', 'country'); + $a_href = 'index.php?video=' . $table . '&id='; + $output.= search($table, $search_sql, $search_array, $a_href, $setting); + } + if ($_GET['video'] == 'search_tvshows') { + $table = 'tvshows'; + $search_sql = 'SELECT id, title, rating, originaltitle, hide FROM ' . $table . ' WHERE (title LIKE "%' . $_GET['search'] . '%" OR originaltitle LIKE "%' . $_GET['search'] . '%") AND hide=0 LIMIT 0, ' . $setting['live_search_max_res']; + $search_array = array('genre'); + $a_href = 'index.php?video=' . $table . '&id='; + $output.= search($table, $search_sql, $search_array, $a_href, $setting); + } + + $table = 'actor'; + $search_sql = 'SELECT id, actor FROM ' . $table . ' WHERE actor LIKE "%' . $_GET['search'] . '%" LIMIT 0, ' . $setting['live_search_max_res']; + $search_array = array(); + $a_href = 'index.php?video=' . ($_GET['video'] == 'search_movies' ? 'movies' : 'tvshows') . '&filter=actor&filterid='; + $output.= search($table, $search_sql, $search_array, $a_href, $setting); + + echo $output; +} + +// remote control +if ($option == 'remote') { + // admin permission + if (!isset($_SESSION['logged_admin']) or $_SESSION['logged_admin'] !== true) { + die('no permission'); + } + include('function.php'); + $setting = get_settings(); + + $time_assoc['http'] = array('timeout' => 3); + $timeout = stream_context_create($time_assoc); + + switch ($_GET['f']) { + case 'list': + file_put_contents('cache/list.m3u', $_GET['file']); + break; + case 'play': + if ($_GET['video'] == 'tvshows') { + $video = 'episodeid'; + } else { + $video = 'movieid'; + } + $json = urlencode('{"jsonrpc": "2.0", "params": {"item": {"' . $video . '": ' . $_GET['id'] . '}}, "method": "Player.Open", "id": 1}'); + break; + case 'stepforward': // stepforward + case '190': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "stepforward"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'stepback': // stepback + case '188': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "stepback"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'bigstepforward': // bigstepforward + case '221': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "bigstepforward"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'bigstepback': // bigstepback + case '219': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "bigstepback"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'v_up': // volume up + case '61': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "volumeup"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'v_down': // volume down + case '173': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "volumedown"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'mute': // volume mute + case '48': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "mute"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'stop': // stop + case '88': + $json = urlencode('{"jsonrpc": "2.0", "params": {"playerid": 1}, "method": "Player.Stop", "id": 1}'); + break; + case 'pause': // pause + case '32': + $json = urlencode('{"jsonrpc": "2.0", "params": {"playerid": 1}, "method": "Player.PlayPause", "id": 1}'); + break; + case 'right': // right + case '39': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.Right", "id": 1}'); + break; + case 'left': // left + case '37': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.Left", "id": 1}'); + break; + case 'up': // up + case '38': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.Up", "id": 1}'); + break; + case 'down': // down + case '40': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.Down", "id": 1}'); + break; + case 'watch': // watched + case '87': + $json = urlencode('{"jsonrpc": "2.0", "params": {"action": "togglewatched"}, "method": "Input.ExecuteAction", "id": 1}'); + break; + case 'info': // info + case '73': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.Info", "id": 1}'); + break; + case 'select': // select + case '13': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.Select", "id": 1}'); + break; + case 'back': // back + case '8': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.Back", "id": 1}'); + break; + case 'context': // context menu + case '67': + $json = urlencode('{"jsonrpc": "2.0", "method": "Input.ContextMenu", "id": 1}'); + break; + case 'power': // shutdown menu + case '83': + $json = urlencode('{"jsonrpc": "2.0", "params": {"window":"shutdownmenu"}, "method": "GUI.ActivateWindow", "id": 1}'); + break; + case 'sync': // sync + case '82': + $json = urlencode('{"jsonrpc": "2.0", "params": {"addonid":"script.movielib"}, "method": "Addons.ExecuteAddon", "id": 1}'); + break; + + case 'playing': + // get player status + $json_player = urlencode('{"jsonrpc": "2.0", "params": {"playerid": 1}, "method": "Player.GetItem", "id": 1}'); + $get_player = @file_get_contents('http://' . $setting['xbmc_login'] . ':' . $setting['xbmc_pass'] . '@' . $setting['xbmc_host'] . ':' . $setting['xbmc_port'] . '/jsonrpc?request=' . $json_player, false, $timeout); + $player = json_decode($get_player, true); + if (isset($player['result'])) { + $json_player_status = urlencode('{"jsonrpc": "2.0", "params": {"playerid": 1, "properties": ["percentage", "time", "totaltime"]}, "method": "Player.GetProperties", "id": 1}'); + $get_player_status = @file_get_contents('http://' . $setting['xbmc_login'] . ':' . $setting['xbmc_pass'] . '@' . $setting['xbmc_host'] . ':' . $setting['xbmc_port'] . '/jsonrpc?request=' . $json_player_status, false, $timeout); + $player_status = json_decode($get_player_status, true); + $item = array_merge($player['result']['item'], $player_status['result']); + connect($mysql_ml); + include('lang/' . $setting['language'] . '/lang.php'); + if ($item['type'] == 'episode') { + // get episode + $episode_sql = 'SELECT tvshow, season, episode, title, plot FROM episodes WHERE id = "' . $item['id'] . '"'; + $episode_result = mysql_q($episode_sql); + $episode = mysql_fetch_assoc($episode_result); + // get tvshow + $tvshow_sql = 'SELECT title, rating FROM tvshows WHERE id = "' . $episode['tvshow'] . '"'; + $tvshow_result = mysql_q($tvshow_sql); + $tvshow = mysql_fetch_assoc($tvshow_result); + // get panels + $search_array = array('genre'); + foreach ($search_array as $val) { + $sel_sql = 'SELECT ' . $val . '.' . $val . ' FROM ' . $val . ', tvshows_' . $val . ' WHERE ' . $val . '.id = tvshows_' . $val . '.' . $val . 'id AND tvshows_' . $val . '.id = "' . $item['id'] . '"'; + $sel_res = mysql_q($sel_sql); + $out = array(); + while ($s = mysql_fetch_row($sel_res)) { + $out[] = $s[0]; + } + $tvshow[$val] = implode(' / ', $out); + } + $item['type'] = 'tvshows'; + $item['id'] = $episode['tvshow']; + $item['details'] = ' +
' . $tvshow['title'] . '
+
' . zero($episode['season']) . 'x' . zero($episode['episode']) . ' ' . $episode['title'] . '
+
+
' . zero($item['time']['hours']) . ':' . zero($item['time']['minutes']) . ':' . zero($item['time']['seconds']) . ' / ' . zero($item['totaltime']['hours']) . ':' . zero($item['totaltime']['minutes']) . ':' . zero($item['totaltime']['seconds']) . '
+ ' . (file_exists('cache/tvshows_' . $item['id'] . '.jpg') ? '' : '') . ' +
+
' . $lang['i_season'] . ': ' . $episode['season'] . '
+
' . $lang['i_episode'] . ': ' . $episode['episode'] . '
+
' . $lang['i_rating'] . ': ' . $tvshow['rating'] . '
+
' . $lang['i_genre'] . ': ' . $tvshow['genre'] . '
+
' . $lang['i_plot'] . ': ' . $episode['plot'] . '
+
'; + } else if($item['type'] == 'movie') { + // get movie + $movie_sql = 'SELECT `title`, `originaltitle`, `rating`, `runtime`, `plot`, `set`, `year` FROM movies WHERE id = "' . $item['id'] . '"'; + $movie_result = mysql_q($movie_sql); + $movie = mysql_fetch_assoc($movie_result); + // get panels + $search_array = array('genre', 'country', 'director', 'studio'); + foreach ($search_array as $val) { + $sel_sql = 'SELECT ' . $val . '.' . $val . ' FROM ' . $val . ', movies_' . $val . ' WHERE ' . $val . '.id = movies_' . $val . '.' . $val . 'id AND movies_' . $val . '.id = "' . $item['id'] . '"'; + $sel_res = mysql_q($sel_sql); + $out = array(); + while ($s = mysql_fetch_row($sel_res)) { + $out[] = $s[0]; + } + $movie[$val] = implode(' / ', $out); + } + $item['type'] = 'movies'; + $item['details'] = ' +
' . $movie['title'] . '
+
' . $movie['originaltitle'] . '
+
+
' . zero($item['time']['hours']) . ':' . zero($item['time']['minutes']) . ':' . zero($item['time']['seconds']) . ' / ' . zero($item['totaltime']['hours']) . ':' . zero($item['totaltime']['minutes']) . ':' . zero($item['totaltime']['seconds']) . '
+ ' . (file_exists('cache/movies_' . $item['id'] . '.jpg') ? '' : '') . ' +
' + . ($movie['year'] == '' ? '' : '
' . $lang['i_year'] . ': ' . $movie['year'] . '
') + . ($movie['rating'] == '' ? '' : '
' . $lang['i_rating'] . ': ' . $movie['rating'] . '
') + . ($movie['runtime'] == '' ? '' : '
' . $lang['i_runtime'] . ': ' . $movie['runtime'] . ' ' . $lang['i_minute'] . '
') + . ($movie['genre'] == '' ? '' : '
' . $lang['i_genre'] . ': ' . $movie['genre'] . '
') + . ($movie['country'] == '' ? '' : '
' . $lang['i_country'] . ': ' . $movie['country'] . '
') + . ($movie['director'] == '' ? '' : '
' . $lang['i_director'] . ': ' . $movie['director'] . '
') + . ($movie['set'] == '' ? '' : '
' . $lang['i_set'] . ': ' . $movie['set'] . '
') + . ($movie['studio'] == '' ? '' : '
' . $lang['i_studio'] . ': ' . $movie['studio'] . '
') + . ($movie['plot'] == '' ? '' : '
' . $lang['i_plot'] . ': ' . $movie['plot'] . '
') . ' +
'; + } else { + $item['details'] = ' +
' . $item['label'] . '
+
+
' . zero($item['time']['hours']) . ':' . zero($item['time']['minutes']) . ':' . zero($item['time']['seconds']) . ' / ' . zero($item['totaltime']['hours']) . ':' . zero($item['totaltime']['minutes']) . ':' . zero($item['totaltime']['seconds']) . '
+ '; + + } + echo json_encode($item); + } else { + echo '{"stop": "stop"}'; + } + break; + case 'check': + $json = urlencode('{"jsonrpc": "2.0", "params": {"labels": ["System.BuildVersion"]}, "method": "XBMC.GetInfoLabels", "id": 1}'); + break; + case 'xbmc_test': + $json_test = urlencode('{"jsonrpc": "2.0", "params": {"labels": ["System.BuildVersion"]}, "method": "XBMC.GetInfoLabels", "id": 1}'); + $get_test = @file_get_contents('http://' . $_GET['xbmc_login'] . ':' . $_GET['xbmc_pass'] . '@' . $_GET['xbmc_host'] . ':' . $_GET['xbmc_port'] . '/jsonrpc?request=' . $json_test, false, $timeout); + if (!$get_test) { + echo '{"error": "error"}'; + } else { + echo $get_test; + } + break; + } + if (isset($json)) { + $get = @file_get_contents('http://' . $setting['xbmc_login'] . ':' . $setting['xbmc_pass'] . '@' . $setting['xbmc_host'] . ':' . $setting['xbmc_port'] . '/jsonrpc?request=' . $json, false, $timeout); + if (!$get) { + echo '{"error": "error"}'; + } else { + echo $get; + } + } +} + +// delete movie or tvshow +if ($option == 'deletemovie' or $option == 'deletetvshow') { + // admin permission + if (!isset($_SESSION['logged_admin']) or $_SESSION['logged_admin'] !== true) { + die('no permission'); + } + include('function.php'); + connect($mysql_ml); + if ($option == 'deletemovie') { + sync_delete(array($_GET['id']), 'movies'); + } else { + $episodes_sql = 'SELECT id FROM episodes WHERE tvshow = "' . $_GET['id'] . '"'; + $episodes_res = mysql_q($episodes_sql); + $episodes_id = array(); + while ($epi = mysql_fetch_assoc($episodes_res)) { + $episodes_id[] = $epi['id']; + } + sync_delete(array($_GET['id']), 'tvshows'); + sync_delete($episodes_id, 'episodes'); + } +} + +// delete img +if ($option == 'deleteposter' or $option == 'deletefanart') { + // admin permission + if (!isset($_SESSION['logged_admin']) or $_SESSION['logged_admin'] !== true) { + die('no permission'); + } + include('function.php'); + connect($mysql_ml); + $filename = $_GET['video'] . '_' . $_GET['id'] . ($option == 'deletefanart' ? '_f' : '') . '.jpg'; + remove_images(array($filename)); +} + +// hide movie or tvshow +if ($option == 'hidemovie' or $option == 'hidetvshow' or $option == 'visiblemovie' or $option == 'visibletvshow') { + // admin permission + if (!isset($_SESSION['logged_admin']) or $_SESSION['logged_admin'] !== true) { + die('no permission'); + } + include('function.php'); + $id = $_GET['id']; + if($option == 'hidemovie' or $option == 'hidetvshow') { + $hide = 1; + } else { + $hide = 0; + } + if($option == 'hidemovie' or $option == 'visiblemovie') { + $table = 'movies'; + } else { + $table = 'tvshows'; + } + connect($mysql_ml); + $hide_sql = 'UPDATE `' . $table . '` SET hide = ' . $hide . ' WHERE id = "' . $id . '"'; + mysql_q($hide_sql); +} + +// banner +if ($option == 'banner') { + // admin permission + if (!isset($_SESSION['logged_admin']) or $_SESSION['logged_admin'] !== true) { + die('no permission'); + } + include('function.php'); + connect($mysql_ml); + $setting = get_settings(); + include('lang/' . $setting['language'] . '/lang.php'); + $b = create_banner($lang, 'banner_v.jpg', $_GET['banner']); +} + +// fanart exist +if ($option == 'fexist') { + if (file_exists('cache/' . $_GET['id'] . '_f.jpg')) { + echo '{"fexist": "exist"}'; + } else { + echo '{"fexist": "notexist"}'; + } +} + +?> \ No newline at end of file diff --git a/movielib/function.php b/movielib/function.php new file mode 100644 index 0000000..02c50a6 --- /dev/null +++ b/movielib/function.php @@ -0,0 +1,780 @@ +file = 'templates/' . $setting['theme'] . '/' . $file; + $this->set = $setting; + $this->lang = $lang; + $this->tpl = array(); + $this->show = array(); + } + function tpl($title, $val) { + $this->tpl[$title] = $val; + } + function show($title, $val) { + $this->show[$title] = $val; + } + function init() { + $cont = file_get_contents($this->file); + + foreach ($this->tpl as $key => $val) { + $cont = str_replace('{' . $key . '}', $val, $cont); + } + foreach ($this->lang as $key => $val) { + $cont = str_replace('{LANG.' . $key . '}', $val, $cont); + } + foreach ($this->set as $key => $val) { + $cont = str_replace('{SET.' . $key . '}', $val, $cont); + } + foreach ($this->show as $key => $val) { + if ($val == 0) { + $cont = preg_replace('|{SHOW\.' . $key . '}.*?{/SHOW\.' . $key . '}|s', '', $cont); + } + } + $cont = preg_replace('|{.?SHOW\.[^}]+}|s', '', $cont); + return $cont; + } +} + +/* ############# + * # FUNCTIONS # + */############# + +/* ############### + * # MYSQL query # + */############### + +function mysql_q($query) { + $time = microtime(true); + $result = mysql_query($query); + if (!$result) { + echo $query . '
'; + die ('ERROR: MySQL - ' . mysql_error()); + } else { + if (isset($_GET['debug'])) { + echo $query . ' - ' . (microtime(true) - $time) . '
'; + } + return $result; + } +} + +/* ######################## + * # Connect to databaase # + */######################## +function connect($mysql_ml) { + $conn_ml = @mysql_connect($mysql_ml[0] . ':' . $mysql_ml[1], $mysql_ml[2], $mysql_ml[3]); + if (!$conn_ml) { + die(mysql_error()); + } + $sel_ml = @mysql_select_db($mysql_ml[4]); + if (!$sel_ml) { + die(mysql_error()); + } + + // Sets utf8 connections + mysql_q('SET CHARACTER SET utf8'); + mysql_q('SET NAMES utf8'); +} + +/* ############################## + * # Get settings from database # + */############################## +function get_settings() { + + // if settings in session not exists get it from database + if (!isset($_SESSION) or count($_SESSION) < 10) { + $set_sql = 'SELECT * FROM `config`'; + $set_res = mysql_q($set_sql); + $get_set = mysql_fetch_assoc($set_res); + foreach($get_set as $key => $val) { + $_SESSION[$key] = $val; + } + } + return $_SESSION; +} + +/* ########################### + * # Create and check tables # + */########################### +function create_table($mysql_tables, $mysql_indexes, $lang, $version, $drop) { + + // drop tables + if ($drop == 1) { + foreach ($mysql_tables as $table => $table_val) { + $drop_table_sql = 'DROP TABLE IF EXISTS `' . $table . '`'; + $drop_table_res = mysql_q($drop_table_sql); + } + } + + $tables_array = array(); + $tables_sql = 'SHOW TABLES'; + $tables_result = mysql_q($tables_sql); + while ($tables_db = mysql_fetch_array($tables_result)) { + $tables_array[] = $tables_db[0]; + } + + // all tables + foreach ($mysql_tables as $table => $table_val) { + if (!in_array($table, $tables_array)) { + $create_sql_array = array(); + foreach($table_val as $key => $val) { + $create_sql_array[] = '`' . $key . '` ' . $val; + } + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $table . '` (' . implode(', ', $create_sql_array) . ') DEFAULT CHARSET=utf8'; + $create_res = mysql_q($create_sql); + } + } + // insert config + $sel = 'SELECT * FROM config'; + $res = mysql_q($sel); + if (mysql_num_rows($res) == 0) { + $insert_config_sql = 'INSERT INTO `config` () VALUES ()'; + $insert_config_res = mysql_q($insert_config_sql); + } + // insert users + $sel = 'SELECT * FROM users'; + $res = mysql_q($sel); + if (mysql_num_rows($res) == 0) { + $insert_users_sql = 'INSERT INTO `users` (`id`, `login`, `password`) VALUES (1, "admin", "21232f297a57a5a743894a0e4a801fc3"), (2, "user", "ee11cbb19052e40b07aac0ca060c23ee")'; + $insert_users_res = mysql_q($insert_users_sql); + } + // insert hash + $sel = 'SELECT * FROM hash'; + $res = mysql_q($sel); + if (mysql_num_rows($res) == 0) { + $insert_hash_sql = 'INSERT INTO `hash` () VALUES ()'; + $insert_hash_res = mysql_q ($insert_hash_sql); + } + // check columns + $columns_db_array = array(); + foreach ($mysql_tables as $table => $table_val) { + $columns_sql = 'SHOW COLUMNS FROM `' . $table . '`'; + $columns_result = mysql_q($columns_sql); + while($columns = mysql_fetch_assoc($columns_result)) { + $columns_db_array[$table][] = $columns['Field']; + } + } + foreach ($mysql_tables as $table => $tables_val) { + $alter = array(); + foreach($tables_val as $col_key => $col_type) { + if (!in_array($col_key, $columns_db_array[$table])) { + $alter[] = 'ADD `' . $col_key . '` ' . $col_type; + } else { + if ($col_key !== 'id') { + $alter[] = 'CHANGE `' . $col_key . '` `' . $col_key . '` ' . $col_type; + } + } + } + foreach ($columns_db_array[$table] as $col) { + if (!array_key_exists($col, $mysql_tables[$table])) { + $alter[] = 'DROP COLUMN `' . $col . '`'; + } + } + $alter_sql = 'ALTER TABLE `' . $table . '` ' . implode(', ', $alter); + mysql_q($alter_sql); + } + // check indexes + $index_db_array = array(); + foreach ($mysql_indexes as $table => $index_val) { + $index_sql = 'SHOW INDEX FROM `' . $table . '`'; + $index_res = mysql_q($index_sql); + while($index = mysql_fetch_assoc($index_res)) { + if ($index['Key_name'] !== 'PRIMARY') { + $index_db_array[$table][] = $index['Key_name']; + } + } + } + foreach ($mysql_indexes as $table => $index_val) { + if (in_array($table, array_keys($index_db_array))) { + foreach (array_unique($index_db_array[$table]) as $index) { + $alter_sql = 'DROP INDEX `' . $index . '` ON `' . $table . '`'; + mysql_q($alter_sql); + } + } + foreach($index_val as $index_name) { + $alter_sql = 'CREATE INDEX `' . $index_name . '` ON `' . $table . '` (`' . substr($index_name, 3) . '`)'; + mysql_q($alter_sql); + } + } + // update version + $update_v_sql = 'UPDATE `config` SET `version` = "' . $version . '" WHERE `version` LIKE "%"'; + mysql_q($update_v_sql); + $output_create_table = $lang['a_tables_updated'] . '
'; + return $output_create_table; +} + +/* ############################# + * # SYNC - show video from db # + */############################# +function show($cols, $table) { + $show_sql = 'SELECT `' . implode('`, `', $cols) . '` FROM `' . $table . '`'; + $show_result = mysql_q($show_sql); + + $output = array(); + while ($d = mysql_fetch_row($show_result)) { + $output[$d[0]] = $d[1]; + } + if (count($output) > 0) { + echo json_encode($output); + } else { + echo '{}'; + } +} + +/* ###################### + * # SYNC - show images # + */###################### +function show_images() { + $types = array( + 'movies' => array( + 'poster' => '^movies_([0-9]+)\.jpg$', + 'fanart' => '^movies_([0-9]+)_f\.jpg$', + 'exthumb' => '^movies_([0-9]+)_t([0-9])\.jpg$' + ), + 'tvshows' => array( + 'poster' => '^tvshows_([0-9]+)\.jpg$', + 'fanart' => '^tvshows_([0-9]+)_f\.jpg$', + 'exthumb' => '^tvshows_([0-9]+)_t([0-9])\.jpg$' + ), + 'episodes' => array( + 'poster' => '^episodes_([0-9]+)\.jpg$' + ), + 'actors' => array( + 'thumb' => '^([^_]{10})\.jpg$' + ) + ); + $files = scandir('cache'); + $files_a = scandir('cache/actors'); + $output = array( + 'movies' => array('poster' => array(), 'fanart' => array(), 'exthumb' => array()), + 'tvshows' => array('poster' => array(), 'fanart' => array(), 'exthumb' => array()), + 'episodes' => array('poster' => array()), + 'actors' => array('thumb' => array()) + ); + foreach ($types as $type => $img_type) { + $thumb_temp = array(); + foreach ($img_type as $img => $regexp) { + if ($type == 'actors') { + foreach ($files_a as $file) { + preg_match('|' . $regexp . '|', $file, $match); + if (count($match) > 1) { + $output[$type][$img][] = $match[1]; + } + } + } else { + foreach ($files as $file) { + preg_match('|' . $regexp . '|', $file, $match); + if (count($match) > 1) { + if ($img == 'exthumb') { + $output[$type]['exthumb'][] = $match[1] . '_t' . $match[2]; + } else { + $output[$type][$img][] = (int)$match[1]; + } + } + } + } + } + } + if (count($output) > 0) { + echo json_encode($output); + } else { + echo '{}'; + } +} + +/* ##################### + * # SYNC - add images # + */##################### +function add_images($data) { + // create img + $name = $data['name']; + $img_thumb = base64_decode($data['img']); + if (!file_exists('cache/' . $name) && $img_thumb !== '') { + $fp = fopen('cache/' . $name, 'wb'); + fwrite($fp, $img_thumb); + fclose($fp); + if (preg_match('|^([^_]+_[0-9]+_t[0-9]).jpg|', $name, $t)) { + gd_convert('cache/' . $t[1] . 'm.jpg', 'cache/' . $name, 100, 54); + } + } +} + +/* ####################### +* # SYNC - remove images # +*/######################## +function remove_images($data) { + foreach ($data as $name) { + if (file_exists('cache/' . $name)) { + unlink('cache/' . $name); + } + } + reset_hash(); +} + +/* ########################## + * # SYNC - add Video to DB # + */########################## +function sync_add($mysql_tables) { + $insert_array = array(); + // add actors, genres, countries + $panels = array('actor', 'genre', 'country', 'studio', 'director', 'stream'); + foreach ($panels as $panel) { + if (isset($_POST[$panel])) { + $values = array(); + foreach ($_POST[$panel] as $key => $val) { + // add stream + if ($panel == 'stream') { + $cols = array_keys($mysql_tables['movies_stream']); + $str = explode(';', $val); + foreach ($str as $k => $s) { + if (substr($mysql_tables['movies_stream'][$cols[$k+1]], 0, 3) == 'int') { + $str[$k] = ($s == '' ? 'NULL' : $s); + } else { + $str[$k] = '"' . $s . '"'; + } + } + $values[] = '("' . $_POST['id'] . '", ' . implode(', ', $str) . ')'; + + } else { + // check if panel exist + $sql_id = 'SELECT `id` FROM `' . $panel . '` WHERE `' . $panel . '` = "' . add_slash($val) . '"'; + $res_id = mysql_q($sql_id); + if (!mysql_num_rows($res_id)) { + $sql_ins = 'INSERT INTO `' . $panel . '` (`' . $panel . '`) VALUES ("' . add_slash($val) . '")'; + mysql_q($sql_ins); + $id = mysql_insert_id(); + } + else { + $row = mysql_fetch_assoc($res_id); + $id = $row['id']; + } + // add panels info + if($panel == 'actor') { + $cols = array('id', $panel . 'id', 'order'); + $values[] = '("' . $_POST['id'] . '", "' . $id . '", "' . $key . '")'; + } else { + $cols = array('id', $panel . 'id'); + $values[] = '("' . $_POST['id'] . '", "' . $id . '")'; + } + } + } + $insert_sql = 'INSERT INTO `' . $_POST['table'] . '_' . $panel . '` (`' . implode('`, `', $cols) . '`) VALUES ' . implode(', ', $values); + $result = mysql_q($insert_sql); + unset($_POST[$panel]); + } + } + + # insert values + foreach($mysql_tables[$_POST['table']] as $key => $val) { + if (isset($_POST[$key]) && strlen($_POST[$key]) > 0) { + if (substr($val, 0, 3) == 'int' or substr($val, 0, 5) == 'float') { + $insert_array['`' . $key . '`'] = add_slash($_POST[$key]); + } else { + $insert_array['`' . $key . '`'] = '"' . add_slash($_POST[$key]) . '"'; + } + } + } + $insert_sql = 'INSERT INTO `' . $_POST['table'] . '` (' . implode(', ', array_keys($insert_array)) . ') VALUES (' . implode(', ', $insert_array) . ')'; + $insert = mysql_q($insert_sql); +} + +/* ############################### + * # SYNC - delete Video from DB # + */############################### +function sync_delete($id, $table) { + $del_array = array($table); + if ($table == 'movies') { + array_push($del_array, $table . '_actor', $table . '_genre', $table . '_country', $table . '_studio', $table . '_director', $table . '_stream'); + } + if ($table == 'tvshows') { + array_push($del_array, $table . '_actor', $table . '_genre'); + } + if ($table == 'episodes') { + array_push($del_array, $table . '_stream'); + } + foreach ($del_array as $t) { + $delete_sql = 'DELETE FROM `' . $t . '` WHERE `id` IN ("' . implode('", "', $id) . '")'; + $delete = mysql_q($delete_sql); + } + + # delete images + $files_to_remove = array(); + $files = scandir('cache/'); + foreach ($id as $i) { + foreach($files as $file) { + $match = preg_match('/^' . $table . '_' . $i . '[_\.]/', $file); + if ($match == 1) { + $files_to_remove[] = $file; + } + } + } + remove_images($files_to_remove); +} + +/* ################## + * # Clean database # + */################## +function clean_db() { + $clean_array = array('movies_actor', 'movies_country', 'movies_director', 'movies_genre', 'movies_studio', 'movies_stream', 'tvshows_actor', 'tvshows_genre', 'episodes_stream'); + foreach ($clean_array as $table) { + $split = explode('_', $table); + $video = $split[0]; + $panel = $split[1]; + # delete from video_panel not existing id in movies or tvshow table + $clean_sql = 'DELETE FROM `' . $table . '` WHERE `id` NOT IN (SELECT `' . $video . '`.`id` FROM `' . $video . '`)'; + mysql_q($clean_sql); + # delete from video_panel not existing id in panel table + if ($panel != 'stream') { + $clean_sql = 'DELETE FROM `' . $table . '` WHERE `' . $panel . 'id` NOT IN (SELECT `' . $panel . '`.`id` FROM `' . $panel . '`)'; + mysql_q($clean_sql); + } + # delete from panel not existing id in video_panel table + if ($video == 'movies' && $panel != 'stream') { + $clean_sql = 'DELETE FROM `' . $panel . '` WHERE `id` NOT IN (SELECT `movies_' . $panel . '`.`' . $panel . 'id` FROM `movies_' . $panel . '`)'; + if ($panel == 'actor' or $panel == 'genre') { + $clean_sql.= ' AND `id` NOT IN (SELECT `tvshows_' . $panel . '`.`' . $panel . 'id` FROM `tvshows_' . $panel . '`)'; + } + mysql_q($clean_sql); + } + } +} + +/* ############## + * # Reset hash # + */############## +function reset_hash() { + $reset_sql = 'UPDATE `hash` SET `movies` = "", `tvshows` = "", `episodes` = "", `images` = ""'; + mysql_q($reset_sql); +} + +/* ################ + * # Change Token # + */################ +function change_token() { + $array = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',0,1,2,3,4,5,6,7,8,9); + $new_token = ''; + for ($i = 1; $i <= 6; $i++) { + $new_token.= $array[array_rand($array)]; + } + $update_sql = 'UPDATE `config` SET `token` = "' . $new_token . '"'; + $update = mysql_q($update_sql); + $_SESSION['token'] = $new_token; + return $new_token; +} + +/* ################# + * # GD conversion # + */################# +function gd_convert($cache_path, $img_link, $new_width, $new_height) { + if (!file_exists($cache_path) and !empty($img_link)) { + $img = @imagecreatefromjpeg($img_link); + if (!$img) { + $curl_opt = array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true + ); + $c = curl_init($img_link); + curl_setopt_array($c, $curl_opt); + curl_exec($c); + $redirect = curl_getinfo($c); + curl_close($c); + $img = @imagecreatefromjpeg($redirect['redirect_url']); + } + if ($img) { + $width = imagesx($img); + $height = imagesy($img); + $img_temp = imagecreatetruecolor($new_width, $new_height); + imagecopyresampled($img_temp, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height); + imagejpeg($img_temp, $cache_path, 80); + } + } +} + +/* ############### + * # ADD SLASHES # + */############### +function add_slash($string){ + if (get_magic_quotes_gpc()) { + return $string; + } else { + return addslashes($string); + } +} + +/* #################### + * # ARRAYS FOR PANEL # + */#################### +function panels_array($columns, $table) { + + $sep_tab = array('actor', 'genre', 'country', 'studio', 'director'); + $panels_array = array(); + foreach ($columns as $val) { + if (in_array($val, $sep_tab)) { + $sel = 'SELECT DISTINCT ' . $val . '.id, ' . $val . '.' . $val . ' FROM `' . $val . '`, `' . $table . '_' . $val . '` WHERE ' . $val . '.id=' . $table . '_' . $val . '.' . $val . 'id ORDER BY ' . $val . '.' . $val; + $res = mysql_q($sel); + while ($r = mysql_fetch_assoc($res)) { + $panels_array[$val][$r['id']] = $r[$val]; + } + } else { + $sel = 'SELECT DISTINCT `' . $val . '` FROM `' . $table . '` WHERE `hide` = 0 ORDER BY `' . $val . '`'; + $res = mysql_q($sel); + if (mysql_num_rows($res) > 0) { + while ($r = mysql_fetch_assoc($res)) { + if ($r[$val] != '') { + $panels_array[$val][] = $r[$val]; + } + } + } + } + } + if (isset($panels_array['year'])) { rsort($panels_array['year']); } + + return $panels_array; +} + +/* ############## + * # CREATE URL # + */############## +function create_url($setting, $urls) { + if ($setting['mod_rewrite'] == 1 && array_key_exists('HTTP_MOD_REWRITE', $_SERVER)) { + $index = 'index,'; + $p = '-'; + $c = ','; + $end = '.html'; + } else { + $index = 'index.php?'; + $p = '='; + $c = '&'; + $end = ''; + } + $pair = array(); + foreach ($urls as $k => $v) { + if (strlen($v) > 0) { + $pair[] = $k . $p . $v; + } + } + return $index . implode($c, $pair) . $end; +} + +/* ###################### + * # AUTO CONFIG REMOTE # + */###################### +function auto_conf_remote($s) { + $ip = $_SERVER['REMOTE_ADDR']; + $xbmc_update_sql = 'UPDATE `config` SET + `xbmc_host` = "' . $ip . '", + `xbmc_port` = "' . $s['webserverport'] . '", + `xbmc_login` = "' . $s['webserverusername'] . '", + `xbmc_pass` = "' . $s['webserverpassword'] . '"'; + mysql_q($xbmc_update_sql); + $_SESSION = array(); +} + +/* ################# + * # CREATE BANNER # + */################# +function create_banner($lang, $file, $data) { + + $movie_sql = 'SELECT `id`, `title`, `originaltitle`, `rating`, `runtime`, `year`, `last_played` FROM `movies` ORDER BY `last_played` DESC LIMIT 0, 1'; + $movie_result = mysql_q($movie_sql); + $movie = mysql_fetch_assoc($movie_result); + + $episode_sql = 'SELECT `episode`, `season`, `tvshow`, `title`, `last_played` FROM `episodes` ORDER BY `last_played` DESC LIMIT 0, 1'; + $episode_result = mysql_q($episode_sql); + $episode = mysql_fetch_assoc($episode_result); + $episode['e_title'] = $episode['title']; + unset($episode['title']); + + if (isset($episode['last_played']) && $episode['last_played'] > $movie['last_played']) { + $tvshow_sql = 'SELECT `id`, `title`, `originaltitle`, `rating`, `last_played` FROM `tvshows` WHERE `id` = ' . $episode['tvshow']; + $tvshow_result = mysql_q($tvshow_sql); + $tvshow = mysql_fetch_assoc($tvshow_result); + $ban = array_merge($tvshow, $episode); + $table = 'tvshows'; + $panels_array = array('genre'); + } else { + $ban = $movie; + $table = 'movies'; + $panels_array = array('genre', 'country'); + } + + if(isset($ban['id'])) { + foreach ($panels_array as $val) { + $sel_sql = 'SELECT ' . $val . '.' . $val . ' FROM ' . $val . ', ' . $table . '_' . $val . ' WHERE ' . $val . '.id = ' . $table . '_' . $val . '.' . $val . 'id AND ' . $table . '_' . $val . '.id = "' . $ban['id'] . '"'; + $sel_res = mysql_q($sel_sql); + $out = array(); + while ($s = mysql_fetch_row($sel_res)) { + $out[] = $s[0]; + } + $ban[$val] = implode(' / ', $out); + } + } + + $b = array(); + $b['w'] = 400; // banner width + $b['h'] = 70; // banner height + $b['bg_c'] = '141414'; // background color + $b['lw_c'] = 'FFFFFF'; // last watched color + $b['lw_s'] = 10; // last watched font size + $b['lw_x'] = 130; // last watched pos. x + $b['lw_y'] = 20; // last watched pos. y + $b['t_c'] = 'FFFFFF'; // title color + $b['t_s'] = 8; // title font size + $b['t_x'] = 136; // title pos. x + $b['t_y'] = 36; // title pos. y + $b['o_c'] = 'AAAAAA'; // title color + $b['o_s'] = 8; // title font size + $b['o_x'] = 136; // title pos. x + $b['o_y'] = 51; // title pos. y + $b['i_c'] = '808080'; // info color + $b['i_s'] = 6; // info font size + $b['i_x'] = 130; // info pos. x + $b['i_y'] = 63; // info pos. y + $b['st_c'] = '000000'; // stroke color + $b['b_c'] = 'FFFFFF'; // border color + + if ($data !== '0') { + $banner_array = explode(';', $data); + $banner = array(); + foreach ($banner_array as $val) { + $i = explode(':', $val); + $banner[$i[0]] = $i[1]; + } + $b = $banner; + } + + $bg_c = hex2rgb($b['bg_c']); + $lw_c = hex2rgb($b['lw_c']); + $t_c = hex2rgb($b['t_c']); + $o_c = hex2rgb($b['o_c']); + $i_c = hex2rgb($b['i_c']); + $st_c = hex2rgb($b['st_c']); + $b_c = hex2rgb($b['b_c']); + + $font = 'admin/css/font/archivonarrow.ttf'; + + // background + $banner = imagecreatetruecolor($b['w'], $b['h']); + $bg_color = imagecolorallocate($banner, $bg_c['r'], $bg_c['g'], $bg_c['b']); + imagefill($banner, 0, 0, $bg_color); + + // get poster and copy + if (file_exists('cache/' . $table . '_' . $ban['id'] . '_f.jpg')) { + $post = imagecreatefromjpeg('cache/' . $table . '_' . $ban['id'] . '_f.jpg'); + } elseif (file_exists('cache/' . $table . '_' . $ban['id'] . '.jpg')) { + $post = imagecreatefromjpeg('cache/' . $table . '_' . $ban['id'] . '.jpg'); + } else { + $post = imagecreatefromjpeg('templates/default/img/d_poster.jpg'); + } + $width = imagesx($post); + $height = imagesy($post); + $new_height = $b['h']; + $new_width = $width / ($height / $new_height); + imagecopyresampled($banner, $post, 0, 0, 0, 0, $new_width, $new_height, $width, $height); + + // add gradient + $width = $b['h']; + $gradient = imagecreatetruecolor($width, $b['h']); + $gradient_color = imagecolorallocatealpha($gradient, $bg_c['r'], $bg_c['g'], $bg_c['b'], 127); + imagefill($gradient, 0, 0, $gradient_color); + for ($x=0; $x < $width; ++$x) { + $alpha = 127 - $x*(127/$width); + $gradient_color = imagecolorallocatealpha($gradient, $bg_c['r'], $bg_c['g'], $bg_c['b'], $alpha); + imageline($gradient, $x, 0, $x, $b['h'], $gradient_color); + } + imagecopyresampled($banner, $gradient, $new_width-$width, 0, 0, 0, $width, $b['h'], $width, $b['h']); + + // add text + $last_watched_color = imagecolorallocate($banner, $lw_c['r'], $lw_c['g'], $lw_c['b']); + $title_color = imagecolorallocate($banner, $t_c['r'], $t_c['g'], $t_c['b']); + $o_title_color = imagecolorallocate($banner, $o_c['r'], $o_c['g'], $o_c['b']); + $info_color = imagecolorallocate($banner, $i_c['r'], $i_c['g'], $i_c['b']); + $stroke_color = imagecolorallocate($banner, $st_c['r'], $st_c['g'], $st_c['b']); + imagettfstroketext($banner, $b['lw_s'], 0, $b['lw_x'], $b['lw_y'], $last_watched_color, $stroke_color, $font, $lang['i_last_played'], 1); + imagettfstroketext($banner, $b['t_s'], 0, $b['t_x'], $b['t_y'], $title_color, $stroke_color, $font, + (isset($ban['title']) ? $ban['title'] : '') . + (isset($ban['season']) ? ' - ' . $ban['season'] . 'x' : '') . + (isset($ban['episode']) ? $ban['episode'] . ' ' : '') . + (isset($ban['e_title']) ? $ban['e_title'] : '') + , 1); + imagettfstroketext($banner, $b['o_s'], 0, $b['o_x'], $b['o_y'], $o_title_color, $stroke_color, $font, (isset($ban['originaltitle']) ? $ban['originaltitle'] : ''), 1); + imagettfstroketext($banner, $b['i_s'], 0, $b['i_x'], $b['i_y'], $info_color, $stroke_color, $font, + (isset($ban['year']) ? $ban['year'] : '') . ' | ' . + (isset($ban['rating']) ? $ban['rating'] : '') . ' | ' . + (isset($ban['runtime']) ? $ban['runtime'] . ' ' . $lang['i_minute'] : '') . ' | ' . + (isset($ban['genre']) ? $ban['genre'] : '') . ' | ' . + (isset($ban['country']) ? $ban['country'] : '') + , 1); + + // icon + $icon = imagecreatefrompng('admin/img/' . $table . '.png'); + imagecopy($banner, $icon, $b['w']-26, 6, 0, 0, 18, 18); + + // border + $border_color = imagecolorallocate($banner, $b_c['r'], $b_c['g'], $b_c['b']); + imageline($banner, 0, 0, $b['w']-1, 0, $border_color); + imageline($banner, $b['w']-1, 0, $b['w']-1, $b['h']-1, $border_color); + imageline($banner, 0, $b['h']-1, $b['w']-1, $b['h']-1, $border_color); + imageline($banner, 0, 0, 0, $b['h']-1, $border_color); + + // save as file + imagejpeg($banner, 'cache/' . $file, 100); + return $b; +} + +/* ################ + * # BANNER 2 STR # + */################ +function banner2str($array) { + $banner = ''; + foreach ($array as $key => $val) { + $banner.= $key . ':' . strtoupper($val) . ';'; + } + return substr($banner, 0, -1); +} + +/* ############# + * # HEX 2 RGB # + */############# +function hex2rgb($hex) { + $match = preg_match('/^[0-9abcdefABCDEF]{6}$/', $hex); + if ($match == true) { + $rgb = str_split($hex, 2); + $rgb = array('r' => hexdec($rgb[0]), 'g' => hexdec($rgb[1]), 'b' => hexdec($rgb[2])); + return $rgb; + } else { + return False; + } +} + +/* ########################## + * # STROKE FOR BANNER TEXT # + */########################## +function imagettfstroketext(&$image, $size, $angle, $x, $y, &$textcolor, &$strokecolor, $fontfile, $text, $px) { + for($c1 = ($x-abs($px)); $c1 <= ($x+abs($px)); $c1++) + for($c2 = ($y-abs($px)); $c2 <= ($y+abs($px)); $c2++) + $banner = imagettftext($image, $size, $angle, $c1, $c2, $strokecolor, $fontfile, $text); + return imagettftext($image, $size, $angle, $x, $y, $textcolor, $fontfile, $text); +} + +/* ################# + * # ADD 0 TO LEFT # + */################# +function zero($dig) { + return str_pad($dig, 2, 0, STR_PAD_LEFT); +} + +/* ################# + * # LANGUAGE FLAG # + */################# +function check_flag($f, $iso_lang) { + foreach ($iso_lang as $k => $v) { + if (in_array($f, $v)) { + return $k; + } + } +} + +?> \ No newline at end of file diff --git a/movielib/index.php b/movielib/index.php new file mode 100644 index 0000000..ef586f8 --- /dev/null +++ b/movielib/index.php @@ -0,0 +1,910 @@ + $video, 'view' => $view, 'sort' => $sort)); +} else { + $output['url_delete_filter'] = create_url($setting, array('video' => $video, 'view' => $view, 'sort' => $sort, 'filter' => $filter, 'filterid' => $filterid)); +} + +/* ################ + * # SELECT MEDIA # + */################ +if ($video == 'tvshows') { + $mysql_table = 'tvshows'; +} else { + $mysql_table = 'movies'; +} +$output['select_media'] = '' . mb_strtoupper($lang['i_movies']) . '' . mb_strtoupper($lang['i_tvshows']) . ''; +if ($setting['select_media_header'] == 1) { + $count_movies = mysql_result(mysql_q('SELECT COUNT( * ) FROM movies'), 0); + $count_tvshows = mysql_result(mysql_q('SELECT COUNT( * ) FROM tvshows'), 0); + if ($count_movies == 0 or $count_tvshows == 0) { + $output['select_media'] = ''; + } +} + +/* ############# + * # TOP PANEL # + */############# +$show['panel_top'] = $setting['panel_top']; +if ($setting['panel_top'] == 1) { + $top_panel_sql = array( + 'top_item_last_added' => 'SELECT id, title, date_added, hide FROM ' . $mysql_table . ' WHERE hide=0 ORDER BY date_added DESC LIMIT ' . $setting['panel_top_limit'], + 'top_item_most_watched' => 'SELECT id, title, hide FROM ' . $mysql_table . ' WHERE hide=0 ORDER BY play_count DESC LIMIT ' . $setting['panel_top_limit'], + 'top_item_last_played' => 'SELECT id, title, last_played, hide FROM ' . $mysql_table . ' WHERE hide=0 ORDER BY last_played DESC LIMIT ' . $setting['panel_top_limit'], + 'top_item_top_rated' => 'SELECT id, title, rating, hide FROM ' . $mysql_table . ' WHERE hide=0 ORDER BY rating DESC LIMIT ' . $setting['panel_top_limit'] + ); + foreach ($top_panel_sql as $name => $item_top_sql) { + $output[$name] = ''; + $item_top_result = mysql_q($item_top_sql); + while ($item_top = mysql_fetch_array($item_top_result)) { + if (file_exists('cache/' . $mysql_table . '_' . $item_top['id'] . '.jpg')) { + $output[$name].= ''; + } + } + } +} + +/* #################### + * # ARRAYS FOR PANEL # + */#################### +if ($video == 'tvshows') { + $columns = array('actor', 'genre', 'premiered'); +} else { + $columns = array('actor', 'genre', 'country', 'year', 'director', 'set', 'studio'); +} +$panels_array = panels_array($columns, $mysql_table); + +$filter_array = array('actor', 'genre', 'country', 'studio', 'director'); +if ($filter == '') { + $mysql_table2 = ''; + $filter_mysql = ''; +} else if (in_array($filter, $filter_array)) { + $mysql_table2 = ', ' . $mysql_table . '_' . $filter; + $filter_mysql = $mysql_table . '_' . $filter . '.' . $filter . 'id = '. $filterid . ' AND ' . $mysql_table . '.id = ' . $mysql_table . '_' . $filter . '.id AND'; +} else { + $mysql_table2 = ''; + $filter_mysql = $mysql_table . '.' . $filter . ' LIKE "%' . $panels_array[$filter][$filterid] . '%" AND'; +} + +/* ############## + * # LEFT PANEL # + */############## + +// overall panel +$show['panel_overall'] = $setting['panel_overall']; +if ($setting['panel_overall'] > 0) { + $overall_sql = 'SELECT play_count, hide FROM ' . $mysql_table . ' WHERE hide=0'; + $overall_result = mysql_q($overall_sql); + $overall_all = mysql_num_rows($overall_result); + $overall_watched = 0; + while($overall = mysql_fetch_array($overall_result)) { + if ($overall['play_count'] > 0) { + $overall_watched++; + } + } + $output['overall_all'] = $overall_all; + $output['overall_watched'] = $overall_watched; + $output['overall_unwatched'] = $overall_all - $overall_watched; +} + +// menu panel +$menu_array = array('genre', 'year', 'country', 'set', 'studio'); +foreach ($menu_array as $menu_name) { + $output['panel_' . $menu_name] = ''; + if ($setting['panel_' . $menu_name] <> 0 && isset($panels_array[$menu_name]) && count($panels_array[$menu_name]) > 0) { + $show['panel_' . $menu_name] = 1; + foreach ($panels_array[$menu_name] as $key => $val) { + if ($filter == $menu_name && $filterid == $key) { + $output['panel_' . $menu_name].= '
  • ' . $val . '
  • '; + } else { + $output['panel_' . $menu_name].= '
  • ' . $val . '
  • '; + } + } + } +} + +/* ######## + * # SORT # + */######## +$sort_array = array( + 1 => array($lang['i_title'], 'title ASC'), + 2 => array($lang['i_premiered'], 'premiered DESC'), + 3 => array($lang['i_year'], 'year DESC'), + 4 => array($lang['i_rating'], 'rating DESC'), + 5 => array($lang['i_added'], 'date_added DESC'), + 6 => array($lang['i_runtime'], ' CAST( runtime AS DECIMAL( 10, 2 ) ) DESC'), + 7 => array($lang['i_last_played'], 'last_played DESC'), + 8 => array($lang['i_most_watched'], 'play_count DESC') + ); + +if ($video == 'tvshows') { + unset($sort_array[3], $sort_array[6]); +} else { + unset($sort_array[2]); +} + +$output['panel_sort'] = ''; +foreach ($sort_array as $key => $val) { + $output['panel_sort'].= ($sort == $key ? + '' . $val[0] . '' : + '' . $val[0] . ''); +} + +/* ######### + * # WATCH # + */######### +$show['panel_watch'] = 1; +$watch_arr = array(0 => 'all', 1 => 'watched', 2 => 'unwatched'); +$output['panel_watch'].= '
    ' . $lang['i_watched_status'] . ': ' . $lang['i_' . $watch_arr[$watch]] . '
    '; +foreach ($watch_arr as $key => $val) { + if ($watch == $key) { + $output['panel_watch'].= '' . $lang['i_' . $val] . ''; + } else { + $output['panel_watch'].= '' . $lang['i_' . $val] . ''; + } +} +if ($watch == 1) { + $watch_mysql = ' > 0'; +} elseif ($watch == 2) { + $watch_mysql = ' = 0'; +} else { + $watch_mysql = ' >= 0'; +} +$output['panel_watch'].= '
    '; + +/* ######## + * # VIEW # + */######## +if ($setting['panel_view'] > 0) { + $show['panel_view'] = 1; + $output['panel_view'].= '
    ' . $lang['i_view'] . ': ' . $lang['i_' . $views[$view]] . '
    '; + foreach ($views as $key => $val) { + if ($view == $key) { + $output['panel_view'].= '' . $lang['i_' . $val] . ''; + } else { + $output['panel_view'].= '' . $lang['i_' . $val] . ''; + } + } + $output['panel_view'].= '
    '; +} + +/* ########## + * # SEARCH # + */########## + $show['panel_live_search'] = $setting['live_search']; +$search_mysql = '%'; +if ($search !== '') { + $search_mysql = $search; +} + +/* ############# + * # PANEL NAV # + */############# +$id_mysql = ($id == 0 ? '%' : $id); +$nav_sql = 'SELECT ' . $mysql_table . '.id FROM ' . $mysql_table . $mysql_table2 . ' WHERE + ' . $filter_mysql . ' + ' . $mysql_table . '.title LIKE "%' . $search_mysql . '%" AND + ' . $mysql_table . '.id LIKE "' . $id_mysql . '" AND + ' . $mysql_table . '.play_count ' . $watch_mysql . ' AND + ' . $mysql_table . '.hide=0 + ORDER BY ' . $sort_array[$sort][1]; + +$nav_result = mysql_q($nav_sql); +$row = mysql_num_rows($nav_result); +if ($setting['per_page'] == 0) { + $i_pages = 1; + $output['panel_nav'] = ''; +} else { + $i_pages = (ceil($row / $setting['per_page'])); + $output['panel_nav'] = ($page == 1 ? '' . $lang['i_previous'] . '' : '' . $lang['i_previous'] . '') + . ' ' . $lang['i_page'] . ' ' . $page . ' / ' . $i_pages . ' ' . + ($page == $i_pages ? '' . $lang['i_next'] . '' : '' . $lang['i_next'] . ''); + if ($row == 0) { + $output['panel_nav'] = ''; + } +} + +/* ################ + * # PANEL FILTER # + */################ +if ($filter !== '') { + $output['panel_filter'] = '' . $lang['i_filter'] . ': ' . $lang['i_' . $filter] . ' » ' . $panels_array[$filter][$filterid]; + $show['panel_filter'] = 1; +} +if ($search !== '') { + $output['panel_filter'] = '' . $lang['i_search'] . ': ' . $lang['i_result'] . ' » ' . $search; + $show['panel_filter'] = 1; +} +if ($id > 0) { + $output['panel_filter'] = '' . $lang['i_filter'] . ': ' . $lang['i_title']; + $show['panel_filter'] = 1; +} + +/* ################## + * # CONTROL REMOTE # + */################## +if (isset($_SESSION['logged_admin']) && $_SESSION['logged_admin'] == true) { + $show['panel_remote'] = 1; +} + +/* ############## + * # MOVIE LIST # + */############## +if ($setting['per_page'] == 0) { + $limit_sql = ''; +} else { + $start = ($page - 1) * $setting['per_page']; + $limit_sql = ' LIMIT ' . $start . ', ' . $setting['per_page']; +} +$list_sql = 'SELECT ' . $mysql_table . '.* FROM ' . $mysql_table . $mysql_table2 . ' WHERE + ' . $filter_mysql . ' + ' . $mysql_table . '.title LIKE "%' . $search_mysql . '%" AND + ' . $mysql_table . '.id LIKE "' . $id_mysql . '" AND + ' . $mysql_table . '.play_count ' . $watch_mysql . ' AND + ' . $mysql_table . '.hide=0 + ORDER BY ' . $sort_array[$sort][1] . $limit_sql; + +$list_result = mysql_q($list_sql); + +// get date for last added +$new_sql = 'SELECT ' . $mysql_table . '.date_added FROM ' . $mysql_table . ' ORDER BY ' . $mysql_table . '.date_added DESC LIMIT 0, 1'; +$new_result = mysql_q($new_sql); +$new_date = mysql_fetch_assoc($new_result); +$new_date = substr($new_date['date_added'], 0, 10); + +$output_panel_list = ''; +while ($list = mysql_fetch_assoc($list_result)) { + + // output and show desc arrays + $output_desc = array(); + $show_desc = array(); + foreach ($item_desc as $val) { + $output_desc[$val] = ''; + $show_desc[$val] = 0; + } + + $output_desc['mysql_table'] = $mysql_table; + $output_desc['id'] = $list['id']; + $output_desc['video'] = $video; + $output_desc['view'] = $view; + $output_desc['sort'] = $sort; + $output_desc['title'] = $list['title']; + + $show_desc['mysql_table'] = 1; + $show_desc['id'] = 1; + $show_desc['video'] = 1; + $show_desc['title'] = 1; + + if (isset($_SESSION['logged_admin']) && $_SESSION['logged_admin'] == true && $video == 'movies') { + $show_desc['xbmc'] = 1; + } + + // link title + $output_desc['url_title'] = create_url($setting, array('id' => $list['id'], 'video' => $video, 'view' => $view, 'sort' => $sort, 'filter' => $filter, 'filterid' => $filterid)); + + // originaltitle + if ($list['originaltitle'] !== '') { + $show_desc['originaltitle'] = 1; + $output_desc['originaltitle'] = $list['originaltitle']; + } + + // file + if ($video == 'movies') { + $output_desc['file'] = 'http://' . $setting['xbmc_login'] . ':' . $setting['xbmc_pass'] . '@' . $setting['xbmc_host'] . ':' . $setting['xbmc_port'] . '/vfs/' . urlencode($list['file']); + } + + // poster + $poster = 'cache/' . $mysql_table . '_' . $list['id'] . '.jpg'; + if (!file_exists($poster)) { + $output_desc['poster'] = 'templates/' . $setting['theme'] . '/img/d_poster.jpg'; + } else { + $output_desc['poster'] = $poster; + } + + // wached status + if ($setting['watched_status'] == 1 && $list['play_count'] > 0) { + $output_desc['watched_img'] = ''; + } + + // play count + if ($setting['show_playcount'] == 1 && $list['play_count'] > 0) { + $playcount_array = str_split($list['play_count']); + $output_desc['playcount_img'] = '
    '; + foreach ($playcount_array as $int) { + $output_desc['playcount_img'].= ''; + } + $output_desc['playcount_img'].= '
    '; + } + + // genre + $output_genre_array = array(); + $genre_sql = 'SELECT genre.id, genre.genre FROM genre, ' . $video . '_genre WHERE ' . $video . '_genre.id = "' . $list['id'] . '" AND genre.id = ' . $video . '_genre.genreid'; + $genre_res = mysql_q($genre_sql); + + while ($val = mysql_fetch_assoc($genre_res)) { + $output_genre_array[] = '' . $val['genre'] . ''; + } + if (count($output_genre_array) > 0) { + $show_desc['genre'] = 1; + $output_desc['genre'] = implode(' / ', $output_genre_array); + } + + // rating + if ($list['rating'] !== '') { + $show_desc['rating'] = 1; + $output_desc['rating'] = $list['rating']; + + $show_desc['rating_star'] = 1; + $output_desc['rating_star'] = ''; + $r = $output_desc['rating']; + for ($s = 1; $s <= 10; $s++) { + if ($r >= 1) { + $output_desc['rating_star'].= ' '; + } else if ($r >= 0.5) { + $output_desc['rating_star'].= ' '; + } else { + $output_desc['rating_star'].= ' '; + } + $r--; + } + } + + // actors + $output_actor_array = array(); + $actor_sql = 'SELECT actor.id, actor.actor FROM actor, ' . $video . '_actor WHERE ' . $video . '_actor.id = "' . $list['id'] . '" AND actor.id = ' . $video . '_actor.actorid ORDER BY ' . $video . '_actor.order'; + $actor_res = mysql_q($actor_sql); + + while ($val = mysql_fetch_assoc($actor_res)) { + if ($val['actor'] !== '') { + if (file_exists('cache/actors/' . substr(md5($val['actor']), 0, 10) . '.jpg')) { + $actor_thumb = ''; + } else { + $actor_thumb = ''; + } + $output_actor_array[] = '' . $actor_thumb . $val['actor'] . ''; + } + } + if (count($output_actor_array) > 0) { + $show_desc['actor'] = 1; + $output_desc['actor'] = implode(' / ', $output_actor_array); + } + + // plot + if ($list['plot'] !== '') { + $show_desc['plot'] = 1; + $output_desc['plot'] = $list['plot']; + } + + // only movies + if ($video == 'movies') { + + // year + if ($list['year'] !== '') { + $show_desc['year'] = 1; + $output_desc['year'] = '' . $list['year'] . ''; + } + + // country + $output_country_array = array(); + $country_sql = 'SELECT country.id, country.country FROM country, ' . $video . '_country WHERE ' . $video . '_country.id = "' . $list['id'] . '" AND country.id = ' . $video . '_country.countryid'; + $country_res = mysql_q($country_sql); + + while ($val = mysql_fetch_assoc($country_res)) { + $output_country_array[] = '' . $val['country'] . ''; + } + if (count($output_country_array) > 0) { + $show_desc['country'] = 1; + $output_desc['country'] = implode(' / ', $output_country_array); + } + + // runtime + if ($list['runtime'] !== NULL) { + $show_desc['runtime'] = 1; + $output_desc['runtime'] = $list['runtime']; + } + + // director + $director_sql = 'SELECT director.id, director.director FROM director, ' . $video . '_director WHERE ' . $video . '_director.id = "' . $list['id'] . '" AND director.id = ' . $video . '_director.directorid'; + $director_res = mysql_q($director_sql); + $val = mysql_fetch_assoc($director_res); + if (isset($val['director'])) { + $show_desc['director'] = 1; + $output_desc['director'] = '' . $val['director'] . ''; + } + + // set + if ($list['set'] !== '') { + $show_desc['set'] = 1; + $output_desc['set'] = '' . $list['set'] . ''; + } + + // imdb id + if ($list['imdbid'] !== '' && $list['imdbid']{0} == 't') { + $output_desc['imdb_url'] = ''; + } + + // studio + $studio_sql = 'SELECT studio.id, studio.studio FROM studio, ' . $video . '_studio WHERE ' . $video . '_studio.id = "' . $list['id'] . '" AND studio.id = ' . $video . '_studio.studioid'; + $studio_res = mysql_q($studio_sql); + $val = mysql_fetch_assoc($studio_res); + if (isset($val['studio'])) { + $show_desc['studio'] = 1; + $output_desc['studio'] = '' . $val['studio'] . ''; + if (file_exists('templates/' . $setting['theme'] . '/img/studios/' . $val['studio'] . '.png')) { + $show_desc['studio_art'] = 1; + $output_desc['studio_art'] = ''; + } + } + + // ribbon new + if (substr($list['date_added'], 0, 10) == $new_date) { + $show_desc['ribbon_new'] = 1; + $output_desc['ribbon_new'] = '
    ' . mb_strtoupper($lang['i_ribbon_new']) . '
    '; + } + + // streams + $stream_sql = 'SELECT * FROM `movies_stream` WHERE id = "' . $list['id'] . '"'; + $stream_res = mysql_q($stream_sql); + + if (mysql_num_rows($stream_res) > 0) { + $str = array('v' => array(), 'a' => array(), 's' => array()); + while ($stream = mysql_fetch_assoc($stream_res)) { + $str[$stream['type']][] = $stream; + } + } + + $img_flag_vres = ''; + $img_flag_vtype = ''; + $img_flag_vq = ''; + if (isset($str['v'])) { + foreach ($str['v'] as $s) { + // video resolution + foreach ($vres_assoc as $key => $val) { + if (is_numeric($s['v_width']) && $s['v_width'] >= $key) { + $img_flag_vres = ''; + } + } + + // video codec + foreach ($vtype_assoc as $key => $val) { + if (in_array($s['v_codec'], $vtype_assoc[$key])) { + $img_flag_vtype = ''; + } + } + + // video sd, hd or uhd + $img_flag_vq = ''; + if (is_numeric($s['v_width']) && $s['v_width'] >= 1280) { + $img_flag_vq = ''; + } + if (is_numeric($s['v_width']) && $s['v_width'] >= 3000) { + $img_flag_vq = ''; + } + + $output_desc['img_flag_v'].= '
    ' . $img_flag_vres . $img_flag_vtype . $img_flag_vq . '
    '; + } + } + if (isset($str['a'])) { + foreach ($str['a'] as $s) { + // audio codec + foreach ($atype_assoc as $key => $val) { + if(in_array($s['a_codec'], $atype_assoc[$key])) { + $img_flag_atype = ''; + } + } + + // audio channel + foreach ($achan_assoc as $val) { + if (is_numeric($s['a_chan']) && $s['a_chan'] >= $val) { + $img_flag_achan = ''; + } + } + + // audio language + if (file_exists('templates/' . $setting['theme'] . '/img/flags/l_' . check_flag($s['a_lang'], $iso_lang) . '.png')) { + $img_flag_alang = ''; + } else { + $img_flag_alang = $s['a_lang']; + } + $output_desc['img_flag_a'].= '
    ' . $img_flag_atype . $img_flag_achan . $img_flag_alang . '
    '; + } + } + + // subtitles + if (isset($str['s'])) { + foreach ($str['s'] as $s) { + if (file_exists('templates/' . $setting['theme'] . '/img/flags/l_' . check_flag($s['s_lang'], $iso_lang) . '.png')) { + $img_flag_slang = ''; + } else { + $img_flag_slang = $s['s_lang']; + } + $output_desc['img_flag_s'].= '
    ' . $img_flag_slang . '
    '; + } + } + + // extra thumbs + $ex_thumb_array = array(); + for ($c=1;$c<10;$c++) { + $ex_t = 'cache/movies_' . $list['id'] . '_t' . $c . 'm.jpg'; + if (file_exists($ex_t)) { + $ex_thumb_array[] = ''; + } + } + if (count($ex_thumb_array) > 0) { + $show_desc['extra_thumbs'] = 1; + $output_desc['extra_thumbs'] = '
    ' . implode('', $ex_thumb_array) . '
    '; + } + + // trailer + if ($list['trailer'] !== '' && $setting['show_trailer'] == 1) { + $output_desc['trailer_img'] = ''; + } + if ($list['trailer'] !== '' && $setting['show_trailer'] == 1 && $id <> 0) { + $show_desc['trailer'] = 1; + if (substr($list['trailer'], 0, 18) == 'http://www.youtube') { + $output_desc['trailer'].= ' + + '; + } else { + $ext = substr($list['trailer'], strrpos($list['trailer'], '.')+1, strlen($list['trailer'])); + foreach ($mimetype_assoc as $key => $val) { + if(in_array($ext, $val)) { + $mimetype = $key; + break; + } else { + $mimetype = ''; + } + } + if ($ext == 'mov') { + $output_desc['trailer'].= ' + '; + } else { + $output_desc['trailer'].= ' + '; + } + } + } + } + + // only tvshows + if ($video == 'tvshows') { + + // premiered + if ($list['premiered'] !== '') { + $show_desc['premiered'] = 1; + $output_desc['premiered'] = '' . $list['premiered'] . ''; + } + + // seasons + $season_array = array(); + $seasons_sql = 'SELECT season FROM episodes WHERE tvshow = "' . $list['id'] . '" ORDER BY season'; + $seasons_result = mysql_q($seasons_sql); + while ($seasons = mysql_fetch_array($seasons_result)) { + if (!array_key_exists($seasons['season'], $season_array)) { + $season_array[$seasons['season']] = '' . $lang['i_season'] . ' ' . $seasons['season'] . ''; + } + } + if (count($season_array) <> 0) { + $show_desc['seasons'] = 1; + $output_desc['seasons'] = implode(' / ', $season_array); + } + + // episodes + if ($id <> 0) { + // get date for last added episode + $new_episode_sql = 'SELECT date_added FROM episodes ORDER BY date_added DESC LIMIT 0, 1'; + $new_episode_result = mysql_q($new_episode_sql); + $new_episode_date = mysql_fetch_assoc($new_episode_result); + $new_episode_date = substr($new_episode_date['date_added'], 0, 10); + + $show_desc['episodes'] = 1; + $episodes_sql = 'SELECT id, title, episode, season, plot, firstaired, file, play_count, date_added, last_played FROM episodes WHERE tvshow = "' . $list['id'] . '" ORDER BY season, episode ASC'; + $episodes_result = mysql_q($episodes_sql); + $i = -1; + + $output_epiosde_list = ''; + while ($episodes = mysql_fetch_assoc($episodes_result)) { + + // output and show episodes arrays + $output_episode = array(); + $show_episode = array(); + foreach ($item_episode as $val) { + $output_episode[$val] = ''; + $show_episode[$val] = 0; + } + + if (isset($_SESSION['logged_admin']) && $_SESSION['logged_admin'] == true && $video == 'tvshows') { + $show_episode['xbmc'] = 1; + } + + $output_episode['episode'] = $episodes['id']; + $output_episode['season'] = $episodes['season']; + $output_episode['plot'] = $episodes['plot']; + $output_episode['aired'] = $episodes['firstaired']; + + // title + $output_episode['title'] = $episodes['episode'] . '. ' . ($episodes['title'] == '' ? $lang['i_episode'] . ' ' . $episodes['episode'] : $episodes['title']); + + // file + $output_episode['file'] = 'http://' . $setting['xbmc_login'] . ':' . $setting['xbmc_pass'] . '@' . $setting['xbmc_host'] . ':' . $setting['xbmc_port'] . '/vfs/' . urlencode($episodes['file']); + + // thumbnail + if (file_exists('cache/episodes_' . $episodes['id'] . '.jpg')) { + $output_episode['thumbnail'] = ''; + } else { + $output_episode['thumbnail'] = ''; + } + + // wached status + if ($setting['watched_status'] == 1 && $episodes['play_count'] > 0) { + $output_episode['watched_img'] = ''; + } + + // episode ribbon new + if (substr($episodes['date_added'], 0, 10) == $new_episode_date) { + $output_episode['ribbon_new'] = '
    ' . mb_strtoupper($lang['i_ribbon_new']) . '
    '; + } + + // episode streams + $stream_sql = 'SELECT * FROM `episodes_stream` WHERE id = "' . $episodes['id'] . '"'; + $stream_res = mysql_q($stream_sql); + + if (mysql_num_rows($stream_res) > 0) { + $str = array('v' => array(), 'a' => array(), 's' => array()); + while ($stream = mysql_fetch_assoc($stream_res)) { + $str[$stream['type']][] = $stream; + } + } + + $img_flag_vres = ''; + $img_flag_vtype = ''; + $img_flag_vq = ''; + if (isset($str['v'])) { + foreach ($str['v'] as $s) { + // episode video resolution + foreach ($vres_assoc as $key => $val) { + if (is_numeric($s['v_width']) && $s['v_width'] >= $key) { + $img_flag_vres = ''; + } + } + // episode video codec + foreach ($vtype_assoc as $key => $val) { + if (in_array($s['v_codec'], $vtype_assoc[$key])) { + $img_flag_vtype = ''; + } + } + // episode video sd, hd or uhd + $img_flag_vq = ''; + if (is_numeric($s['v_width']) && $s['v_width'] >= 1280) { + $img_flag_vq = ''; + } + if (is_numeric($s['v_width']) && $s['v_width'] >= 3000) { + $img_flag_vq = ''; + } + $output_episode['img_flag_v'].= $img_flag_vres . $img_flag_vtype . $img_flag_vq; + } + } + if (isset($str['a'])) { + foreach ($str['a'] as $s) { + // episode audio codec + foreach ($atype_assoc as $key => $val) { + if(in_array($s['a_codec'], $atype_assoc[$key])) { + $img_flag_atype = ''; + } + } + // episode audio channel + foreach ($achan_assoc as $val) { + if (is_numeric($s['a_chan']) && $s['a_chan'] >= $val) { + $img_flag_achan = ''; + } + } + // episode audio language + if (file_exists('templates/' . $setting['theme'] . '/img/flags/l_' . check_flag($s['a_lang'], $iso_lang) . '.png')) { + $img_flag_alang = ''; + } else { + $img_flag_alang = $s['a_lang']; + } + $output_episode['img_flag_a'].= $img_flag_atype . $img_flag_achan . $img_flag_alang; + } + } + if (isset($str['s'])) { + foreach ($str['s'] as $s) { + // episode subtitles + if (file_exists('templates/' . $setting['theme'] . '/img/flags/l_' . check_flag($s['s_lang'], $iso_lang) . '.png')) { + $img_flag_slang = ''; + } else { + $img_flag_slang = $s['s_lang']; + } + $output_episode['img_flag_s'].= $img_flag_slang ; + } + } + if ($episodes['season'] <> $i) { + $show_episode['season_title'] = 1; + } + $i = $episodes['season']; + + $episode_list = new Teamplate('episodes.tpl', $setting, $lang); + foreach ($output_episode as $key => $val) { + $episode_list->tpl($key, $val); + } + foreach ($show_episode as $key => $val) { + $episode_list->show($key, $val); + } + $output_epiosde_list.= $episode_list->init(); + $output_desc['episodes'] = $output_epiosde_list; + } + } + } + + // facebook meta data + if ($setting['show_facebook'] == 1) { + $show_desc['facebook_button'] = 1; + } + $url = 'http://' . $_SERVER['SERVER_NAME'] . implode('/', array_slice(explode('/', $_SERVER['REQUEST_URI']), 0, -1)) . '/'; + $output_desc['fb_url'] = $url . 'index.php?video=' . $video . '&fb_link=' . urlencode($list['title']) . ($video == 'movies' ? $list['year'] : ''); + if ($id <> 0) { + $output['meta_img'] = (file_exists('cache/' . $mysql_table . '_' . $id . '.jpg') ? $url . 'cache/' . $mysql_table . '_' . $id . '.jpg' : 'templates/' . $setting['theme'] . '/img/d_poster.jpg'); + $output['meta_title'] = htmlspecialchars($list['title']); + $output['meta_desc'] = htmlspecialchars($list['plot']); + $output['meta_url'] = $output_desc['fb_url']; + $output['meta_type'] = ($video == 'tvshows' ? 'video.tv_show' : 'video.movie'); + } + + // panel movie + $panel_list = new Teamplate($views[$include_view] . '.tpl', $setting, $lang); + foreach ($output_desc as $key => $val) { + $panel_list->tpl($key, $val); + } + foreach ($show_desc as $key => $val) { + $panel_list->show($key, $val); + } + $output_panel_list.= $panel_list->init(); +} +$output['panel_list'] = $output_panel_list; +$output['sort'] = $sort; + +// faccebok meta data +if ($id == 0) { + $url = 'http://' . $_SERVER['SERVER_NAME'] . implode('/', array_slice(explode('/', $_SERVER['REQUEST_URI']), 0, -1)) . '/'; + $output['meta_title'] = $setting['site_name']; + $output['meta_url'] = $url . 'index.php'; + $output['meta_img'] = $url . ('templates/' . $setting['theme'] . '/img/logo.jpg'); + $output['meta_type'] = 'website'; + $output['meta_desc'] = 'Page whereby using XBMC can present your library of movies and TV series.'; +} +if ($setting['show_facebook'] == 1) { + $show['facebook'] = 1; + if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { + $get_lang = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2)); + } else { + $get_lang = 'en'; + } + if (array_key_exists ($get_lang , $lang_fb_assoc)) { + $lang_fb = $lang_fb_assoc[$get_lang]; + } else { + $lang_fb = $lang_fb_assoc['en']; + } + $output['facebook'] = '
    + '; +} + +// create page +$index = new Teamplate('index.tpl', $setting, $lang); +foreach ($output as $key => $val) { + $index->tpl($key, $val); +} +foreach ($show as $key => $val) { + $index->show($key, $val); +} + +$site = $index->init(); +print $site; + +?> \ No newline at end of file diff --git a/movielib/install.php b/movielib/install.php new file mode 100644 index 0000000..eed4b45 --- /dev/null +++ b/movielib/install.php @@ -0,0 +1,186 @@ +' . $lang_title . ''; + } +} +include('lang/' . $install_lang . '/lang.php'); +$output_panel = ''; + +switch ($option) { + + case 'license': + /* ########### + * # LICENSE # + */########### + $license_file = 'LICENSE.txt'; + if (file_exists($license_file)) { + $fp = fopen($license_file, 'r'); + $license = fread($fp, 88192); + } else { + $license = 'No license file.'; + } + $title = $lang['ins_license']; + $output_panel = ' +
    + +
    + ' . $lang['ins_accept'] . ' + '; + break; + + case 'database': + /* ################ + * # SET DATABASE # + */################ + if (file_exists('db.php')) { + $output_panel_info.= $lang['ins_db_exist'] . '
    '; + } + $title = $lang['inst_conn_db']; + $output_panel = ' +
    + + + + + + +
    ' . $lang['inst_server'] . ':
    ' . $lang['inst_port'] . ':
    ' . $lang['inst_login'] . ':
    ' . $lang['inst_pass'] . ':
    ' . $lang['inst_database'] . ':
    + +
    '; + break; + + case 'success': + /* ################## + * # CHECK DATABASE # + */################## + $conn_install = mysql_connect($_POST['host'] . ':' . $_POST['port'], $_POST['login'], $_POST['pass']); + if (!$conn_install) { + die($lang['ins_could_connect'] . ' - ' . mysql_error()); + } + $create_sql = 'CREATE DATABASE IF NOT EXISTS ' . $_POST['database']; + mysql_q($create_sql); + + $sel_install = mysql_select_db($_POST['database']); + if (!$sel_install) { + die($lang['ins_could_connect'] . ' - ' . mysql_error()); + } + create_table($mysql_tables, $mysql_indexes, $lang, $version, 1); + + // create db.php + $to_write = ''; + $fp = @fopen('db.php', 'w'); + if (!$fp) { + $title = $lang['ins_error']; + if (file_exists('db.php')) { + $output_panel_error.= $lang['ins_file_db_ex'] . ' ' . substr(decoct(fileperms('db.php')), -3) . '
    '; + } else { + $output_panel_error.= $lang['ins_file_db_not'] . ' ' . substr(decoct(fileperms('.')), -3) . '
    '; + } + $output_panel = ' +
    ' . $lang['ins_file_db_cre'] . ':
    +
    + +
    '; + } else { + fwrite($fp, $to_write); + fclose($fp); + $title = $lang['ins_finished']; + $output_panel = '' . $lang['ins_admin'] . ''; + } + + // delete session var + $_SESSION = array(); + + break; + + default: + /* ########## + * # README # + */########## + + $readme_file = 'lang/' . $_SESSION['install_lang'] . '/readme'; + if (!file_exists($readme_file)) { + $readme_file = 'README.txt'; + } + $fp = fopen($readme_file, 'r'); + $readme = fread($fp, 88192); + $title = $lang['ins_lang_file']; + $output_panel = ' +
    + +
    +
    + +
    + ' . $lang['ins_next'] . ' + '; + break; + +} + +/* ############## + * # PANEL INFO # + */############## +if ($output_panel_info !== '') { + $output_panel_info = '
    ' . $output_panel_info . '
    '; +} +if ($output_panel_error !== '') { + $output_panel_error = '
    ' . $output_panel_error . '
    '; +} +?> + + + + MovieLib - <?PHP echo $lang['ins_title'] ?> + + + + + + + + + + +
    +
    + +
    + + \ No newline at end of file diff --git a/movielib/js/jquery-1.9.1.js b/movielib/js/jquery-1.9.1.js new file mode 100644 index 0000000..e2c203f --- /dev/null +++ b/movielib/js/jquery-1.9.1.js @@ -0,0 +1,9597 @@ +/*! + * jQuery JavaScript Library v1.9.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-2-4 + */ +(function( window, undefined ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +//"use strict"; +var + // The deferred used on DOM ready + readyList, + + // A central reference to the root jQuery(document) + rootjQuery, + + // Support: IE<9 + // For `typeof node.method` instead of `node.method !== undefined` + core_strundefined = typeof undefined, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + location = window.location, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // [[Class]] -> type pairs + class2type = {}, + + // List of deleted data cache ids, so we can reuse them + core_deletedIds = [], + + core_version = "1.9.1", + + // Save a reference to some core methods + core_concat = core_deletedIds.concat, + core_push = core_deletedIds.push, + core_slice = core_deletedIds.slice, + core_indexOf = core_deletedIds.indexOf, + core_toString = class2type.toString, + core_hasOwn = class2type.hasOwnProperty, + core_trim = core_version.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, + + // Used for splitting on whitespace + core_rnotwhite = /\S+/g, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // The ready event handler + completed = function( event ) { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } + }, + // Clean-up method for dom ready events + detach = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: core_version, + + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + if ( obj == null ) { + return String( obj ); + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ core_toString.call(obj) ] || "object" : + typeof obj; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // keepScripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, keepScripts ) { + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + context = context || document; + + var parsed = rsingleTag.exec( data ), + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ); + if ( scripts ) { + jQuery( scripts ).remove(); + } + return jQuery.merge( [], parsed.childNodes ); + }, + + parseJSON: function( data ) { + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + if ( data === null ) { + return data; + } + + if ( typeof data === "string" ) { + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + if ( data ) { + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + } + } + } + + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + core_push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return core_concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || type !== "function" && + ( length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj ); +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, all, a, + input, select, fragment, + opt, eventName, isSupported, i, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
    a"; + + // Support tests won't run in some limited or non-browser environments + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + if ( !all || !a || !all.length ) { + return {}; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + support = { + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) + checkOn: !!input.value, + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Tests for enctype support on a form (#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: document.compatMode === "CSS1Compat", + + // Will be defined later + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Support: IE<9 + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + // Check if we can trust getAttribute("value") + input = document.createElement("input"); + input.setAttribute( "value", "" ); + support.input = input.getAttribute( "value" ) === ""; + + // Check if an input maintains its value after becoming a radio + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "checked", "t" ); + input.setAttribute( "name", "t" ); + + fragment = document.createDocumentFragment(); + fragment.appendChild( input ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php + for ( i in { submit: true, change: true, focusin: true }) { + div.setAttribute( eventName = "on" + i, "t" ); + + support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; + } + + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, marginDiv, tds, + divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; + + body.appendChild( container ).appendChild( div ); + + // Support: IE8 + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Support: IE8 + // Check if empty table cells still have offsetWidth/Height + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // Use window.getComputedStyle because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. (#3333) + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = div.appendChild( document.createElement("div") ); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== core_strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + div.style.display = "block"; + div.innerHTML = "
    "; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + if ( support.inlineBlockNeedsLayout ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); + + // Null elements to avoid leaks in IE + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + all = select = fragment = opt = a = input = null; + + return support; +})(); + +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +function internalData( elem, name, data, pvt /* Internal Use Only */ ){ + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var i, l, thisCache, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + // Do not set data on non-element because it will not be cleared (#8335). + if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { + return false; + } + + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var attrs, name, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attrs = elem.attributes; + for ( ; i < attrs.length; i++ ) { + name = attrs[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.slice(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + // Try to fetch any internally stored data first + return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; + } + + this.each(function() { + jQuery.data( this, key, value ); + }); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + hooks.cur = fn; + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rfocusable = /^(?:input|select|textarea|button|object)$/i, + rclickable = /^(?:a|area)$/i, + rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, + ruseDefault = /^(?:checked|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + getSetInput = jQuery.support.input; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call( this, j, this.className ) ); + }); + } + + if ( proceed ) { + // The disjunction here is for better compressibility (see removeClass) + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + " " + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + elem.className = jQuery.trim( cur ); + + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = arguments.length === 0 || typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call( this, j, this.className ) ); + }); + } + if ( proceed ) { + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + "" + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + elem.className = value ? jQuery.trim( cur ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.match( core_rnotwhite ) || []; + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + // Toggle whole class name + } else if ( type === core_strundefined || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // If the element has a class name or if we're passed "false", + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var ret, hooks, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attr: function( elem, name, value ) { + var hooks, notxml, ret, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === core_strundefined ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + + } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + // In IE9+, Flash objects don't have .getAttribute (#12945) + // Support: IE9+ + if ( typeof elem.getAttribute !== core_strundefined ) { + ret = elem.getAttribute( name ); + } + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var name, propName, + i = 0, + attrNames = value && value.match( core_rnotwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( (name = attrNames[i++]) ) { + propName = jQuery.propFix[ name ] || name; + + // Boolean attributes get special treatment (#10870) + if ( rboolean.test( name ) ) { + // Set corresponding property to false for boolean attributes + // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 + if ( !getSetAttribute && ruseDefault.test( name ) ) { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } else { + elem[ propName ] = false; + } + + // See #9699 for explanation of this approach (setting first, then removal) + } else { + jQuery.attr( elem, name, "" ); + } + + elem.removeAttribute( getSetAttribute ? name : propName ); + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to default in case type is set after value during creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + 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( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + var + // Use .prop to determine if this attribute is understood as boolean + prop = jQuery.prop( elem, name ), + + // Fetch it accordingly + attr = typeof prop === "boolean" && elem.getAttribute( name ), + detail = typeof prop === "boolean" ? + + getSetInput && getSetAttribute ? + attr != null : + // oldIE fabricates an empty string for missing boolean attributes + // and conflates checked/selected into attroperties + ruseDefault.test( name ) ? + elem[ jQuery.camelCase( "default-" + name ) ] : + !!attr : + + // fetch an attribute node for properties not recognized as boolean + elem.getAttributeNode( name ); + + return detail && detail.value !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + // IE<8 needs the *property* name + elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); + + // Use defaultChecked and defaultSelected for oldIE + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; + } + + return name; + } +}; + +// fix oldIE value attroperty +if ( !getSetInput || !getSetAttribute ) { + jQuery.attrHooks.value = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return jQuery.nodeName( elem, "input" ) ? + + // Ignore the value *property* by using defaultValue + elem.defaultValue : + + ret && ret.specified ? ret.value : undefined; + }, + set: function( elem, value, name ) { + if ( jQuery.nodeName( elem, "input" ) ) { + // Does not return so that setAttribute is also used + elem.defaultValue = value; + } else { + // Use nodeHook if defined (#1954); otherwise setAttribute is fine + return nodeHook && nodeHook.set( elem, value, name ); + } + } + }; +} + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + elem.setAttributeNode( + (ret = elem.ownerDocument.createAttribute( name )) + ); + } + + ret.value = value += ""; + + // Break association with cloned elements by also using setAttribute (#9646) + return name === "value" || value === elem.getAttribute( name ) ? + value : + undefined; + } + }; + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + nodeHook.set( elem, value === "" ? false : value, name ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret == null ? undefined : ret; + } + }); + }); + + // href/src property should get the full normalized URL (#10299/#12915) + jQuery.each([ "href", "src" ], function( i, name ) { + jQuery.propHooks[ name ] = { + get: function( elem ) { + return elem.getAttribute( name, 4 ); + } + }; + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Note: IE uppercases css property names, but if we were to .toLowerCase() + // .cssText, that would destroy case senstitivity in URL's, like in "background" + return elem.style.cssText || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = core_hasOwn.call( event, "type" ) ? event.type : event, + namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + event.isTrigger = true; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = core_slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + for ( ; cur != this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + } + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== document.activeElement && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === document.activeElement && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === core_strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var i, + cachedruns, + Expr, + getText, + isXML, + compile, + hasDuplicate, + outermostContext, + + // Local document vars + setDocument, + document, + docElem, + documentIsXML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + sortOrder, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + support = {}, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Array methods + arr = [], + pop = arr.pop, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments quoted, + // then not containing pseudos/brackets, + // then attribute selectors/non-parenthetical expressions, + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rsibling = /[\x20\t\r\n\f]*[+~]/, + + rnative = /^[^{]+\{\s*\[native code/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, + funescape = function( _, escaped ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + return high !== high ? + escaped : + // BMP codepoint + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Use a stripped-down slice if we can't use a native one +try { + slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + while ( (elem = this[i++]) ) { + results.push( elem ); + } + return results; + }; +} + +/** + * For feature detection + * @param {Function} fn The function to test for native support + */ +function isNative( fn ) { + return rnative.test( fn + "" ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var cache, + keys = []; + + return (cache = function( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key += " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key ] = value); + }); +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( !documentIsXML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + + // QSA path + if ( support.qsa && !rbuggyQSA.test(selector) ) { + old = true; + nid = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Detect xml + * @param {Element|Object} elem An element or a document + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var doc = node ? node.ownerDocument || node : preferredDoc; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsXML = isXML( doc ); + + // Check if getElementsByTagName("*") returns only elements + support.tagNameNoComments = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if attributes should be retrieved by attribute nodes + support.attributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }); + + // Check if getElementsByClassName can be trusted + support.getByClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }); + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + support.getByName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
    "; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = doc.getElementsByName && + // buggy browsers will return fewer than the correct 2 + doc.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + doc.getElementsByName( expando + 0 ).length; + support.getIdNotName = !doc.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + + // IE6/7 return modified attributes + Expr.attrHandle = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }) ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }; + + // ID find and filter + if ( support.getIdNotName ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.tagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Name + Expr.find["NAME"] = support.getByName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }; + + // Class + Expr.find["CLASS"] = support.getByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { + return context.getElementsByClassName( className ); + } + }; + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21), + // no need to also add to buggyMatches since matches checks buggyQSA + // A support test would require too much code (would include document ready) + rbuggyQSA = [ ":focus" ]; + + if ( (support.qsa = isNative(doc.querySelectorAll)) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE8 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = ""; + if ( div.querySelectorAll("[i^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = new RegExp( rbuggyMatches.join("|") ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + // Document order sorting + sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + var compare; + + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) { + if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) { + if ( a === doc || contains( preferredDoc, a ) ) { + return -1; + } + if ( b === doc || contains( preferredDoc, b ) ) { + return 1; + } + return 0; + } + return compare & 4 ? -1 : 1; + } + + return a.compareDocumentPosition ? -1 : 1; + } : + function( a, b ) { + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Parentless nodes are either documents or disconnected + } else if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + // Always assume the presence of duplicates if sort doesn't + // pass them to our comparison function (as in Google Chrome). + hasDuplicate = false; + [0, 0].sort( sortOrder ); + support.detectDuplicates = hasDuplicate; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyQSA always contains :focus, so no need for an existence check + if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [elem] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + var val; + + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + if ( !documentIsXML ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( documentIsXML || support.attributes ) { + return elem.getAttribute( name ); + } + return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? + name : + val && val.specified ? val.value : null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 1, + j = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[5] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[4] ) { + match[2] = match[4]; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + + nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifider + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsXML ? + elem.getAttribute("xml:lang") || elem.getAttribute("lang") : + elem.lang) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push( { + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var data, cache, outerCache, + dirkey = dirruns + " " + doneName; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { + if ( (data = cache[1]) === true || data === cachedruns ) { + return data === true; + } + } else { + cache = outerCache[ dir ] = [ dirkey ]; + cache[1] = matcher( elem, context, xml ) || cachedruns; + if ( cache[1] === true ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + // A counter to specify which element is currently being matched + var matcherCachedRuns = 0, + bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = matcherCachedRuns; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++matcherCachedRuns; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + match = tokenize( selector ); + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !documentIsXML && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && context.parentNode || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + documentIsXML, + results, + rsibling.test( selector ) + ); + return results; +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Easy API for creating new setFilters +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Initialize with the default document +setDocument(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, ret, self, + len = this.length; + + if ( typeof selector !== "string" ) { + self = this; + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + ret = []; + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, this[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false) ); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true) ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( jQuery.unique(all) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
    ", "
    " ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
    " ], + tr: [ 2, "", "
    " ], + col: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
    ", "
    " ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + var isFunc = jQuery.isFunction( value ); + + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( !isFunc && typeof value !== "string" ) { + value = jQuery( value ).not( this ).detach(); + } + + return this.domManip( [ value ], true, function( elem ) { + var next = this.nextSibling, + parent = this.parentNode; + + if ( parent ) { + jQuery( this ).remove(); + parent.insertBefore( elem, next ); + } + }); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = core_concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, table ? self.html() : undefined ); + } + self.domManip( args, table, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + node, + i + ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Hope ajax is available... + jQuery.ajax({ + url: node.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + var attr = elem.getAttributeNode("type"); + elem.type = ( attr && attr.specified ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + core_push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( manipulation_rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
    " && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== core_strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + core_deletedIds.push( id ); + } + } + } + } + } +}); +var iframe, getStyles, curCSS, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity\s*=\s*([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var display, elem, hidden, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + values[ index ] = jQuery._data( elem, "olddisplay" ); + display = elem.style.display; + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + + if ( !values[ index ] ) { + hidden = isHidden( elem ); + + if ( display && display !== "none" || !hidden ) { + jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); + } + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + var len, styles, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + var bool = typeof state === "boolean"; + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "columnCount": true, + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, + // but it would mean to define eight (for every problematic property) identical functions + if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var num, val, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: we've included the "window" in window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + getStyles = function( elem ) { + return window.getComputedStyle( elem, null ); + }; + + curCSS = function( elem, name, _computed ) { + var width, minWidth, maxWidth, + computed = _computed || getStyles( elem ), + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, + style = elem.style; + + if ( computed ) { + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + getStyles = function( elem ) { + return elem.currentStyle; + }; + + curCSS = function( elem, name, _computed ) { + var left, rs, rsLeft, + computed = _computed || getStyles( elem ), + ret = computed ? computed[ name ] : undefined, + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rs = elem.runtimeStyle; + rsLeft = rs && rs.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + rs.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + rs.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + // at this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var valueIsBorderBox = true, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + styles = getStyles( elem ), + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + // Use the already-created iframe if possible + iframe = ( iframe || + jQuery("