From 81675874b9a928c6fa1c3ee2d9da706dd9d2259a Mon Sep 17 00:00:00 2001 From: root Date: Sat, 16 Jan 2010 16:13:20 +0100 Subject: [PATCH] Initial checkin. --- www/banners.json | 22 +- www/ipfire.py | 24 - www/menu.json | 39 +- www/pages/builds.py | 190 --- www/pages/cluster.py | 103 -- www/pages/static/ancient_download.xml | 212 ---- www/pages/static/download.xml | 143 --- www/pages/static/imprint.xml | 127 -- www/pages/static/index.xml | 107 -- www/pages/static/links.xml | 149 --- www/pages/torrent/__init__.py | 88 -- www/pages/torrent/client/ConfigDir.py | 401 ------- www/pages/torrent/client/ConfigReader.py | 1068 ----------------- www/pages/torrent/client/ConnChoice.py | 31 - www/pages/torrent/client/CreateIcons.py | 105 -- .../torrent/client/CurrentRateMeasure.py | 37 - www/pages/torrent/client/HTTPHandler.py | 167 --- www/pages/torrent/client/PSYCO.py | 5 - www/pages/torrent/client/RateLimiter.py | 153 --- www/pages/torrent/client/RateMeasure.py | 75 -- www/pages/torrent/client/RawServer.py | 195 --- www/pages/torrent/client/ServerPortHandler.py | 188 --- www/pages/torrent/client/SocketHandler.py | 375 ------ www/pages/torrent/client/__init__.py | 63 - www/pages/torrent/client/bencode.py | 319 ----- www/pages/torrent/client/bitfield.py | 162 --- www/pages/torrent/client/clock.py | 27 - www/pages/torrent/client/download_bt1.py | 882 -------------- www/pages/torrent/client/inifile.py | 169 --- www/pages/torrent/client/iprangeparse.py | 194 --- www/pages/torrent/client/launchmanycore.py | 381 ------ www/pages/torrent/client/natpunch.py | 254 ---- www/pages/torrent/client/parseargs.py | 137 --- www/pages/torrent/client/parsedir.py | 150 --- www/pages/torrent/client/piecebuffer.py | 86 -- www/pages/torrent/client/selectpoll.py | 109 -- www/pages/torrent/client/subnetparse.py | 218 ---- www/pages/torrent/client/torrentlistparse.py | 38 - www/pages/torrent/client/zurllib.py | 100 -- www/pages/translate/__init__.py | 163 --- www/releases.json | 87 ++ www/{include => static/css}/ie6.css | 0 www/static/css/jquery.megamenu.css | 144 +++ www/{include => static/css}/style.css | 56 +- www/{ => static}/favicon.ico | Bin www/{ => static}/images/Network-1.png | Bin www/{ => static}/images/Stats1.png | Bin www/{ => static}/images/Stats2.png | Bin www/{ => static}/images/art/Banner.png | Bin www/{ => static}/images/art/Banner_thumb.png | Bin www/{ => static}/images/art/CD1.png | Bin www/{ => static}/images/art/CD1_thumb.png | Bin www/{ => static}/images/art/CD2.png | Bin www/{ => static}/images/art/CD2_thumb.png | Bin www/{ => static}/images/art/Firetest1.png | Bin www/{ => static}/images/art/Tux.png | Bin www/{ => static}/images/art/Tux_thumb.png | Bin www/{ => static}/images/art/logo2.png | Bin www/{ => static}/images/bg-menu99.png | Bin www/{ => static}/images/bg-shl.png | Bin www/{ => static}/images/bg-shr.png | Bin www/{ => static}/images/bg.png | Bin www/{ => static}/images/bg1.png | Bin www/{ => static}/images/box_ipfire.png | Bin www/{ => static}/images/btn-blue.png | Bin www/{ => static}/images/btn-break.png | Bin www/{ => static}/images/btn-empty.png | Bin www/{ => static}/images/btn-green.png | Bin www/{ => static}/images/btn-orange.png | Bin www/{ => static}/images/btn-red.png | Bin www/{ => static}/images/btn-red2.png | Bin www/{ => static}/images/btn-white.png | Bin www/{ => static}/images/btn-yellow.png | Bin .../images/buttons/cebit_96x320.png | Bin .../images/buttons/download_core_96x320.png | Bin www/{ => static}/images/cebit-171px.png | Bin .../images/cebit-177px_schatten.png | Bin www/{ => static}/images/cebit2010_logo_en.png | Bin www/{ => static}/images/de.gif | Bin www/{ => static}/images/development.png | Bin www/{ => static}/images/download.png | Bin www/{ => static}/images/en.gif | Bin www/{ => static}/images/error/403.png | Bin www/{ => static}/images/error/404.png | Bin www/{ => static}/images/error/500.png | Bin www/{ => static}/images/features.png | Bin www/{ => static}/images/feed.png | Bin www/{ => static}/images/flags/ad.png | Bin www/{ => static}/images/flags/ae.png | Bin www/{ => static}/images/flags/af.png | Bin www/{ => static}/images/flags/ag.png | Bin www/{ => static}/images/flags/ai.png | Bin www/{ => static}/images/flags/al.png | Bin www/{ => static}/images/flags/am.png | Bin www/{ => static}/images/flags/an.png | Bin www/{ => static}/images/flags/ao.png | Bin www/{ => static}/images/flags/ar.png | Bin www/{ => static}/images/flags/as.png | Bin www/{ => static}/images/flags/at.png | Bin www/{ => static}/images/flags/au.png | Bin www/{ => static}/images/flags/aw.png | Bin www/{ => static}/images/flags/ax.png | Bin www/{ => static}/images/flags/az.png | Bin www/{ => static}/images/flags/ba.png | Bin www/{ => static}/images/flags/bb.png | Bin www/{ => static}/images/flags/bd.png | Bin www/{ => static}/images/flags/be.png | Bin www/{ => static}/images/flags/bf.png | Bin www/{ => static}/images/flags/bg.png | Bin www/{ => static}/images/flags/bh.png | Bin www/{ => static}/images/flags/bi.png | Bin www/{ => static}/images/flags/bj.png | Bin www/{ => static}/images/flags/bm.png | Bin www/{ => static}/images/flags/bn.png | Bin www/{ => static}/images/flags/bo.png | Bin www/{ => static}/images/flags/br.png | Bin www/{ => static}/images/flags/bs.png | Bin www/{ => static}/images/flags/bt.png | Bin www/{ => static}/images/flags/bv.png | Bin www/{ => static}/images/flags/bw.png | Bin www/{ => static}/images/flags/by.png | Bin www/{ => static}/images/flags/bz.png | Bin www/{ => static}/images/flags/ca.png | Bin www/{ => static}/images/flags/catalonia.png | Bin www/{ => static}/images/flags/cc.png | Bin www/{ => static}/images/flags/cd.png | Bin www/{ => static}/images/flags/cf.png | Bin www/{ => static}/images/flags/cg.png | Bin www/{ => static}/images/flags/ch.png | Bin www/{ => static}/images/flags/ci.png | Bin www/{ => static}/images/flags/ck.png | Bin www/{ => static}/images/flags/cl.png | Bin www/{ => static}/images/flags/cm.png | Bin www/{ => static}/images/flags/cn.png | Bin www/{ => static}/images/flags/co.png | Bin www/{ => static}/images/flags/cr.png | Bin www/{ => static}/images/flags/cs.png | Bin www/{ => static}/images/flags/cu.png | Bin www/{ => static}/images/flags/cv.png | Bin www/{ => static}/images/flags/cx.png | Bin www/{ => static}/images/flags/cy.png | Bin www/{ => static}/images/flags/cz.png | Bin www/{ => static}/images/flags/da.png | 0 www/{ => static}/images/flags/de.png | Bin www/{ => static}/images/flags/dj.png | Bin www/{ => static}/images/flags/dk.png | Bin www/{ => static}/images/flags/dm.png | Bin www/{ => static}/images/flags/do.png | Bin www/{ => static}/images/flags/dz.png | Bin www/{ => static}/images/flags/ec.png | Bin www/{ => static}/images/flags/ee.png | Bin www/{ => static}/images/flags/eg.png | Bin www/{ => static}/images/flags/eh.png | Bin www/{ => static}/images/flags/england.png | Bin www/{ => static}/images/flags/er.png | Bin www/{ => static}/images/flags/es.png | Bin www/{ => static}/images/flags/et.png | Bin .../images/flags/europeanunion.png | Bin www/{ => static}/images/flags/fam.png | Bin www/{ => static}/images/flags/fi.png | Bin www/{ => static}/images/flags/fj.png | Bin www/{ => static}/images/flags/fk.png | Bin www/{ => static}/images/flags/fm.png | Bin www/{ => static}/images/flags/fo.png | Bin www/{ => static}/images/flags/fr.png | Bin www/{ => static}/images/flags/ga.png | Bin www/{ => static}/images/flags/gb.png | Bin www/{ => static}/images/flags/gd.png | Bin www/{ => static}/images/flags/ge.png | Bin www/{ => static}/images/flags/gf.png | Bin www/{ => static}/images/flags/gh.png | Bin www/{ => static}/images/flags/gi.png | Bin www/{ => static}/images/flags/gl.png | Bin www/{ => static}/images/flags/gm.png | Bin www/{ => static}/images/flags/gn.png | Bin www/{ => static}/images/flags/gp.png | Bin www/{ => static}/images/flags/gq.png | Bin www/{ => static}/images/flags/gr.png | Bin www/{ => static}/images/flags/gs.png | Bin www/{ => static}/images/flags/gt.png | Bin www/{ => static}/images/flags/gu.png | Bin www/{ => static}/images/flags/gw.png | Bin www/{ => static}/images/flags/gy.png | Bin www/{ => static}/images/flags/hk.png | Bin www/{ => static}/images/flags/hm.png | Bin www/{ => static}/images/flags/hn.png | Bin www/{ => static}/images/flags/hr.png | Bin www/{ => static}/images/flags/ht.png | Bin www/{ => static}/images/flags/hu.png | Bin www/{ => static}/images/flags/id.png | Bin www/{ => static}/images/flags/ie.png | Bin www/{ => static}/images/flags/il.png | Bin www/{ => static}/images/flags/in.png | Bin www/{ => static}/images/flags/io.png | Bin www/{ => static}/images/flags/iq.png | Bin www/{ => static}/images/flags/ir.png | Bin www/{ => static}/images/flags/is.png | Bin www/{ => static}/images/flags/it.png | Bin www/{ => static}/images/flags/jm.png | Bin www/{ => static}/images/flags/jo.png | Bin www/{ => static}/images/flags/jp.png | Bin www/{ => static}/images/flags/ke.png | Bin www/{ => static}/images/flags/kg.png | Bin www/{ => static}/images/flags/kh.png | Bin www/{ => static}/images/flags/ki.png | Bin www/{ => static}/images/flags/km.png | Bin www/{ => static}/images/flags/kn.png | Bin www/{ => static}/images/flags/kp.png | Bin www/{ => static}/images/flags/kr.png | Bin www/{ => static}/images/flags/kw.png | Bin www/{ => static}/images/flags/ky.png | Bin www/{ => static}/images/flags/kz.png | Bin www/{ => static}/images/flags/la.png | Bin www/{ => static}/images/flags/lb.png | Bin www/{ => static}/images/flags/lc.png | Bin www/{ => static}/images/flags/li.png | Bin www/{ => static}/images/flags/lk.png | Bin www/{ => static}/images/flags/lr.png | Bin www/{ => static}/images/flags/ls.png | Bin www/{ => static}/images/flags/lt.png | Bin www/{ => static}/images/flags/lu.png | Bin www/{ => static}/images/flags/lv.png | Bin www/{ => static}/images/flags/ly.png | Bin www/{ => static}/images/flags/ma.png | Bin www/{ => static}/images/flags/mc.png | Bin www/{ => static}/images/flags/md.png | Bin www/{ => static}/images/flags/me.png | Bin www/{ => static}/images/flags/mg.png | Bin www/{ => static}/images/flags/mh.png | Bin www/{ => static}/images/flags/mk.png | Bin www/{ => static}/images/flags/ml.png | Bin www/{ => static}/images/flags/mm.png | Bin www/{ => static}/images/flags/mn.png | Bin www/{ => static}/images/flags/mo.png | Bin www/{ => static}/images/flags/mp.png | Bin www/{ => static}/images/flags/mq.png | Bin www/{ => static}/images/flags/mr.png | Bin www/{ => static}/images/flags/ms.png | Bin www/{ => static}/images/flags/mt.png | Bin www/{ => static}/images/flags/mu.png | Bin www/{ => static}/images/flags/mv.png | Bin www/{ => static}/images/flags/mw.png | Bin www/{ => static}/images/flags/mx.png | Bin www/{ => static}/images/flags/my.png | Bin www/{ => static}/images/flags/mz.png | Bin www/{ => static}/images/flags/na.png | Bin www/{ => static}/images/flags/nc.png | Bin www/{ => static}/images/flags/ne.png | Bin www/{ => static}/images/flags/nf.png | Bin www/{ => static}/images/flags/ng.png | Bin www/{ => static}/images/flags/ni.png | Bin www/{ => static}/images/flags/nl.png | Bin www/{ => static}/images/flags/no.png | Bin www/{ => static}/images/flags/np.png | Bin www/{ => static}/images/flags/nr.png | Bin www/{ => static}/images/flags/nu.png | Bin www/{ => static}/images/flags/nz.png | Bin www/{ => static}/images/flags/om.png | Bin www/{ => static}/images/flags/pa.png | Bin www/{ => static}/images/flags/pe.png | Bin www/{ => static}/images/flags/pf.png | Bin www/{ => static}/images/flags/pg.png | Bin www/{ => static}/images/flags/ph.png | Bin www/{ => static}/images/flags/pk.png | Bin www/{ => static}/images/flags/pl.png | Bin www/{ => static}/images/flags/pm.png | Bin www/{ => static}/images/flags/pn.png | Bin www/{ => static}/images/flags/pr.png | Bin www/{ => static}/images/flags/ps.png | Bin www/{ => static}/images/flags/pt.png | Bin www/{ => static}/images/flags/pw.png | Bin www/{ => static}/images/flags/py.png | Bin www/{ => static}/images/flags/qa.png | Bin www/{ => static}/images/flags/re.png | Bin www/{ => static}/images/flags/ro.png | Bin www/{ => static}/images/flags/rs.png | Bin www/{ => static}/images/flags/ru.png | Bin www/{ => static}/images/flags/rw.png | Bin www/{ => static}/images/flags/sa.png | Bin www/{ => static}/images/flags/sb.png | Bin www/{ => static}/images/flags/sc.png | Bin www/{ => static}/images/flags/scotland.png | Bin www/{ => static}/images/flags/sd.png | Bin www/{ => static}/images/flags/se.png | Bin www/{ => static}/images/flags/sg.png | Bin www/{ => static}/images/flags/sh.png | Bin www/{ => static}/images/flags/si.png | Bin www/{ => static}/images/flags/sj.png | Bin www/{ => static}/images/flags/sk.png | Bin www/{ => static}/images/flags/sl.png | Bin www/{ => static}/images/flags/sm.png | Bin www/{ => static}/images/flags/sn.png | Bin www/{ => static}/images/flags/so.png | Bin www/{ => static}/images/flags/sr.png | Bin www/{ => static}/images/flags/st.png | Bin www/{ => static}/images/flags/sv.png | Bin www/{ => static}/images/flags/sy.png | Bin www/{ => static}/images/flags/sz.png | Bin www/{ => static}/images/flags/tc.png | Bin www/{ => static}/images/flags/td.png | Bin www/{ => static}/images/flags/tf.png | Bin www/{ => static}/images/flags/tg.png | Bin www/{ => static}/images/flags/th.png | Bin www/{ => static}/images/flags/tj.png | Bin www/{ => static}/images/flags/tk.png | Bin www/{ => static}/images/flags/tl.png | Bin www/{ => static}/images/flags/tm.png | Bin www/{ => static}/images/flags/tn.png | Bin www/{ => static}/images/flags/to.png | Bin www/{ => static}/images/flags/tr.png | Bin www/{ => static}/images/flags/tt.png | Bin www/{ => static}/images/flags/tv.png | Bin www/{ => static}/images/flags/tw.png | Bin www/{ => static}/images/flags/tz.png | Bin www/{ => static}/images/flags/ua.png | Bin www/{ => static}/images/flags/ug.png | Bin www/{ => static}/images/flags/um.png | Bin www/{ => static}/images/flags/us.png | Bin www/{ => static}/images/flags/uy.png | Bin www/{ => static}/images/flags/uz.png | Bin www/{ => static}/images/flags/va.png | Bin www/{ => static}/images/flags/vc.png | Bin www/{ => static}/images/flags/ve.png | Bin www/{ => static}/images/flags/vg.png | Bin www/{ => static}/images/flags/vi.png | Bin www/{ => static}/images/flags/vn.png | Bin www/{ => static}/images/flags/vu.png | Bin www/{ => static}/images/flags/wales.png | Bin www/{ => static}/images/flags/wf.png | Bin www/{ => static}/images/flags/ws.png | Bin www/{ => static}/images/flags/ye.png | Bin www/{ => static}/images/flags/yt.png | Bin www/{ => static}/images/flags/za.png | Bin www/{ => static}/images/flags/zm.png | Bin www/{ => static}/images/flags/zw.png | Bin www/{ => static}/images/ft.png | Bin www/{ => static}/images/icons/ipfire.png | Bin www/{ => static}/images/icons/ipfire_sw.png | Bin www/static/images/ipfire_download.png | Bin 0 -> 22597 bytes www/static/images/ipfire_download.png_1 | Bin 0 -> 17129 bytes www/{ => static}/images/lf1.png | Bin www/{ => static}/images/lf2.png | Bin www/{ => static}/images/lf3.png | Bin .../images/lightbox/lightbox-blank.gif | Bin .../images/lightbox/lightbox-btn-close.gif | Bin .../images/lightbox/lightbox-btn-next.gif | Bin .../images/lightbox/lightbox-btn-prev.gif | Bin .../images/lightbox/lightbox-ico-loading.gif | Bin www/{ => static}/images/links.png | Bin www/{ => static}/images/linux_icon.png | Bin .../images/linux_new_media_ag.jpg | Bin www/{ => static}/images/logo.png | Bin www/{ => static}/images/mac_icon.png | Bin www/{ => static}/images/mnu2l.png | Bin www/{ => static}/images/mnu2r.png | Bin www/{ => static}/images/mnu2t1.png | Bin www/{ => static}/images/mnu2t2.png | Bin www/{ => static}/images/n1.gif | Bin www/{ => static}/images/n2.gif | Bin www/{ => static}/images/n3.gif | Bin www/{ => static}/images/n4.gif | Bin www/{ => static}/images/n5.gif | Bin www/{ => static}/images/n6.gif | Bin www/{ => static}/images/paypal-folder.png | Bin www/{ => static}/images/pic.gif | Bin www/{ => static}/images/pic2.png | Bin www/{ => static}/images/progressbar.gif | Bin www/{ => static}/images/progressbg_black.gif | Bin www/{ => static}/images/progressbg_green.gif | Bin www/{ => static}/images/progressbg_orange.gif | Bin www/{ => static}/images/progressbg_red.gif | Bin www/{ => static}/images/progressbg_yellow.gif | Bin www/{ => static}/images/pxe.png | Bin .../images/screens/de/final/connsched.png | Bin .../images/screens/de/final/disk.png | Bin .../images/screens/de/final/dyndns.png | Bin .../images/screens/de/final/fwdiag.png | Bin .../images/screens/de/final/fwlog-port.png | Bin .../images/screens/de/final/fwlog.png | Bin .../images/screens/de/final/ids.png | Bin .../images/screens/de/final/index.png | Bin .../images/screens/de/final/ipsec.png | Bin .../images/screens/de/final/nettraffic.png | Bin .../images/screens/de/final/nw-internal.png | Bin .../images/screens/de/final/outgoingfw-1.png | Bin .../images/screens/de/final/outgoingfw-2.png | Bin .../images/screens/de/final/pakfire-1.png | Bin .../images/screens/de/final/pakfire-2.png | Bin .../images/screens/de/final/proxy.png | Bin .../images/screens/de/final/qos-2.png | Bin .../images/screens/de/final/samba.png | Bin .../images/screens/de/final/system.png | Bin .../screens/de/final/thumb/fwlog-port.png | Bin .../images/screens/de/final/thumb/index.png | Bin .../images/screens/de/final/thumb/ipsec.png | Bin .../screens/de/final/thumb/pakfire-1.png | Bin .../images/screens/de/final/thumb/proxy.png | Bin .../images/screens/de/final/thumb/qos-2.png | Bin .../images/screens/de/final/thumb/system.png | Bin .../images/screens/de/final/xtaccess.png | Bin .../images/screenshots/backup_de.png | Bin .../images/screenshots/backup_de_tn.png | Bin .../images/screenshots/backup_en.png | Bin .../images/screenshots/backup_en_tn.png | Bin .../images/screenshots/connections_de.png | Bin .../images/screenshots/connections_de_tn.png | Bin .../images/screenshots/connections_en.png | Bin .../images/screenshots/connections_en_tn.png | Bin .../images/screenshots/dhcp_de.png | Bin .../images/screenshots/dhcp_de_tn.png | Bin .../images/screenshots/dhcp_en.png | Bin .../images/screenshots/dhcp_en_tn.png | Bin .../images/screenshots/fwlog_ip_de.png | Bin .../images/screenshots/fwlog_ip_de_tn.png | Bin .../images/screenshots/fwlog_ip_en.png | Bin .../images/screenshots/fwlog_ip_en_tn.png | Bin .../images/screenshots/index_de.png | Bin .../images/screenshots/index_de_tn.png | Bin .../images/screenshots/index_en.png | Bin .../images/screenshots/index_en_tn.png | Bin .../images/screenshots/ipsec_de.png | Bin .../images/screenshots/ipsec_de_tn.png | Bin .../images/screenshots/ipsec_en.png | Bin .../images/screenshots/ipsec_en_tn.png | Bin .../images/screenshots/monitor.png | Bin .../images/screenshots/networkother_de.png | Bin .../images/screenshots/networkother_de_tn.png | Bin .../images/screenshots/networkother_en.png | Bin .../images/screenshots/networkother_en_tn.png | Bin .../images/screenshots/outgoing_fw_de.png | Bin .../images/screenshots/outgoing_fw_de_tn.png | Bin .../images/screenshots/outgoing_fw_en.png | Bin .../images/screenshots/outgoing_fw_en_tn.png | Bin .../images/screenshots/pakfire_de.png | Bin .../images/screenshots/pakfire_de_tn.png | Bin .../images/screenshots/pakfire_en.png | Bin .../images/screenshots/pakfire_en_tn.png | Bin .../images/screenshots/proxy_de.png | Bin .../images/screenshots/proxy_de_tn.png | Bin .../images/screenshots/proxy_en.png | Bin .../images/screenshots/proxy_en_tn.png | Bin .../images/screenshots/qos_de.png | Bin .../images/screenshots/qos_de_tn.png | Bin .../images/screenshots/qos_en.png | Bin .../images/screenshots/qos_en_tn.png | Bin .../images/screenshots/samba_de.png | Bin .../images/screenshots/samba_de_tn.png | Bin .../images/screenshots/samba_en.png | Bin .../images/screenshots/samba_en_tn.png | Bin .../images/screenshots/services_de.png | Bin .../images/screenshots/services_de_tn.png | Bin .../images/screenshots/services_en.png | Bin .../images/screenshots/services_en_tn.png | Bin www/{ => static}/images/sh-bl.png | Bin www/{ => static}/images/sh-br.png | Bin www/{ => static}/images/sh-btn.png | Bin www/{ => static}/images/sh-lft.png | Bin www/{ => static}/images/sh-rgt.png | Bin www/{ => static}/images/sh-tl.png | Bin www/{ => static}/images/sh-top.png | Bin www/{ => static}/images/sh-tr.png | Bin www/{ => static}/images/spacer.gif | Bin www/{ => static}/images/sponsors/isp42.png | Bin www/{ => static}/images/sponsors/isp42_2.png | Bin www/{ => static}/images/tux.png | Bin www/{ => static}/images/tux2-99.png | Bin www/{ => static}/images/tux2.png | Bin www/{ => static}/images/tux_menu_99x100.png | Bin .../images/ui-bg_flat_75_f5f5f5_40x100.png | Bin .../images/ui-bg_glass_75_dadada_1x400.png | Bin .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin www/{ => static}/images/win_icon.png | Bin www/{ => static}/images/x-click-but04.gif | Bin www/static/js/cluster.js | 65 + www/{include => static/js}/correctpng.js | 0 www/static/js/jquery-ui.js | 298 +++++ www/static/js/jquery.js | 19 + www/static/js/jquery.megamenu.js | 120 ++ .../js/jquery.progressbar.js} | 2 +- www/templates/base.html | 97 ++ www/templates/builds.html | 44 + www/templates/downloads-all.html | 23 + www/templates/downloads-development.html | 21 + www/templates/downloads-torrents.html | 43 + www/templates/downloads.html | 42 + www/templates/error-404.html | 1 + www/templates/error-500.html | 13 + www/templates/error.html | 28 + www/templates/index.html | 62 + www/templates/modules/builds.html | 15 + www/templates/modules/menu-item.html | 65 + www/templates/modules/menu.html | 7 + www/templates/modules/news-item.html | 6 + www/templates/modules/release-item.html | 15 + www/templates/modules/sidebar-banner.html | 5 + www/templates/modules/sidebar-item.html | 2 + www/templates/modules/sidebar-release.html | 23 + www/templates/news.html | 7 + www/templates/static/cluster.html | 35 + www/templates/static/imprint.html | 109 ++ www/templates/static/screenshots.html | 28 + www/templates/translations.html | 55 + www/translations/de_DE.csv | 25 + www/webapp.py | 12 + www/webapp/__init__.py | 57 + www/webapp/banners.py | 27 + www/webapp/builds.py | 85 ++ www/webapp/cluster.py | 149 +++ www/webapp/handlers.py | 208 ++++ www/webapp/helpers.py | 25 + www/webapp/menu.py | 38 + www/webapp/news.py | 35 + www/webapp/releases.py | 174 +++ www/webapp/translations.py | 102 ++ www/webapp/ui_modules.py | 84 ++ www/webapp/uriel.py | 87 ++ 517 files changed, 2650 insertions(+), 7451 deletions(-) delete mode 100755 www/ipfire.py delete mode 100644 www/pages/builds.py delete mode 100644 www/pages/cluster.py delete mode 100644 www/pages/static/ancient_download.xml delete mode 100644 www/pages/static/download.xml delete mode 100644 www/pages/static/imprint.xml delete mode 100644 www/pages/static/index.xml delete mode 100644 www/pages/static/links.xml delete mode 100644 www/pages/torrent/__init__.py delete mode 100644 www/pages/torrent/client/ConfigDir.py delete mode 100644 www/pages/torrent/client/ConfigReader.py delete mode 100644 www/pages/torrent/client/ConnChoice.py delete mode 100644 www/pages/torrent/client/CreateIcons.py delete mode 100644 www/pages/torrent/client/CurrentRateMeasure.py delete mode 100644 www/pages/torrent/client/HTTPHandler.py delete mode 100644 www/pages/torrent/client/PSYCO.py delete mode 100644 www/pages/torrent/client/RateLimiter.py delete mode 100644 www/pages/torrent/client/RateMeasure.py delete mode 100644 www/pages/torrent/client/RawServer.py delete mode 100644 www/pages/torrent/client/ServerPortHandler.py delete mode 100644 www/pages/torrent/client/SocketHandler.py delete mode 100644 www/pages/torrent/client/__init__.py delete mode 100644 www/pages/torrent/client/bencode.py delete mode 100644 www/pages/torrent/client/bitfield.py delete mode 100644 www/pages/torrent/client/clock.py delete mode 100644 www/pages/torrent/client/download_bt1.py delete mode 100644 www/pages/torrent/client/inifile.py delete mode 100644 www/pages/torrent/client/iprangeparse.py delete mode 100644 www/pages/torrent/client/launchmanycore.py delete mode 100644 www/pages/torrent/client/natpunch.py delete mode 100644 www/pages/torrent/client/parseargs.py delete mode 100644 www/pages/torrent/client/parsedir.py delete mode 100644 www/pages/torrent/client/piecebuffer.py delete mode 100644 www/pages/torrent/client/selectpoll.py delete mode 100644 www/pages/torrent/client/subnetparse.py delete mode 100644 www/pages/torrent/client/torrentlistparse.py delete mode 100644 www/pages/torrent/client/zurllib.py delete mode 100644 www/pages/translate/__init__.py create mode 100644 www/releases.json rename www/{include => static/css}/ie6.css (100%) create mode 100644 www/static/css/jquery.megamenu.css rename www/{include => static/css}/style.css (87%) rename www/{ => static}/favicon.ico (100%) rename www/{ => static}/images/Network-1.png (100%) rename www/{ => static}/images/Stats1.png (100%) rename www/{ => static}/images/Stats2.png (100%) rename www/{ => static}/images/art/Banner.png (100%) rename www/{ => static}/images/art/Banner_thumb.png (100%) rename www/{ => static}/images/art/CD1.png (100%) rename www/{ => static}/images/art/CD1_thumb.png (100%) rename www/{ => static}/images/art/CD2.png (100%) rename www/{ => static}/images/art/CD2_thumb.png (100%) rename www/{ => static}/images/art/Firetest1.png (100%) rename www/{ => static}/images/art/Tux.png (100%) rename www/{ => static}/images/art/Tux_thumb.png (100%) rename www/{ => static}/images/art/logo2.png (100%) rename www/{ => static}/images/bg-menu99.png (100%) rename www/{ => static}/images/bg-shl.png (100%) rename www/{ => static}/images/bg-shr.png (100%) rename www/{ => static}/images/bg.png (100%) rename www/{ => static}/images/bg1.png (100%) rename www/{ => static}/images/box_ipfire.png (100%) rename www/{ => static}/images/btn-blue.png (100%) rename www/{ => static}/images/btn-break.png (100%) rename www/{ => static}/images/btn-empty.png (100%) rename www/{ => static}/images/btn-green.png (100%) rename www/{ => static}/images/btn-orange.png (100%) rename www/{ => static}/images/btn-red.png (100%) rename www/{ => static}/images/btn-red2.png (100%) rename www/{ => static}/images/btn-white.png (100%) rename www/{ => static}/images/btn-yellow.png (100%) rename www/{ => static}/images/buttons/cebit_96x320.png (100%) rename www/{ => static}/images/buttons/download_core_96x320.png (100%) rename www/{ => static}/images/cebit-171px.png (100%) rename www/{ => static}/images/cebit-177px_schatten.png (100%) rename www/{ => static}/images/cebit2010_logo_en.png (100%) rename www/{ => static}/images/de.gif (100%) rename www/{ => static}/images/development.png (100%) rename www/{ => static}/images/download.png (100%) rename www/{ => static}/images/en.gif (100%) rename www/{ => static}/images/error/403.png (100%) rename www/{ => static}/images/error/404.png (100%) rename www/{ => static}/images/error/500.png (100%) rename www/{ => static}/images/features.png (100%) rename www/{ => static}/images/feed.png (100%) rename www/{ => static}/images/flags/ad.png (100%) rename www/{ => static}/images/flags/ae.png (100%) rename www/{ => static}/images/flags/af.png (100%) rename www/{ => static}/images/flags/ag.png (100%) rename www/{ => static}/images/flags/ai.png (100%) rename www/{ => static}/images/flags/al.png (100%) rename www/{ => static}/images/flags/am.png (100%) rename www/{ => static}/images/flags/an.png (100%) rename www/{ => static}/images/flags/ao.png (100%) rename www/{ => static}/images/flags/ar.png (100%) rename www/{ => static}/images/flags/as.png (100%) rename www/{ => static}/images/flags/at.png (100%) rename www/{ => static}/images/flags/au.png (100%) rename www/{ => static}/images/flags/aw.png (100%) rename www/{ => static}/images/flags/ax.png (100%) rename www/{ => static}/images/flags/az.png (100%) rename www/{ => static}/images/flags/ba.png (100%) rename www/{ => static}/images/flags/bb.png (100%) rename www/{ => static}/images/flags/bd.png (100%) rename www/{ => static}/images/flags/be.png (100%) rename www/{ => static}/images/flags/bf.png (100%) rename www/{ => static}/images/flags/bg.png (100%) rename www/{ => static}/images/flags/bh.png (100%) rename www/{ => static}/images/flags/bi.png (100%) rename www/{ => static}/images/flags/bj.png (100%) rename www/{ => static}/images/flags/bm.png (100%) rename www/{ => static}/images/flags/bn.png (100%) rename www/{ => static}/images/flags/bo.png (100%) rename www/{ => static}/images/flags/br.png (100%) rename www/{ => static}/images/flags/bs.png (100%) rename www/{ => static}/images/flags/bt.png (100%) rename www/{ => static}/images/flags/bv.png (100%) rename www/{ => static}/images/flags/bw.png (100%) rename www/{ => static}/images/flags/by.png (100%) rename www/{ => static}/images/flags/bz.png (100%) rename www/{ => static}/images/flags/ca.png (100%) rename www/{ => static}/images/flags/catalonia.png (100%) rename www/{ => static}/images/flags/cc.png (100%) rename www/{ => static}/images/flags/cd.png (100%) rename www/{ => static}/images/flags/cf.png (100%) rename www/{ => static}/images/flags/cg.png (100%) rename www/{ => static}/images/flags/ch.png (100%) rename www/{ => static}/images/flags/ci.png (100%) rename www/{ => static}/images/flags/ck.png (100%) rename www/{ => static}/images/flags/cl.png (100%) rename www/{ => static}/images/flags/cm.png (100%) rename www/{ => static}/images/flags/cn.png (100%) rename www/{ => static}/images/flags/co.png (100%) rename www/{ => static}/images/flags/cr.png (100%) rename www/{ => static}/images/flags/cs.png (100%) rename www/{ => static}/images/flags/cu.png (100%) rename www/{ => static}/images/flags/cv.png (100%) rename www/{ => static}/images/flags/cx.png (100%) rename www/{ => static}/images/flags/cy.png (100%) rename www/{ => static}/images/flags/cz.png (100%) rename www/{ => static}/images/flags/da.png (100%) rename www/{ => static}/images/flags/de.png (100%) rename www/{ => static}/images/flags/dj.png (100%) rename www/{ => static}/images/flags/dk.png (100%) rename www/{ => static}/images/flags/dm.png (100%) rename www/{ => static}/images/flags/do.png (100%) rename www/{ => static}/images/flags/dz.png (100%) rename www/{ => static}/images/flags/ec.png (100%) rename www/{ => static}/images/flags/ee.png (100%) rename www/{ => static}/images/flags/eg.png (100%) rename www/{ => static}/images/flags/eh.png (100%) rename www/{ => static}/images/flags/england.png (100%) rename www/{ => static}/images/flags/er.png (100%) rename www/{ => static}/images/flags/es.png (100%) rename www/{ => static}/images/flags/et.png (100%) rename www/{ => static}/images/flags/europeanunion.png (100%) rename www/{ => static}/images/flags/fam.png (100%) rename www/{ => static}/images/flags/fi.png (100%) rename www/{ => static}/images/flags/fj.png (100%) rename www/{ => static}/images/flags/fk.png (100%) rename www/{ => static}/images/flags/fm.png (100%) rename www/{ => static}/images/flags/fo.png (100%) rename www/{ => static}/images/flags/fr.png (100%) rename www/{ => static}/images/flags/ga.png (100%) rename www/{ => static}/images/flags/gb.png (100%) rename www/{ => static}/images/flags/gd.png (100%) rename www/{ => static}/images/flags/ge.png (100%) rename www/{ => static}/images/flags/gf.png (100%) rename www/{ => static}/images/flags/gh.png (100%) rename www/{ => static}/images/flags/gi.png (100%) rename www/{ => static}/images/flags/gl.png (100%) rename www/{ => static}/images/flags/gm.png (100%) rename www/{ => static}/images/flags/gn.png (100%) rename www/{ => static}/images/flags/gp.png (100%) rename www/{ => static}/images/flags/gq.png (100%) rename www/{ => static}/images/flags/gr.png (100%) rename www/{ => static}/images/flags/gs.png (100%) rename www/{ => static}/images/flags/gt.png (100%) rename www/{ => static}/images/flags/gu.png (100%) rename www/{ => static}/images/flags/gw.png (100%) rename www/{ => static}/images/flags/gy.png (100%) rename www/{ => static}/images/flags/hk.png (100%) rename www/{ => static}/images/flags/hm.png (100%) rename www/{ => static}/images/flags/hn.png (100%) rename www/{ => static}/images/flags/hr.png (100%) rename www/{ => static}/images/flags/ht.png (100%) rename www/{ => static}/images/flags/hu.png (100%) rename www/{ => static}/images/flags/id.png (100%) rename www/{ => static}/images/flags/ie.png (100%) rename www/{ => static}/images/flags/il.png (100%) rename www/{ => static}/images/flags/in.png (100%) rename www/{ => static}/images/flags/io.png (100%) rename www/{ => static}/images/flags/iq.png (100%) rename www/{ => static}/images/flags/ir.png (100%) rename www/{ => static}/images/flags/is.png (100%) rename www/{ => static}/images/flags/it.png (100%) rename www/{ => static}/images/flags/jm.png (100%) rename www/{ => static}/images/flags/jo.png (100%) rename www/{ => static}/images/flags/jp.png (100%) rename www/{ => static}/images/flags/ke.png (100%) rename www/{ => static}/images/flags/kg.png (100%) rename www/{ => static}/images/flags/kh.png (100%) rename www/{ => static}/images/flags/ki.png (100%) rename www/{ => static}/images/flags/km.png (100%) rename www/{ => static}/images/flags/kn.png (100%) rename www/{ => static}/images/flags/kp.png (100%) rename www/{ => static}/images/flags/kr.png (100%) rename www/{ => static}/images/flags/kw.png (100%) rename www/{ => static}/images/flags/ky.png (100%) rename www/{ => static}/images/flags/kz.png (100%) rename www/{ => static}/images/flags/la.png (100%) rename www/{ => static}/images/flags/lb.png (100%) rename www/{ => static}/images/flags/lc.png (100%) rename www/{ => static}/images/flags/li.png (100%) rename www/{ => static}/images/flags/lk.png (100%) rename www/{ => static}/images/flags/lr.png (100%) rename www/{ => static}/images/flags/ls.png (100%) rename www/{ => static}/images/flags/lt.png (100%) rename www/{ => static}/images/flags/lu.png (100%) rename www/{ => static}/images/flags/lv.png (100%) rename www/{ => static}/images/flags/ly.png (100%) rename www/{ => static}/images/flags/ma.png (100%) rename www/{ => static}/images/flags/mc.png (100%) rename www/{ => static}/images/flags/md.png (100%) rename www/{ => static}/images/flags/me.png (100%) rename www/{ => static}/images/flags/mg.png (100%) rename www/{ => static}/images/flags/mh.png (100%) rename www/{ => static}/images/flags/mk.png (100%) rename www/{ => static}/images/flags/ml.png (100%) rename www/{ => static}/images/flags/mm.png (100%) rename www/{ => static}/images/flags/mn.png (100%) rename www/{ => static}/images/flags/mo.png (100%) rename www/{ => static}/images/flags/mp.png (100%) rename www/{ => static}/images/flags/mq.png (100%) rename www/{ => static}/images/flags/mr.png (100%) rename www/{ => static}/images/flags/ms.png (100%) rename www/{ => static}/images/flags/mt.png (100%) rename www/{ => static}/images/flags/mu.png (100%) rename www/{ => static}/images/flags/mv.png (100%) rename www/{ => static}/images/flags/mw.png (100%) rename www/{ => static}/images/flags/mx.png (100%) rename www/{ => static}/images/flags/my.png (100%) rename www/{ => static}/images/flags/mz.png (100%) rename www/{ => static}/images/flags/na.png (100%) rename www/{ => static}/images/flags/nc.png (100%) rename www/{ => static}/images/flags/ne.png (100%) rename www/{ => static}/images/flags/nf.png (100%) rename www/{ => static}/images/flags/ng.png (100%) rename www/{ => static}/images/flags/ni.png (100%) rename www/{ => static}/images/flags/nl.png (100%) rename www/{ => static}/images/flags/no.png (100%) rename www/{ => static}/images/flags/np.png (100%) rename www/{ => static}/images/flags/nr.png (100%) rename www/{ => static}/images/flags/nu.png (100%) rename www/{ => static}/images/flags/nz.png (100%) rename www/{ => static}/images/flags/om.png (100%) rename www/{ => static}/images/flags/pa.png (100%) rename www/{ => static}/images/flags/pe.png (100%) rename www/{ => static}/images/flags/pf.png (100%) rename www/{ => static}/images/flags/pg.png (100%) rename www/{ => static}/images/flags/ph.png (100%) rename www/{ => static}/images/flags/pk.png (100%) rename www/{ => static}/images/flags/pl.png (100%) rename www/{ => static}/images/flags/pm.png (100%) rename www/{ => static}/images/flags/pn.png (100%) rename www/{ => static}/images/flags/pr.png (100%) rename www/{ => static}/images/flags/ps.png (100%) rename www/{ => static}/images/flags/pt.png (100%) rename www/{ => static}/images/flags/pw.png (100%) rename www/{ => static}/images/flags/py.png (100%) rename www/{ => static}/images/flags/qa.png (100%) rename www/{ => static}/images/flags/re.png (100%) rename www/{ => static}/images/flags/ro.png (100%) rename www/{ => static}/images/flags/rs.png (100%) rename www/{ => static}/images/flags/ru.png (100%) rename www/{ => static}/images/flags/rw.png (100%) rename www/{ => static}/images/flags/sa.png (100%) rename www/{ => static}/images/flags/sb.png (100%) rename www/{ => static}/images/flags/sc.png (100%) rename www/{ => static}/images/flags/scotland.png (100%) rename www/{ => static}/images/flags/sd.png (100%) rename www/{ => static}/images/flags/se.png (100%) rename www/{ => static}/images/flags/sg.png (100%) rename www/{ => static}/images/flags/sh.png (100%) rename www/{ => static}/images/flags/si.png (100%) rename www/{ => static}/images/flags/sj.png (100%) rename www/{ => static}/images/flags/sk.png (100%) rename www/{ => static}/images/flags/sl.png (100%) rename www/{ => static}/images/flags/sm.png (100%) rename www/{ => static}/images/flags/sn.png (100%) rename www/{ => static}/images/flags/so.png (100%) rename www/{ => static}/images/flags/sr.png (100%) rename www/{ => static}/images/flags/st.png (100%) rename www/{ => static}/images/flags/sv.png (100%) rename www/{ => static}/images/flags/sy.png (100%) rename www/{ => static}/images/flags/sz.png (100%) rename www/{ => static}/images/flags/tc.png (100%) rename www/{ => static}/images/flags/td.png (100%) rename www/{ => static}/images/flags/tf.png (100%) rename www/{ => static}/images/flags/tg.png (100%) rename www/{ => static}/images/flags/th.png (100%) rename www/{ => static}/images/flags/tj.png (100%) rename www/{ => static}/images/flags/tk.png (100%) rename www/{ => static}/images/flags/tl.png (100%) rename www/{ => static}/images/flags/tm.png (100%) rename www/{ => static}/images/flags/tn.png (100%) rename www/{ => static}/images/flags/to.png (100%) rename www/{ => static}/images/flags/tr.png (100%) rename www/{ => static}/images/flags/tt.png (100%) rename www/{ => static}/images/flags/tv.png (100%) rename www/{ => static}/images/flags/tw.png (100%) rename www/{ => static}/images/flags/tz.png (100%) rename www/{ => static}/images/flags/ua.png (100%) rename www/{ => static}/images/flags/ug.png (100%) rename www/{ => static}/images/flags/um.png (100%) rename www/{ => static}/images/flags/us.png (100%) rename www/{ => static}/images/flags/uy.png (100%) rename www/{ => static}/images/flags/uz.png (100%) rename www/{ => static}/images/flags/va.png (100%) rename www/{ => static}/images/flags/vc.png (100%) rename www/{ => static}/images/flags/ve.png (100%) rename www/{ => static}/images/flags/vg.png (100%) rename www/{ => static}/images/flags/vi.png (100%) rename www/{ => static}/images/flags/vn.png (100%) rename www/{ => static}/images/flags/vu.png (100%) rename www/{ => static}/images/flags/wales.png (100%) rename www/{ => static}/images/flags/wf.png (100%) rename www/{ => static}/images/flags/ws.png (100%) rename www/{ => static}/images/flags/ye.png (100%) rename www/{ => static}/images/flags/yt.png (100%) rename www/{ => static}/images/flags/za.png (100%) rename www/{ => static}/images/flags/zm.png (100%) rename www/{ => static}/images/flags/zw.png (100%) rename www/{ => static}/images/ft.png (100%) rename www/{ => static}/images/icons/ipfire.png (100%) rename www/{ => static}/images/icons/ipfire_sw.png (100%) create mode 100644 www/static/images/ipfire_download.png create mode 100644 www/static/images/ipfire_download.png_1 rename www/{ => static}/images/lf1.png (100%) rename www/{ => static}/images/lf2.png (100%) rename www/{ => static}/images/lf3.png (100%) rename www/{ => static}/images/lightbox/lightbox-blank.gif (100%) rename www/{ => static}/images/lightbox/lightbox-btn-close.gif (100%) rename www/{ => static}/images/lightbox/lightbox-btn-next.gif (100%) rename www/{ => static}/images/lightbox/lightbox-btn-prev.gif (100%) rename www/{ => static}/images/lightbox/lightbox-ico-loading.gif (100%) rename www/{ => static}/images/links.png (100%) rename www/{ => static}/images/linux_icon.png (100%) rename www/{ => static}/images/linux_new_media_ag.jpg (100%) rename www/{ => static}/images/logo.png (100%) rename www/{ => static}/images/mac_icon.png (100%) rename www/{ => static}/images/mnu2l.png (100%) rename www/{ => static}/images/mnu2r.png (100%) rename www/{ => static}/images/mnu2t1.png (100%) rename www/{ => static}/images/mnu2t2.png (100%) rename www/{ => static}/images/n1.gif (100%) rename www/{ => static}/images/n2.gif (100%) rename www/{ => static}/images/n3.gif (100%) rename www/{ => static}/images/n4.gif (100%) rename www/{ => static}/images/n5.gif (100%) rename www/{ => static}/images/n6.gif (100%) rename www/{ => static}/images/paypal-folder.png (100%) rename www/{ => static}/images/pic.gif (100%) rename www/{ => static}/images/pic2.png (100%) rename www/{ => static}/images/progressbar.gif (100%) rename www/{ => static}/images/progressbg_black.gif (100%) rename www/{ => static}/images/progressbg_green.gif (100%) rename www/{ => static}/images/progressbg_orange.gif (100%) rename www/{ => static}/images/progressbg_red.gif (100%) rename www/{ => static}/images/progressbg_yellow.gif (100%) rename www/{ => static}/images/pxe.png (100%) rename www/{ => static}/images/screens/de/final/connsched.png (100%) rename www/{ => static}/images/screens/de/final/disk.png (100%) rename www/{ => static}/images/screens/de/final/dyndns.png (100%) rename www/{ => static}/images/screens/de/final/fwdiag.png (100%) rename www/{ => static}/images/screens/de/final/fwlog-port.png (100%) rename www/{ => static}/images/screens/de/final/fwlog.png (100%) rename www/{ => static}/images/screens/de/final/ids.png (100%) rename www/{ => static}/images/screens/de/final/index.png (100%) rename www/{ => static}/images/screens/de/final/ipsec.png (100%) rename www/{ => static}/images/screens/de/final/nettraffic.png (100%) rename www/{ => static}/images/screens/de/final/nw-internal.png (100%) rename www/{ => static}/images/screens/de/final/outgoingfw-1.png (100%) rename www/{ => static}/images/screens/de/final/outgoingfw-2.png (100%) rename www/{ => static}/images/screens/de/final/pakfire-1.png (100%) rename www/{ => static}/images/screens/de/final/pakfire-2.png (100%) rename www/{ => static}/images/screens/de/final/proxy.png (100%) rename www/{ => static}/images/screens/de/final/qos-2.png (100%) rename www/{ => static}/images/screens/de/final/samba.png (100%) rename www/{ => static}/images/screens/de/final/system.png (100%) rename www/{ => static}/images/screens/de/final/thumb/fwlog-port.png (100%) rename www/{ => static}/images/screens/de/final/thumb/index.png (100%) rename www/{ => static}/images/screens/de/final/thumb/ipsec.png (100%) rename www/{ => static}/images/screens/de/final/thumb/pakfire-1.png (100%) rename www/{ => static}/images/screens/de/final/thumb/proxy.png (100%) rename www/{ => static}/images/screens/de/final/thumb/qos-2.png (100%) rename www/{ => static}/images/screens/de/final/thumb/system.png (100%) rename www/{ => static}/images/screens/de/final/xtaccess.png (100%) rename www/{ => static}/images/screenshots/backup_de.png (100%) rename www/{ => static}/images/screenshots/backup_de_tn.png (100%) rename www/{ => static}/images/screenshots/backup_en.png (100%) rename www/{ => static}/images/screenshots/backup_en_tn.png (100%) rename www/{ => static}/images/screenshots/connections_de.png (100%) rename www/{ => static}/images/screenshots/connections_de_tn.png (100%) rename www/{ => static}/images/screenshots/connections_en.png (100%) rename www/{ => static}/images/screenshots/connections_en_tn.png (100%) rename www/{ => static}/images/screenshots/dhcp_de.png (100%) rename www/{ => static}/images/screenshots/dhcp_de_tn.png (100%) rename www/{ => static}/images/screenshots/dhcp_en.png (100%) rename www/{ => static}/images/screenshots/dhcp_en_tn.png (100%) rename www/{ => static}/images/screenshots/fwlog_ip_de.png (100%) rename www/{ => static}/images/screenshots/fwlog_ip_de_tn.png (100%) rename www/{ => static}/images/screenshots/fwlog_ip_en.png (100%) rename www/{ => static}/images/screenshots/fwlog_ip_en_tn.png (100%) rename www/{ => static}/images/screenshots/index_de.png (100%) rename www/{ => static}/images/screenshots/index_de_tn.png (100%) rename www/{ => static}/images/screenshots/index_en.png (100%) rename www/{ => static}/images/screenshots/index_en_tn.png (100%) rename www/{ => static}/images/screenshots/ipsec_de.png (100%) rename www/{ => static}/images/screenshots/ipsec_de_tn.png (100%) rename www/{ => static}/images/screenshots/ipsec_en.png (100%) rename www/{ => static}/images/screenshots/ipsec_en_tn.png (100%) rename www/{ => static}/images/screenshots/monitor.png (100%) rename www/{ => static}/images/screenshots/networkother_de.png (100%) rename www/{ => static}/images/screenshots/networkother_de_tn.png (100%) rename www/{ => static}/images/screenshots/networkother_en.png (100%) rename www/{ => static}/images/screenshots/networkother_en_tn.png (100%) rename www/{ => static}/images/screenshots/outgoing_fw_de.png (100%) rename www/{ => static}/images/screenshots/outgoing_fw_de_tn.png (100%) rename www/{ => static}/images/screenshots/outgoing_fw_en.png (100%) rename www/{ => static}/images/screenshots/outgoing_fw_en_tn.png (100%) rename www/{ => static}/images/screenshots/pakfire_de.png (100%) rename www/{ => static}/images/screenshots/pakfire_de_tn.png (100%) rename www/{ => static}/images/screenshots/pakfire_en.png (100%) rename www/{ => static}/images/screenshots/pakfire_en_tn.png (100%) rename www/{ => static}/images/screenshots/proxy_de.png (100%) rename www/{ => static}/images/screenshots/proxy_de_tn.png (100%) rename www/{ => static}/images/screenshots/proxy_en.png (100%) rename www/{ => static}/images/screenshots/proxy_en_tn.png (100%) rename www/{ => static}/images/screenshots/qos_de.png (100%) rename www/{ => static}/images/screenshots/qos_de_tn.png (100%) rename www/{ => static}/images/screenshots/qos_en.png (100%) rename www/{ => static}/images/screenshots/qos_en_tn.png (100%) rename www/{ => static}/images/screenshots/samba_de.png (100%) rename www/{ => static}/images/screenshots/samba_de_tn.png (100%) rename www/{ => static}/images/screenshots/samba_en.png (100%) rename www/{ => static}/images/screenshots/samba_en_tn.png (100%) rename www/{ => static}/images/screenshots/services_de.png (100%) rename www/{ => static}/images/screenshots/services_de_tn.png (100%) rename www/{ => static}/images/screenshots/services_en.png (100%) rename www/{ => static}/images/screenshots/services_en_tn.png (100%) rename www/{ => static}/images/sh-bl.png (100%) rename www/{ => static}/images/sh-br.png (100%) rename www/{ => static}/images/sh-btn.png (100%) rename www/{ => static}/images/sh-lft.png (100%) rename www/{ => static}/images/sh-rgt.png (100%) rename www/{ => static}/images/sh-tl.png (100%) rename www/{ => static}/images/sh-top.png (100%) rename www/{ => static}/images/sh-tr.png (100%) rename www/{ => static}/images/spacer.gif (100%) rename www/{ => static}/images/sponsors/isp42.png (100%) rename www/{ => static}/images/sponsors/isp42_2.png (100%) rename www/{ => static}/images/tux.png (100%) rename www/{ => static}/images/tux2-99.png (100%) rename www/{ => static}/images/tux2.png (100%) rename www/{ => static}/images/tux_menu_99x100.png (100%) rename www/{ => static}/images/ui-bg_flat_75_f5f5f5_40x100.png (100%) rename www/{ => static}/images/ui-bg_glass_75_dadada_1x400.png (100%) rename www/{ => static}/images/ui-bg_glass_75_e6e6e6_1x400.png (100%) rename www/{ => static}/images/ui-bg_highlight-soft_75_cccccc_1x100.png (100%) rename www/{ => static}/images/win_icon.png (100%) rename www/{ => static}/images/x-click-but04.gif (100%) create mode 100644 www/static/js/cluster.js rename www/{include => static/js}/correctpng.js (100%) create mode 100644 www/static/js/jquery-ui.js create mode 100644 www/static/js/jquery.js create mode 100644 www/static/js/jquery.megamenu.js rename www/{include/jquery.progressbar.min.js => static/js/jquery.progressbar.js} (87%) create mode 100644 www/templates/base.html create mode 100644 www/templates/builds.html create mode 100644 www/templates/downloads-all.html create mode 100644 www/templates/downloads-development.html create mode 100644 www/templates/downloads-torrents.html create mode 100644 www/templates/downloads.html create mode 100644 www/templates/error-404.html create mode 100644 www/templates/error-500.html create mode 100644 www/templates/error.html create mode 100644 www/templates/index.html create mode 100644 www/templates/modules/builds.html create mode 100644 www/templates/modules/menu-item.html create mode 100644 www/templates/modules/menu.html create mode 100644 www/templates/modules/news-item.html create mode 100644 www/templates/modules/release-item.html create mode 100644 www/templates/modules/sidebar-banner.html create mode 100644 www/templates/modules/sidebar-item.html create mode 100644 www/templates/modules/sidebar-release.html create mode 100644 www/templates/news.html create mode 100644 www/templates/static/cluster.html create mode 100644 www/templates/static/imprint.html create mode 100644 www/templates/static/screenshots.html create mode 100644 www/templates/translations.html create mode 100644 www/translations/de_DE.csv create mode 100755 www/webapp.py create mode 100644 www/webapp/__init__.py create mode 100644 www/webapp/banners.py create mode 100644 www/webapp/builds.py create mode 100644 www/webapp/cluster.py create mode 100644 www/webapp/handlers.py create mode 100644 www/webapp/helpers.py create mode 100644 www/webapp/menu.py create mode 100644 www/webapp/news.py create mode 100644 www/webapp/releases.py create mode 100644 www/webapp/translations.py create mode 100644 www/webapp/ui_modules.py create mode 100644 www/webapp/uriel.py diff --git a/www/banners.json b/www/banners.json index 56da7d2..56757bb 100644 --- a/www/banners.json +++ b/www/banners.json @@ -1,11 +1,11 @@ -{ - "01" : { "uri" : "/images/sponsors/isp42.png", - "title" : "Hosting-Sponsor", - "link" : "http://www.isp42.de/" }, - "02" : { "uri" : "/images/sponsors/isp42_2.png", - "title" : "Hosting-Sponsor", - "link" : "http://www.isp42.de/" }, - "03" : { "uri" : "/images/cebit2010_logo_en.png", - "title" : "CeBIT 2010", - "link" : "cebit" } -} +[ + { "uri" : "images/sponsors/isp42.png", + "title" : "Hosting-Sponsor", + "link" : "http://www.isp42.de/" }, + { "uri" : "images/sponsors/isp42_2.png", + "title" : "Hosting-Sponsor", + "link" : "http://www.isp42.de/" }, + { "uri" : "images/cebit2010_logo_en.png", + "title" : "CeBIT 2010", + "link" : "cebit" } +] diff --git a/www/ipfire.py b/www/ipfire.py deleted file mode 100755 index 6296b92..0000000 --- a/www/ipfire.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/python - -import cgitb -cgitb.enable() - -import sys -import cgi -import imputil - -site = cgi.FieldStorage().getfirst("site") or "index" - -sys.path = [ "pages",] + sys.path -for s in (site, "static"): - try: - found = imputil.imp.find_module(s) - loaded = imputil.imp.load_module(s, found[0], found[1], found[2]) - - p = loaded.__dict__["page"] - - break - except ImportError, e: - pass - -p() diff --git a/www/menu.json b/www/menu.json index 4f43478..1f3dfd9 100644 --- a/www/menu.json +++ b/www/menu.json @@ -1,18 +1,21 @@ -{ - "10" : { "uri" : "/index", - "name" : "Home" }, - "20" : { "uri" : "/download", - "name" : "Downloads" }, - "30" : { "uri" : "/screenshots", - "name" : "Screenshots" }, - "40" : { "uri" : "http://wiki.ipfire.org/", - "name" : { "de" : "Wiki", "en" : "Wiki" }}, - "50" : { "uri" : "http://forum.ipfire.org/", - "name" : "Forum" }, - "60" : { "uri" : "/development", - "name" : { "de" : "Entwicklung", "en" : "Development" }}, - "70" : { "uri" : "/links", - "name" : "Links" }, - "80" : { "uri" : "/cebit", - "name" : "
CeBIT 2010
" } -} +[ + { "name" : "Home", + "link" : "/", + "desc" : "The place where we start." }, + + { "name" : "Support", + "subs" : [ + { "name" : "Forum", + "link" : "http://forum.ipfire.org/", + "desc" : "The IPFire Forum." }, + + { "name" : "Wiki", + "link" : "http://wiki.ipfire.org/", + "desc" : "Documentation" }, + + { "name" : "IRC", + "link" : "/irc", + "desc" : "Get help in a chat" } + ] + } +] diff --git a/www/pages/builds.py b/www/pages/builds.py deleted file mode 100644 index 4a3b500..0000000 --- a/www/pages/builds.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/python - -import os -import time - -import web -import web.elements -import web.javascript - -from web.info import Info -info = Info() - -def size(file): - size = os.path.getsize(file) - suffixes = [("B",2**10), ("K",2**20), ("M",2**30), ("G",2**40), ("T",2**50)] - for suf, lim in suffixes: - if size > lim: - continue - else: - return "%s%s" % (round(size/float(lim/2**10),2), suf) - - -class Build(object): - def __init__(self, path, basedir, url): - self.path = path - self.basedir = basedir - self.url = os.path.join(url, path[len(basedir)+1:]) - - # Read .buildinfo - f = open("%s/.buildinfo" % path) - self.info = f.readlines() - f.close() - - def __repr__(self): - return "" % self.path - - def __cmp__(self, other): - return cmp(float(other.get("date")), float(self.get("date"))) - - def get(self, key): - key = key.upper() + "=" - for line in self.info: - if line.startswith(key): - return line.split("=")[1].rstrip("\n") - return None - - @property - def hostname(self): - return self.get("hostname") - - @property - def release(self): - return self.get("release") - - @property - def date(self): - return time.strftime("%Y-%m-%d %H:%M", time.localtime(float(self.get("date")))) - - @property - def arch(self): - return self.get("arch") - - @property - def duration(self): - if not self.get("duration") or self.get("duration") == "": - return "--:--" - return time.strftime("%H:%M", time.gmtime(float(self.get("duration")))) - - @property - def iso(self): - return self.get("iso") - - @property - def packages(self): - path = "%s/packages_%s" % (self.path, self.arch,) - if not os.path.exists(path): - return [] - return os.listdir(path) - - @property - def pxe(self): - dir = "/srv/www/ipfire.org/pxe" - for iso in os.listdir(dir): - # Skip non-iso files - if not iso.endswith(".iso"): - continue - if os.readlink(os.path.join(dir, iso)) == os.path.join(self.path, self.iso): - return "[PXE]" - return "" - - -class Content(web.Content): - def __init__(self): - web.Content.__init__(self) - - self.builds = [] - for location in info["nightly_builds"]: - # Only process correctly configured locations - if not location.has_key("path") or not location.has_key("url"): - continue - - # Continue if path does not exist - if not os.path.exists(location["path"]): - continue - - for (dir, subdirs, files) in os.walk(location["path"]): - if not os.path.exists("%s/.buildinfo" % dir): - continue - self.builds.append(Build(dir, location["path"], location["url"])) - self.builds.sort() - - def __call__(self, lang): - today = time.strftime("%A, %Y-%m-%d", time.localtime()) - last_day = "" - - ret = """

Nightly builds

- - - """ - - # if there are no builds - if not self.builds: - ret += """""" - - else: - for build in self.builds: - # write headers - day = time.strftime("%A, %Y-%m-%d", time.localtime(float(build.get("date")))) - if day != last_day: - if day == today: - ret += """""" - else: - ret += """""" % day - last_day = day - - ret += """ - """ - else: - ret += """IPFire""" - - ret += """\ - - - - """ % { "release" : build.release, - "hostname" : build.hostname, - "arch" : build.arch, - "date" : build.date, - "duration" : build.duration, - "url" : build.url, - "iso" : build.iso, - "size_iso" : size(os.path.join(build.path, build.iso)), - "num_packages" : len(build.packages), - "pxe" : build.pxe } - - ret += """\ - -
There are currently no builds available.
Today
 
 
%s
""" % build.url - - if day == today: - ret += """IPFire 
- %(release)s (%(arch)s) %(pxe)s
- %(iso)s %(size_iso)s
 
- %(hostname)s
- %(date)s [%(duration)sh]
%(num_packages)s [PAKS]
""" - - return ret - - -page = web.Page() -page.content = Content() -page.sidebar = web.elements.DevelopmentSidebar() - -### Disabled because it looks awful -#page.javascript = web.javascript.Javascript(jquery=1) -#page.javascript.jquery_plugin("alternate") -#page.javascript.write(""" -# -#""") diff --git a/www/pages/cluster.py b/www/pages/cluster.py deleted file mode 100644 index 11ec869..0000000 --- a/www/pages/cluster.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/python - -import web -import web.elements -from web.javascript import Javascript - -class Content(web.Content): - def __init__(self): - web.Content.__init__(self) - - def __call__(self, lang): - ret = """

Icecream Cluster Monitoring

-

Cluster's CPU load: - Job load:

- - - - - - - - - - - - -
NameArchLoadJobsSpeed
-

 
Number of nodes: -

""" - - return ret - -page = web.Page() -page.content = Content() -page.sidebar = web.elements.DevelopmentSidebar() - -page.javascript = Javascript(jquery=1) -page.javascript.jquery_plugin("progressbar") -page.javascript.write("""""") diff --git a/www/pages/static/ancient_download.xml b/www/pages/static/ancient_download.xml deleted file mode 100644 index 108f987..0000000 --- a/www/pages/static/ancient_download.xml +++ /dev/null @@ -1,212 +0,0 @@ - - - - Downloads - Downloads - - - - ancient Downloads - ältere Downloads - - - ]]> - - - The release of 2.5 and the - good old stables 2.3, 2.1 and 1.4.9. - ]]> - - Die stabile Version 2.5 sowie die guten alten - Versionen 2.3, 2.1 und 1.4.9. - ]]> - - - - - - - IPFire 2.5 Core 32 - - 32. - ]]> - 32. - ]]> - - - IPFire 2.5 Core32 - TORRENT - DISK
- IPFire 2.5 Core32 - HTTP - DISK  - MD5

- IPFire 2.5 Core32 - HTTP - USB (HDD)  - MD5
- IPFire 2.5 Core32 - HTTP - USB (FDD)  - MD5

- IPFire 2.5 Core32 - XEN   - MD5

- - ]]>
- - For Alix Boards: IPFire 2.5 Core32 - HTTP - FLASH 1G  - MD5 - - ]]> - - Für Alix Boards: IPFire 2.5 Core32 - HTTP - FLASH 1G  - MD5 - - ]]> -
- - - IPFire 2.5 - - stable 2.5 with kernel 2.6.27.25. - ]]> - stabile Version vom 22. Juni 2009 mit Kernel 2.6.27.25. - ]]> - - - IPFire 2.5 - TORRENT - DISK
- IPFire 2.5 - HTTP - DISK  - MD5

- - - - IPFire 2.5 - HTTP - USB (FDD)  - MD5

- - ]]>
- - For Alix Boards: IPFire 2.5 - HTTP - FLASH 1G  - MD5 - - ]]> - - Für Alix Boards: IPFire 2.5 - HTTP - FLASH 1G  - MD5 - - ]]> -
- - - IPFire 2.3 - - old stable 2.3 with kernel 2.6.25.19. - ]]> - stabile Version vom 8. November 2008 mit Kernel 2.6.25.19. - ]]> - - - IPFire 2.3 - TORRENT - DISK
- IPFire 2.3 - HTTP - DISK  - MD5

- IPFire 2.3 - HTTP - USB (HDD)  - MD5
- IPFire 2.3 - HTTP - USB (FDD)  - MD5 - - ]]>
-
- - - IPFire 2.1 - - - - The team recommends using IPFire 2.3. - ]]> - Das Team empfielt den Einsatz von IPFire 2.3. - ]]> - - - IPFire 2.1 - TORRENT - DISK
- IPFire 2.1 - HTTP - DISK  - MD5

- IPFire 2.1 - HTTP - USB (HDD)  - MD5
- IPFire 2.1 - HTTP - USB (FDD)  - MD5 - - ]]>
-
- - - IPFire 1.4.9 - - - - - After 4 years, the team has decided to cease support for this release. - ]]> - Nach 4 Jahren produktivem Einsatz hat das Team sich entschlossen
- den Support für diese Version einzustellen. - ]]>
- - - IPFire 1.4.9 - TORRENT
- IPFire 1.4.9 - HTTP  - MD5 - - ]]>
-
- -
- - - - - - Torrent clients]]> - Torrent Clients]]> - - -
  • WindowsMac OS µtorrent
  • -
  • LinuxMac OS Transmission
  • - - ]]>
    -
    - - - -
    -
    diff --git a/www/pages/static/download.xml b/www/pages/static/download.xml deleted file mode 100644 index 5513301..0000000 --- a/www/pages/static/download.xml +++ /dev/null @@ -1,143 +0,0 @@ - - - - Downloads - Downloads - - - - Downloads - - - ]]> - - - ]]> - - ]]> - -



    - ]]>
    -


    - ]]>
    - - - - - ]]> -
    - - - IPFire 2.5 (latest Core) - - 33. - ]]> - 33. - ]]> - - - IPFire 2.5 Core33 - TORRENT - DISK
    - IPFire 2.5 Core33 - HTTP - DISK  - MD5

    - IPFire 2.5 Core33 - HTTP - USB (HDD)  - MD5
    - IPFire 2.5 Core33 - HTTP - USB (FDD)  - MD5

    - IPFire 2.5 Core33 - XEN   - MD5

    - - ]]>
    - - For Alix Boards: IPFire 2.5 Core33 - HTTP - FLASH 1G  - MD5 - - ]]> - - Für Alix Boards: IPFire 2.5 Core33 - HTTP - FLASH 1G  - MD5 - - ]]> -
    - - - ancient IPFire builds - ältere IPFire Versionen - - here. - ]]> - hier. - ]]> - - - - Development builds - Entwicklungsversionen - - - Diese Versionen dienen dem Test und sind unter Umständen nicht für den - Produktiveinsatz geeignet. - ]]> - - - IPFire 3 - Alpha1 -   - MD5
    - - ]]>
    - - nightly builds - - ]]> - - Nightly Builds - - ]]> -
    - -
    - - - - - - Torrent clients]]> - Torrent Clients]]> - - -
  • WindowsMac OS µtorrent
  • -
  • LinuxMac OS Transmission
  • - - ]]>
    -
    - - - -
    -
    diff --git a/www/pages/static/imprint.xml b/www/pages/static/imprint.xml deleted file mode 100644 index 586dbe9..0000000 --- a/www/pages/static/imprint.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - Imprint - Imprint - - - - IPFire is OpenSource - - german legal notes. - ]]> - - - - Die Distribution "IPFire" steht unter der GPLv3 zur Verfügung und darf den Bedingung zufolge weitergegeben werden. - ]]> - - - michael@ipfire.org)
    - Gerhardstrasse 8
    - 45711 Datteln

    - - Christian Schmidt (maniacikarus@ipfire.org)
    - Mathildenstr. 25
    - 90489 Nürnberg

    - ]]>
    - - - 1. Inhalt des Onlineangebotes
    - Der Autor übernimmt keinerlei Gewähr für die Aktualität, Korrektheit, Vollständigkeit - oder Qualität der bereitgestellten Informationen. Haftungsansprüche gegen den Autor, - welche sich auf Schäden materieller oder ideeller Art beziehen, die durch die Nutzung - oder Nichtnutzung der dargebotenen Informationen bzw. durch die Nutzung fehlerhafter - und unvollständiger Informationen verursacht wurden, sind grundsätzlich ausgeschlossen, - sofern seitens des Autors kein nachweislich vorsätzliches oder grob fahrlässiges - Verschulden vorliegt.
    - Alle Angebote sind freibleibend und unverbindlich. Der Autor behält es sich ausdrücklich vor, - Teile der Seiten oder das gesamte Angebot ohne gesonderte Ankündigung zu verändern, - zu ergänzen, zu löschen oder die Veröffentlichung zeitweise oder endgültig einzustellen. - ]]>
    - - - 2. Verweise und Links
    - Bei direkten oder indirekten Verweisen auf fremde Internetseiten ("Links"), - die außerhalb des Verantwortungsbereiches des Autors liegen, würde eine - Haftungsverpflichtung ausschließlich in dem Fall in Kraft treten, in dem der - Autor von den Inhalten Kenntnis hat und es ihm technisch möglich und zumutbar wäre, - die Nutzung im Falle rechtswidriger Inhalte zu verhindern.
    - Der Autor erklärt hiermit ausdrücklich, dass zum Zeitpunkt der Linksetzung keine - illegalen Inhalte auf den zu verlinkenden Seiten erkennbar waren. - Auf die aktuelle und zukünftige Gestaltung, die Inhalte oder die Urheberschaft - der gelinkten/verknüpften Seiten hat der Autor keinerlei Einfluss. Deshalb distanziert - er sich hiermit ausdrücklich von allen Inhalten aller gelinkten /verknüpften Seiten, - die nach der Linksetzung verändert wurden. Diese Feststellung gilt für alle innerhalb - des eigenen Internetangebotes gesetzten Links und Verweise sowie für Fremdeinträge - in vom Autor eingerichteten Gästebüchern, Diskussionsforen und Mailinglisten. - Für illegale, fehlerhafte oder unvollständige Inhalte und insbesondere für Schäden, - die aus der Nutzung oder Nichtnutzung solcherart dargebotener Informationen entstehen, - haftet allein der Anbieter der Seite, auf welche verwiesen wurde, nicht derjenige, - der über Links auf die jeweilige Veröffentlichung lediglich verweist. - ]]>
    - - - 3. Urheber- und Kennzeichenrecht
    - Der Autor ist bestrebt, in allen Publikationen die Urheberrechte der verwendeten Grafiken, - Tondokumente, Videosequenzen und Texte zu beachten, von ihm selbst erstellte Grafiken, - Tondokumente, Videosequenzen und Texte zu nutzen oder auf lizenzfreie Grafiken, Tondokumente, - Videosequenzen und Texte zurückzugreifen.
    - Alle innerhalb des Internetangebotes genannten und ggf. durch Dritte geschützten Marken- - und Warenzeichen unterliegen uneingeschränkt den Bestimmungen des jeweils gültigen Kennzeichenrechts - und den Besitzrechten der jeweiligen eingetragenen Eigentümer. Allein aufgrund der bloßen Nennung - ist nicht der Schluss zu ziehen, dass Markenzeichen nicht durch Rechte Dritter geschützt sind!
    - Das Copyright für veröffentlichte, vom Autor selbst erstellte Objekte bleibt allein beim Autor der Seiten. - Eine Vervielfältigung oder Verwendung solcher Grafiken, Tondokumente, Videosequenzen und Texte in - anderen elektronischen oder gedruckten Publikationen ist ohne ausdrückliche Zustimmung des Autors nicht gestattet. - ]]>
    - - - 4. Datenschutz
    - Sofern innerhalb des Internetangebotes die Möglichkeit zur Eingabe persönlicher oder geschäftlicher Daten - (Emailadressen, Namen, Anschriften) besteht, so erfolgt die Preisgabe dieser Daten seitens - des Nutzers auf ausdrücklich freiwilliger Basis. Die Inanspruchnahme und Bezahlung aller - angebotenen Dienste ist - soweit technisch möglich und zumutbar - auch ohne Angabe solcher Daten - bzw. unter Angabe anonymisierter Daten oder eines Pseudonyms gestattet. Die Nutzung der im Rahmen - des Impressums oder vergleichbarer Angaben veröffentlichten Kontaktdaten wie Postanschriften, - Telefon- und Faxnummern sowie Emailadressen durch Dritte zur Übersendung von nicht ausdrücklich - angeforderten Informationen ist nicht gestattet. Rechtliche Schritte gegen die Versender von - sogenannten Spam- Mails bei Verstössen gegen dieses Verbot sind ausdrücklich vorbehalten. - ]]>
    - - - 5. Rechtswirksamkeit dieses Haftungsausschlusses
    - Dieser Haftungsausschluss ist als Teil des Internetangebotes zu betrachten, von dem aus auf diese - Seite verwiesen wurde. Sofern Teile oder einzelne Formulierungen dieses Textes der geltenden - Rechtslage nicht, nicht mehr oder nicht vollständig entsprechen sollten, bleiben die übrigen - Teile des Dokumentes in ihrem Inhalt und ihrer Gültigkeit davon unberührt. - ]]>
    - - - -
    -
    - - -
    diff --git a/www/pages/static/index.xml b/www/pages/static/index.xml deleted file mode 100644 index 735a063..0000000 --- a/www/pages/static/index.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - - Welcome - Willkommen - - - - more security for your network - mehr Sicherheit für Ihr Netzwerk - - IPFire is a linux-distribution that focusses on easy setup, good handling and a - high niveau of security.
    It is operable via an intuitive webinterface, which offers a - lot of playground for beginners and even experienced administrators. - IPFire is maintained by experienced developers, who are really concerned about security and regulary - updates to keep it secure. - ]]>
    - IPFire-System ist eine Linux-Distribution, welche die Zielsetzung hat ein einfach zu - installierendes Grundsystem zu bieten und dabei ein hohes Sicherheitsniveau zu gewährleisten. - IPFire ist komplett über sein intuitiv zu bedienendes Webinterface zu konfigurieren - und bietet sowohl Anfängern, als auch erfahrenen Administratoren eine Fülle von - Einstellungsmöglichkeiten. Ein Schwerpunkt bei der Weiterentwickling legen die erfahrenen Entwickler - klar auf regelmäßige System und vor allem Sicherheitsupdates.

    - ]]>
    - - IPFire ships with a custom built paket-manager called Pakfire, so the system can be - expanded with various addons. - ]]> - Pakfire lässt sich der IPFire mit diversen - Addons, - bishin zu einem Server-System erweitern. - ]]> - - - - - ]]> - - - - ]]> - - - ]]> - - IPFire is a GPLv3-licensed project developed and maintained by - an open community of developers. - ]]> - IPFire ist eine freie Software, die unter der GPLv3 lizensiert ist und - von einer offenen Community entwickelt wird. - ]]> - - - -
    - - -
    - - - - - - Internet Relay Chat]]> - Server: irc.freenode.net
    - Channel: #ipfire
    - Web-Chat - ]]>
    -
    - - - - - RSS feed]]> - - IPFire - News -
    - news archive
    ]]>
    - IPFire - News -
    - News-Archiv

    ]]>
    -
    - -
    -
    diff --git a/www/pages/static/links.xml b/www/pages/static/links.xml deleted file mode 100644 index ea73492..0000000 --- a/www/pages/static/links.xml +++ /dev/null @@ -1,149 +0,0 @@ - - - - Links - Links - - - - Links - - ]]> - - IPFire-Project. - There are some links to our partners, friends or sponsors and of course references to articles by - some magazines. - ]]> - - - - Friends of IPFire - - - - - http://www.firewall-service.com - Rene Zingel - - - http://www.rowie.at - Ronald Wiesinger - - - http://www.scp-systems.ch - Peter Schaelchli - - - http://www.kbarthel.de - Kim Barthel - - - http://ipfire.earl-net.com - Jan Paul Tücking - - - Seite im Aufbau - Sebastian Winter - - -
    - ]]>
    - talk about IPFire at the - Warpzone, - a draft is available as well as a video. - ]]> - Vortrag über IPFire in der - Warpzone - gehalten, wer will kann sich das Paper wie auch das Video des Vortrags anschauen. - ]]> -
    - - IPFire in Media - IPFire in den Medien (diverse Zeitschriften) - - - http://linuxmini.blogspot.com/2007/10/ipfire-free-firewall-for-your-home-or.html
    - http://www.pro-linux.de/news/2006/9219.html
    - http://www.kriptopolis.org/ipfire
    - http://freedommafia.net/main/index.php?option=com_content&task=view&id=103&Itemid=47
    - http://www.lintelligence.de/news/1026
    - http://www.techmonkey.de/2008/09/15/ipfire-der-nachste-star-am-soho-himmel/
    - http://www.pcwelt.de/start/sicherheit/firewall/news/187759/ipfire_auf_version_23_aktualisiert/
    - ]]>
    -
    - - Discussion about IPFire - Boards und Foren (Diskussionen über IPFire) - - - http://forum.linuxcast.eu/viewtopic.php?f=13&p=438
    - http://forum.golem.de/read.php?26129,1364598,1364598#msg-1364598
    - http://www.ipcop-forum.de/forum/viewtopic.php?f=28&t=21055&hilit=IPFire
    - http://forum.cdrinfo.pl/f102/jaki-dysk-sieciowy-78524/
    - http://forum.mini-pc-pro.de/projekt-forum/3681-epia-ipcop-router-projekt-wirft-mir-diverse-fragen-auf.html
    - http://nachtwandler.blogage.de/entries/2008/10/4/IPFire
    - http://zahlenzerkleinerer.de/1085/der-erste-ipfire-test.html
    - ]]>
    -
    - - Sites that link to here - Nach IPFire verlinkende Seiten - - - http://www.ohloh.net/projects/ipfire
    - http://forum.softgil.com/weblinks.php?cat_id=1
    - ]]>
    - -
    -
    - - - more links]]> - mehr links]]> - - We are grateful for any assistance! - ]]> - Für jede Hilfe sind wir dankbar! - ]]> - - -
    diff --git a/www/pages/torrent/__init__.py b/www/pages/torrent/__init__.py deleted file mode 100644 index 112e63b..0000000 --- a/www/pages/torrent/__init__.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/python - -TRACKER_URL ="http://tracker.ipfire.org:6969/stats?format=txt&mode=tpbs" -TORRENT_BASE="/srv/pakfire/data/torrent" - -import os -import sha -import urllib2 - -from client.bencode import bencode, bdecode -import web -import web.elements - -class TrackerInfo: - def __init__(self, url): - self.info = {} - - f = urllib2.urlopen(url) - for line in f.readlines(): - (hash, seeds, peers,) = line.split(":") - self.info[hash] = (seeds, peers.rstrip("\n"),) - f.close() - - def __call__(self): - print self.info - - def get(self, hash): - try: - return self.info[hash] - except KeyError: - return 0, 0 - - -class TorrentObject: - def __init__(self, file): - self.name = os.path.basename(file) - f = open(file, "rb") - self.info = bdecode(f.read()) - f.close() - - def __call__(self): - print "File : %s" % self.get_file() - print "Hash : %s" % self.get_hash() - - def get_hash(self): - return sha.sha(bencode(self.info["info"])).hexdigest().upper() - - def get_file(self): - return self.name - - -torrent_files = [] -for file in os.listdir(TORRENT_BASE): - if not file.endswith(".torrent"): - continue - file = os.path.join(TORRENT_BASE, file) - torrent_files.insert(0, TorrentObject(file)) - - -tracker = TrackerInfo(TRACKER_URL) - -class TorrentBox(web.elements.Box): - def __init__(self, file): - web.elements.Box.__init__(self, file.name, file.get_hash()) - self.w(""" -

    - Seeders: %s
    - Leechers: %s -

    """ % tracker.get(file.get_hash())) - self.w(""" -

    - Download -

    """ % (file.name,)) - - -class Content(web.Content): - def __init__(self): - web.Content.__init__(self) - - def content(self): - self.w("

    IPFire Torrent Tracker

    ") - for t in torrent_files: - b = TorrentBox(t) - self.w(b()) - -page = web.Page() -page.content = Content() -page.sidebar = web.elements.Sidebar() diff --git a/www/pages/torrent/client/ConfigDir.py b/www/pages/torrent/client/ConfigDir.py deleted file mode 100644 index ee2b23d..0000000 --- a/www/pages/torrent/client/ConfigDir.py +++ /dev/null @@ -1,401 +0,0 @@ -#written by John Hoffman - -from inifile import ini_write, ini_read -from bencode import bencode, bdecode -from types import IntType, LongType, StringType, FloatType -from CreateIcons import GetIcons, CreateIcon -from parseargs import defaultargs -from __init__ import product_name, version_short -import sys,os -from time import time, strftime - -try: - True -except: - True = 1 - False = 0 - -try: - realpath = os.path.realpath -except: - realpath = lambda x:x -OLDICONPATH = os.path.abspath(os.path.dirname(realpath(sys.argv[0]))) - -DIRNAME = '.'+product_name - -hexchars = '0123456789abcdef' -hexmap = [] -revmap = {} -for i in xrange(256): - x = hexchars[(i&0xF0)/16]+hexchars[i&0x0F] - hexmap.append(x) - revmap[x] = chr(i) - -def tohex(s): - r = [] - for c in s: - r.append(hexmap[ord(c)]) - return ''.join(r) - -def unhex(s): - r = [ revmap[s[x:x+2]] for x in xrange(0, len(s), 2) ] - return ''.join(r) - -def copyfile(oldpath, newpath): # simple file copy, all in RAM - try: - f = open(oldpath,'rb') - r = f.read() - success = True - except: - success = False - try: - f.close() - except: - pass - if not success: - return False - try: - f = open(newpath,'wb') - f.write(r) - except: - success = False - try: - f.close() - except: - pass - return success - - -class ConfigDir: - - ###### INITIALIZATION TASKS ###### - - def __init__(self, config_type = None): - self.config_type = config_type - if config_type: - config_ext = '.'+config_type - else: - config_ext = '' - - def check_sysvars(x): - y = os.path.expandvars(x) - if y != x and os.path.isdir(y): - return y - return None - - for d in ['${APPDATA}', '${HOME}', '${HOMEPATH}', '${USERPROFILE}']: - dir_root = check_sysvars(d) - if dir_root: - break - else: - dir_root = os.path.expanduser('~') - if not os.path.isdir(dir_root): - dir_root = os.path.abspath(os.path.dirname(sys.argv[0])) - - dir_root = os.path.join(dir_root,DIRNAME) - self.dir_root = dir_root - - if not os.path.isdir(self.dir_root): - os.mkdir(self.dir_root,0700) # exception if failed - - self.dir_icons = os.path.join(dir_root,'icons') - if not os.path.isdir(self.dir_icons): - os.mkdir(self.dir_icons) - for icon in GetIcons(): - i = os.path.join(self.dir_icons,icon) - if not os.path.exists(i): - if not copyfile(os.path.join(OLDICONPATH,icon),i): - CreateIcon(icon,self.dir_icons) - - self.dir_torrentcache = os.path.join(dir_root,'torrentcache') - if not os.path.isdir(self.dir_torrentcache): - os.mkdir(self.dir_torrentcache) - - self.dir_datacache = os.path.join(dir_root,'datacache') - if not os.path.isdir(self.dir_datacache): - os.mkdir(self.dir_datacache) - - self.dir_piececache = os.path.join(dir_root,'piececache') - if not os.path.isdir(self.dir_piececache): - os.mkdir(self.dir_piececache) - - self.configfile = os.path.join(dir_root,'config'+config_ext+'.ini') - self.statefile = os.path.join(dir_root,'state'+config_ext) - - self.TorrentDataBuffer = {} - - - ###### CONFIG HANDLING ###### - - def setDefaults(self, defaults, ignore=[]): - self.config = defaultargs(defaults) - for k in ignore: - if self.config.has_key(k): - del self.config[k] - - def checkConfig(self): - return os.path.exists(self.configfile) - - def loadConfig(self): - try: - r = ini_read(self.configfile)[''] - except: - return self.config - l = self.config.keys() - for k,v in r.items(): - if self.config.has_key(k): - t = type(self.config[k]) - try: - if t == StringType: - self.config[k] = v - elif t == IntType or t == LongType: - self.config[k] = long(v) - elif t == FloatType: - self.config[k] = float(v) - l.remove(k) - except: - pass - if l: # new default values since last save - self.saveConfig() - return self.config - - def saveConfig(self, new_config = None): - if new_config: - for k,v in new_config.items(): - if self.config.has_key(k): - self.config[k] = v - try: - ini_write( self.configfile, self.config, - 'Generated by '+product_name+'/'+version_short+'\n' - + strftime('%x %X') ) - return True - except: - return False - - def getConfig(self): - return self.config - - - ###### STATE HANDLING ###### - - def getState(self): - try: - f = open(self.statefile,'rb') - r = f.read() - except: - r = None - try: - f.close() - except: - pass - try: - r = bdecode(r) - except: - r = None - return r - - def saveState(self, state): - try: - f = open(self.statefile,'wb') - f.write(bencode(state)) - success = True - except: - success = False - try: - f.close() - except: - pass - return success - - - ###### TORRENT HANDLING ###### - - def getTorrents(self): - d = {} - for f in os.listdir(self.dir_torrentcache): - f = os.path.basename(f) - try: - f, garbage = f.split('.') - except: - pass - d[unhex(f)] = 1 - return d.keys() - - def getTorrentVariations(self, t): - t = tohex(t) - d = [] - for f in os.listdir(self.dir_torrentcache): - f = os.path.basename(f) - if f[:len(t)] == t: - try: - garbage, ver = f.split('.') - except: - ver = '0' - d.append(int(ver)) - d.sort() - return d - - def getTorrent(self, t, v = -1): - t = tohex(t) - if v == -1: - v = max(self.getTorrentVariations(t)) # potential exception - if v: - t += '.'+str(v) - try: - f = open(os.path.join(self.dir_torrentcache,t),'rb') - r = bdecode(f.read()) - except: - r = None - try: - f.close() - except: - pass - return r - - def writeTorrent(self, data, t, v = -1): - t = tohex(t) - if v == -1: - try: - v = max(self.getTorrentVariations(t))+1 - except: - v = 0 - if v: - t += '.'+str(v) - try: - f = open(os.path.join(self.dir_torrentcache,t),'wb') - f.write(bencode(data)) - except: - v = None - try: - f.close() - except: - pass - return v - - - ###### TORRENT DATA HANDLING ###### - - def getTorrentData(self, t): - if self.TorrentDataBuffer.has_key(t): - return self.TorrentDataBuffer[t] - t = os.path.join(self.dir_datacache,tohex(t)) - if not os.path.exists(t): - return None - try: - f = open(t,'rb') - r = bdecode(f.read()) - except: - r = None - try: - f.close() - except: - pass - self.TorrentDataBuffer[t] = r - return r - - def writeTorrentData(self, t, data): - self.TorrentDataBuffer[t] = data - try: - f = open(os.path.join(self.dir_datacache,tohex(t)),'wb') - f.write(bencode(data)) - success = True - except: - success = False - try: - f.close() - except: - pass - if not success: - self.deleteTorrentData(t) - return success - - def deleteTorrentData(self, t): - try: - os.remove(os.path.join(self.dir_datacache,tohex(t))) - except: - pass - - def getPieceDir(self, t): - return os.path.join(self.dir_piececache,tohex(t)) - - - ###### EXPIRATION HANDLING ###### - - def deleteOldCacheData(self, days, still_active = [], delete_torrents = False): - if not days: - return - exptime = time() - (days*24*3600) - names = {} - times = {} - - for f in os.listdir(self.dir_torrentcache): - p = os.path.join(self.dir_torrentcache,f) - f = os.path.basename(f) - try: - f, garbage = f.split('.') - except: - pass - try: - f = unhex(f) - assert len(f) == 20 - except: - continue - if delete_torrents: - names.setdefault(f,[]).append(p) - try: - t = os.path.getmtime(p) - except: - t = time() - times.setdefault(f,[]).append(t) - - for f in os.listdir(self.dir_datacache): - p = os.path.join(self.dir_datacache,f) - try: - f = unhex(os.path.basename(f)) - assert len(f) == 20 - except: - continue - names.setdefault(f,[]).append(p) - try: - t = os.path.getmtime(p) - except: - t = time() - times.setdefault(f,[]).append(t) - - for f in os.listdir(self.dir_piececache): - p = os.path.join(self.dir_piececache,f) - try: - f = unhex(os.path.basename(f)) - assert len(f) == 20 - except: - continue - for f2 in os.listdir(p): - p2 = os.path.join(p,f2) - names.setdefault(f,[]).append(p2) - try: - t = os.path.getmtime(p2) - except: - t = time() - times.setdefault(f,[]).append(t) - names.setdefault(f,[]).append(p) - - for k,v in times.items(): - if max(v) < exptime and not k in still_active: - for f in names[k]: - try: - os.remove(f) - except: - try: - os.removedirs(f) - except: - pass - - - def deleteOldTorrents(self, days, still_active = []): - self.deleteOldCacheData(days, still_active, True) - - - ###### OTHER ###### - - def getIconDir(self): - return self.dir_icons diff --git a/www/pages/torrent/client/ConfigReader.py b/www/pages/torrent/client/ConfigReader.py deleted file mode 100644 index e9353bb..0000000 --- a/www/pages/torrent/client/ConfigReader.py +++ /dev/null @@ -1,1068 +0,0 @@ -#written by John Hoffman - -from ConnChoice import * -from wxPython.wx import * -from types import IntType, FloatType, StringType -from download_bt1 import defaults -from ConfigDir import ConfigDir -import sys,os -import socket -from parseargs import defaultargs - -try: - True -except: - True = 1 - False = 0 - -try: - wxFULL_REPAINT_ON_RESIZE -except: - wxFULL_REPAINT_ON_RESIZE = 0 # fix for wx pre-2.5 - -if (sys.platform == 'win32'): - _FONT = 9 -else: - _FONT = 10 - -def HexToColor(s): - r,g,b = s.split(' ') - return wxColour(red=int(r,16), green=int(g,16), blue=int(b,16)) - -def hex2(c): - h = hex(c)[2:] - if len(h) == 1: - h = '0'+h - return h -def ColorToHex(c): - return hex2(c.Red()) + ' ' + hex2(c.Green()) + ' ' + hex2(c.Blue()) - -ratesettingslist = [] -for x in connChoices: - if not x.has_key('super-seed'): - ratesettingslist.append(x['name']) - - -configFileDefaults = [ - #args only available for the gui client - ('win32_taskbar_icon', 1, - "whether to iconize do system try or not on win32"), - ('gui_stretchwindow', 0, - "whether to stretch the download status window to fit the torrent name"), - ('gui_displaystats', 1, - "whether to display statistics on peers and seeds"), - ('gui_displaymiscstats', 1, - "whether to display miscellaneous other statistics"), - ('gui_ratesettingsdefault', ratesettingslist[0], - "the default setting for maximum upload rate and users"), - ('gui_ratesettingsmode', 'full', - "what rate setting controls to display; options are 'none', 'basic', and 'full'"), - ('gui_forcegreenonfirewall', 0, - "forces the status icon to be green even if the client seems to be firewalled"), - ('gui_default_savedir', '', - "default save directory"), - ('last_saved', '', # hidden; not set in config - "where the last torrent was saved"), - ('gui_font', _FONT, - "the font size to use"), - ('gui_saveas_ask', -1, - "whether to ask where to download to (0 = never, 1 = always, -1 = automatic resume"), -] - -def setwxconfigfiledefaults(): - CHECKINGCOLOR = ColorToHex(wxSystemSettings_GetColour(wxSYS_COLOUR_3DSHADOW)) - DOWNLOADCOLOR = ColorToHex(wxSystemSettings_GetColour(wxSYS_COLOUR_ACTIVECAPTION)) - - configFileDefaults.extend([ - ('gui_checkingcolor', CHECKINGCOLOR, - "progress bar checking color"), - ('gui_downloadcolor', DOWNLOADCOLOR, - "progress bar downloading color"), - ('gui_seedingcolor', '00 FF 00', - "progress bar seeding color"), - ]) - -defaultsToIgnore = ['responsefile', 'url', 'priority'] - - -class configReader: - - def __init__(self): - self.configfile = wxConfig("BitTorrent",style=wxCONFIG_USE_LOCAL_FILE) - self.configMenuBox = None - self.advancedMenuBox = None - self._configReset = True # run reset for the first time - - setwxconfigfiledefaults() - - defaults.extend(configFileDefaults) - self.defaults = defaultargs(defaults) - - self.configDir = ConfigDir('gui') - self.configDir.setDefaults(defaults,defaultsToIgnore) - if self.configDir.checkConfig(): - self.config = self.configDir.loadConfig() - else: - self.config = self.configDir.getConfig() - self.importOldGUIConfig() - self.configDir.saveConfig() - - updated = False # make all config default changes here - - if self.config['gui_ratesettingsdefault'] not in ratesettingslist: - self.config['gui_ratesettingsdefault'] = ( - self.defaults['gui_ratesettingsdefault'] ) - updated = True - if self.config['ipv6_enabled'] and ( - sys.version_info < (2,3) or not socket.has_ipv6 ): - self.config['ipv6_enabled'] = 0 - updated = True - for c in ['gui_checkingcolor','gui_downloadcolor','gui_seedingcolor']: - try: - HexToColor(self.config[c]) - except: - self.config[c] = self.defaults[c] - updated = True - - if updated: - self.configDir.saveConfig() - - self.configDir.deleteOldCacheData(self.config['expire_cache_data']) - - - def importOldGUIConfig(self): - oldconfig = wxConfig("BitTorrent",style=wxCONFIG_USE_LOCAL_FILE) - cont, s, i = oldconfig.GetFirstEntry() - if not cont: - oldconfig.DeleteAll() - return False - while cont: # import old config data - if self.config.has_key(s): - t = oldconfig.GetEntryType(s) - try: - if t == 1: - assert type(self.config[s]) == type('') - self.config[s] = oldconfig.Read(s) - elif t == 2 or t == 3: - assert type(self.config[s]) == type(1) - self.config[s] = int(oldconfig.ReadInt(s)) - elif t == 4: - assert type(self.config[s]) == type(1.0) - self.config[s] = oldconfig.ReadFloat(s) - except: - pass - cont, s, i = oldconfig.GetNextEntry(i) - -# oldconfig.DeleteAll() - return True - - - def resetConfigDefaults(self): - for p,v in self.defaults.items(): - if not p in defaultsToIgnore: - self.config[p] = v - self.configDir.saveConfig() - - def writeConfigFile(self): - self.configDir.saveConfig() - - def WriteLastSaved(self, l): - self.config['last_saved'] = l - self.configDir.saveConfig() - - - def getcheckingcolor(self): - return HexToColor(self.config['gui_checkingcolor']) - def getdownloadcolor(self): - return HexToColor(self.config['gui_downloadcolor']) - def getseedingcolor(self): - return HexToColor(self.config['gui_seedingcolor']) - - def configReset(self): - r = self._configReset - self._configReset = False - return r - - def getConfigDir(self): - return self.configDir - - def getIconDir(self): - return self.configDir.getIconDir() - - def getTorrentData(self,t): - return self.configDir.getTorrentData(t) - - def setColorIcon(self, xxicon, xxiconptr, xxcolor): - idata = wxMemoryDC() - idata.SelectObject(xxicon) - idata.SetBrush(wxBrush(xxcolor,wxSOLID)) - idata.DrawRectangle(0,0,16,16) - idata.SelectObject(wxNullBitmap) - xxiconptr.Refresh() - - - def getColorFromUser(self, parent, colInit): - data = wxColourData() - if colInit.Ok(): - data.SetColour(colInit) - data.SetCustomColour(0, self.checkingcolor) - data.SetCustomColour(1, self.downloadcolor) - data.SetCustomColour(2, self.seedingcolor) - dlg = wxColourDialog(parent,data) - if not dlg.ShowModal(): - return colInit - return dlg.GetColourData().GetColour() - - - def configMenu(self, parent): - self.parent = parent - try: - self.FONT = self.config['gui_font'] - self.default_font = wxFont(self.FONT, wxDEFAULT, wxNORMAL, wxNORMAL, False) - self.checkingcolor = HexToColor(self.config['gui_checkingcolor']) - self.downloadcolor = HexToColor(self.config['gui_downloadcolor']) - self.seedingcolor = HexToColor(self.config['gui_seedingcolor']) - - if (self.configMenuBox is not None): - try: - self.configMenuBox.Close() - except wxPyDeadObjectError, e: - self.configMenuBox = None - - self.configMenuBox = wxFrame(None, -1, 'BitTorrent Preferences', size = (1,1), - style = wxDEFAULT_FRAME_STYLE|wxFULL_REPAINT_ON_RESIZE) - if (sys.platform == 'win32'): - self.icon = self.parent.icon - self.configMenuBox.SetIcon(self.icon) - - panel = wxPanel(self.configMenuBox, -1) - self.panel = panel - - def StaticText(text, font = self.FONT, underline = False, color = None, panel = panel): - x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT) - x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline)) - if color is not None: - x.SetForegroundColour(color) - return x - - colsizer = wxFlexGridSizer(cols = 1, vgap = 8) - - self.gui_stretchwindow_checkbox = wxCheckBox(panel, -1, "Stretch window to fit torrent name *") - self.gui_stretchwindow_checkbox.SetFont(self.default_font) - self.gui_stretchwindow_checkbox.SetValue(self.config['gui_stretchwindow']) - - self.gui_displaystats_checkbox = wxCheckBox(panel, -1, "Display peer and seed statistics") - self.gui_displaystats_checkbox.SetFont(self.default_font) - self.gui_displaystats_checkbox.SetValue(self.config['gui_displaystats']) - - self.gui_displaymiscstats_checkbox = wxCheckBox(panel, -1, "Display miscellaneous other statistics") - self.gui_displaymiscstats_checkbox.SetFont(self.default_font) - self.gui_displaymiscstats_checkbox.SetValue(self.config['gui_displaymiscstats']) - - self.security_checkbox = wxCheckBox(panel, -1, "Don't allow multiple connections from the same IP") - self.security_checkbox.SetFont(self.default_font) - self.security_checkbox.SetValue(self.config['security']) - - self.autokick_checkbox = wxCheckBox(panel, -1, "Kick/ban clients that send you bad data *") - self.autokick_checkbox.SetFont(self.default_font) - self.autokick_checkbox.SetValue(self.config['auto_kick']) - - self.buffering_checkbox = wxCheckBox(panel, -1, "Enable read/write buffering *") - self.buffering_checkbox.SetFont(self.default_font) - self.buffering_checkbox.SetValue(self.config['buffer_reads']) - - self.breakup_checkbox = wxCheckBox(panel, -1, "Break-up seed bitfield to foil ISP manipulation") - self.breakup_checkbox.SetFont(self.default_font) - self.breakup_checkbox.SetValue(self.config['breakup_seed_bitfield']) - - self.autoflush_checkbox = wxCheckBox(panel, -1, "Flush data to disk every 5 minutes") - self.autoflush_checkbox.SetFont(self.default_font) - self.autoflush_checkbox.SetValue(self.config['auto_flush']) - - if sys.version_info >= (2,3) and socket.has_ipv6: - self.ipv6enabled_checkbox = wxCheckBox(panel, -1, "Initiate and receive connections via IPv6 *") - self.ipv6enabled_checkbox.SetFont(self.default_font) - self.ipv6enabled_checkbox.SetValue(self.config['ipv6_enabled']) - - self.gui_forcegreenonfirewall_checkbox = wxCheckBox(panel, -1, - "Force icon to display green when firewalled") - self.gui_forcegreenonfirewall_checkbox.SetFont(self.default_font) - self.gui_forcegreenonfirewall_checkbox.SetValue(self.config['gui_forcegreenonfirewall']) - - - self.minport_data = wxSpinCtrl(panel, -1, '', (-1,-1), (self.FONT*8, -1)) - self.minport_data.SetFont(self.default_font) - self.minport_data.SetRange(1,65535) - self.minport_data.SetValue(self.config['minport']) - - self.maxport_data = wxSpinCtrl(panel, -1, '', (-1,-1), (self.FONT*8, -1)) - self.maxport_data.SetFont(self.default_font) - self.maxport_data.SetRange(1,65535) - self.maxport_data.SetValue(self.config['maxport']) - - self.randomport_checkbox = wxCheckBox(panel, -1, "randomize") - self.randomport_checkbox.SetFont(self.default_font) - self.randomport_checkbox.SetValue(self.config['random_port']) - - self.gui_font_data = wxSpinCtrl(panel, -1, '', (-1,-1), (self.FONT*5, -1)) - self.gui_font_data.SetFont(self.default_font) - self.gui_font_data.SetRange(8,16) - self.gui_font_data.SetValue(self.config['gui_font']) - - self.gui_ratesettingsdefault_data=wxChoice(panel, -1, choices = ratesettingslist) - self.gui_ratesettingsdefault_data.SetFont(self.default_font) - self.gui_ratesettingsdefault_data.SetStringSelection(self.config['gui_ratesettingsdefault']) - - self.maxdownload_data = wxSpinCtrl(panel, -1, '', (-1,-1), (self.FONT*7, -1)) - self.maxdownload_data.SetFont(self.default_font) - self.maxdownload_data.SetRange(0,5000) - self.maxdownload_data.SetValue(self.config['max_download_rate']) - - self.gui_ratesettingsmode_data=wxRadioBox(panel, -1, 'Rate Settings Mode', - choices = [ 'none', 'basic', 'full' ] ) - self.gui_ratesettingsmode_data.SetFont(self.default_font) - self.gui_ratesettingsmode_data.SetStringSelection(self.config['gui_ratesettingsmode']) - - if (sys.platform == 'win32'): - self.win32_taskbar_icon_checkbox = wxCheckBox(panel, -1, "Minimize to system tray") - self.win32_taskbar_icon_checkbox.SetFont(self.default_font) - self.win32_taskbar_icon_checkbox.SetValue(self.config['win32_taskbar_icon']) - -# self.upnp_checkbox = wxCheckBox(panel, -1, "Enable automatic UPnP port forwarding") -# self.upnp_checkbox.SetFont(self.default_font) -# self.upnp_checkbox.SetValue(self.config['upnp_nat_access']) - self.upnp_data=wxChoice(panel, -1, - choices = ['disabled', 'type 1 (fast)', 'type 2 (slow)']) - self.upnp_data.SetFont(self.default_font) - self.upnp_data.SetSelection(self.config['upnp_nat_access']) - - self.gui_default_savedir_ctrl = wxTextCtrl(parent = panel, id = -1, - value = self.config['gui_default_savedir'], - size = (26*self.FONT, -1), style = wxTE_PROCESS_TAB) - self.gui_default_savedir_ctrl.SetFont(self.default_font) - - self.gui_savemode_data=wxRadioBox(panel, -1, 'Ask where to save: *', - choices = [ 'always', 'never', 'auto-resume' ] ) - self.gui_savemode_data.SetFont(self.default_font) - self.gui_savemode_data.SetSelection(1-self.config['gui_saveas_ask']) - - self.checkingcolor_icon = wxEmptyBitmap(16,16) - self.checkingcolor_iconptr = wxStaticBitmap(panel, -1, self.checkingcolor_icon) - self.setColorIcon(self.checkingcolor_icon, self.checkingcolor_iconptr, self.checkingcolor) - - self.downloadcolor_icon = wxEmptyBitmap(16,16) - self.downloadcolor_iconptr = wxStaticBitmap(panel, -1, self.downloadcolor_icon) - self.setColorIcon(self.downloadcolor_icon, self.downloadcolor_iconptr, self.downloadcolor) - - self.seedingcolor_icon = wxEmptyBitmap(16,16) - self.seedingcolor_iconptr = wxStaticBitmap(panel, -1, self.seedingcolor_icon) - self.setColorIcon(self.seedingcolor_icon, self.downloadcolor_iconptr, self.seedingcolor) - - rowsizer = wxFlexGridSizer(cols = 2, hgap = 20) - - block12sizer = wxFlexGridSizer(cols = 1, vgap = 7) - - block1sizer = wxFlexGridSizer(cols = 1, vgap = 2) - if (sys.platform == 'win32'): - block1sizer.Add(self.win32_taskbar_icon_checkbox) -# block1sizer.Add(self.upnp_checkbox) - block1sizer.Add(self.gui_stretchwindow_checkbox) - block1sizer.Add(self.gui_displaystats_checkbox) - block1sizer.Add(self.gui_displaymiscstats_checkbox) - block1sizer.Add(self.security_checkbox) - block1sizer.Add(self.autokick_checkbox) - block1sizer.Add(self.buffering_checkbox) - block1sizer.Add(self.breakup_checkbox) - block1sizer.Add(self.autoflush_checkbox) - if sys.version_info >= (2,3) and socket.has_ipv6: - block1sizer.Add(self.ipv6enabled_checkbox) - block1sizer.Add(self.gui_forcegreenonfirewall_checkbox) - - block12sizer.Add(block1sizer) - - colorsizer = wxStaticBoxSizer(wxStaticBox(panel, -1, "Gauge Colors:"), wxVERTICAL) - colorsizer1 = wxFlexGridSizer(cols = 7) - colorsizer1.Add(StaticText(' Checking: '), 1, wxALIGN_BOTTOM) - colorsizer1.Add(self.checkingcolor_iconptr, 1, wxALIGN_BOTTOM) - colorsizer1.Add(StaticText(' Downloading: '), 1, wxALIGN_BOTTOM) - colorsizer1.Add(self.downloadcolor_iconptr, 1, wxALIGN_BOTTOM) - colorsizer1.Add(StaticText(' Seeding: '), 1, wxALIGN_BOTTOM) - colorsizer1.Add(self.seedingcolor_iconptr, 1, wxALIGN_BOTTOM) - colorsizer1.Add(StaticText(' ')) - minsize = self.checkingcolor_iconptr.GetBestSize() - minsize.SetHeight(minsize.GetHeight()+5) - colorsizer1.SetMinSize(minsize) - colorsizer.Add(colorsizer1) - - block12sizer.Add(colorsizer, 1, wxALIGN_LEFT) - - rowsizer.Add(block12sizer) - - block3sizer = wxFlexGridSizer(cols = 1) - - portsettingsSizer = wxStaticBoxSizer(wxStaticBox(panel, -1, "Port Range:*"), wxVERTICAL) - portsettingsSizer1 = wxGridSizer(cols = 2, vgap = 1) - portsettingsSizer1.Add(StaticText('From: '), 1, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT) - portsettingsSizer1.Add(self.minport_data, 1, wxALIGN_BOTTOM) - portsettingsSizer1.Add(StaticText('To: '), 1, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT) - portsettingsSizer1.Add(self.maxport_data, 1, wxALIGN_BOTTOM) - portsettingsSizer.Add(portsettingsSizer1) - portsettingsSizer.Add(self.randomport_checkbox, 1, wxALIGN_CENTER) - block3sizer.Add(portsettingsSizer, 1, wxALIGN_CENTER) - block3sizer.Add(StaticText(' ')) - block3sizer.Add(self.gui_ratesettingsmode_data, 1, wxALIGN_CENTER) - block3sizer.Add(StaticText(' ')) - ratesettingsSizer = wxFlexGridSizer(cols = 1, vgap = 2) - ratesettingsSizer.Add(StaticText('Default Rate Setting: *'), 1, wxALIGN_CENTER) - ratesettingsSizer.Add(self.gui_ratesettingsdefault_data, 1, wxALIGN_CENTER) - block3sizer.Add(ratesettingsSizer, 1, wxALIGN_CENTER) - if (sys.platform == 'win32'): - block3sizer.Add(StaticText(' ')) - upnpSizer = wxFlexGridSizer(cols = 1, vgap = 2) - upnpSizer.Add(StaticText('UPnP Port Forwarding: *'), 1, wxALIGN_CENTER) - upnpSizer.Add(self.upnp_data, 1, wxALIGN_CENTER) - block3sizer.Add(upnpSizer, 1, wxALIGN_CENTER) - - rowsizer.Add(block3sizer) - colsizer.Add(rowsizer) - - block4sizer = wxFlexGridSizer(cols = 3, hgap = 15) - savepathsizer = wxFlexGridSizer(cols = 2, vgap = 1) - savepathsizer.Add(StaticText('Default Save Path: *')) - savepathsizer.Add(StaticText(' ')) - savepathsizer.Add(self.gui_default_savedir_ctrl, 1, wxEXPAND) - savepathButton = wxButton(panel, -1, '...', size = (18,18)) -# savepathButton.SetFont(self.default_font) - savepathsizer.Add(savepathButton, 0, wxALIGN_CENTER) - savepathsizer.Add(self.gui_savemode_data, 0, wxALIGN_CENTER) - block4sizer.Add(savepathsizer, -1, wxALIGN_BOTTOM) - - fontsizer = wxFlexGridSizer(cols = 1, vgap = 2) - fontsizer.Add(StaticText('')) - fontsizer.Add(StaticText('Font: *'), 1, wxALIGN_CENTER) - fontsizer.Add(self.gui_font_data, 1, wxALIGN_CENTER) - block4sizer.Add(fontsizer, 1, wxALIGN_CENTER_VERTICAL) - - dratesettingsSizer = wxFlexGridSizer(cols = 1, vgap = 2) - dratesettingsSizer.Add(StaticText('Default Max'), 1, wxALIGN_CENTER) - dratesettingsSizer.Add(StaticText('Download Rate'), 1, wxALIGN_CENTER) - dratesettingsSizer.Add(StaticText('(kB/s): *'), 1, wxALIGN_CENTER) - dratesettingsSizer.Add(self.maxdownload_data, 1, wxALIGN_CENTER) - dratesettingsSizer.Add(StaticText('(0 = disabled)'), 1, wxALIGN_CENTER) - - block4sizer.Add(dratesettingsSizer, 1, wxALIGN_CENTER_VERTICAL) - - colsizer.Add(block4sizer, 0, wxALIGN_CENTER) -# colsizer.Add(StaticText(' ')) - - savesizer = wxGridSizer(cols = 4, hgap = 10) - saveButton = wxButton(panel, -1, 'Save') -# saveButton.SetFont(self.default_font) - savesizer.Add(saveButton, 0, wxALIGN_CENTER) - - cancelButton = wxButton(panel, -1, 'Cancel') -# cancelButton.SetFont(self.default_font) - savesizer.Add(cancelButton, 0, wxALIGN_CENTER) - - defaultsButton = wxButton(panel, -1, 'Revert to Defaults') -# defaultsButton.SetFont(self.default_font) - savesizer.Add(defaultsButton, 0, wxALIGN_CENTER) - - advancedButton = wxButton(panel, -1, 'Advanced...') -# advancedButton.SetFont(self.default_font) - savesizer.Add(advancedButton, 0, wxALIGN_CENTER) - colsizer.Add(savesizer, 1, wxALIGN_CENTER) - - resizewarningtext=StaticText('* These settings will not take effect until the next time you start BitTorrent', self.FONT-2) - colsizer.Add(resizewarningtext, 1, wxALIGN_CENTER) - - border = wxBoxSizer(wxHORIZONTAL) - border.Add(colsizer, 1, wxEXPAND | wxALL, 4) - - panel.SetSizer(border) - panel.SetAutoLayout(True) - - self.advancedConfig = {} - - def setDefaults(evt, self = self): - try: - self.minport_data.SetValue(self.defaults['minport']) - self.maxport_data.SetValue(self.defaults['maxport']) - self.randomport_checkbox.SetValue(self.defaults['random_port']) - self.gui_stretchwindow_checkbox.SetValue(self.defaults['gui_stretchwindow']) - self.gui_displaystats_checkbox.SetValue(self.defaults['gui_displaystats']) - self.gui_displaymiscstats_checkbox.SetValue(self.defaults['gui_displaymiscstats']) - self.security_checkbox.SetValue(self.defaults['security']) - self.autokick_checkbox.SetValue(self.defaults['auto_kick']) - self.buffering_checkbox.SetValue(self.defaults['buffer_reads']) - self.breakup_checkbox.SetValue(self.defaults['breakup_seed_bitfield']) - self.autoflush_checkbox.SetValue(self.defaults['auto_flush']) - if sys.version_info >= (2,3) and socket.has_ipv6: - self.ipv6enabled_checkbox.SetValue(self.defaults['ipv6_enabled']) - self.gui_forcegreenonfirewall_checkbox.SetValue(self.defaults['gui_forcegreenonfirewall']) - self.gui_font_data.SetValue(self.defaults['gui_font']) - self.gui_ratesettingsdefault_data.SetStringSelection(self.defaults['gui_ratesettingsdefault']) - self.maxdownload_data.SetValue(self.defaults['max_download_rate']) - self.gui_ratesettingsmode_data.SetStringSelection(self.defaults['gui_ratesettingsmode']) - self.gui_default_savedir_ctrl.SetValue(self.defaults['gui_default_savedir']) - self.gui_savemode_data.SetSelection(1-self.defaults['gui_saveas_ask']) - - self.checkingcolor = HexToColor(self.defaults['gui_checkingcolor']) - self.setColorIcon(self.checkingcolor_icon, self.checkingcolor_iconptr, self.checkingcolor) - self.downloadcolor = HexToColor(self.defaults['gui_downloadcolor']) - self.setColorIcon(self.downloadcolor_icon, self.downloadcolor_iconptr, self.downloadcolor) - self.seedingcolor = HexToColor(self.defaults['gui_seedingcolor']) - self.setColorIcon(self.seedingcolor_icon, self.seedingcolor_iconptr, self.seedingcolor) - - if (sys.platform == 'win32'): - self.win32_taskbar_icon_checkbox.SetValue(self.defaults['win32_taskbar_icon']) -# self.upnp_checkbox.SetValue(self.defaults['upnp_nat_access']) - self.upnp_data.SetSelection(self.defaults['upnp_nat_access']) - - # reset advanced too - self.advancedConfig = {} - for key in ['ip', 'bind', 'min_peers', 'max_initiate', 'display_interval', - 'alloc_type', 'alloc_rate', 'max_files_open', 'max_connections', 'super_seeder', - 'ipv6_binds_v4', 'double_check', 'triple_check', 'lock_files', 'lock_while_reading', - 'expire_cache_data']: - self.advancedConfig[key] = self.defaults[key] - self.CloseAdvanced() - except: - self.parent.exception() - - - def saveConfigs(evt, self = self): - try: - self.config['gui_stretchwindow']=int(self.gui_stretchwindow_checkbox.GetValue()) - self.config['gui_displaystats']=int(self.gui_displaystats_checkbox.GetValue()) - self.config['gui_displaymiscstats']=int(self.gui_displaymiscstats_checkbox.GetValue()) - self.config['security']=int(self.security_checkbox.GetValue()) - self.config['auto_kick']=int(self.autokick_checkbox.GetValue()) - buffering=int(self.buffering_checkbox.GetValue()) - self.config['buffer_reads']=buffering - if buffering: - self.config['write_buffer_size']=self.defaults['write_buffer_size'] - else: - self.config['write_buffer_size']=0 - self.config['breakup_seed_bitfield']=int(self.breakup_checkbox.GetValue()) - if self.autoflush_checkbox.GetValue(): - self.config['auto_flush']=5 - else: - self.config['auto_flush']=0 - if sys.version_info >= (2,3) and socket.has_ipv6: - self.config['ipv6_enabled']=int(self.ipv6enabled_checkbox.GetValue()) - self.config['gui_forcegreenonfirewall']=int(self.gui_forcegreenonfirewall_checkbox.GetValue()) - self.config['minport']=self.minport_data.GetValue() - self.config['maxport']=self.maxport_data.GetValue() - self.config['random_port']=int(self.randomport_checkbox.GetValue()) - self.config['gui_font']=self.gui_font_data.GetValue() - self.config['gui_ratesettingsdefault']=self.gui_ratesettingsdefault_data.GetStringSelection() - self.config['max_download_rate']=self.maxdownload_data.GetValue() - self.config['gui_ratesettingsmode']=self.gui_ratesettingsmode_data.GetStringSelection() - self.config['gui_default_savedir']=self.gui_default_savedir_ctrl.GetValue() - self.config['gui_saveas_ask']=1-self.gui_savemode_data.GetSelection() - self.config['gui_checkingcolor']=ColorToHex(self.checkingcolor) - self.config['gui_downloadcolor']=ColorToHex(self.downloadcolor) - self.config['gui_seedingcolor']=ColorToHex(self.seedingcolor) - - if (sys.platform == 'win32'): - self.config['win32_taskbar_icon']=int(self.win32_taskbar_icon_checkbox.GetValue()) -# self.config['upnp_nat_access']=int(self.upnp_checkbox.GetValue()) - self.config['upnp_nat_access']=self.upnp_data.GetSelection() - - if self.advancedConfig: - for key,val in self.advancedConfig.items(): - self.config[key] = val - - self.writeConfigFile() - self._configReset = True - self.Close() - except: - self.parent.exception() - - def cancelConfigs(evt, self = self): - self.Close() - - def savepath_set(evt, self = self): - try: - d = self.gui_default_savedir_ctrl.GetValue() - if d == '': - d = self.config['last_saved'] - dl = wxDirDialog(self.panel, 'Choose a default directory to save to', - d, style = wxDD_DEFAULT_STYLE | wxDD_NEW_DIR_BUTTON) - if dl.ShowModal() == wxID_OK: - self.gui_default_savedir_ctrl.SetValue(dl.GetPath()) - except: - self.parent.exception() - - def checkingcoloricon_set(evt, self = self): - try: - newcolor = self.getColorFromUser(self.panel,self.checkingcolor) - self.setColorIcon(self.checkingcolor_icon, self.checkingcolor_iconptr, newcolor) - self.checkingcolor = newcolor - except: - self.parent.exception() - - def downloadcoloricon_set(evt, self = self): - try: - newcolor = self.getColorFromUser(self.panel,self.downloadcolor) - self.setColorIcon(self.downloadcolor_icon, self.downloadcolor_iconptr, newcolor) - self.downloadcolor = newcolor - except: - self.parent.exception() - - def seedingcoloricon_set(evt, self = self): - try: - newcolor = self.getColorFromUser(self.panel,self.seedingcolor) - self.setColorIcon(self.seedingcolor_icon, self.seedingcolor_iconptr, newcolor) - self.seedingcolor = newcolor - except: - self.parent.exception() - - EVT_BUTTON(self.configMenuBox, saveButton.GetId(), saveConfigs) - EVT_BUTTON(self.configMenuBox, cancelButton.GetId(), cancelConfigs) - EVT_BUTTON(self.configMenuBox, defaultsButton.GetId(), setDefaults) - EVT_BUTTON(self.configMenuBox, advancedButton.GetId(), self.advancedMenu) - EVT_BUTTON(self.configMenuBox, savepathButton.GetId(), savepath_set) - EVT_LEFT_DOWN(self.checkingcolor_iconptr, checkingcoloricon_set) - EVT_LEFT_DOWN(self.downloadcolor_iconptr, downloadcoloricon_set) - EVT_LEFT_DOWN(self.seedingcolor_iconptr, seedingcoloricon_set) - - self.configMenuBox.Show () - border.Fit(panel) - self.configMenuBox.Fit() - except: - self.parent.exception() - - - def Close(self): - self.CloseAdvanced() - if self.configMenuBox is not None: - try: - self.configMenuBox.Close () - except wxPyDeadObjectError, e: - pass - self.configMenuBox = None - - def advancedMenu(self, event = None): - try: - if not self.advancedConfig: - for key in ['ip', 'bind', 'min_peers', 'max_initiate', 'display_interval', - 'alloc_type', 'alloc_rate', 'max_files_open', 'max_connections', 'super_seeder', - 'ipv6_binds_v4', 'double_check', 'triple_check', 'lock_files', 'lock_while_reading', - 'expire_cache_data']: - self.advancedConfig[key] = self.config[key] - - if (self.advancedMenuBox is not None): - try: - self.advancedMenuBox.Close () - except wxPyDeadObjectError, e: - self.advancedMenuBox = None - - self.advancedMenuBox = wxFrame(None, -1, 'BitTorrent Advanced Preferences', size = (1,1), - style = wxDEFAULT_FRAME_STYLE|wxFULL_REPAINT_ON_RESIZE) - if (sys.platform == 'win32'): - self.advancedMenuBox.SetIcon(self.icon) - - panel = wxPanel(self.advancedMenuBox, -1) -# self.panel = panel - - def StaticText(text, font = self.FONT, underline = False, color = None, panel = panel): - x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT) - x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline)) - if color is not None: - x.SetForegroundColour(color) - return x - - colsizer = wxFlexGridSizer(cols = 1, hgap = 13, vgap = 13) - warningtext = StaticText('CHANGE THESE SETTINGS AT YOUR OWN RISK', self.FONT+4, True, 'Red') - colsizer.Add(warningtext, 1, wxALIGN_CENTER) - - self.ip_data = wxTextCtrl(parent = panel, id = -1, - value = self.advancedConfig['ip'], - size = (self.FONT*13, int(self.FONT*2.2)), style = wxTE_PROCESS_TAB) - self.ip_data.SetFont(self.default_font) - - self.bind_data = wxTextCtrl(parent = panel, id = -1, - value = self.advancedConfig['bind'], - size = (self.FONT*13, int(self.FONT*2.2)), style = wxTE_PROCESS_TAB) - self.bind_data.SetFont(self.default_font) - - if sys.version_info >= (2,3) and socket.has_ipv6: - self.ipv6bindsv4_data=wxChoice(panel, -1, - choices = ['separate sockets', 'single socket']) - self.ipv6bindsv4_data.SetFont(self.default_font) - self.ipv6bindsv4_data.SetSelection(self.advancedConfig['ipv6_binds_v4']) - - self.minpeers_data = wxSpinCtrl(panel, -1, '', (-1,-1), (self.FONT*7, -1)) - self.minpeers_data.SetFont(self.default_font) - self.minpeers_data.SetRange(10,100) - self.minpeers_data.SetValue(self.advancedConfig['min_peers']) - # max_initiate = 2*minpeers - - self.displayinterval_data = wxSpinCtrl(panel, -1, '', (-1,-1), (self.FONT*7, -1)) - self.displayinterval_data.SetFont(self.default_font) - self.displayinterval_data.SetRange(100,2000) - self.displayinterval_data.SetValue(int(self.advancedConfig['display_interval']*1000)) - - self.alloctype_data=wxChoice(panel, -1, - choices = ['normal', 'background', 'pre-allocate', 'sparse']) - self.alloctype_data.SetFont(self.default_font) - self.alloctype_data.SetStringSelection(self.advancedConfig['alloc_type']) - - self.allocrate_data = wxSpinCtrl(panel, -1, '', (-1,-1), (self.FONT*7,-1)) - self.allocrate_data.SetFont(self.default_font) - self.allocrate_data.SetRange(1,100) - self.allocrate_data.SetValue(int(self.advancedConfig['alloc_rate'])) - - self.locking_data=wxChoice(panel, -1, - choices = ['no locking', 'lock while writing', 'lock always']) - self.locking_data.SetFont(self.default_font) - if self.advancedConfig['lock_files']: - if self.advancedConfig['lock_while_reading']: - self.locking_data.SetSelection(2) - else: - self.locking_data.SetSelection(1) - else: - self.locking_data.SetSelection(0) - - self.doublecheck_data=wxChoice(panel, -1, - choices = ['no extra checking', 'double-check', 'triple-check']) - self.doublecheck_data.SetFont(self.default_font) - if self.advancedConfig['double_check']: - if self.advancedConfig['triple_check']: - self.doublecheck_data.SetSelection(2) - else: - self.doublecheck_data.SetSelection(1) - else: - self.doublecheck_data.SetSelection(0) - - self.maxfilesopen_choices = ['50', '100', '200', 'no limit '] - self.maxfilesopen_data=wxChoice(panel, -1, choices = self.maxfilesopen_choices) - self.maxfilesopen_data.SetFont(self.default_font) - setval = self.advancedConfig['max_files_open'] - if setval == 0: - setval = 'no limit ' - else: - setval = str(setval) - if not setval in self.maxfilesopen_choices: - setval = self.maxfilesopen_choices[0] - self.maxfilesopen_data.SetStringSelection(setval) - - self.maxconnections_choices = ['no limit ', '20', '30', '40', '50', '60', '100', '200'] - self.maxconnections_data=wxChoice(panel, -1, choices = self.maxconnections_choices) - self.maxconnections_data.SetFont(self.default_font) - setval = self.advancedConfig['max_connections'] - if setval == 0: - setval = 'no limit ' - else: - setval = str(setval) - if not setval in self.maxconnections_choices: - setval = self.maxconnections_choices[0] - self.maxconnections_data.SetStringSelection(setval) - - self.superseeder_data=wxChoice(panel, -1, - choices = ['normal', 'super-seed']) - self.superseeder_data.SetFont(self.default_font) - self.superseeder_data.SetSelection(self.advancedConfig['super_seeder']) - - self.expirecache_choices = ['never ', '3', '5', '7', '10', '15', '30', '60', '90'] - self.expirecache_data=wxChoice(panel, -1, choices = self.expirecache_choices) - setval = self.advancedConfig['expire_cache_data'] - if setval == 0: - setval = 'never ' - else: - setval = str(setval) - if not setval in self.expirecache_choices: - setval = self.expirecache_choices[0] - self.expirecache_data.SetFont(self.default_font) - self.expirecache_data.SetStringSelection(setval) - - - twocolsizer = wxFlexGridSizer(cols = 2, hgap = 20) - datasizer = wxFlexGridSizer(cols = 2, vgap = 2) - datasizer.Add(StaticText('Local IP: '), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.ip_data) - datasizer.Add(StaticText('IP to bind to: '), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.bind_data) - if sys.version_info >= (2,3) and socket.has_ipv6: - datasizer.Add(StaticText('IPv6 socket handling: '), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.ipv6bindsv4_data) - datasizer.Add(StaticText('Minimum number of peers: '), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.minpeers_data) - datasizer.Add(StaticText('Display interval (ms): '), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.displayinterval_data) - datasizer.Add(StaticText('Disk allocation type:'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.alloctype_data) - datasizer.Add(StaticText('Allocation rate (MiB/s):'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.allocrate_data) - datasizer.Add(StaticText('File locking:'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.locking_data) - datasizer.Add(StaticText('Extra data checking:'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.doublecheck_data) - datasizer.Add(StaticText('Max files open:'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.maxfilesopen_data) - datasizer.Add(StaticText('Max peer connections:'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.maxconnections_data) - datasizer.Add(StaticText('Default seeding mode:'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.superseeder_data) - datasizer.Add(StaticText('Expire resume data(days):'), 1, wxALIGN_CENTER_VERTICAL) - datasizer.Add(self.expirecache_data) - - twocolsizer.Add(datasizer) - - infosizer = wxFlexGridSizer(cols = 1) - self.hinttext = StaticText('', self.FONT, False, 'Blue') - infosizer.Add(self.hinttext, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL) - infosizer.SetMinSize((180,100)) - twocolsizer.Add(infosizer, 1, wxEXPAND) - - colsizer.Add(twocolsizer) - - savesizer = wxGridSizer(cols = 3, hgap = 20) - okButton = wxButton(panel, -1, 'OK') -# okButton.SetFont(self.default_font) - savesizer.Add(okButton, 0, wxALIGN_CENTER) - - cancelButton = wxButton(panel, -1, 'Cancel') -# cancelButton.SetFont(self.default_font) - savesizer.Add(cancelButton, 0, wxALIGN_CENTER) - - defaultsButton = wxButton(panel, -1, 'Revert to Defaults') -# defaultsButton.SetFont(self.default_font) - savesizer.Add(defaultsButton, 0, wxALIGN_CENTER) - colsizer.Add(savesizer, 1, wxALIGN_CENTER) - - resizewarningtext=StaticText('None of these settings will take effect until the next time you start BitTorrent', self.FONT-2) - colsizer.Add(resizewarningtext, 1, wxALIGN_CENTER) - - border = wxBoxSizer(wxHORIZONTAL) - border.Add(colsizer, 1, wxEXPAND | wxALL, 4) - - panel.SetSizer(border) - panel.SetAutoLayout(True) - - def setDefaults(evt, self = self): - try: - self.ip_data.SetValue(self.defaults['ip']) - self.bind_data.SetValue(self.defaults['bind']) - if sys.version_info >= (2,3) and socket.has_ipv6: - self.ipv6bindsv4_data.SetSelection(self.defaults['ipv6_binds_v4']) - self.minpeers_data.SetValue(self.defaults['min_peers']) - self.displayinterval_data.SetValue(int(self.defaults['display_interval']*1000)) - self.alloctype_data.SetStringSelection(self.defaults['alloc_type']) - self.allocrate_data.SetValue(int(self.defaults['alloc_rate'])) - if self.defaults['lock_files']: - if self.defaults['lock_while_reading']: - self.locking_data.SetSelection(2) - else: - self.locking_data.SetSelection(1) - else: - self.locking_data.SetSelection(0) - if self.defaults['double_check']: - if self.defaults['triple_check']: - self.doublecheck_data.SetSelection(2) - else: - self.doublecheck_data.SetSelection(1) - else: - self.doublecheck_data.SetSelection(0) - setval = self.defaults['max_files_open'] - if setval == 0: - setval = 'no limit ' - else: - setval = str(setval) - if not setval in self.maxfilesopen_choices: - setval = self.maxfilesopen_choices[0] - self.maxfilesopen_data.SetStringSelection(setval) - setval = self.defaults['max_connections'] - if setval == 0: - setval = 'no limit ' - else: - setval = str(setval) - if not setval in self.maxconnections_choices: - setval = self.maxconnections_choices[0] - self.maxconnections_data.SetStringSelection(setval) - self.superseeder_data.SetSelection(int(self.defaults['super_seeder'])) - setval = self.defaults['expire_cache_data'] - if setval == 0: - setval = 'never ' - else: - setval = str(setval) - if not setval in self.expirecache_choices: - setval = self.expirecache_choices[0] - self.expirecache_data.SetStringSelection(setval) - except: - self.parent.exception() - - def saveConfigs(evt, self = self): - try: - self.advancedConfig['ip'] = self.ip_data.GetValue() - self.advancedConfig['bind'] = self.bind_data.GetValue() - if sys.version_info >= (2,3) and socket.has_ipv6: - self.advancedConfig['ipv6_binds_v4'] = self.ipv6bindsv4_data.GetSelection() - self.advancedConfig['min_peers'] = self.minpeers_data.GetValue() - self.advancedConfig['display_interval'] = float(self.displayinterval_data.GetValue())/1000 - self.advancedConfig['alloc_type'] = self.alloctype_data.GetStringSelection() - self.advancedConfig['alloc_rate'] = float(self.allocrate_data.GetValue()) - self.advancedConfig['lock_files'] = int(self.locking_data.GetSelection() >= 1) - self.advancedConfig['lock_while_reading'] = int(self.locking_data.GetSelection() > 1) - self.advancedConfig['double_check'] = int(self.doublecheck_data.GetSelection() >= 1) - self.advancedConfig['triple_check'] = int(self.doublecheck_data.GetSelection() > 1) - try: - self.advancedConfig['max_files_open'] = int(self.maxfilesopen_data.GetStringSelection()) - except: # if it ain't a number, it must be "no limit" - self.advancedConfig['max_files_open'] = 0 - try: - self.advancedConfig['max_connections'] = int(self.maxconnections_data.GetStringSelection()) - self.advancedConfig['max_initiate'] = min( - 2*self.advancedConfig['min_peers'], self.advancedConfig['max_connections']) - except: # if it ain't a number, it must be "no limit" - self.advancedConfig['max_connections'] = 0 - self.advancedConfig['max_initiate'] = 2*self.advancedConfig['min_peers'] - self.advancedConfig['super_seeder']=int(self.superseeder_data.GetSelection()) - try: - self.advancedConfig['expire_cache_data'] = int(self.expirecache_data.GetStringSelection()) - except: - self.advancedConfig['expire_cache_data'] = 0 - self.advancedMenuBox.Close() - except: - self.parent.exception() - - def cancelConfigs(evt, self = self): - self.advancedMenuBox.Close() - - def ip_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nThe IP reported to the tracker.\n' + - 'unless the tracker is on the\n' + - 'same intranet as this client,\n' + - 'the tracker will autodetect the\n' + - "client's IP and ignore this\n" + - "value.") - - def bind_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nThe IP the client will bind to.\n' + - 'Only useful if your machine is\n' + - 'directly handling multiple IPs.\n' + - "If you don't know what this is,\n" + - "leave it blank.") - - def ipv6bindsv4_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nCertain operating systems will\n' + - 'open IPv4 protocol connections on\n' + - 'an IPv6 socket; others require you\n' + - "to open two sockets on the same\n" + - "port, one IPv4 and one IPv6.") - - def minpeers_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nThe minimum number of peers the\n' + - 'client tries to stay connected\n' + - 'with. Do not set this higher\n' + - 'unless you have a very fast\n' + - "connection and a lot of system\n" + - "resources.") - - def displayinterval_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nHow often to update the\n' + - 'graphical display, in 1/1000s\n' + - 'of a second. Setting this too low\n' + - "will strain your computer's\n" + - "processor and video access.") - - def alloctype_hint(evt, self = self): - self.hinttext.SetLabel('\n\nHow to allocate disk space.\n' + - 'normal allocates space as data is\n' + - 'received, background also adds\n' + - "space in the background, pre-\n" + - "allocate reserves up front, and\n" + - 'sparse is only for filesystems\n' + - 'that support it by default.') - - def allocrate_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nAt what rate to allocate disk\n' + - 'space when allocating in the\n' + - 'background. Set this too high on a\n' + - "slow filesystem and your download\n" + - "will slow to a crawl.") - - def locking_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\n\nFile locking prevents other\n' + - 'programs (including other instances\n' + - 'of BitTorrent) from accessing files\n' + - "you are downloading.") - - def doublecheck_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nHow much extra checking to do\n' + - 'making sure no data is corrupted.\n' + - 'Double-check mode uses more CPU,\n' + - "while triple-check mode increases\n" + - "disk accesses.") - - def maxfilesopen_hint(evt, self = self): - self.hinttext.SetLabel('\n\n\nThe maximum number of files to\n' + - 'keep open at the same time. Zero\n' + - 'means no limit. Please note that\n' + - "if this option is in effect,\n" + - "files are not guaranteed to be\n" + - "locked.") - - def maxconnections_hint(evt, self = self): - self.hinttext.SetLabel('\n\nSome operating systems, most\n' + - 'notably Windows 9x/ME combined\n' + - 'with certain network drivers,\n' + - "cannot handle more than a certain\n" + - "number of open ports. If the\n" + - "client freezes, try setting this\n" + - "to 60 or below.") - - def superseeder_hint(evt, self = self): - self.hinttext.SetLabel('\n\nThe "super-seed" method allows\n' + - 'a single source to more efficiently\n' + - 'seed a large torrent, but is not\n' + - "necessary in a well-seeded torrent,\n" + - "and causes problems with statistics.\n" + - "Unless you routinely seed torrents\n" + - "you can enable this by selecting\n" + - '"SUPER-SEED" for connection type.\n' + - '(once enabled it does not turn off.)') - - def expirecache_hint(evt, self = self): - self.hinttext.SetLabel('\n\nThe client stores temporary data\n' + - 'in order to handle downloading only\n' + - 'specific files from the torrent and\n' + - "so it can resume downloads more\n" + - "quickly. This sets how long the\n" + - "client will keep this data before\n" + - "deleting it to free disk space.") - - EVT_BUTTON(self.advancedMenuBox, okButton.GetId(), saveConfigs) - EVT_BUTTON(self.advancedMenuBox, cancelButton.GetId(), cancelConfigs) - EVT_BUTTON(self.advancedMenuBox, defaultsButton.GetId(), setDefaults) - EVT_ENTER_WINDOW(self.ip_data, ip_hint) - EVT_ENTER_WINDOW(self.bind_data, bind_hint) - if sys.version_info >= (2,3) and socket.has_ipv6: - EVT_ENTER_WINDOW(self.ipv6bindsv4_data, ipv6bindsv4_hint) - EVT_ENTER_WINDOW(self.minpeers_data, minpeers_hint) - EVT_ENTER_WINDOW(self.displayinterval_data, displayinterval_hint) - EVT_ENTER_WINDOW(self.alloctype_data, alloctype_hint) - EVT_ENTER_WINDOW(self.allocrate_data, allocrate_hint) - EVT_ENTER_WINDOW(self.locking_data, locking_hint) - EVT_ENTER_WINDOW(self.doublecheck_data, doublecheck_hint) - EVT_ENTER_WINDOW(self.maxfilesopen_data, maxfilesopen_hint) - EVT_ENTER_WINDOW(self.maxconnections_data, maxconnections_hint) - EVT_ENTER_WINDOW(self.superseeder_data, superseeder_hint) - EVT_ENTER_WINDOW(self.expirecache_data, expirecache_hint) - - self.advancedMenuBox.Show () - border.Fit(panel) - self.advancedMenuBox.Fit() - except: - self.parent.exception() - - - def CloseAdvanced(self): - if self.advancedMenuBox is not None: - try: - self.advancedMenuBox.Close() - except wxPyDeadObjectError, e: - self.advancedMenuBox = None - diff --git a/www/pages/torrent/client/ConnChoice.py b/www/pages/torrent/client/ConnChoice.py deleted file mode 100644 index 8d07396..0000000 --- a/www/pages/torrent/client/ConnChoice.py +++ /dev/null @@ -1,31 +0,0 @@ -connChoices=( - {'name':'automatic', - 'rate':{'min':0, 'max':5000, 'def': 0}, - 'conn':{'min':0, 'max':100, 'def': 0}, - 'automatic':1}, - {'name':'unlimited', - 'rate':{'min':0, 'max':5000, 'def': 0, 'div': 50}, - 'conn':{'min':4, 'max':100, 'def': 4}}, - {'name':'dialup/isdn', - 'rate':{'min':3, 'max': 8, 'def': 5}, - 'conn':{'min':2, 'max': 3, 'def': 2}, - 'initiate': 12}, - {'name':'dsl/cable slow', - 'rate':{'min':10, 'max': 48, 'def': 13}, - 'conn':{'min':4, 'max': 20, 'def': 4}}, - {'name':'dsl/cable fast', - 'rate':{'min':20, 'max': 100, 'def': 40}, - 'conn':{'min':4, 'max': 30, 'def': 6}}, - {'name':'T1', - 'rate':{'min':100, 'max': 300, 'def':150}, - 'conn':{'min':4, 'max': 40, 'def':10}}, - {'name':'T3+', - 'rate':{'min':400, 'max':2000, 'def':500}, - 'conn':{'min':4, 'max':100, 'def':20}}, - {'name':'seeder', - 'rate':{'min':0, 'max':5000, 'def':0, 'div': 50}, - 'conn':{'min':1, 'max':100, 'def':1}}, - {'name':'SUPER-SEED', 'super-seed':1} - ) - -connChoiceList = map(lambda x:x['name'], connChoices) diff --git a/www/pages/torrent/client/CreateIcons.py b/www/pages/torrent/client/CreateIcons.py deleted file mode 100644 index 72e0241..0000000 --- a/www/pages/torrent/client/CreateIcons.py +++ /dev/null @@ -1,105 +0,0 @@ -# Generated from bt_MakeCreateIcons - 05/10/04 22:15:33 -# T-0.3.0 (BitTornado) - -from binascii import a2b_base64 -from zlib import decompress -from os.path import join - -icons = { - "icon_bt.ico": - "eJyt1K+OFEEQx/FaQTh5GDRZhSQpiUHwCrxCBYXFrjyJLXeXEARPsZqUPMm+" + - "AlmP+PGtngoLDji69zMz2zt/qqtr1mxHv7621d4+MnvK/jl66Bl2drV+e7Wz" + - "S/v12A7rY4fDtuvOwfF4tOPXo52/fLLz+WwpWd6nqRXHKXux39sTrtnjNd7g" + - "PW7wGSd860f880kffjvJ2QYS1Zcw4AjcoaA5yRFIFDQXOgKJguZmjkCioB4T" + - "Y2CqxpTXA7sHEgVNEC8RSBQ0gfk7xtknCupgk3EEEgXlNgFHIFHQTMoRSBQ0" + - "E+1ouicKmsk7AomCJiGOQKKgSZIjkChoEucIJAqaZDoCiYImwb4iydULmqQ7" + - "AomC1kLcEQ/jSBQ0i+MIJAqaBXMEElVdi9siOgKJgmZhfWWlVjTddXW/FtsR" + - "SBQ0BeAIJAqaonAEEgVNoTgCiYKmeByBREHaqiVWRtSRrAJzBBIFTdE5AomC" + - "phBPpxPP57dVkDfrTl063nUVnWe383fZx9tb3uN+o7U+BLDtuvcQm8d/27Y/" + - "jO3o5/ay+YPv/+f6y30e1OyB7QcsGWFj", - "icon_done.ico": - "eJyt1K2OVEEQhuEaQbJyMWgyCklSEoPgFvYWKigsduRKbLndhCC4itGk5Erm" + - "Fsh4xMdbfSoMOGDpnuf89Jyf6uqaMdvRr69ttbdPzJ6xf4Eeeo6dXa3vXu/s" + - "0n49tsP62OGw7bpzcDwe7fj1aOcvn+x8PltKlg9pasVxyl7u9/aUe/Z4gxu8" + - "xy0+44Rv/Yp/vujDbxc520Ci+hYGHIF7FDQXOQKJguZGRyBR0DzMEUgU1GNi" + - "DEzVmPJ6YfdAoqAJ4hUCiYImMH/HOPtEQR1sMo5AoqDcJuAIJAqaSTkCiYJm" + - "oh1N90RBM3lHIFHQJMQRSBQ0SXIEEgVN4hyBREGTTEcgUdAk2FckuXpBk3RH" + - "IFHQWoh74mEciYJmcRyBREGzYI5AoqprcVtERyBR0Cysr6zUiqa7rh7WYjsC" + - "iYKmAByBREFTFI5AoqApFEcgUdAUjyOQKEhbtcTKiDqSVWCOQKKgKTpHIFHQ" + - "FOLpdOL9fLcK8nY9qUvHu66i8+x2/i77eHfH77h/0VofAth23Xuoz/+2bX8Y" + - "29HP7WXzB+f/5/7Lcx7V7JHtB9dPG3I=", - "black.ico": - "eJzt1zsOgkAYReFLLCztjJ2UlpLY485kOS7DpbgESwqTcQZDghjxZwAfyfl0" + - "LIieGzUWSom/pan840rHnbSUtPHHX9Je9+tAh2ybNe8TZZ/vk8ajJ4zl6JVJ" + - "+xFx+0R03Djx1/2B8bcT9L/bt0+4Wq+4se8e/VTfMvGqb4n3nYiIGz+lvt9s" + - "9EpE2T4xJN4xNFYWU6t+JWXuXDFzTom7SodSyi/S+iwtwjlJ80KaNY/C34rW" + - "aT8nvK5uhF7ohn7Yqfb87kffLAAAAAAAAAAAAAAAAAAAGMUNy7dADg==", - "blue.ico": - "eJzt10EOwUAYhuGv6cLSTux06QD2dTM9jmM4iiNYdiEZ81cIFTWddtDkfbQW" + - "De8XogtS5h9FIf+81H4jLSSt/ekvaavrdaCDez4SZV+PpPHoicBy9ErSfkQ8" + - "fCI6Hjgx6f7A+McJ+r/t95i46xMP7bf8Uz9o4k0/XMT338voP5shK0MkjXcM" + - "YSqam6Qunatyf7Nk7iztaqk8SaujNLfzIM0qKX88ZX8rWmf7Nfa+W8N61rW+" + - "7TR7fverHxYAAAAAAAAAAAAAAAAAAIziApVZ444=", - "green.ico": - "eJzt1zEOgjAAheFHGBzdjJuMHsAdbybxNB7Do3gERwaT2mJIBCOWlqok/yc4" + - "EP1fNDIoZfZRFLLPa5120krS1p72kvZ6XAeGHLtHouzrkTQePOFZDl5J2g+I" + - "+08Exz0nZt2PjH+coP/bvveEaY2L+/VN13/1PSbe9v0FfP+jTP6ziVmJkTQ+" + - "MISZaO6SujSmyu3dkpmbdKil8iptLtLSnWdpUUn58yn3t6J39l/j3tc2XM91" + - "Xd/tNHt296sfFgAAAAAAAAAAAAAAAAAATOIOVLEoDg==", - "red.ico": - "eJzt10EOwUAYhuGv6cLSTux06QD2dTOO4xiO4giWXUjG/BVCRTuddtDkfbQW" + - "De8XogtS5h9FIf+81GEjLSSt/ekvaavbdaCVez0SZd+PpPHoicBy9ErSfkQ8" + - "fCI6Hjgx6f7AeOcE/d/2QyceesaD+g1/1u+e+NwPF/H99zL6z2bIyhBJ4y1D" + - "mIb6LqlK5/a5v1syd5F2lVSepdVJmtt5lGZ7KX8+ZX8rGmfzNfa+e8N61rW+" + - "7dR7fverHxYAAAAAAAAAAAAAAAAAAIziCpgs444=", - "white.ico": - "eJzt1zsOgkAYReFLKCztjJ2ULsAed6bLcRnuwYTaJVhSmIwzGBLEiD8D+EjO" + - "p2NB9NyosVBK/C3L5B+XOmykhaS1P/6StrpfBzoUp6J5nyj7fJ80Hj1hLEev" + - "TNqPiNsnouPGib/uD4y/naD/3b59wtV6xY199+in+paJV31LvO9ERNz4KfX9" + - "ZqNXIsr2iSHxjqGxspha9Sspc+f2qXNK3FXalVJ+kVZnaR7OUZrtpbR5FP5W" + - "tE77OeF1dSP0Qjf0w06153c/+mYBAAAAAAAAAAAAAAAAAMAobj//I7s=", - "yellow.ico": - "eJzt1zsOgkAYReFLKCztjJ2ULsAedybLcRkuxSVYUpiM82M0ihGHgVFJzidY" + - "ED03vgqlzN+KQv5+qf1GWkha+9Nf0lbX60AX556ORNnXI2k8eiKwHL2StB8R" + - "D5+IjgdOTLo/MP5xgv5v+8ETd/3iYf2W/+oHTLzth4t4/3sZ/WszZGWIpPGO" + - "IUxE8yupS+eq3H9smTtLu1oqT9LqKM3tPEizSsofT9nfitbZfow979awnnWt" + - "bzvNnt/96osFAAAAAAAAAAAAAAAAAACjuABhjmIs", - "black1.ico": - "eJzt0zEOgkAUANEhFpZSGTstTWzkVt5Cj8ZROAIHMNGPWBCFDYgxMZkHn2Iz" + - "G5YCyOLKc+K54XSANbCPiSV2tOt/qjgW3XtSnN41FH/Qv29Jx/P7qefp7W8P" + - "4z85HQ+9JRG/7BpTft31DPUKyiVcFjEZzQ/TTtdzrWnKmCr6evv780qSJEmS" + - "JEmSJEmSJEmSpPnunVFDcA==", - "green1.ico": - "eJzt0zEKwkAQRuEXLCyTSuy0DHgxb6F4shzFI+QAgpkkFoombowIwvt2Z4vh" + - "X5gtFrJYRUGca/Y7WAFlVLTY0vf/1elxTwqP3xoKf5B/vjIenp+fOs+r/LWT" + - "/uQ34aGpUqQnv+1ygDqHagnHRVRG+2H6unfrtZkq6hz5evP7eSVJkiRJkiRJ" + - "kiRJkiRJ0nwNoWQ+AA==", - "yellow1.ico": - "eJzt0zEKwkAQRuEXLCxNJXZaCl7MW8Sj5SgeIQcQ4oS1UDTJxkhAeN/ubDH8" + - "C7PFQhGrLIlzx/kEW+AYFS0OpP6/atuXPSk8fKsv/EX+/cpweH5+6jyf8kn+" + - "k0fCfVPlyE/+2q2CZgP1Gi6rqILuw6R69uh1mTrqGvlmv/y8kiRJkiRJkiRJ" + - "kiRJkiRpvjsp9L8k", - "alloc.gif": - "eJxz93SzsEw0YRBh+M4ABi0MS3ue///P8H8UjIIRBhR/sjAyMDAx6IAyAihP" + - "MHAcYWDlkPHYsOBgM4ewVsyJDQsPNzEoebF8CHjo0smjH3dmRsDjI33C7Dw3" + - "MiYuOtjNyDShRSNwyemJguJJKhaGS32nGka61Vg2NJyYKRd+bY+nwtMzjbqV" + - "Qh84gxMCJgnlL4vJuqJyaa5NfFLNLsNVV2a7syacfVWkHd4bv7RN1ltM7ejm" + - "tMtNZ19Oyb02p8C3aqr3dr2GbXl/7fZyOej5rW653WZ7MzzHZV+v7O2/EZM+" + - "Pt45kbX6ScWHNWfOilo3n5thucXv8org1XF3DRQYrAEWiVY3" -} - -def GetIcons(): - return icons.keys() - -def CreateIcon(icon, savedir): - try: - f = open(join(savedir,icon),"wb") - f.write(decompress(a2b_base64(icons[icon]))) - success = 1 - except: - success = 0 - try: - f.close() - except: - pass - return success diff --git a/www/pages/torrent/client/CurrentRateMeasure.py b/www/pages/torrent/client/CurrentRateMeasure.py deleted file mode 100644 index a363565..0000000 --- a/www/pages/torrent/client/CurrentRateMeasure.py +++ /dev/null @@ -1,37 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -from clock import clock - -class Measure: - def __init__(self, max_rate_period, fudge = 1): - self.max_rate_period = max_rate_period - self.ratesince = clock() - fudge - self.last = self.ratesince - self.rate = 0.0 - self.total = 0l - - def update_rate(self, amount): - self.total += amount - t = clock() - self.rate = (self.rate * (self.last - self.ratesince) + - amount) / (t - self.ratesince + 0.0001) - self.last = t - if self.ratesince < t - self.max_rate_period: - self.ratesince = t - self.max_rate_period - - def get_rate(self): - self.update_rate(0) - return self.rate - - def get_rate_noupdate(self): - return self.rate - - def time_until_rate(self, newrate): - if self.rate <= newrate: - return 0 - t = clock() - self.ratesince - return ((self.rate * t) / newrate) - t - - def get_total(self): - return self.total \ No newline at end of file diff --git a/www/pages/torrent/client/HTTPHandler.py b/www/pages/torrent/client/HTTPHandler.py deleted file mode 100644 index b8146e5..0000000 --- a/www/pages/torrent/client/HTTPHandler.py +++ /dev/null @@ -1,167 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -from cStringIO import StringIO -from sys import stdout -import time -from clock import clock -from gzip import GzipFile -try: - True -except: - True = 1 - False = 0 - -DEBUG = False - -weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] - -months = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - -class HTTPConnection: - def __init__(self, handler, connection): - self.handler = handler - self.connection = connection - self.buf = '' - self.closed = False - self.done = False - self.donereading = False - self.next_func = self.read_type - - def get_ip(self): - return self.connection.get_ip() - - def data_came_in(self, data): - if self.donereading or self.next_func is None: - return True - self.buf += data - while True: - try: - i = self.buf.index('\n') - except ValueError: - return True - val = self.buf[:i] - self.buf = self.buf[i+1:] - self.next_func = self.next_func(val) - if self.donereading: - return True - if self.next_func is None or self.closed: - return False - - def read_type(self, data): - self.header = data.strip() - words = data.split() - if len(words) == 3: - self.command, self.path, garbage = words - self.pre1 = False - elif len(words) == 2: - self.command, self.path = words - self.pre1 = True - if self.command != 'GET': - return None - else: - return None - if self.command not in ('HEAD', 'GET'): - return None - self.headers = {} - return self.read_header - - def read_header(self, data): - data = data.strip() - if data == '': - self.donereading = True - if self.headers.get('accept-encoding','').find('gzip') > -1: - self.encoding = 'gzip' - else: - self.encoding = 'identity' - r = self.handler.getfunc(self, self.path, self.headers) - if r is not None: - self.answer(r) - return None - try: - i = data.index(':') - except ValueError: - return None - self.headers[data[:i].strip().lower()] = data[i+1:].strip() - if DEBUG: - print data[:i].strip() + ": " + data[i+1:].strip() - return self.read_header - - def answer(self, (responsecode, responsestring, headers, data)): - if self.closed: - return - if self.encoding == 'gzip': - compressed = StringIO() - gz = GzipFile(fileobj = compressed, mode = 'wb', compresslevel = 9) - gz.write(data) - gz.close() - cdata = compressed.getvalue() - if len(cdata) >= len(data): - self.encoding = 'identity' - else: - if DEBUG: - print "Compressed: %i Uncompressed: %i\n" % (len(cdata),len(data)) - data = cdata - headers['Content-Encoding'] = 'gzip' - - # i'm abusing the identd field here, but this should be ok - if self.encoding == 'identity': - ident = '-' - else: - ident = self.encoding - self.handler.log( self.connection.get_ip(), ident, '-', - self.header, responsecode, len(data), - self.headers.get('referer','-'), - self.headers.get('user-agent','-') ) - self.done = True - r = StringIO() - r.write('HTTP/1.0 ' + str(responsecode) + ' ' + - responsestring + '\r\n') - if not self.pre1: - headers['Content-Length'] = len(data) - for key, value in headers.items(): - r.write(key + ': ' + str(value) + '\r\n') - r.write('\r\n') - if self.command != 'HEAD': - r.write(data) - self.connection.write(r.getvalue()) - if self.connection.is_flushed(): - self.connection.shutdown(1) - -class HTTPHandler: - def __init__(self, getfunc, minflush): - self.connections = {} - self.getfunc = getfunc - self.minflush = minflush - self.lastflush = clock() - - def external_connection_made(self, connection): - self.connections[connection] = HTTPConnection(self, connection) - - def connection_flushed(self, connection): - if self.connections[connection].done: - connection.shutdown(1) - - def connection_lost(self, connection): - ec = self.connections[connection] - ec.closed = True - del ec.connection - del ec.next_func - del self.connections[connection] - - def data_came_in(self, connection, data): - c = self.connections[connection] - if not c.data_came_in(data) and not c.closed: - c.connection.shutdown(1) - - def log(self, ip, ident, username, header, - responsecode, length, referrer, useragent): - year, month, day, hour, minute, second, a, b, c = time.localtime(time.time()) - print '%s %s %s [%02d/%3s/%04d:%02d:%02d:%02d] "%s" %i %i "%s" "%s"' % ( - ip, ident, username, day, months[month], year, hour, - minute, second, header, responsecode, length, referrer, useragent) - t = clock() - if t - self.lastflush > self.minflush: - self.lastflush = t - stdout.flush() diff --git a/www/pages/torrent/client/PSYCO.py b/www/pages/torrent/client/PSYCO.py deleted file mode 100644 index e5e7dae..0000000 --- a/www/pages/torrent/client/PSYCO.py +++ /dev/null @@ -1,5 +0,0 @@ -# edit this file to enable/disable Psyco -# psyco = 1 -- enabled -# psyco = 0 -- disabled - -psyco = 0 diff --git a/www/pages/torrent/client/RateLimiter.py b/www/pages/torrent/client/RateLimiter.py deleted file mode 100644 index 4e64966..0000000 --- a/www/pages/torrent/client/RateLimiter.py +++ /dev/null @@ -1,153 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -from traceback import print_exc -from binascii import b2a_hex -from clock import clock -from CurrentRateMeasure import Measure -from cStringIO import StringIO -from math import sqrt - -try: - True -except: - True = 1 - False = 0 -try: - sum([1]) -except: - sum = lambda a: reduce(lambda x,y: x+y, a, 0) - -DEBUG = False - -MAX_RATE_PERIOD = 20.0 -MAX_RATE = 10e10 -PING_BOUNDARY = 1.2 -PING_SAMPLES = 7 -PING_DISCARDS = 1 -PING_THRESHHOLD = 5 -PING_DELAY = 5 # cycles 'til first upward adjustment -PING_DELAY_NEXT = 2 # 'til next -ADJUST_UP = 1.05 -ADJUST_DOWN = 0.95 -UP_DELAY_FIRST = 5 -UP_DELAY_NEXT = 2 -SLOTS_STARTING = 6 -SLOTS_FACTOR = 1.66/1000 - -class RateLimiter: - def __init__(self, sched, unitsize, slotsfunc = lambda x: None): - self.sched = sched - self.last = None - self.unitsize = unitsize - self.slotsfunc = slotsfunc - self.measure = Measure(MAX_RATE_PERIOD) - self.autoadjust = False - self.upload_rate = MAX_RATE * 1000 - self.slots = SLOTS_STARTING # garbage if not automatic - - def set_upload_rate(self, rate): - # rate = -1 # test automatic - if rate < 0: - if self.autoadjust: - return - self.autoadjust = True - self.autoadjustup = 0 - self.pings = [] - rate = MAX_RATE - self.slots = SLOTS_STARTING - self.slotsfunc(self.slots) - else: - self.autoadjust = False - if not rate: - rate = MAX_RATE - self.upload_rate = rate * 1000 - self.lasttime = clock() - self.bytes_sent = 0 - - def queue(self, conn): - assert conn.next_upload is None - if self.last is None: - self.last = conn - conn.next_upload = conn - self.try_send(True) - else: - conn.next_upload = self.last.next_upload - self.last.next_upload = conn - self.last = conn - - def try_send(self, check_time = False): - t = clock() - self.bytes_sent -= (t - self.lasttime) * self.upload_rate - self.lasttime = t - if check_time: - self.bytes_sent = max(self.bytes_sent, 0) - cur = self.last.next_upload - while self.bytes_sent <= 0: - bytes = cur.send_partial(self.unitsize) - self.bytes_sent += bytes - self.measure.update_rate(bytes) - if bytes == 0 or cur.backlogged(): - if self.last is cur: - self.last = None - cur.next_upload = None - break - else: - self.last.next_upload = cur.next_upload - cur.next_upload = None - cur = self.last.next_upload - else: - self.last = cur - cur = cur.next_upload - else: - self.sched(self.try_send, self.bytes_sent / self.upload_rate) - - def adjust_sent(self, bytes): - self.bytes_sent = min(self.bytes_sent+bytes, self.upload_rate*3) - self.measure.update_rate(bytes) - - - def ping(self, delay): - if DEBUG: - print delay - if not self.autoadjust: - return - self.pings.append(delay > PING_BOUNDARY) - if len(self.pings) < PING_SAMPLES+PING_DISCARDS: - return - if DEBUG: - print 'cycle' - pings = sum(self.pings[PING_DISCARDS:]) - del self.pings[:] - if pings >= PING_THRESHHOLD: # assume flooded - if self.upload_rate == MAX_RATE: - self.upload_rate = self.measure.get_rate()*ADJUST_DOWN - else: - self.upload_rate = min(self.upload_rate, - self.measure.get_rate()*1.1) - self.upload_rate = max(int(self.upload_rate*ADJUST_DOWN),2) - self.slots = int(sqrt(self.upload_rate*SLOTS_FACTOR)) - self.slotsfunc(self.slots) - if DEBUG: - print 'adjust down to '+str(self.upload_rate) - self.lasttime = clock() - self.bytes_sent = 0 - self.autoadjustup = UP_DELAY_FIRST - else: # not flooded - if self.upload_rate == MAX_RATE: - return - self.autoadjustup -= 1 - if self.autoadjustup: - return - self.upload_rate = int(self.upload_rate*ADJUST_UP) - self.slots = int(sqrt(self.upload_rate*SLOTS_FACTOR)) - self.slotsfunc(self.slots) - if DEBUG: - print 'adjust up to '+str(self.upload_rate) - self.lasttime = clock() - self.bytes_sent = 0 - self.autoadjustup = UP_DELAY_NEXT - - - - diff --git a/www/pages/torrent/client/RateMeasure.py b/www/pages/torrent/client/RateMeasure.py deleted file mode 100644 index 7b7310a..0000000 --- a/www/pages/torrent/client/RateMeasure.py +++ /dev/null @@ -1,75 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -from clock import clock -try: - True -except: - True = 1 - False = 0 - -FACTOR = 0.999 - -class RateMeasure: - def __init__(self): - self.last = None - self.time = 1.0 - self.got = 0.0 - self.remaining = None - self.broke = False - self.got_anything = False - self.last_checked = None - self.rate = 0 - self.lastten = False - - def data_came_in(self, amount): - if not self.got_anything: - self.got_anything = True - self.last = clock() - return - self.update(amount) - - def data_rejected(self, amount): - pass - - def get_time_left(self, left): - t = clock() - if not self.got_anything: - return None - if t - self.last > 15: - self.update(0) - try: - remaining = left/self.rate - if not self.lastten and remaining <= 10: - self.lastten = True - if self.lastten: - return remaining - delta = max(remaining/20,2) - if self.remaining is None: - self.remaining = remaining - elif abs(self.remaining-remaining) > delta: - self.remaining = remaining - else: - self.remaining -= t - self.last_checked - except ZeroDivisionError: - self.remaining = None - if self.remaining is not None and self.remaining < 0.1: - self.remaining = 0.1 - self.last_checked = t - return self.remaining - - def update(self, amount): - t = clock() - t1 = int(t) - l1 = int(self.last) - for i in xrange(l1,t1): - self.time *= FACTOR - self.got *= FACTOR - self.got += amount - if t - self.last < 20: - self.time += t - self.last - self.last = t - try: - self.rate = self.got / self.time - except ZeroDivisionError: - pass diff --git a/www/pages/torrent/client/RawServer.py b/www/pages/torrent/client/RawServer.py deleted file mode 100644 index 1274934..0000000 --- a/www/pages/torrent/client/RawServer.py +++ /dev/null @@ -1,195 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -from bisect import insort -from SocketHandler import SocketHandler, UPnP_ERROR -import socket -from cStringIO import StringIO -from traceback import print_exc -from select import error -from threading import Thread, Event -from time import sleep -from clock import clock -import sys -try: - True -except: - True = 1 - False = 0 - - -def autodetect_ipv6(): - try: - assert sys.version_info >= (2,3) - assert socket.has_ipv6 - socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - except: - return 0 - return 1 - -def autodetect_socket_style(): - if sys.platform.find('linux') < 0: - return 1 - else: - try: - f = open('/proc/sys/net/ipv6/bindv6only','r') - dual_socket_style = int(f.read()) - f.close() - return int(not dual_socket_style) - except: - return 0 - - -READSIZE = 100000 - -class RawServer: - def __init__(self, doneflag, timeout_check_interval, timeout, noisy = True, - ipv6_enable = True, failfunc = lambda x: None, errorfunc = None, - sockethandler = None, excflag = Event()): - self.timeout_check_interval = timeout_check_interval - self.timeout = timeout - self.servers = {} - self.single_sockets = {} - self.dead_from_write = [] - self.doneflag = doneflag - self.noisy = noisy - self.failfunc = failfunc - self.errorfunc = errorfunc - self.exccount = 0 - self.funcs = [] - self.externally_added = [] - self.finished = Event() - self.tasks_to_kill = [] - self.excflag = excflag - - if sockethandler is None: - sockethandler = SocketHandler(timeout, ipv6_enable, READSIZE) - self.sockethandler = sockethandler - self.add_task(self.scan_for_timeouts, timeout_check_interval) - - def get_exception_flag(self): - return self.excflag - - def _add_task(self, func, delay, id = None): - assert float(delay) >= 0 - insort(self.funcs, (clock() + delay, func, id)) - - def add_task(self, func, delay = 0, id = None): - assert float(delay) >= 0 - self.externally_added.append((func, delay, id)) - - def scan_for_timeouts(self): - self.add_task(self.scan_for_timeouts, self.timeout_check_interval) - self.sockethandler.scan_for_timeouts() - - def bind(self, port, bind = '', reuse = False, - ipv6_socket_style = 1, upnp = False): - self.sockethandler.bind(port, bind, reuse, ipv6_socket_style, upnp) - - def find_and_bind(self, minport, maxport, bind = '', reuse = False, - ipv6_socket_style = 1, upnp = 0, randomizer = False): - return self.sockethandler.find_and_bind(minport, maxport, bind, reuse, - ipv6_socket_style, upnp, randomizer) - - def start_connection_raw(self, dns, socktype, handler = None): - return self.sockethandler.start_connection_raw(dns, socktype, handler) - - def start_connection(self, dns, handler = None, randomize = False): - return self.sockethandler.start_connection(dns, handler, randomize) - - def get_stats(self): - return self.sockethandler.get_stats() - - def pop_external(self): - while self.externally_added: - (a, b, c) = self.externally_added.pop(0) - self._add_task(a, b, c) - - - def listen_forever(self, handler): - self.sockethandler.set_handler(handler) - try: - while not self.doneflag.isSet(): - try: - self.pop_external() - self._kill_tasks() - if self.funcs: - period = self.funcs[0][0] + 0.001 - clock() - else: - period = 2 ** 30 - if period < 0: - period = 0 - events = self.sockethandler.do_poll(period) - if self.doneflag.isSet(): - return - while self.funcs and self.funcs[0][0] <= clock(): - garbage1, func, id = self.funcs.pop(0) - if id in self.tasks_to_kill: - pass - try: -# print func.func_name - func() - except (SystemError, MemoryError), e: - self.failfunc(str(e)) - return - except KeyboardInterrupt: -# self.exception(True) - return - except: - if self.noisy: - self.exception() - self.sockethandler.close_dead() - self.sockethandler.handle_events(events) - if self.doneflag.isSet(): - return - self.sockethandler.close_dead() - except (SystemError, MemoryError), e: - self.failfunc(str(e)) - return - except error: - if self.doneflag.isSet(): - return - except KeyboardInterrupt: -# self.exception(True) - return - except: - self.exception() - if self.exccount > 10: - return - finally: -# self.sockethandler.shutdown() - self.finished.set() - - def is_finished(self): - return self.finished.isSet() - - def wait_until_finished(self): - self.finished.wait() - - def _kill_tasks(self): - if self.tasks_to_kill: - new_funcs = [] - for (t, func, id) in self.funcs: - if id not in self.tasks_to_kill: - new_funcs.append((t, func, id)) - self.funcs = new_funcs - self.tasks_to_kill = [] - - def kill_tasks(self, id): - self.tasks_to_kill.append(id) - - def exception(self, kbint = False): - if not kbint: - self.excflag.set() - self.exccount += 1 - if self.errorfunc is None: - print_exc() - else: - data = StringIO() - print_exc(file = data) -# print data.getvalue() # report exception here too - if not kbint: # don't report here if it's a keyboard interrupt - self.errorfunc(data.getvalue()) - - def shutdown(self): - self.sockethandler.shutdown() diff --git a/www/pages/torrent/client/ServerPortHandler.py b/www/pages/torrent/client/ServerPortHandler.py deleted file mode 100644 index 63df089..0000000 --- a/www/pages/torrent/client/ServerPortHandler.py +++ /dev/null @@ -1,188 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -from cStringIO import StringIO -#from RawServer import RawServer -try: - True -except: - True = 1 - False = 0 - -from BT1.Encrypter import protocol_name - -default_task_id = [] - -class SingleRawServer: - def __init__(self, info_hash, multihandler, doneflag, protocol): - self.info_hash = info_hash - self.doneflag = doneflag - self.protocol = protocol - self.multihandler = multihandler - self.rawserver = multihandler.rawserver - self.finished = False - self.running = False - self.handler = None - self.taskqueue = [] - - def shutdown(self): - if not self.finished: - self.multihandler.shutdown_torrent(self.info_hash) - - def _shutdown(self): - if not self.finished: - self.finished = True - self.running = False - self.rawserver.kill_tasks(self.info_hash) - if self.handler: - self.handler.close_all() - - def _external_connection_made(self, c, options, already_read): - if self.running: - c.set_handler(self.handler) - self.handler.externally_handshaked_connection_made( - c, options, already_read) - - ### RawServer functions ### - - def add_task(self, func, delay=0, id = default_task_id): - if id is default_task_id: - id = self.info_hash - if not self.finished: - self.rawserver.add_task(func, delay, id) - -# def bind(self, port, bind = '', reuse = False): -# pass # not handled here - - def start_connection(self, dns, handler = None): - if not handler: - handler = self.handler - c = self.rawserver.start_connection(dns, handler) - return c - -# def listen_forever(self, handler): -# pass # don't call with this - - def start_listening(self, handler): - self.handler = handler - self.running = True - return self.shutdown # obviously, doesn't listen forever - - def is_finished(self): - return self.finished - - def get_exception_flag(self): - return self.rawserver.get_exception_flag() - - -class NewSocketHandler: # hand a new socket off where it belongs - def __init__(self, multihandler, connection): - self.multihandler = multihandler - self.connection = connection - connection.set_handler(self) - self.closed = False - self.buffer = StringIO() - self.complete = False - self.next_len, self.next_func = 1, self.read_header_len - self.multihandler.rawserver.add_task(self._auto_close, 15) - - def _auto_close(self): - if not self.complete: - self.close() - - def close(self): - if not self.closed: - self.connection.close() - self.closed = True - - -# header format: -# connection.write(chr(len(protocol_name)) + protocol_name + -# (chr(0) * 8) + self.encrypter.download_id + self.encrypter.my_id) - - # copied from Encrypter and modified - - def read_header_len(self, s): - l = ord(s) - return l, self.read_header - - def read_header(self, s): - self.protocol = s - return 8, self.read_reserved - - def read_reserved(self, s): - self.options = s - return 20, self.read_download_id - - def read_download_id(self, s): - if self.multihandler.singlerawservers.has_key(s): - if self.multihandler.singlerawservers[s].protocol == self.protocol: - return True - return None - - def read_dead(self, s): - return None - - def data_came_in(self, garbage, s): - while True: - if self.closed: - return - i = self.next_len - self.buffer.tell() - if i > len(s): - self.buffer.write(s) - return - self.buffer.write(s[:i]) - s = s[i:] - m = self.buffer.getvalue() - self.buffer.reset() - self.buffer.truncate() - try: - x = self.next_func(m) - except: - self.next_len, self.next_func = 1, self.read_dead - raise - if x is None: - self.close() - return - if x == True: # ready to process - self.multihandler.singlerawservers[m]._external_connection_made( - self.connection, self.options, s) - self.complete = True - return - self.next_len, self.next_func = x - - def connection_flushed(self, ss): - pass - - def connection_lost(self, ss): - self.closed = True - -class MultiHandler: - def __init__(self, rawserver, doneflag): - self.rawserver = rawserver - self.masterdoneflag = doneflag - self.singlerawservers = {} - self.connections = {} - self.taskqueues = {} - - def newRawServer(self, info_hash, doneflag, protocol=protocol_name): - new = SingleRawServer(info_hash, self, doneflag, protocol) - self.singlerawservers[info_hash] = new - return new - - def shutdown_torrent(self, info_hash): - self.singlerawservers[info_hash]._shutdown() - del self.singlerawservers[info_hash] - - def listen_forever(self): - self.rawserver.listen_forever(self) - for srs in self.singlerawservers.values(): - srs.finished = True - srs.running = False - srs.doneflag.set() - - ### RawServer handler functions ### - # be wary of name collisions - - def external_connection_made(self, ss): - NewSocketHandler(self, ss) diff --git a/www/pages/torrent/client/SocketHandler.py b/www/pages/torrent/client/SocketHandler.py deleted file mode 100644 index 7676830..0000000 --- a/www/pages/torrent/client/SocketHandler.py +++ /dev/null @@ -1,375 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -import socket -from errno import EWOULDBLOCK, ECONNREFUSED, EHOSTUNREACH -try: - from select import poll, error, POLLIN, POLLOUT, POLLERR, POLLHUP - timemult = 1000 -except ImportError: - from selectpoll import poll, error, POLLIN, POLLOUT, POLLERR, POLLHUP - timemult = 1 -from time import sleep -from clock import clock -import sys -from random import shuffle, randrange -from natpunch import UPnP_open_port, UPnP_close_port -# from BT1.StreamCheck import StreamCheck -# import inspect -try: - True -except: - True = 1 - False = 0 - -all = POLLIN | POLLOUT - -UPnP_ERROR = "unable to forward port via UPnP" - -class SingleSocket: - def __init__(self, socket_handler, sock, handler, ip = None): - self.socket_handler = socket_handler - self.socket = sock - self.handler = handler - self.buffer = [] - self.last_hit = clock() - self.fileno = sock.fileno() - self.connected = False - self.skipped = 0 -# self.check = StreamCheck() - try: - self.ip = self.socket.getpeername()[0] - except: - if ip is None: - self.ip = 'unknown' - else: - self.ip = ip - - def get_ip(self, real=False): - if real: - try: - self.ip = self.socket.getpeername()[0] - except: - pass - return self.ip - - def close(self): - ''' - for x in xrange(5,0,-1): - try: - f = inspect.currentframe(x).f_code - print (f.co_filename,f.co_firstlineno,f.co_name) - del f - except: - pass - print '' - ''' - assert self.socket - self.connected = False - sock = self.socket - self.socket = None - self.buffer = [] - del self.socket_handler.single_sockets[self.fileno] - self.socket_handler.poll.unregister(sock) - sock.close() - - def shutdown(self, val): - self.socket.shutdown(val) - - def is_flushed(self): - return not self.buffer - - def write(self, s): -# self.check.write(s) - assert self.socket is not None - self.buffer.append(s) - if len(self.buffer) == 1: - self.try_write() - - def try_write(self): - if self.connected: - dead = False - try: - while self.buffer: - buf = self.buffer[0] - amount = self.socket.send(buf) - if amount == 0: - self.skipped += 1 - break - self.skipped = 0 - if amount != len(buf): - self.buffer[0] = buf[amount:] - break - del self.buffer[0] - except socket.error, e: - try: - dead = e[0] != EWOULDBLOCK - except: - dead = True - self.skipped += 1 - if self.skipped >= 3: - dead = True - if dead: - self.socket_handler.dead_from_write.append(self) - return - if self.buffer: - self.socket_handler.poll.register(self.socket, all) - else: - self.socket_handler.poll.register(self.socket, POLLIN) - - def set_handler(self, handler): - self.handler = handler - -class SocketHandler: - def __init__(self, timeout, ipv6_enable, readsize = 100000): - self.timeout = timeout - self.ipv6_enable = ipv6_enable - self.readsize = readsize - self.poll = poll() - # {socket: SingleSocket} - self.single_sockets = {} - self.dead_from_write = [] - self.max_connects = 1000 - self.port_forwarded = None - self.servers = {} - - def scan_for_timeouts(self): - t = clock() - self.timeout - tokill = [] - for s in self.single_sockets.values(): - if s.last_hit < t: - tokill.append(s) - for k in tokill: - if k.socket is not None: - self._close_socket(k) - - def bind(self, port, bind = '', reuse = False, ipv6_socket_style = 1, upnp = 0): - port = int(port) - addrinfos = [] - self.servers = {} - self.interfaces = [] - # if bind != "" thread it as a comma seperated list and bind to all - # addresses (can be ips or hostnames) else bind to default ipv6 and - # ipv4 address - if bind: - if self.ipv6_enable: - socktype = socket.AF_UNSPEC - else: - socktype = socket.AF_INET - bind = bind.split(',') - for addr in bind: - if sys.version_info < (2,2): - addrinfos.append((socket.AF_INET, None, None, None, (addr, port))) - else: - addrinfos.extend(socket.getaddrinfo(addr, port, - socktype, socket.SOCK_STREAM)) - else: - if self.ipv6_enable: - addrinfos.append([socket.AF_INET6, None, None, None, ('', port)]) - if not addrinfos or ipv6_socket_style != 0: - addrinfos.append([socket.AF_INET, None, None, None, ('', port)]) - for addrinfo in addrinfos: - try: - server = socket.socket(addrinfo[0], socket.SOCK_STREAM) - if reuse: - server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server.setblocking(0) - server.bind(addrinfo[4]) - self.servers[server.fileno()] = server - if bind: - self.interfaces.append(server.getsockname()[0]) - server.listen(64) - self.poll.register(server, POLLIN) - except socket.error, e: - for server in self.servers.values(): - try: - server.close() - except: - pass - if self.ipv6_enable and ipv6_socket_style == 0 and self.servers: - raise socket.error('blocked port (may require ipv6_binds_v4 to be set)') - raise socket.error(str(e)) - if not self.servers: - raise socket.error('unable to open server port') - if upnp: - if not UPnP_open_port(port): - for server in self.servers.values(): - try: - server.close() - except: - pass - self.servers = None - self.interfaces = None - raise socket.error(UPnP_ERROR) - self.port_forwarded = port - self.port = port - - def find_and_bind(self, minport, maxport, bind = '', reuse = False, - ipv6_socket_style = 1, upnp = 0, randomizer = False): - e = 'maxport less than minport - no ports to check' - if maxport-minport < 50 or not randomizer: - portrange = range(minport, maxport+1) - if randomizer: - shuffle(portrange) - portrange = portrange[:20] # check a maximum of 20 ports - else: - portrange = [] - while len(portrange) < 20: - listen_port = randrange(minport, maxport+1) - if not listen_port in portrange: - portrange.append(listen_port) - for listen_port in portrange: - try: - self.bind(listen_port, bind, - ipv6_socket_style = ipv6_socket_style, upnp = upnp) - return listen_port - except socket.error, e: - pass - raise socket.error(str(e)) - - - def set_handler(self, handler): - self.handler = handler - - - def start_connection_raw(self, dns, socktype = socket.AF_INET, handler = None): - if handler is None: - handler = self.handler - sock = socket.socket(socktype, socket.SOCK_STREAM) - sock.setblocking(0) - try: - sock.connect_ex(dns) - except socket.error: - raise - except Exception, e: - raise socket.error(str(e)) - self.poll.register(sock, POLLIN) - s = SingleSocket(self, sock, handler, dns[0]) - self.single_sockets[sock.fileno()] = s - return s - - - def start_connection(self, dns, handler = None, randomize = False): - if handler is None: - handler = self.handler - if sys.version_info < (2,2): - s = self.start_connection_raw(dns,socket.AF_INET,handler) - else: - if self.ipv6_enable: - socktype = socket.AF_UNSPEC - else: - socktype = socket.AF_INET - try: - addrinfos = socket.getaddrinfo(dns[0], int(dns[1]), - socktype, socket.SOCK_STREAM) - except socket.error, e: - raise - except Exception, e: - raise socket.error(str(e)) - if randomize: - shuffle(addrinfos) - for addrinfo in addrinfos: - try: - s = self.start_connection_raw(addrinfo[4],addrinfo[0],handler) - break - except: - pass - else: - raise socket.error('unable to connect') - return s - - - def _sleep(self): - sleep(1) - - def handle_events(self, events): - for sock, event in events: - s = self.servers.get(sock) - if s: - if event & (POLLHUP | POLLERR) != 0: - self.poll.unregister(s) - s.close() - del self.servers[sock] - print "lost server socket" - elif len(self.single_sockets) < self.max_connects: - try: - newsock, addr = s.accept() - newsock.setblocking(0) - nss = SingleSocket(self, newsock, self.handler) - self.single_sockets[newsock.fileno()] = nss - self.poll.register(newsock, POLLIN) - self.handler.external_connection_made(nss) - except socket.error: - self._sleep() - else: - s = self.single_sockets.get(sock) - if not s: - continue - s.connected = True - if (event & (POLLHUP | POLLERR)): - self._close_socket(s) - continue - if (event & POLLIN): - try: - s.last_hit = clock() - data = s.socket.recv(100000) - if not data: - self._close_socket(s) - else: - s.handler.data_came_in(s, data) - except socket.error, e: - code, msg = e - if code != EWOULDBLOCK: - self._close_socket(s) - continue - if (event & POLLOUT) and s.socket and not s.is_flushed(): - s.try_write() - if s.is_flushed(): - s.handler.connection_flushed(s) - - def close_dead(self): - while self.dead_from_write: - old = self.dead_from_write - self.dead_from_write = [] - for s in old: - if s.socket: - self._close_socket(s) - - def _close_socket(self, s): - s.close() - s.handler.connection_lost(s) - - def do_poll(self, t): - r = self.poll.poll(t*timemult) - if r is None: - connects = len(self.single_sockets) - to_close = int(connects*0.05)+1 # close 5% of sockets - self.max_connects = connects-to_close - closelist = self.single_sockets.values() - shuffle(closelist) - closelist = closelist[:to_close] - for sock in closelist: - self._close_socket(sock) - return [] - return r - - def get_stats(self): - return { 'interfaces': self.interfaces, - 'port': self.port, - 'upnp': self.port_forwarded is not None } - - - def shutdown(self): - for ss in self.single_sockets.values(): - try: - ss.close() - except: - pass - for server in self.servers.values(): - try: - server.close() - except: - pass - if self.port_forwarded is not None: - UPnP_close_port(self.port_forwarded) - diff --git a/www/pages/torrent/client/__init__.py b/www/pages/torrent/client/__init__.py deleted file mode 100644 index 20a831b..0000000 --- a/www/pages/torrent/client/__init__.py +++ /dev/null @@ -1,63 +0,0 @@ -product_name = 'BitTornado' -version_short = 'T-0.3.17' - -version = version_short+' ('+product_name+')' -report_email = version_short+'@degreez.net' - -from types import StringType -from sha import sha -from time import time, clock -try: - from os import getpid -except ImportError: - def getpid(): - return 1 - -mapbase64 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-' - -_idprefix = version_short[0] -for subver in version_short[2:].split('.'): - try: - subver = int(subver) - except: - subver = 0 - _idprefix += mapbase64[subver] -_idprefix += ('-' * (6-len(_idprefix))) -_idrandom = [None] - -def resetPeerIDs(): - try: - f = open('/dev/urandom','rb') - x = f.read(20) - f.close() - except: - x = '' - - l1 = 0 - t = clock() - while t == clock(): - l1 += 1 - l2 = 0 - t = long(time()*100) - while t == long(time()*100): - l2 += 1 - l3 = 0 - if l2 < 1000: - t = long(time()*10) - while t == long(clock()*10): - l3 += 1 - x += ( repr(time()) + '/' + str(time()) + '/' - + str(l1) + '/' + str(l2) + '/' + str(l3) + '/' - + str(getpid()) ) - - s = '' - for i in sha(x).digest()[-11:]: - s += mapbase64[ord(i) & 0x3F] - _idrandom[0] = s - -resetPeerIDs() - -def createPeerID(ins = '---'): - assert type(ins) is StringType - assert len(ins) == 3 - return _idprefix + ins + _idrandom[0] diff --git a/www/pages/torrent/client/bencode.py b/www/pages/torrent/client/bencode.py deleted file mode 100644 index 1ff0736..0000000 --- a/www/pages/torrent/client/bencode.py +++ /dev/null @@ -1,319 +0,0 @@ -# Written by Petru Paler, Uoti Urpala, Ross Cohen and John Hoffman -# see LICENSE.txt for license information - -from types import IntType, LongType, StringType, ListType, TupleType, DictType -try: - from types import BooleanType -except ImportError: - BooleanType = None -try: - from types import UnicodeType -except ImportError: - UnicodeType = None -from cStringIO import StringIO - -def decode_int(x, f): - f += 1 - newf = x.index('e', f) - try: - n = int(x[f:newf]) - except: - n = long(x[f:newf]) - if x[f] == '-': - if x[f + 1] == '0': - raise ValueError - elif x[f] == '0' and newf != f+1: - raise ValueError - return (n, newf+1) - -def decode_string(x, f): - colon = x.index(':', f) - try: - n = int(x[f:colon]) - except (OverflowError, ValueError): - n = long(x[f:colon]) - if x[f] == '0' and colon != f+1: - raise ValueError - colon += 1 - return (x[colon:colon+n], colon+n) - -def decode_unicode(x, f): - s, f = decode_string(x, f+1) - return (s.decode('UTF-8'),f) - -def decode_list(x, f): - r, f = [], f+1 - while x[f] != 'e': - v, f = decode_func[x[f]](x, f) - r.append(v) - return (r, f + 1) - -def decode_dict(x, f): - r, f = {}, f+1 - lastkey = None - while x[f] != 'e': - k, f = decode_string(x, f) - if lastkey >= k: - raise ValueError - lastkey = k - r[k], f = decode_func[x[f]](x, f) - return (r, f + 1) - -decode_func = {} -decode_func['l'] = decode_list -decode_func['d'] = decode_dict -decode_func['i'] = decode_int -decode_func['0'] = decode_string -decode_func['1'] = decode_string -decode_func['2'] = decode_string -decode_func['3'] = decode_string -decode_func['4'] = decode_string -decode_func['5'] = decode_string -decode_func['6'] = decode_string -decode_func['7'] = decode_string -decode_func['8'] = decode_string -decode_func['9'] = decode_string -#decode_func['u'] = decode_unicode - -def bdecode(x, sloppy = 0): - try: - r, l = decode_func[x[0]](x, 0) -# except (IndexError, KeyError): - except (IndexError, KeyError, ValueError): - raise ValueError, "bad bencoded data" - if not sloppy and l != len(x): - raise ValueError, "bad bencoded data" - return r - -def test_bdecode(): - try: - bdecode('0:0:') - assert 0 - except ValueError: - pass - try: - bdecode('ie') - assert 0 - except ValueError: - pass - try: - bdecode('i341foo382e') - assert 0 - except ValueError: - pass - assert bdecode('i4e') == 4L - assert bdecode('i0e') == 0L - assert bdecode('i123456789e') == 123456789L - assert bdecode('i-10e') == -10L - try: - bdecode('i-0e') - assert 0 - except ValueError: - pass - try: - bdecode('i123') - assert 0 - except ValueError: - pass - try: - bdecode('') - assert 0 - except ValueError: - pass - try: - bdecode('i6easd') - assert 0 - except ValueError: - pass - try: - bdecode('35208734823ljdahflajhdf') - assert 0 - except ValueError: - pass - try: - bdecode('2:abfdjslhfld') - assert 0 - except ValueError: - pass - assert bdecode('0:') == '' - assert bdecode('3:abc') == 'abc' - assert bdecode('10:1234567890') == '1234567890' - try: - bdecode('02:xy') - assert 0 - except ValueError: - pass - try: - bdecode('l') - assert 0 - except ValueError: - pass - assert bdecode('le') == [] - try: - bdecode('leanfdldjfh') - assert 0 - except ValueError: - pass - assert bdecode('l0:0:0:e') == ['', '', ''] - try: - bdecode('relwjhrlewjh') - assert 0 - except ValueError: - pass - assert bdecode('li1ei2ei3ee') == [1, 2, 3] - assert bdecode('l3:asd2:xye') == ['asd', 'xy'] - assert bdecode('ll5:Alice3:Bobeli2ei3eee') == [['Alice', 'Bob'], [2, 3]] - try: - bdecode('d') - assert 0 - except ValueError: - pass - try: - bdecode('defoobar') - assert 0 - except ValueError: - pass - assert bdecode('de') == {} - assert bdecode('d3:agei25e4:eyes4:bluee') == {'age': 25, 'eyes': 'blue'} - assert bdecode('d8:spam.mp3d6:author5:Alice6:lengthi100000eee') == {'spam.mp3': {'author': 'Alice', 'length': 100000}} - try: - bdecode('d3:fooe') - assert 0 - except ValueError: - pass - try: - bdecode('di1e0:e') - assert 0 - except ValueError: - pass - try: - bdecode('d1:b0:1:a0:e') - assert 0 - except ValueError: - pass - try: - bdecode('d1:a0:1:a0:e') - assert 0 - except ValueError: - pass - try: - bdecode('i03e') - assert 0 - except ValueError: - pass - try: - bdecode('l01:ae') - assert 0 - except ValueError: - pass - try: - bdecode('9999:x') - assert 0 - except ValueError: - pass - try: - bdecode('l0:') - assert 0 - except ValueError: - pass - try: - bdecode('d0:0:') - assert 0 - except ValueError: - pass - try: - bdecode('d0:') - assert 0 - except ValueError: - pass - -bencached_marker = [] - -class Bencached: - def __init__(self, s): - self.marker = bencached_marker - self.bencoded = s - -BencachedType = type(Bencached('')) # insufficient, but good as a filter - -def encode_bencached(x,r): - assert x.marker == bencached_marker - r.append(x.bencoded) - -def encode_int(x,r): - r.extend(('i',str(x),'e')) - -def encode_bool(x,r): - encode_int(int(x),r) - -def encode_string(x,r): - r.extend((str(len(x)),':',x)) - -def encode_unicode(x,r): - #r.append('u') - encode_string(x.encode('UTF-8'),r) - -def encode_list(x,r): - r.append('l') - for e in x: - encode_func[type(e)](e, r) - r.append('e') - -def encode_dict(x,r): - r.append('d') - ilist = x.items() - ilist.sort() - for k,v in ilist: - r.extend((str(len(k)),':',k)) - encode_func[type(v)](v, r) - r.append('e') - -encode_func = {} -encode_func[BencachedType] = encode_bencached -encode_func[IntType] = encode_int -encode_func[LongType] = encode_int -encode_func[StringType] = encode_string -encode_func[ListType] = encode_list -encode_func[TupleType] = encode_list -encode_func[DictType] = encode_dict -if BooleanType: - encode_func[BooleanType] = encode_bool -if UnicodeType: - encode_func[UnicodeType] = encode_unicode - -def bencode(x): - r = [] - try: - encode_func[type(x)](x, r) - except: - print "*** error *** could not encode type %s (value: %s)" % (type(x), x) - assert 0 - return ''.join(r) - -def test_bencode(): - assert bencode(4) == 'i4e' - assert bencode(0) == 'i0e' - assert bencode(-10) == 'i-10e' - assert bencode(12345678901234567890L) == 'i12345678901234567890e' - assert bencode('') == '0:' - assert bencode('abc') == '3:abc' - assert bencode('1234567890') == '10:1234567890' - assert bencode([]) == 'le' - assert bencode([1, 2, 3]) == 'li1ei2ei3ee' - assert bencode([['Alice', 'Bob'], [2, 3]]) == 'll5:Alice3:Bobeli2ei3eee' - assert bencode({}) == 'de' - assert bencode({'age': 25, 'eyes': 'blue'}) == 'd3:agei25e4:eyes4:bluee' - assert bencode({'spam.mp3': {'author': 'Alice', 'length': 100000}}) == 'd8:spam.mp3d6:author5:Alice6:lengthi100000eee' - try: - bencode({1: 'foo'}) - assert 0 - except AssertionError: - pass - - -try: - import psyco - psyco.bind(bdecode) - psyco.bind(bencode) -except ImportError: - pass diff --git a/www/pages/torrent/client/bitfield.py b/www/pages/torrent/client/bitfield.py deleted file mode 100644 index 3d532e3..0000000 --- a/www/pages/torrent/client/bitfield.py +++ /dev/null @@ -1,162 +0,0 @@ -# Written by Bram Cohen, Uoti Urpala, and John Hoffman -# see LICENSE.txt for license information - -try: - True -except: - True = 1 - False = 0 - bool = lambda x: not not x - -try: - sum([1]) - negsum = lambda a: len(a)-sum(a) -except: - negsum = lambda a: reduce(lambda x,y: x+(not y), a, 0) - -def _int_to_booleans(x): - r = [] - for i in range(8): - r.append(bool(x & 0x80)) - x <<= 1 - return tuple(r) - -lookup_table = [] -reverse_lookup_table = {} -for i in xrange(256): - x = _int_to_booleans(i) - lookup_table.append(x) - reverse_lookup_table[x] = chr(i) - - -class Bitfield: - def __init__(self, length = None, bitstring = None, copyfrom = None): - if copyfrom is not None: - self.length = copyfrom.length - self.array = copyfrom.array[:] - self.numfalse = copyfrom.numfalse - return - if length is None: - raise ValueError, "length must be provided unless copying from another array" - self.length = length - if bitstring is not None: - extra = len(bitstring) * 8 - length - if extra < 0 or extra >= 8: - raise ValueError - t = lookup_table - r = [] - for c in bitstring: - r.extend(t[ord(c)]) - if extra > 0: - if r[-extra:] != [0] * extra: - raise ValueError - del r[-extra:] - self.array = r - self.numfalse = negsum(r) - else: - self.array = [False] * length - self.numfalse = length - - def __setitem__(self, index, val): - val = bool(val) - self.numfalse += self.array[index]-val - self.array[index] = val - - def __getitem__(self, index): - return self.array[index] - - def __len__(self): - return self.length - - def tostring(self): - booleans = self.array - t = reverse_lookup_table - s = len(booleans) % 8 - r = [ t[tuple(booleans[x:x+8])] for x in xrange(0, len(booleans)-s, 8) ] - if s: - r += t[tuple(booleans[-s:] + ([0] * (8-s)))] - return ''.join(r) - - def complete(self): - return not self.numfalse - - -def test_bitfield(): - try: - x = Bitfield(7, 'ab') - assert False - except ValueError: - pass - try: - x = Bitfield(7, 'ab') - assert False - except ValueError: - pass - try: - x = Bitfield(9, 'abc') - assert False - except ValueError: - pass - try: - x = Bitfield(0, 'a') - assert False - except ValueError: - pass - try: - x = Bitfield(1, '') - assert False - except ValueError: - pass - try: - x = Bitfield(7, '') - assert False - except ValueError: - pass - try: - x = Bitfield(8, '') - assert False - except ValueError: - pass - try: - x = Bitfield(9, 'a') - assert False - except ValueError: - pass - try: - x = Bitfield(7, chr(1)) - assert False - except ValueError: - pass - try: - x = Bitfield(9, chr(0) + chr(0x40)) - assert False - except ValueError: - pass - assert Bitfield(0, '').tostring() == '' - assert Bitfield(1, chr(0x80)).tostring() == chr(0x80) - assert Bitfield(7, chr(0x02)).tostring() == chr(0x02) - assert Bitfield(8, chr(0xFF)).tostring() == chr(0xFF) - assert Bitfield(9, chr(0) + chr(0x80)).tostring() == chr(0) + chr(0x80) - x = Bitfield(1) - assert x.numfalse == 1 - x[0] = 1 - assert x.numfalse == 0 - x[0] = 1 - assert x.numfalse == 0 - assert x.tostring() == chr(0x80) - x = Bitfield(7) - assert len(x) == 7 - x[6] = 1 - assert x.numfalse == 6 - assert x.tostring() == chr(0x02) - x = Bitfield(8) - x[7] = 1 - assert x.tostring() == chr(1) - x = Bitfield(9) - x[8] = 1 - assert x.numfalse == 8 - assert x.tostring() == chr(0) + chr(0x80) - x = Bitfield(8, chr(0xC4)) - assert len(x) == 8 - assert x.numfalse == 5 - assert x.tostring() == chr(0xC4) diff --git a/www/pages/torrent/client/clock.py b/www/pages/torrent/client/clock.py deleted file mode 100644 index e42c59b..0000000 --- a/www/pages/torrent/client/clock.py +++ /dev/null @@ -1,27 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -from time import * -import sys - -_MAXFORWARD = 100 -_FUDGE = 1 - -class RelativeTime: - def __init__(self): - self.time = time() - self.offset = 0 - - def get_time(self): - t = time() + self.offset - if t < self.time or t > self.time + _MAXFORWARD: - self.time += _FUDGE - self.offset += self.time - t - return self.time - self.time = t - return t - -if sys.platform != 'win32': - _RTIME = RelativeTime() - def clock(): - return _RTIME.get_time() \ No newline at end of file diff --git a/www/pages/torrent/client/download_bt1.py b/www/pages/torrent/client/download_bt1.py deleted file mode 100644 index f4aef0c..0000000 --- a/www/pages/torrent/client/download_bt1.py +++ /dev/null @@ -1,882 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -from zurllib import urlopen -from urlparse import urlparse -from BT1.btformats import check_message -from BT1.Choker import Choker -from BT1.Storage import Storage -from BT1.StorageWrapper import StorageWrapper -from BT1.FileSelector import FileSelector -from BT1.Uploader import Upload -from BT1.Downloader import Downloader -from BT1.HTTPDownloader import HTTPDownloader -from BT1.Connecter import Connecter -from RateLimiter import RateLimiter -from BT1.Encrypter import Encoder -from RawServer import RawServer, autodetect_ipv6, autodetect_socket_style -from BT1.Rerequester import Rerequester -from BT1.DownloaderFeedback import DownloaderFeedback -from RateMeasure import RateMeasure -from CurrentRateMeasure import Measure -from BT1.PiecePicker import PiecePicker -from BT1.Statistics import Statistics -from ConfigDir import ConfigDir -from bencode import bencode, bdecode -from natpunch import UPnP_test -from sha import sha -from os import path, makedirs, listdir -from parseargs import parseargs, formatDefinitions, defaultargs -from socket import error as socketerror -from random import seed -from threading import Thread, Event -from clock import clock -from __init__ import createPeerID - -try: - True -except: - True = 1 - False = 0 - -defaults = [ - ('max_uploads', 7, - "the maximum number of uploads to allow at once."), - ('keepalive_interval', 120.0, - 'number of seconds to pause between sending keepalives'), - ('download_slice_size', 2 ** 14, - "How many bytes to query for per request."), - ('upload_unit_size', 1460, - "when limiting upload rate, how many bytes to send at a time"), - ('request_backlog', 10, - "maximum number of requests to keep in a single pipe at once."), - ('max_message_length', 2 ** 23, - "maximum length prefix encoding you'll accept over the wire - larger values get the connection dropped."), - ('ip', '', - "ip to report you have to the tracker."), - ('minport', 10000, 'minimum port to listen on, counts up if unavailable'), - ('maxport', 60000, 'maximum port to listen on'), - ('random_port', 1, 'whether to choose randomly inside the port range ' + - 'instead of counting up linearly'), - ('responsefile', '', - 'file the server response was stored in, alternative to url'), - ('url', '', - 'url to get file from, alternative to responsefile'), - ('selector_enabled', 1, - 'whether to enable the file selector and fast resume function'), - ('expire_cache_data', 10, - 'the number of days after which you wish to expire old cache data ' + - '(0 = disabled)'), - ('priority', '', - 'a list of file priorities separated by commas, must be one per file, ' + - '0 = highest, 1 = normal, 2 = lowest, -1 = download disabled'), - ('saveas', '', - 'local file name to save the file as, null indicates query user'), - ('timeout', 300.0, - 'time to wait between closing sockets which nothing has been received on'), - ('timeout_check_interval', 60.0, - 'time to wait between checking if any connections have timed out'), - ('max_slice_length', 2 ** 17, - "maximum length slice to send to peers, larger requests are ignored"), - ('max_rate_period', 20.0, - "maximum amount of time to guess the current rate estimate represents"), - ('bind', '', - 'comma-separated list of ips/hostnames to bind to locally'), -# ('ipv6_enabled', autodetect_ipv6(), - ('ipv6_enabled', 0, - 'allow the client to connect to peers via IPv6'), - ('ipv6_binds_v4', autodetect_socket_style(), - "set if an IPv6 server socket won't also field IPv4 connections"), - ('upnp_nat_access', 1, - 'attempt to autoconfigure a UPnP router to forward a server port ' + - '(0 = disabled, 1 = mode 1 [fast], 2 = mode 2 [slow])'), - ('upload_rate_fudge', 5.0, - 'time equivalent of writing to kernel-level TCP buffer, for rate adjustment'), - ('tcp_ack_fudge', 0.03, - 'how much TCP ACK download overhead to add to upload rate calculations ' + - '(0 = disabled)'), - ('display_interval', .5, - 'time between updates of displayed information'), - ('rerequest_interval', 5 * 60, - 'time to wait between requesting more peers'), - ('min_peers', 20, - 'minimum number of peers to not do rerequesting'), - ('http_timeout', 60, - 'number of seconds to wait before assuming that an http connection has timed out'), - ('max_initiate', 40, - 'number of peers at which to stop initiating new connections'), - ('check_hashes', 1, - 'whether to check hashes on disk'), - ('max_upload_rate', 0, - 'maximum kB/s to upload at (0 = no limit, -1 = automatic)'), - ('max_download_rate', 0, - 'maximum kB/s to download at (0 = no limit)'), - ('alloc_type', 'normal', - 'allocation type (may be normal, background, pre-allocate or sparse)'), - ('alloc_rate', 2.0, - 'rate (in MiB/s) to allocate space at using background allocation'), - ('buffer_reads', 1, - 'whether to buffer disk reads'), - ('write_buffer_size', 4, - 'the maximum amount of space to use for buffering disk writes ' + - '(in megabytes, 0 = disabled)'), - ('breakup_seed_bitfield', 1, - 'sends an incomplete bitfield and then fills with have messages, ' - 'in order to get around stupid ISP manipulation'), - ('snub_time', 30.0, - "seconds to wait for data to come in over a connection before assuming it's semi-permanently choked"), - ('spew', 0, - "whether to display diagnostic info to stdout"), - ('rarest_first_cutoff', 2, - "number of downloads at which to switch from random to rarest first"), - ('rarest_first_priority_cutoff', 5, - 'the number of peers which need to have a piece before other partials take priority over rarest first'), - ('min_uploads', 4, - "the number of uploads to fill out to with extra optimistic unchokes"), - ('max_files_open', 50, - 'the maximum number of files to keep open at a time, 0 means no limit'), - ('round_robin_period', 30, - "the number of seconds between the client's switching upload targets"), - ('super_seeder', 0, - "whether to use special upload-efficiency-maximizing routines (only for dedicated seeds)"), - ('security', 1, - "whether to enable extra security features intended to prevent abuse"), - ('max_connections', 0, - "the absolute maximum number of peers to connect with (0 = no limit)"), - ('auto_kick', 1, - "whether to allow the client to automatically kick/ban peers that send bad data"), - ('double_check', 1, - "whether to double-check data being written to the disk for errors (may increase CPU load)"), - ('triple_check', 0, - "whether to thoroughly check data being written to the disk (may slow disk access)"), - ('lock_files', 1, - "whether to lock files the client is working with"), - ('lock_while_reading', 0, - "whether to lock access to files being read"), - ('auto_flush', 0, - "minutes between automatic flushes to disk (0 = disabled)"), - ('dedicated_seed_id', '', - "code to send to tracker identifying as a dedicated seed"), - ] - -argslistheader = 'Arguments are:\n\n' - - -def _failfunc(x): - print x - -# old-style downloader -def download(params, filefunc, statusfunc, finfunc, errorfunc, doneflag, cols, - pathFunc = None, presets = {}, exchandler = None, - failed = _failfunc, paramfunc = None): - - try: - config = parse_params(params, presets) - except ValueError, e: - failed('error: ' + str(e) + '\nrun with no args for parameter explanations') - return - if not config: - errorfunc(get_usage()) - return - - myid = createPeerID() - seed(myid) - - rawserver = RawServer(doneflag, config['timeout_check_interval'], - config['timeout'], ipv6_enable = config['ipv6_enabled'], - failfunc = failed, errorfunc = exchandler) - - upnp_type = UPnP_test(config['upnp_nat_access']) - try: - listen_port = rawserver.find_and_bind(config['minport'], config['maxport'], - config['bind'], ipv6_socket_style = config['ipv6_binds_v4'], - upnp = upnp_type, randomizer = config['random_port']) - except socketerror, e: - failed("Couldn't listen - " + str(e)) - return - - response = get_response(config['responsefile'], config['url'], failed) - if not response: - return - - infohash = sha(bencode(response['info'])).digest() - - d = BT1Download(statusfunc, finfunc, errorfunc, exchandler, doneflag, - config, response, infohash, myid, rawserver, listen_port) - - if not d.saveAs(filefunc): - return - - if pathFunc: - pathFunc(d.getFilename()) - - hashcheck = d.initFiles(old_style = True) - if not hashcheck: - return - if not hashcheck(): - return - if not d.startEngine(): - return - d.startRerequester() - d.autoStats() - - statusfunc(activity = 'connecting to peers') - - if paramfunc: - paramfunc({ 'max_upload_rate' : d.setUploadRate, # change_max_upload_rate() - 'max_uploads': d.setConns, # change_max_uploads() - 'listen_port' : listen_port, # int - 'peer_id' : myid, # string - 'info_hash' : infohash, # string - 'start_connection' : d._startConnection, # start_connection((, ), ) - }) - - rawserver.listen_forever(d.getPortHandler()) - - d.shutdown() - - -def parse_params(params, presets = {}): - if len(params) == 0: - return None - config, args = parseargs(params, defaults, 0, 1, presets = presets) - if args: - if config['responsefile'] or config['url']: - raise ValueError,'must have responsefile or url as arg or parameter, not both' - if path.isfile(args[0]): - config['responsefile'] = args[0] - else: - try: - urlparse(args[0]) - except: - raise ValueError, 'bad filename or url' - config['url'] = args[0] - elif (config['responsefile'] == '') == (config['url'] == ''): - raise ValueError, 'need responsefile or url, must have one, cannot have both' - return config - - -def get_usage(defaults = defaults, cols = 100, presets = {}): - return (argslistheader + formatDefinitions(defaults, cols, presets)) - - -def get_response(file, url, errorfunc): - try: - if file: - h = open(file, 'rb') - try: - line = h.read(10) # quick test to see if responsefile contains a dict - front,garbage = line.split(':',1) - assert front[0] == 'd' - int(front[1:]) - except: - errorfunc(file+' is not a valid responsefile') - return None - try: - h.seek(0) - except: - try: - h.close() - except: - pass - h = open(file, 'rb') - else: - try: - h = urlopen(url) - except: - errorfunc(url+' bad url') - return None - response = h.read() - - except IOError, e: - errorfunc('problem getting response info - ' + str(e)) - return None - try: - h.close() - except: - pass - try: - try: - response = bdecode(response) - except: - errorfunc("warning: bad data in responsefile") - response = bdecode(response, sloppy=1) - check_message(response) - except ValueError, e: - errorfunc("got bad file info - " + str(e)) - return None - - return response - - -class BT1Download: - def __init__(self, statusfunc, finfunc, errorfunc, excfunc, doneflag, - config, response, infohash, id, rawserver, port, - appdataobj = None): - self.statusfunc = statusfunc - self.finfunc = finfunc - self.errorfunc = errorfunc - self.excfunc = excfunc - self.doneflag = doneflag - self.config = config - self.response = response - self.infohash = infohash - self.myid = id - self.rawserver = rawserver - self.port = port - - self.info = self.response['info'] - self.pieces = [self.info['pieces'][x:x+20] - for x in xrange(0, len(self.info['pieces']), 20)] - self.len_pieces = len(self.pieces) - self.argslistheader = argslistheader - self.unpauseflag = Event() - self.unpauseflag.set() - self.downloader = None - self.storagewrapper = None - self.fileselector = None - self.super_seeding_active = False - self.filedatflag = Event() - self.spewflag = Event() - self.superseedflag = Event() - self.whenpaused = None - self.finflag = Event() - self.rerequest = None - self.tcp_ack_fudge = config['tcp_ack_fudge'] - - self.selector_enabled = config['selector_enabled'] - if appdataobj: - self.appdataobj = appdataobj - elif self.selector_enabled: - self.appdataobj = ConfigDir() - self.appdataobj.deleteOldCacheData( config['expire_cache_data'], - [self.infohash] ) - - self.excflag = self.rawserver.get_exception_flag() - self.failed = False - self.checking = False - self.started = False - - self.picker = PiecePicker(self.len_pieces, config['rarest_first_cutoff'], - config['rarest_first_priority_cutoff']) - self.choker = Choker(config, rawserver.add_task, - self.picker, self.finflag.isSet) - - - def checkSaveLocation(self, loc): - if self.info.has_key('length'): - return path.exists(loc) - for x in self.info['files']: - if path.exists(path.join(loc, x['path'][0])): - return True - return False - - - def saveAs(self, filefunc, pathfunc = None): - try: - def make(f, forcedir = False): - if not forcedir: - f = path.split(f)[0] - if f != '' and not path.exists(f): - makedirs(f) - - if self.info.has_key('length'): - file_length = self.info['length'] - file = filefunc(self.info['name'], file_length, - self.config['saveas'], False) - if file is None: - return None - make(file) - files = [(file, file_length)] - else: - file_length = 0L - for x in self.info['files']: - file_length += x['length'] - file = filefunc(self.info['name'], file_length, - self.config['saveas'], True) - if file is None: - return None - - # if this path exists, and no files from the info dict exist, we assume it's a new download and - # the user wants to create a new directory with the default name - existing = 0 - if path.exists(file): - if not path.isdir(file): - self.errorfunc(file + 'is not a dir') - return None - if len(listdir(file)) > 0: # if it's not empty - for x in self.info['files']: - if path.exists(path.join(file, x['path'][0])): - existing = 1 - if not existing: - file = path.join(file, self.info['name']) - if path.exists(file) and not path.isdir(file): - if file[-8:] == '.torrent': - file = file[:-8] - if path.exists(file) and not path.isdir(file): - self.errorfunc("Can't create dir - " + self.info['name']) - return None - make(file, True) - - # alert the UI to any possible change in path - if pathfunc != None: - pathfunc(file) - - files = [] - for x in self.info['files']: - n = file - for i in x['path']: - n = path.join(n, i) - files.append((n, x['length'])) - make(n) - except OSError, e: - self.errorfunc("Couldn't allocate dir - " + str(e)) - return None - - self.filename = file - self.files = files - self.datalength = file_length - - return file - - - def getFilename(self): - return self.filename - - - def _finished(self): - self.finflag.set() - try: - self.storage.set_readonly() - except (IOError, OSError), e: - self.errorfunc('trouble setting readonly at end - ' + str(e)) - if self.superseedflag.isSet(): - self._set_super_seed() - self.choker.set_round_robin_period( - max( self.config['round_robin_period'], - self.config['round_robin_period'] * - self.info['piece length'] / 200000 ) ) - self.rerequest_complete() - self.finfunc() - - def _data_flunked(self, amount, index): - self.ratemeasure_datarejected(amount) - if not self.doneflag.isSet(): - self.errorfunc('piece %d failed hash check, re-downloading it' % index) - - def _failed(self, reason): - self.failed = True - self.doneflag.set() - if reason is not None: - self.errorfunc(reason) - - - def initFiles(self, old_style = False, statusfunc = None): - if self.doneflag.isSet(): - return None - if not statusfunc: - statusfunc = self.statusfunc - - disabled_files = None - if self.selector_enabled: - self.priority = self.config['priority'] - if self.priority: - try: - self.priority = self.priority.split(',') - assert len(self.priority) == len(self.files) - self.priority = [int(p) for p in self.priority] - for p in self.priority: - assert p >= -1 - assert p <= 2 - except: - self.errorfunc('bad priority list given, ignored') - self.priority = None - - data = self.appdataobj.getTorrentData(self.infohash) - try: - d = data['resume data']['priority'] - assert len(d) == len(self.files) - disabled_files = [x == -1 for x in d] - except: - try: - disabled_files = [x == -1 for x in self.priority] - except: - pass - - try: - try: - self.storage = Storage(self.files, self.info['piece length'], - self.doneflag, self.config, disabled_files) - except IOError, e: - self.errorfunc('trouble accessing files - ' + str(e)) - return None - if self.doneflag.isSet(): - return None - - self.storagewrapper = StorageWrapper(self.storage, self.config['download_slice_size'], - self.pieces, self.info['piece length'], self._finished, self._failed, - statusfunc, self.doneflag, self.config['check_hashes'], - self._data_flunked, self.rawserver.add_task, - self.config, self.unpauseflag) - - except ValueError, e: - self._failed('bad data - ' + str(e)) - except IOError, e: - self._failed('IOError - ' + str(e)) - if self.doneflag.isSet(): - return None - - if self.selector_enabled: - self.fileselector = FileSelector(self.files, self.info['piece length'], - self.appdataobj.getPieceDir(self.infohash), - self.storage, self.storagewrapper, - self.rawserver.add_task, - self._failed) - if data: - data = data.get('resume data') - if data: - self.fileselector.unpickle(data) - - self.checking = True - if old_style: - return self.storagewrapper.old_style_init() - return self.storagewrapper.initialize - - - def getCachedTorrentData(self): - return self.appdataobj.getTorrentData(self.infohash) - - - def _make_upload(self, connection, ratelimiter, totalup): - return Upload(connection, ratelimiter, totalup, - self.choker, self.storagewrapper, self.picker, - self.config) - - def _kick_peer(self, connection): - def k(connection = connection): - connection.close() - self.rawserver.add_task(k,0) - - def _ban_peer(self, ip): - self.encoder_ban(ip) - - def _received_raw_data(self, x): - if self.tcp_ack_fudge: - x = int(x*self.tcp_ack_fudge) - self.ratelimiter.adjust_sent(x) -# self.upmeasure.update_rate(x) - - def _received_data(self, x): - self.downmeasure.update_rate(x) - self.ratemeasure.data_came_in(x) - - def _received_http_data(self, x): - self.downmeasure.update_rate(x) - self.ratemeasure.data_came_in(x) - self.downloader.external_data_received(x) - - def _cancelfunc(self, pieces): - self.downloader.cancel_piece_download(pieces) - self.httpdownloader.cancel_piece_download(pieces) - def _reqmorefunc(self, pieces): - self.downloader.requeue_piece_download(pieces) - - def startEngine(self, ratelimiter = None, statusfunc = None): - if self.doneflag.isSet(): - return False - if not statusfunc: - statusfunc = self.statusfunc - - self.checking = False - - for i in xrange(self.len_pieces): - if self.storagewrapper.do_I_have(i): - self.picker.complete(i) - self.upmeasure = Measure(self.config['max_rate_period'], - self.config['upload_rate_fudge']) - self.downmeasure = Measure(self.config['max_rate_period']) - - if ratelimiter: - self.ratelimiter = ratelimiter - else: - self.ratelimiter = RateLimiter(self.rawserver.add_task, - self.config['upload_unit_size'], - self.setConns) - self.ratelimiter.set_upload_rate(self.config['max_upload_rate']) - - self.ratemeasure = RateMeasure() - self.ratemeasure_datarejected = self.ratemeasure.data_rejected - - self.downloader = Downloader(self.storagewrapper, self.picker, - self.config['request_backlog'], self.config['max_rate_period'], - self.len_pieces, self.config['download_slice_size'], - self._received_data, self.config['snub_time'], self.config['auto_kick'], - self._kick_peer, self._ban_peer) - self.downloader.set_download_rate(self.config['max_download_rate']) - self.connecter = Connecter(self._make_upload, self.downloader, self.choker, - self.len_pieces, self.upmeasure, self.config, - self.ratelimiter, self.rawserver.add_task) - self.encoder = Encoder(self.connecter, self.rawserver, - self.myid, self.config['max_message_length'], self.rawserver.add_task, - self.config['keepalive_interval'], self.infohash, - self._received_raw_data, self.config) - self.encoder_ban = self.encoder.ban - - self.httpdownloader = HTTPDownloader(self.storagewrapper, self.picker, - self.rawserver, self.finflag, self.errorfunc, self.downloader, - self.config['max_rate_period'], self.infohash, self._received_http_data, - self.connecter.got_piece) - if self.response.has_key('httpseeds') and not self.finflag.isSet(): - for u in self.response['httpseeds']: - self.httpdownloader.make_download(u) - - if self.selector_enabled: - self.fileselector.tie_in(self.picker, self._cancelfunc, - self._reqmorefunc, self.rerequest_ondownloadmore) - if self.priority: - self.fileselector.set_priorities_now(self.priority) - self.appdataobj.deleteTorrentData(self.infohash) - # erase old data once you've started modifying it - - if self.config['super_seeder']: - self.set_super_seed() - - self.started = True - return True - - - def rerequest_complete(self): - if self.rerequest: - self.rerequest.announce(1) - - def rerequest_stopped(self): - if self.rerequest: - self.rerequest.announce(2) - - def rerequest_lastfailed(self): - if self.rerequest: - return self.rerequest.last_failed - return False - - def rerequest_ondownloadmore(self): - if self.rerequest: - self.rerequest.hit() - - def startRerequester(self, seededfunc = None, force_rapid_update = False): - if self.response.has_key('announce-list'): - trackerlist = self.response['announce-list'] - else: - trackerlist = [[self.response['announce']]] - - self.rerequest = Rerequester(trackerlist, self.config['rerequest_interval'], - self.rawserver.add_task, self.connecter.how_many_connections, - self.config['min_peers'], self.encoder.start_connections, - self.rawserver.add_task, self.storagewrapper.get_amount_left, - self.upmeasure.get_total, self.downmeasure.get_total, self.port, self.config['ip'], - self.myid, self.infohash, self.config['http_timeout'], - self.errorfunc, self.excfunc, self.config['max_initiate'], - self.doneflag, self.upmeasure.get_rate, self.downmeasure.get_rate, - self.unpauseflag, self.config['dedicated_seed_id'], - seededfunc, force_rapid_update ) - - self.rerequest.start() - - - def _init_stats(self): - self.statistics = Statistics(self.upmeasure, self.downmeasure, - self.connecter, self.httpdownloader, self.ratelimiter, - self.rerequest_lastfailed, self.filedatflag) - if self.info.has_key('files'): - self.statistics.set_dirstats(self.files, self.info['piece length']) - if self.config['spew']: - self.spewflag.set() - - def autoStats(self, displayfunc = None): - if not displayfunc: - displayfunc = self.statusfunc - - self._init_stats() - DownloaderFeedback(self.choker, self.httpdownloader, self.rawserver.add_task, - self.upmeasure.get_rate, self.downmeasure.get_rate, - self.ratemeasure, self.storagewrapper.get_stats, - self.datalength, self.finflag, self.spewflag, self.statistics, - displayfunc, self.config['display_interval']) - - def startStats(self): - self._init_stats() - d = DownloaderFeedback(self.choker, self.httpdownloader, self.rawserver.add_task, - self.upmeasure.get_rate, self.downmeasure.get_rate, - self.ratemeasure, self.storagewrapper.get_stats, - self.datalength, self.finflag, self.spewflag, self.statistics) - return d.gather - - - def getPortHandler(self): - return self.encoder - - - def shutdown(self, torrentdata = {}): - if self.checking or self.started: - self.storagewrapper.sync() - self.storage.close() - self.rerequest_stopped() - if self.fileselector and self.started: - if not self.failed: - self.fileselector.finish() - torrentdata['resume data'] = self.fileselector.pickle() - try: - self.appdataobj.writeTorrentData(self.infohash,torrentdata) - except: - self.appdataobj.deleteTorrentData(self.infohash) # clear it - return not self.failed and not self.excflag.isSet() - # if returns false, you may wish to auto-restart the torrent - - - def setUploadRate(self, rate): - try: - def s(self = self, rate = rate): - self.config['max_upload_rate'] = rate - self.ratelimiter.set_upload_rate(rate) - self.rawserver.add_task(s) - except AttributeError: - pass - - def setConns(self, conns, conns2 = None): - if not conns2: - conns2 = conns - try: - def s(self = self, conns = conns, conns2 = conns2): - self.config['min_uploads'] = conns - self.config['max_uploads'] = conns2 - if (conns > 30): - self.config['max_initiate'] = conns + 10 - self.rawserver.add_task(s) - except AttributeError: - pass - - def setDownloadRate(self, rate): - try: - def s(self = self, rate = rate): - self.config['max_download_rate'] = rate - self.downloader.set_download_rate(rate) - self.rawserver.add_task(s) - except AttributeError: - pass - - def startConnection(self, ip, port, id): - self.encoder._start_connection((ip, port), id) - - def _startConnection(self, ipandport, id): - self.encoder._start_connection(ipandport, id) - - def setInitiate(self, initiate): - try: - def s(self = self, initiate = initiate): - self.config['max_initiate'] = initiate - self.rawserver.add_task(s) - except AttributeError: - pass - - def getConfig(self): - return self.config - - def getDefaults(self): - return defaultargs(defaults) - - def getUsageText(self): - return self.argslistheader - - def reannounce(self, special = None): - try: - def r(self = self, special = special): - if special is None: - self.rerequest.announce() - else: - self.rerequest.announce(specialurl = special) - self.rawserver.add_task(r) - except AttributeError: - pass - - def getResponse(self): - try: - return self.response - except: - return None - -# def Pause(self): -# try: -# if self.storagewrapper: -# self.rawserver.add_task(self._pausemaker, 0) -# except: -# return False -# self.unpauseflag.clear() -# return True -# -# def _pausemaker(self): -# self.whenpaused = clock() -# self.unpauseflag.wait() # sticks a monkey wrench in the main thread -# -# def Unpause(self): -# self.unpauseflag.set() -# if self.whenpaused and clock()-self.whenpaused > 60: -# def r(self = self): -# self.rerequest.announce(3) # rerequest automatically if paused for >60 seconds -# self.rawserver.add_task(r) - - def Pause(self): - if not self.storagewrapper: - return False - self.unpauseflag.clear() - self.rawserver.add_task(self.onPause) - return True - - def onPause(self): - self.whenpaused = clock() - if not self.downloader: - return - self.downloader.pause(True) - self.encoder.pause(True) - self.choker.pause(True) - - def Unpause(self): - self.unpauseflag.set() - self.rawserver.add_task(self.onUnpause) - - def onUnpause(self): - if not self.downloader: - return - self.downloader.pause(False) - self.encoder.pause(False) - self.choker.pause(False) - if self.rerequest and self.whenpaused and clock()-self.whenpaused > 60: - self.rerequest.announce(3) # rerequest automatically if paused for >60 seconds - - def set_super_seed(self): - try: - self.superseedflag.set() - def s(self = self): - if self.finflag.isSet(): - self._set_super_seed() - self.rawserver.add_task(s) - except AttributeError: - pass - - def _set_super_seed(self): - if not self.super_seeding_active: - self.super_seeding_active = True - self.errorfunc(' ** SUPER-SEED OPERATION ACTIVE **\n' + - ' please set Max uploads so each peer gets 6-8 kB/s') - def s(self = self): - self.downloader.set_super_seed() - self.choker.set_super_seed() - self.rawserver.add_task(s) - if self.finflag.isSet(): # mode started when already finished - def r(self = self): - self.rerequest.announce(3) # so after kicking everyone off, reannounce - self.rawserver.add_task(r) - - def am_I_finished(self): - return self.finflag.isSet() - - def get_transfer_stats(self): - return self.upmeasure.get_total(), self.downmeasure.get_total() diff --git a/www/pages/torrent/client/inifile.py b/www/pages/torrent/client/inifile.py deleted file mode 100644 index 032d339..0000000 --- a/www/pages/torrent/client/inifile.py +++ /dev/null @@ -1,169 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -''' -reads/writes a Windows-style INI file -format: - - aa = "bb" - cc = 11 - - [eee] - ff = "gg" - -decodes to: -d = { '': {'aa':'bb','cc':'11'}, 'eee': {'ff':'gg'} } - -the encoder can also take this as input: - -d = { 'aa': 'bb, 'cc': 11, 'eee': {'ff':'gg'} } - -though it will only decode in the above format. Keywords must be strings. -Values that are strings are written surrounded by quotes, and the decoding -routine automatically strips any. -Booleans are written as integers. Anything else aside from string/int/float -may have unpredictable results. -''' - -from cStringIO import StringIO -from traceback import print_exc -from types import DictType, StringType -try: - from types import BooleanType -except ImportError: - BooleanType = None - -try: - True -except: - True = 1 - False = 0 - -DEBUG = False - -def ini_write(f, d, comment=''): - try: - a = {'':{}} - for k,v in d.items(): - assert type(k) == StringType - k = k.lower() - if type(v) == DictType: - if DEBUG: - print 'new section:' +k - if k: - assert not a.has_key(k) - a[k] = {} - aa = a[k] - for kk,vv in v: - assert type(kk) == StringType - kk = kk.lower() - assert not aa.has_key(kk) - if type(vv) == BooleanType: - vv = int(vv) - if type(vv) == StringType: - vv = '"'+vv+'"' - aa[kk] = str(vv) - if DEBUG: - print 'a['+k+']['+kk+'] = '+str(vv) - else: - aa = a[''] - assert not aa.has_key(k) - if type(v) == BooleanType: - v = int(v) - if type(v) == StringType: - v = '"'+v+'"' - aa[k] = str(v) - if DEBUG: - print 'a[\'\']['+k+'] = '+str(v) - r = open(f,'w') - if comment: - for c in comment.split('\n'): - r.write('# '+c+'\n') - r.write('\n') - l = a.keys() - l.sort() - for k in l: - if k: - r.write('\n['+k+']\n') - aa = a[k] - ll = aa.keys() - ll.sort() - for kk in ll: - r.write(kk+' = '+aa[kk]+'\n') - success = True - except: - if DEBUG: - print_exc() - success = False - try: - r.close() - except: - pass - return success - - -if DEBUG: - def errfunc(lineno, line, err): - print '('+str(lineno)+') '+err+': '+line -else: - errfunc = lambda lineno, line, err: None - -def ini_read(f, errfunc = errfunc): - try: - r = open(f,'r') - ll = r.readlines() - d = {} - dd = {'':d} - for i in xrange(len(ll)): - l = ll[i] - l = l.strip() - if not l: - continue - if l[0] == '#': - continue - if l[0] == '[': - if l[-1] != ']': - errfunc(i,l,'syntax error') - continue - l1 = l[1:-1].strip().lower() - if not l1: - errfunc(i,l,'syntax error') - continue - if dd.has_key(l1): - errfunc(i,l,'duplicate section') - d = dd[l1] - continue - d = {} - dd[l1] = d - continue - try: - k,v = l.split('=',1) - except: - try: - k,v = l.split(':',1) - except: - errfunc(i,l,'syntax error') - continue - k = k.strip().lower() - v = v.strip() - if len(v) > 1 and ( (v[0] == '"' and v[-1] == '"') or - (v[0] == "'" and v[-1] == "'") ): - v = v[1:-1] - if not k: - errfunc(i,l,'syntax error') - continue - if d.has_key(k): - errfunc(i,l,'duplicate entry') - continue - d[k] = v - if DEBUG: - print dd - except: - if DEBUG: - print_exc() - dd = None - try: - r.close() - except: - pass - return dd diff --git a/www/pages/torrent/client/iprangeparse.py b/www/pages/torrent/client/iprangeparse.py deleted file mode 100644 index 52f140e..0000000 --- a/www/pages/torrent/client/iprangeparse.py +++ /dev/null @@ -1,194 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -from bisect import bisect, insort - -try: - True -except: - True = 1 - False = 0 - bool = lambda x: not not x - - -def to_long_ipv4(ip): - ip = ip.split('.') - if len(ip) != 4: - raise ValueError, "bad address" - b = 0L - for n in ip: - b *= 256 - b += int(n) - return b - - -def to_long_ipv6(ip): - if ip == '': - raise ValueError, "bad address" - if ip == '::': # boundary handling - ip = '' - elif ip[:2] == '::': - ip = ip[1:] - elif ip[0] == ':': - raise ValueError, "bad address" - elif ip[-2:] == '::': - ip = ip[:-1] - elif ip[-1] == ':': - raise ValueError, "bad address" - - b = [] - doublecolon = False - for n in ip.split(':'): - if n == '': # double-colon - if doublecolon: - raise ValueError, "bad address" - doublecolon = True - b.append(None) - continue - if n.find('.') >= 0: # IPv4 - n = n.split('.') - if len(n) != 4: - raise ValueError, "bad address" - for i in n: - b.append(int(i)) - continue - n = ('0'*(4-len(n))) + n - b.append(int(n[:2],16)) - b.append(int(n[2:],16)) - bb = 0L - for n in b: - if n is None: - for i in xrange(17-len(b)): - bb *= 256 - continue - bb *= 256 - bb += n - return bb - -ipv4addrmask = 65535L*256*256*256*256 - -class IP_List: - def __init__(self): - self.ipv4list = [] # starts of ranges - self.ipv4dict = {} # start: end of ranges - self.ipv6list = [] # " - self.ipv6dict = {} # " - - def __nonzero__(self): - return bool(self.ipv4list or self.ipv6list) - - - def append(self, ip_beg, ip_end = None): - if ip_end is None: - ip_end = ip_beg - else: - assert ip_beg <= ip_end - if ip_beg.find(':') < 0: # IPv4 - ip_beg = to_long_ipv4(ip_beg) - ip_end = to_long_ipv4(ip_end) - l = self.ipv4list - d = self.ipv4dict - else: - ip_beg = to_long_ipv6(ip_beg) - ip_end = to_long_ipv6(ip_end) - bb = ip_beg % (256*256*256*256) - if bb == ipv4addrmask: - ip_beg -= bb - ip_end -= bb - l = self.ipv4list - d = self.ipv4dict - else: - l = self.ipv6list - d = self.ipv6dict - - pos = bisect(l,ip_beg)-1 - done = pos < 0 - while not done: - p = pos - while p < len(l): - range_beg = l[p] - if range_beg > ip_end+1: - done = True - break - range_end = d[range_beg] - if range_end < ip_beg-1: - p += 1 - if p == len(l): - done = True - break - continue - # if neither of the above conditions is true, the ranges overlap - ip_beg = min(ip_beg, range_beg) - ip_end = max(ip_end, range_end) - del l[p] - del d[range_beg] - break - - insort(l,ip_beg) - d[ip_beg] = ip_end - - - def includes(self, ip): - if not (self.ipv4list or self.ipv6list): - return False - if ip.find(':') < 0: # IPv4 - ip = to_long_ipv4(ip) - l = self.ipv4list - d = self.ipv4dict - else: - ip = to_long_ipv6(ip) - bb = ip % (256*256*256*256) - if bb == ipv4addrmask: - ip -= bb - l = self.ipv4list - d = self.ipv4dict - else: - l = self.ipv6list - d = self.ipv6dict - for ip_beg in l[bisect(l,ip)-1:]: - if ip == ip_beg: - return True - ip_end = d[ip_beg] - if ip > ip_beg and ip <= ip_end: - return True - return False - - - # reads a list from a file in the format 'whatever:whatever:ip-ip' - # (not IPv6 compatible at all) - def read_rangelist(self, file): - f = open(file, 'r') - while True: - line = f.readline() - if not line: - break - line = line.strip() - if not line or line[0] == '#': - continue - line = line.split(':')[-1] - try: - ip1,ip2 = line.split('-') - except: - ip1 = line - ip2 = line - try: - self.append(ip1.strip(),ip2.strip()) - except: - print '*** WARNING *** could not parse IP range: '+line - f.close() - -def is_ipv4(ip): - return ip.find(':') < 0 - -def is_valid_ip(ip): - try: - if is_ipv4(ip): - a = ip.split('.') - assert len(a) == 4 - for i in a: - chr(int(i)) - return True - to_long_ipv6(ip) - return True - except: - return False diff --git a/www/pages/torrent/client/launchmanycore.py b/www/pages/torrent/client/launchmanycore.py deleted file mode 100644 index 8dbb59c..0000000 --- a/www/pages/torrent/client/launchmanycore.py +++ /dev/null @@ -1,381 +0,0 @@ -#!/usr/bin/env python - -# Written by John Hoffman -# see LICENSE.txt for license information - -from BitTornado import PSYCO -if PSYCO.psyco: - try: - import psyco - assert psyco.__version__ >= 0x010100f0 - psyco.full() - except: - pass - -from download_bt1 import BT1Download -from RawServer import RawServer, UPnP_ERROR -from RateLimiter import RateLimiter -from ServerPortHandler import MultiHandler -from parsedir import parsedir -from natpunch import UPnP_test -from random import seed -from socket import error as socketerror -from threading import Event -from sys import argv, exit -import sys, os -from clock import clock -from __init__ import createPeerID, mapbase64, version -from cStringIO import StringIO -from traceback import print_exc - -try: - True -except: - True = 1 - False = 0 - - -def fmttime(n): - try: - n = int(n) # n may be None or too large - assert n < 5184000 # 60 days - except: - return 'downloading' - m, s = divmod(n, 60) - h, m = divmod(m, 60) - return '%d:%02d:%02d' % (h, m, s) - -class SingleDownload: - def __init__(self, controller, hash, response, config, myid): - self.controller = controller - self.hash = hash - self.response = response - self.config = config - - self.doneflag = Event() - self.waiting = True - self.checking = False - self.working = False - self.seed = False - self.closed = False - - self.status_msg = '' - self.status_err = [''] - self.status_errtime = 0 - self.status_done = 0.0 - - self.rawserver = controller.handler.newRawServer(hash, self.doneflag) - - d = BT1Download(self.display, self.finished, self.error, - controller.exchandler, self.doneflag, config, response, - hash, myid, self.rawserver, controller.listen_port) - self.d = d - - def start(self): - if not self.d.saveAs(self.saveAs): - self._shutdown() - return - self._hashcheckfunc = self.d.initFiles() - if not self._hashcheckfunc: - self._shutdown() - return - self.controller.hashchecksched(self.hash) - - - def saveAs(self, name, length, saveas, isdir): - return self.controller.saveAs(self.hash, name, saveas, isdir) - - def hashcheck_start(self, donefunc): - if self.is_dead(): - self._shutdown() - return - self.waiting = False - self.checking = True - self._hashcheckfunc(donefunc) - - def hashcheck_callback(self): - self.checking = False - if self.is_dead(): - self._shutdown() - return - if not self.d.startEngine(ratelimiter = self.controller.ratelimiter): - self._shutdown() - return - self.d.startRerequester() - self.statsfunc = self.d.startStats() - self.rawserver.start_listening(self.d.getPortHandler()) - self.working = True - - def is_dead(self): - return self.doneflag.isSet() - - def _shutdown(self): - self.shutdown(False) - - def shutdown(self, quiet=True): - if self.closed: - return - self.doneflag.set() - self.rawserver.shutdown() - if self.checking or self.working: - self.d.shutdown() - self.waiting = False - self.checking = False - self.working = False - self.closed = True - self.controller.was_stopped(self.hash) - if not quiet: - self.controller.died(self.hash) - - - def display(self, activity = None, fractionDone = None): - # really only used by StorageWrapper now - if activity: - self.status_msg = activity - if fractionDone is not None: - self.status_done = float(fractionDone) - - def finished(self): - self.seed = True - - def error(self, msg): - if self.doneflag.isSet(): - self._shutdown() - self.status_err.append(msg) - self.status_errtime = clock() - - -class LaunchMany: - def __init__(self, config, Output): - try: - self.config = config - self.Output = Output - - self.torrent_dir = config['torrent_dir'] - self.torrent_cache = {} - self.file_cache = {} - self.blocked_files = {} - self.scan_period = config['parse_dir_interval'] - self.stats_period = config['display_interval'] - - self.torrent_list = [] - self.downloads = {} - self.counter = 0 - self.doneflag = Event() - - self.hashcheck_queue = [] - self.hashcheck_current = None - - self.rawserver = RawServer(self.doneflag, config['timeout_check_interval'], - config['timeout'], ipv6_enable = config['ipv6_enabled'], - failfunc = self.failed, errorfunc = self.exchandler) - upnp_type = UPnP_test(config['upnp_nat_access']) - while True: - try: - self.listen_port = self.rawserver.find_and_bind( - config['minport'], config['maxport'], config['bind'], - ipv6_socket_style = config['ipv6_binds_v4'], - upnp = upnp_type, randomizer = config['random_port']) - break - except socketerror, e: - if upnp_type and e == UPnP_ERROR: - self.Output.message('WARNING: COULD NOT FORWARD VIA UPnP') - upnp_type = 0 - continue - self.failed("Couldn't listen - " + str(e)) - return - - self.ratelimiter = RateLimiter(self.rawserver.add_task, - config['upload_unit_size']) - self.ratelimiter.set_upload_rate(config['max_upload_rate']) - - self.handler = MultiHandler(self.rawserver, self.doneflag) - seed(createPeerID()) - self.rawserver.add_task(self.scan, 0) - self.rawserver.add_task(self.stats, 0) - - self.handler.listen_forever() - - self.Output.message('shutting down') - self.hashcheck_queue = [] - for hash in self.torrent_list: - self.Output.message('dropped "'+self.torrent_cache[hash]['path']+'"') - self.downloads[hash].shutdown() - self.rawserver.shutdown() - - except: - data = StringIO() - print_exc(file = data) - Output.exception(data.getvalue()) - - - def scan(self): - self.rawserver.add_task(self.scan, self.scan_period) - - r = parsedir(self.torrent_dir, self.torrent_cache, - self.file_cache, self.blocked_files, - return_metainfo = True, errfunc = self.Output.message) - - ( self.torrent_cache, self.file_cache, self.blocked_files, - added, removed ) = r - - for hash, data in removed.items(): - self.Output.message('dropped "'+data['path']+'"') - self.remove(hash) - for hash, data in added.items(): - self.Output.message('added "'+data['path']+'"') - self.add(hash, data) - - def stats(self): - self.rawserver.add_task(self.stats, self.stats_period) - data = [] - for hash in self.torrent_list: - cache = self.torrent_cache[hash] - if self.config['display_path']: - name = cache['path'] - else: - name = cache['name'] - size = cache['length'] - d = self.downloads[hash] - progress = '0.0%' - peers = 0 - seeds = 0 - seedsmsg = "S" - dist = 0.0 - uprate = 0.0 - dnrate = 0.0 - upamt = 0 - dnamt = 0 - t = 0 - if d.is_dead(): - status = 'stopped' - elif d.waiting: - status = 'waiting for hash check' - elif d.checking: - status = d.status_msg - progress = '%.1f%%' % (d.status_done*100) - else: - stats = d.statsfunc() - s = stats['stats'] - if d.seed: - status = 'seeding' - progress = '100.0%' - seeds = s.numOldSeeds - seedsmsg = "s" - dist = s.numCopies - else: - if s.numSeeds + s.numPeers: - t = stats['time'] - if t == 0: # unlikely - t = 0.01 - status = fmttime(t) - else: - t = -1 - status = 'connecting to peers' - progress = '%.1f%%' % (int(stats['frac']*1000)/10.0) - seeds = s.numSeeds - dist = s.numCopies2 - dnrate = stats['down'] - peers = s.numPeers - uprate = stats['up'] - upamt = s.upTotal - dnamt = s.downTotal - - if d.is_dead() or d.status_errtime+300 > clock(): - msg = d.status_err[-1] - else: - msg = '' - - data.append(( name, status, progress, peers, seeds, seedsmsg, dist, - uprate, dnrate, upamt, dnamt, size, t, msg )) - stop = self.Output.display(data) - if stop: - self.doneflag.set() - - def remove(self, hash): - self.torrent_list.remove(hash) - self.downloads[hash].shutdown() - del self.downloads[hash] - - def add(self, hash, data): - c = self.counter - self.counter += 1 - x = '' - for i in xrange(3): - x = mapbase64[c & 0x3F]+x - c >>= 6 - peer_id = createPeerID(x) - d = SingleDownload(self, hash, data['metainfo'], self.config, peer_id) - self.torrent_list.append(hash) - self.downloads[hash] = d - d.start() - - - def saveAs(self, hash, name, saveas, isdir): - x = self.torrent_cache[hash] - style = self.config['saveas_style'] - if style == 1 or style == 3: - if saveas: - saveas = os.path.join(saveas,x['file'][:-1-len(x['type'])]) - else: - saveas = x['path'][:-1-len(x['type'])] - if style == 3: - if not os.path.isdir(saveas): - try: - os.mkdir(saveas) - except: - raise OSError("couldn't create directory for "+x['path'] - +" ("+saveas+")") - if not isdir: - saveas = os.path.join(saveas, name) - else: - if saveas: - saveas = os.path.join(saveas, name) - else: - saveas = os.path.join(os.path.split(x['path'])[0], name) - - if isdir and not os.path.isdir(saveas): - try: - os.mkdir(saveas) - except: - raise OSError("couldn't create directory for "+x['path'] - +" ("+saveas+")") - return saveas - - - def hashchecksched(self, hash = None): - if hash: - self.hashcheck_queue.append(hash) - if not self.hashcheck_current: - self._hashcheck_start() - - def _hashcheck_start(self): - self.hashcheck_current = self.hashcheck_queue.pop(0) - self.downloads[self.hashcheck_current].hashcheck_start(self.hashcheck_callback) - - def hashcheck_callback(self): - self.downloads[self.hashcheck_current].hashcheck_callback() - if self.hashcheck_queue: - self._hashcheck_start() - else: - self.hashcheck_current = None - - def died(self, hash): - if self.torrent_cache.has_key(hash): - self.Output.message('DIED: "'+self.torrent_cache[hash]['path']+'"') - - def was_stopped(self, hash): - try: - self.hashcheck_queue.remove(hash) - except: - pass - if self.hashcheck_current == hash: - self.hashcheck_current = None - if self.hashcheck_queue: - self._hashcheck_start() - - def failed(self, s): - self.Output.message('FAILURE: '+s) - - def exchandler(self, s): - self.Output.exception(s) diff --git a/www/pages/torrent/client/natpunch.py b/www/pages/torrent/client/natpunch.py deleted file mode 100644 index 896827b..0000000 --- a/www/pages/torrent/client/natpunch.py +++ /dev/null @@ -1,254 +0,0 @@ -# Written by John Hoffman -# derived from NATPortMapping.py by Yejun Yang -# and from example code by Myers Carpenter -# see LICENSE.txt for license information - -import socket -from traceback import print_exc -from subnetparse import IP_List -from clock import clock -from __init__ import createPeerID -try: - True -except: - True = 1 - False = 0 - -DEBUG = False - -EXPIRE_CACHE = 30 # seconds -ID = "BT-"+createPeerID()[-4:] - -try: - import pythoncom, win32com.client - _supported = 1 -except ImportError: - _supported = 0 - - - -class _UPnP1: # derived from Myers Carpenter's code - # seems to use the machine's local UPnP - # system for its operation. Runs fairly fast - - def __init__(self): - self.map = None - self.last_got_map = -10e10 - - def _get_map(self): - if self.last_got_map + EXPIRE_CACHE < clock(): - try: - dispatcher = win32com.client.Dispatch("HNetCfg.NATUPnP") - self.map = dispatcher.StaticPortMappingCollection - self.last_got_map = clock() - except: - self.map = None - return self.map - - def test(self): - try: - assert self._get_map() # make sure a map was found - success = True - except: - success = False - return success - - - def open(self, ip, p): - map = self._get_map() - try: - map.Add(p,'TCP',p,ip,True,ID) - if DEBUG: - print 'port opened: '+ip+':'+str(p) - success = True - except: - if DEBUG: - print "COULDN'T OPEN "+str(p) - print_exc() - success = False - return success - - - def close(self, p): - map = self._get_map() - try: - map.Remove(p,'TCP') - success = True - if DEBUG: - print 'port closed: '+str(p) - except: - if DEBUG: - print 'ERROR CLOSING '+str(p) - print_exc() - success = False - return success - - - def clean(self, retry = False): - if not _supported: - return - try: - map = self._get_map() - ports_in_use = [] - for i in xrange(len(map)): - try: - mapping = map[i] - port = mapping.ExternalPort - prot = str(mapping.Protocol).lower() - desc = str(mapping.Description).lower() - except: - port = None - if port and prot == 'tcp' and desc[:3] == 'bt-': - ports_in_use.append(port) - success = True - for port in ports_in_use: - try: - map.Remove(port,'TCP') - except: - success = False - if not success and not retry: - self.clean(retry = True) - except: - pass - - -class _UPnP2: # derived from Yejun Yang's code - # apparently does a direct search for UPnP hardware - # may work in some cases where _UPnP1 won't, but is slow - # still need to implement "clean" method - - def __init__(self): - self.services = None - self.last_got_services = -10e10 - - def _get_services(self): - if not self.services or self.last_got_services + EXPIRE_CACHE < clock(): - self.services = [] - try: - f=win32com.client.Dispatch("UPnP.UPnPDeviceFinder") - for t in ( "urn:schemas-upnp-org:service:WANIPConnection:1", - "urn:schemas-upnp-org:service:WANPPPConnection:1" ): - try: - conns = f.FindByType(t,0) - for c in xrange(len(conns)): - try: - svcs = conns[c].Services - for s in xrange(len(svcs)): - try: - self.services.append(svcs[s]) - except: - pass - except: - pass - except: - pass - except: - pass - self.last_got_services = clock() - return self.services - - def test(self): - try: - assert self._get_services() # make sure some services can be found - success = True - except: - success = False - return success - - - def open(self, ip, p): - svcs = self._get_services() - success = False - for s in svcs: - try: - s.InvokeAction('AddPortMapping',['',p,'TCP',p,ip,True,ID,0],'') - success = True - except: - pass - if DEBUG and not success: - print "COULDN'T OPEN "+str(p) - print_exc() - return success - - - def close(self, p): - svcs = self._get_services() - success = False - for s in svcs: - try: - s.InvokeAction('DeletePortMapping', ['',p,'TCP'], '') - success = True - except: - pass - if DEBUG and not success: - print "COULDN'T OPEN "+str(p) - print_exc() - return success - - -class _UPnP: # master holding class - def __init__(self): - self.upnp1 = _UPnP1() - self.upnp2 = _UPnP2() - self.upnplist = (None, self.upnp1, self.upnp2) - self.upnp = None - self.local_ip = None - self.last_got_ip = -10e10 - - def get_ip(self): - if self.last_got_ip + EXPIRE_CACHE < clock(): - local_ips = IP_List() - local_ips.set_intranet_addresses() - try: - for info in socket.getaddrinfo(socket.gethostname(),0,socket.AF_INET): - # exception if socket library isn't recent - self.local_ip = info[4][0] - if local_ips.includes(self.local_ip): - self.last_got_ip = clock() - if DEBUG: - print 'Local IP found: '+self.local_ip - break - else: - raise ValueError('couldn\'t find intranet IP') - except: - self.local_ip = None - if DEBUG: - print 'Error finding local IP' - print_exc() - return self.local_ip - - def test(self, upnp_type): - if DEBUG: - print 'testing UPnP type '+str(upnp_type) - if not upnp_type or not _supported or self.get_ip() is None: - if DEBUG: - print 'not supported' - return 0 - pythoncom.CoInitialize() # leave initialized - self.upnp = self.upnplist[upnp_type] # cache this - if self.upnp.test(): - if DEBUG: - print 'ok' - return upnp_type - if DEBUG: - print 'tested bad' - return 0 - - def open(self, p): - assert self.upnp, "must run UPnP_test() with the desired UPnP access type first" - return self.upnp.open(self.get_ip(), p) - - def close(self, p): - assert self.upnp, "must run UPnP_test() with the desired UPnP access type first" - return self.upnp.close(p) - - def clean(self): - return self.upnp1.clean() - -_upnp_ = _UPnP() - -UPnP_test = _upnp_.test -UPnP_open_port = _upnp_.open -UPnP_close_port = _upnp_.close -UPnP_reset = _upnp_.clean - diff --git a/www/pages/torrent/client/parseargs.py b/www/pages/torrent/client/parseargs.py deleted file mode 100644 index 646af10..0000000 --- a/www/pages/torrent/client/parseargs.py +++ /dev/null @@ -1,137 +0,0 @@ -# Written by Bill Bumgarner and Bram Cohen -# see LICENSE.txt for license information - -from types import * -from cStringIO import StringIO - - -def splitLine(line, COLS=80, indent=10): - indent = " " * indent - width = COLS - (len(indent) + 1) - if indent and width < 15: - width = COLS - 2 - indent = " " - s = StringIO() - i = 0 - for word in line.split(): - if i == 0: - s.write(indent+word) - i = len(word) - continue - if i + len(word) >= width: - s.write('\n'+indent+word) - i = len(word) - continue - s.write(' '+word) - i += len(word) + 1 - return s.getvalue() - -def formatDefinitions(options, COLS, presets = {}): - s = StringIO() - for (longname, default, doc) in options: - s.write('--' + longname + ' \n') - default = presets.get(longname, default) - if type(default) in (IntType, LongType): - try: - default = int(default) - except: - pass - if default is not None: - doc += ' (defaults to ' + repr(default) + ')' - s.write(splitLine(doc,COLS,10)) - s.write('\n\n') - return s.getvalue() - - -def usage(str): - raise ValueError(str) - - -def defaultargs(options): - l = {} - for (longname, default, doc) in options: - if default is not None: - l[longname] = default - return l - - -def parseargs(argv, options, minargs = None, maxargs = None, presets = {}): - config = {} - longkeyed = {} - for option in options: - longname, default, doc = option - longkeyed[longname] = option - config[longname] = default - for longname in presets.keys(): # presets after defaults but before arguments - config[longname] = presets[longname] - options = [] - args = [] - pos = 0 - while pos < len(argv): - if argv[pos][:2] != '--': - args.append(argv[pos]) - pos += 1 - else: - if pos == len(argv) - 1: - usage('parameter passed in at end with no value') - key, value = argv[pos][2:], argv[pos+1] - pos += 2 - if not longkeyed.has_key(key): - usage('unknown key --' + key) - longname, default, doc = longkeyed[key] - try: - t = type(config[longname]) - if t is NoneType or t is StringType: - config[longname] = value - elif t in (IntType, LongType): - config[longname] = long(value) - elif t is FloatType: - config[longname] = float(value) - else: - assert 0 - except ValueError, e: - usage('wrong format of --%s - %s' % (key, str(e))) - for key, value in config.items(): - if value is None: - usage("Option --%s is required." % key) - if minargs is not None and len(args) < minargs: - usage("Must supply at least %d args." % minargs) - if maxargs is not None and len(args) > maxargs: - usage("Too many args - %d max." % maxargs) - return (config, args) - -def test_parseargs(): - assert parseargs(('d', '--a', 'pq', 'e', '--b', '3', '--c', '4.5', 'f'), (('a', 'x', ''), ('b', 1, ''), ('c', 2.3, ''))) == ({'a': 'pq', 'b': 3, 'c': 4.5}, ['d', 'e', 'f']) - assert parseargs([], [('a', 'x', '')]) == ({'a': 'x'}, []) - assert parseargs(['--a', 'x', '--a', 'y'], [('a', '', '')]) == ({'a': 'y'}, []) - try: - parseargs([], [('a', 'x', '')]) - except ValueError: - pass - try: - parseargs(['--a', 'x'], []) - except ValueError: - pass - try: - parseargs(['--a'], [('a', 'x', '')]) - except ValueError: - pass - try: - parseargs([], [], 1, 2) - except ValueError: - pass - assert parseargs(['x'], [], 1, 2) == ({}, ['x']) - assert parseargs(['x', 'y'], [], 1, 2) == ({}, ['x', 'y']) - try: - parseargs(['x', 'y', 'z'], [], 1, 2) - except ValueError: - pass - try: - parseargs(['--a', '2.0'], [('a', 3, '')]) - except ValueError: - pass - try: - parseargs(['--a', 'z'], [('a', 2.1, '')]) - except ValueError: - pass - diff --git a/www/pages/torrent/client/parsedir.py b/www/pages/torrent/client/parsedir.py deleted file mode 100644 index 51613ce..0000000 --- a/www/pages/torrent/client/parsedir.py +++ /dev/null @@ -1,150 +0,0 @@ -# Written by John Hoffman and Uoti Urpala -# see LICENSE.txt for license information -from bencode import bencode, bdecode -from BT1.btformats import check_info -from os.path import exists, isfile -from sha import sha -import sys, os - -try: - True -except: - True = 1 - False = 0 - -NOISY = False - -def _errfunc(x): - print ":: "+x - -def parsedir(directory, parsed, files, blocked, - exts = ['.torrent'], return_metainfo = False, errfunc = _errfunc): - if NOISY: - errfunc('checking dir') - dirs_to_check = [directory] - new_files = {} - new_blocked = {} - torrent_type = {} - while dirs_to_check: # first, recurse directories and gather torrents - directory = dirs_to_check.pop() - newtorrents = False - for f in os.listdir(directory): - newtorrent = None - for ext in exts: - if f.endswith(ext): - newtorrent = ext[1:] - break - if newtorrent: - newtorrents = True - p = os.path.join(directory, f) - new_files[p] = [(os.path.getmtime(p), os.path.getsize(p)), 0] - torrent_type[p] = newtorrent - if not newtorrents: - for f in os.listdir(directory): - p = os.path.join(directory, f) - if os.path.isdir(p): - dirs_to_check.append(p) - - new_parsed = {} - to_add = [] - added = {} - removed = {} - # files[path] = [(modification_time, size), hash], hash is 0 if the file - # has not been successfully parsed - for p,v in new_files.items(): # re-add old items and check for changes - oldval = files.get(p) - if not oldval: # new file - to_add.append(p) - continue - h = oldval[1] - if oldval[0] == v[0]: # file is unchanged from last parse - if h: - if blocked.has_key(p): # parseable + blocked means duplicate - to_add.append(p) # other duplicate may have gone away - else: - new_parsed[h] = parsed[h] - new_files[p] = oldval - else: - new_blocked[p] = 1 # same broken unparseable file - continue - if parsed.has_key(h) and not blocked.has_key(p): - if NOISY: - errfunc('removing '+p+' (will re-add)') - removed[h] = parsed[h] - to_add.append(p) - - to_add.sort() - for p in to_add: # then, parse new and changed torrents - new_file = new_files[p] - v,h = new_file - if new_parsed.has_key(h): # duplicate - if not blocked.has_key(p) or files[p][0] != v: - errfunc('**warning** '+ - p +' is a duplicate torrent for '+new_parsed[h]['path']) - new_blocked[p] = 1 - continue - - if NOISY: - errfunc('adding '+p) - try: - ff = open(p, 'rb') - d = bdecode(ff.read()) - check_info(d['info']) - h = sha(bencode(d['info'])).digest() - new_file[1] = h - if new_parsed.has_key(h): - errfunc('**warning** '+ - p +' is a duplicate torrent for '+new_parsed[h]['path']) - new_blocked[p] = 1 - continue - - a = {} - a['path'] = p - f = os.path.basename(p) - a['file'] = f - a['type'] = torrent_type[p] - i = d['info'] - l = 0 - nf = 0 - if i.has_key('length'): - l = i.get('length',0) - nf = 1 - elif i.has_key('files'): - for li in i['files']: - nf += 1 - if li.has_key('length'): - l += li['length'] - a['numfiles'] = nf - a['length'] = l - a['name'] = i.get('name', f) - def setkey(k, d = d, a = a): - if d.has_key(k): - a[k] = d[k] - setkey('failure reason') - setkey('warning message') - setkey('announce-list') - if return_metainfo: - a['metainfo'] = d - except: - errfunc('**warning** '+p+' has errors') - new_blocked[p] = 1 - continue - try: - ff.close() - except: - pass - if NOISY: - errfunc('... successful') - new_parsed[h] = a - added[h] = a - - for p,v in files.items(): # and finally, mark removed torrents - if not new_files.has_key(p) and not blocked.has_key(p): - if NOISY: - errfunc('removing '+p) - removed[v[1]] = parsed[v[1]] - - if NOISY: - errfunc('done checking') - return (new_parsed, new_files, new_blocked, added, removed) - diff --git a/www/pages/torrent/client/piecebuffer.py b/www/pages/torrent/client/piecebuffer.py deleted file mode 100644 index 96cc918..0000000 --- a/www/pages/torrent/client/piecebuffer.py +++ /dev/null @@ -1,86 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -from array import array -from threading import Lock -# import inspect -try: - True -except: - True = 1 - False = 0 - -DEBUG = False - -class SingleBuffer: - def __init__(self, pool): - self.pool = pool - self.buf = array('c') - - def init(self): - if DEBUG: - print self.count - ''' - for x in xrange(6,1,-1): - try: - f = inspect.currentframe(x).f_code - print (f.co_filename,f.co_firstlineno,f.co_name) - del f - except: - pass - print '' - ''' - self.length = 0 - - def append(self, s): - l = self.length+len(s) - self.buf[self.length:l] = array('c',s) - self.length = l - - def __len__(self): - return self.length - - def __getslice__(self, a, b): - if b > self.length: - b = self.length - if b < 0: - b += self.length - if a == 0 and b == self.length and len(self.buf) == b: - return self.buf # optimization - return self.buf[a:b] - - def getarray(self): - return self.buf[:self.length] - - def release(self): - if DEBUG: - print -self.count - self.pool.release(self) - - -class BufferPool: - def __init__(self): - self.pool = [] - self.lock = Lock() - if DEBUG: - self.count = 0 - - def new(self): - self.lock.acquire() - if self.pool: - x = self.pool.pop() - else: - x = SingleBuffer(self) - if DEBUG: - self.count += 1 - x.count = self.count - x.init() - self.lock.release() - return x - - def release(self, x): - self.pool.append(x) - - -_pool = BufferPool() -PieceBuffer = _pool.new diff --git a/www/pages/torrent/client/selectpoll.py b/www/pages/torrent/client/selectpoll.py deleted file mode 100644 index c9d694d..0000000 --- a/www/pages/torrent/client/selectpoll.py +++ /dev/null @@ -1,109 +0,0 @@ -# Written by Bram Cohen -# see LICENSE.txt for license information - -from select import select, error -from time import sleep -from types import IntType -from bisect import bisect -POLLIN = 1 -POLLOUT = 2 -POLLERR = 8 -POLLHUP = 16 - -class poll: - def __init__(self): - self.rlist = [] - self.wlist = [] - - def register(self, f, t): - if type(f) != IntType: - f = f.fileno() - if (t & POLLIN): - insert(self.rlist, f) - else: - remove(self.rlist, f) - if (t & POLLOUT): - insert(self.wlist, f) - else: - remove(self.wlist, f) - - def unregister(self, f): - if type(f) != IntType: - f = f.fileno() - remove(self.rlist, f) - remove(self.wlist, f) - - def poll(self, timeout = None): - if self.rlist or self.wlist: - try: - r, w, e = select(self.rlist, self.wlist, [], timeout) - except ValueError: - return None - else: - sleep(timeout) - return [] - result = [] - for s in r: - result.append((s, POLLIN)) - for s in w: - result.append((s, POLLOUT)) - return result - -def remove(list, item): - i = bisect(list, item) - if i > 0 and list[i-1] == item: - del list[i-1] - -def insert(list, item): - i = bisect(list, item) - if i == 0 or list[i-1] != item: - list.insert(i, item) - -def test_remove(): - x = [2, 4, 6] - remove(x, 2) - assert x == [4, 6] - x = [2, 4, 6] - remove(x, 4) - assert x == [2, 6] - x = [2, 4, 6] - remove(x, 6) - assert x == [2, 4] - x = [2, 4, 6] - remove(x, 5) - assert x == [2, 4, 6] - x = [2, 4, 6] - remove(x, 1) - assert x == [2, 4, 6] - x = [2, 4, 6] - remove(x, 7) - assert x == [2, 4, 6] - x = [2, 4, 6] - remove(x, 5) - assert x == [2, 4, 6] - x = [] - remove(x, 3) - assert x == [] - -def test_insert(): - x = [2, 4] - insert(x, 1) - assert x == [1, 2, 4] - x = [2, 4] - insert(x, 3) - assert x == [2, 3, 4] - x = [2, 4] - insert(x, 5) - assert x == [2, 4, 5] - x = [2, 4] - insert(x, 2) - assert x == [2, 4] - x = [2, 4] - insert(x, 4) - assert x == [2, 4] - x = [2, 3, 4] - insert(x, 3) - assert x == [2, 3, 4] - x = [] - insert(x, 3) - assert x == [3] diff --git a/www/pages/torrent/client/subnetparse.py b/www/pages/torrent/client/subnetparse.py deleted file mode 100644 index 55b46dc..0000000 --- a/www/pages/torrent/client/subnetparse.py +++ /dev/null @@ -1,218 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -from bisect import bisect, insort - -try: - True -except: - True = 1 - False = 0 - bool = lambda x: not not x - -hexbinmap = { - '0': '0000', - '1': '0001', - '2': '0010', - '3': '0011', - '4': '0100', - '5': '0101', - '6': '0110', - '7': '0111', - '8': '1000', - '9': '1001', - 'a': '1010', - 'b': '1011', - 'c': '1100', - 'd': '1101', - 'e': '1110', - 'f': '1111', - 'x': '0000', -} - -chrbinmap = {} -for n in xrange(256): - b = [] - nn = n - for i in xrange(8): - if nn & 0x80: - b.append('1') - else: - b.append('0') - nn <<= 1 - chrbinmap[n] = ''.join(b) - - -def to_bitfield_ipv4(ip): - ip = ip.split('.') - if len(ip) != 4: - raise ValueError, "bad address" - b = [] - for i in ip: - b.append(chrbinmap[int(i)]) - return ''.join(b) - -def to_bitfield_ipv6(ip): - b = '' - doublecolon = False - - if ip == '': - raise ValueError, "bad address" - if ip == '::': # boundary handling - ip = '' - elif ip[:2] == '::': - ip = ip[1:] - elif ip[0] == ':': - raise ValueError, "bad address" - elif ip[-2:] == '::': - ip = ip[:-1] - elif ip[-1] == ':': - raise ValueError, "bad address" - for n in ip.split(':'): - if n == '': # double-colon - if doublecolon: - raise ValueError, "bad address" - doublecolon = True - b += ':' - continue - if n.find('.') >= 0: # IPv4 - n = to_bitfield_ipv4(n) - b += n + '0'*(32-len(n)) - continue - n = ('x'*(4-len(n))) + n - for i in n: - b += hexbinmap[i] - if doublecolon: - pos = b.find(':') - b = b[:pos]+('0'*(129-len(b)))+b[pos+1:] - if len(b) != 128: # always check size - raise ValueError, "bad address" - return b - -ipv4addrmask = to_bitfield_ipv6('::ffff:0:0')[:96] - -class IP_List: - def __init__(self): - self.ipv4list = [] - self.ipv6list = [] - - def __nonzero__(self): - return bool(self.ipv4list or self.ipv6list) - - - def append(self, ip, depth = 256): - if ip.find(':') < 0: # IPv4 - insort(self.ipv4list,to_bitfield_ipv4(ip)[:depth]) - else: - b = to_bitfield_ipv6(ip) - if b.startswith(ipv4addrmask): - insort(self.ipv4list,b[96:][:depth-96]) - else: - insort(self.ipv6list,b[:depth]) - - - def includes(self, ip): - if not (self.ipv4list or self.ipv6list): - return False - if ip.find(':') < 0: # IPv4 - b = to_bitfield_ipv4(ip) - else: - b = to_bitfield_ipv6(ip) - if b.startswith(ipv4addrmask): - b = b[96:] - if len(b) > 32: - l = self.ipv6list - else: - l = self.ipv4list - for map in l[bisect(l,b)-1:]: - if b.startswith(map): - return True - if map > b: - return False - return False - - - def read_fieldlist(self, file): # reads a list from a file in the format 'ip/len ' - f = open(file, 'r') - while True: - line = f.readline() - if not line: - break - line = line.strip().expandtabs() - if not line or line[0] == '#': - continue - try: - line, garbage = line.split(' ',1) - except: - pass - try: - line, garbage = line.split('#',1) - except: - pass - try: - ip, depth = line.split('/') - except: - ip = line - depth = None - try: - if depth is not None: - depth = int(depth) - self.append(ip,depth) - except: - print '*** WARNING *** could not parse IP range: '+line - f.close() - - - def set_intranet_addresses(self): - self.append('127.0.0.1',8) - self.append('10.0.0.0',8) - self.append('172.16.0.0',12) - self.append('192.168.0.0',16) - self.append('169.254.0.0',16) - self.append('::1') - self.append('fe80::',16) - self.append('fec0::',16) - - def set_ipv4_addresses(self): - self.append('::ffff:0:0',96) - -def ipv6_to_ipv4(ip): - ip = to_bitfield_ipv6(ip) - if not ip.startswith(ipv4addrmask): - raise ValueError, "not convertible to IPv4" - ip = ip[-32:] - x = '' - for i in range(4): - x += str(int(ip[:8],2)) - if i < 3: - x += '.' - ip = ip[8:] - return x - -def to_ipv4(ip): - if is_ipv4(ip): - _valid_ipv4(ip) - return ip - return ipv6_to_ipv4(ip) - -def is_ipv4(ip): - return ip.find(':') < 0 - -def _valid_ipv4(ip): - ip = ip.split('.') - if len(ip) != 4: - raise ValueError - for i in ip: - chr(int(i)) - -def is_valid_ip(ip): - try: - if not ip: - return False - if is_ipv4(ip): - _valid_ipv4(ip) - return True - to_bitfield_ipv6(ip) - return True - except: - return False diff --git a/www/pages/torrent/client/torrentlistparse.py b/www/pages/torrent/client/torrentlistparse.py deleted file mode 100644 index 5ed464b..0000000 --- a/www/pages/torrent/client/torrentlistparse.py +++ /dev/null @@ -1,38 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -from binascii import unhexlify - -try: - True -except: - True = 1 - False = 0 - - -# parses a list of torrent hashes, in the format of one hash per line in hex format - -def parsetorrentlist(filename, parsed): - new_parsed = {} - added = {} - removed = parsed - f = open(filename, 'r') - while True: - l = f.readline() - if not l: - break - l = l.strip() - try: - if len(l) != 40: - raise ValueError, 'bad line' - h = unhexlify(l) - except: - print '*** WARNING *** could not parse line in torrent list: '+l - if parsed.has_key(h): - del removed[h] - else: - added[h] = True - new_parsed[h] = True - f.close() - return (new_parsed, added, removed) - diff --git a/www/pages/torrent/client/zurllib.py b/www/pages/torrent/client/zurllib.py deleted file mode 100644 index 2af4032..0000000 --- a/www/pages/torrent/client/zurllib.py +++ /dev/null @@ -1,100 +0,0 @@ -# Written by John Hoffman -# see LICENSE.txt for license information - -from httplib import HTTPConnection, HTTPSConnection, HTTPException -from urlparse import urlparse -from bencode import bdecode -import socket -from gzip import GzipFile -from StringIO import StringIO -from urllib import quote, unquote -from __init__ import product_name, version_short - -VERSION = product_name+'/'+version_short -MAX_REDIRECTS = 10 - - -class btHTTPcon(HTTPConnection): # attempt to add automatic connection timeout - def connect(self): - HTTPConnection.connect(self) - try: - self.sock.settimeout(30) - except: - pass - -class btHTTPScon(HTTPSConnection): # attempt to add automatic connection timeout - def connect(self): - HTTPSConnection.connect(self) - try: - self.sock.settimeout(30) - except: - pass - -class urlopen: - def __init__(self, url): - self.tries = 0 - self._open(url.strip()) - self.error_return = None - - def _open(self, url): - self.tries += 1 - if self.tries > MAX_REDIRECTS: - raise IOError, ('http error', 500, - "Internal Server Error: Redirect Recursion") - (scheme, netloc, path, pars, query, fragment) = urlparse(url) - if scheme != 'http' and scheme != 'https': - raise IOError, ('url error', 'unknown url type', scheme, url) - url = path - if pars: - url += ';'+pars - if query: - url += '?'+query -# if fragment: - try: - if scheme == 'http': - self.connection = btHTTPcon(netloc) - else: - self.connection = btHTTPScon(netloc) - self.connection.request('GET', url, None, - { 'User-Agent': VERSION, - 'Accept-Encoding': 'gzip' } ) - self.response = self.connection.getresponse() - except HTTPException, e: - raise IOError, ('http error', str(e)) - status = self.response.status - if status in (301,302): - try: - self.connection.close() - except: - pass - self._open(self.response.getheader('Location')) - return - if status != 200: - try: - data = self._read() - d = bdecode(data) - if d.has_key('failure reason'): - self.error_return = data - return - except: - pass - raise IOError, ('http error', status, self.response.reason) - - def read(self): - if self.error_return: - return self.error_return - return self._read() - - def _read(self): - data = self.response.read() - if self.response.getheader('Content-Encoding','').find('gzip') >= 0: - try: - compressed = StringIO(data) - f = GzipFile(fileobj = compressed) - data = f.read() - except: - raise IOError, ('http error', 'got corrupt response') - return data - - def close(self): - self.connection.close() diff --git a/www/pages/translate/__init__.py b/www/pages/translate/__init__.py deleted file mode 100644 index 5c126b7..0000000 --- a/www/pages/translate/__init__.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/python - -import os - -import web -import web.elements -from web.javascript import Javascript - -BASE="/srv/checkout" - -projects = [] - -class Po(object): - code2lang = { - "da" : "Dansk (Dansk)", - "de" : "Deutsch (German)", - "fr" : "Français (French)", - } - - def __init__(self, path): - self.path = path - - p = os.popen("msgfmt -v --statistics %s 2>&1" % self.path) - self.line = p.readlines()[0] - - def __cmp__(self, other): - return cmp(self.lang, other.lang) - - @property - def code(self): - return os.path.basename(self.path)[:-3] - - @property - def lang(self): - return self.code2lang.get(self.code, "Unknown (%s)" % self.code) - - @property - def translated(self): - return int(self.line.split()[0]) - - @property - def untranslated(self): - l = self.line.split() - if len(l) == 6: - return int(l[3]) - elif len(l) == 9: - return int(l[6]) - return 0 - - @property - def fuzzy(self): - l = self.line.split() - if len(l) == 9: - return l[3] - return 0 - - -class Project(object): - def __init__(self, id, path, **kwargs): - self.id = id - self.path = path - self._name = kwargs.pop("name") - self.desc = kwargs.pop("desc") - - self._translations = [] - self.pot = None - self.find_pot() - - @property - def name(self): - if self._name: - return self._name - return self.id - - @property - def translations(self): - if not self._translations: - for path in os.listdir(self.path): - if path.endswith(".po"): - self._translations.append(Po(os.path.join(self.path, path))) - return self._translations - - def find_pot(self): - for path in os.listdir(self.path): - if path.endswith(".pot"): - self.pot = Po(os.path.join(self.path, path)) - break - - -projects.append(Project("pomona", BASE + "/ipfire-3.x/src/pomona/po", name="Pomona", desc="The pomona installer for ipfire.")) - -class Content(web.Content): - def __init__(self): - web.Content.__init__(self) - self.projects = projects - - def __call__(self, lang): - ret = """

    IPFire Translation Status

    -
      """ - - for project in self.projects: - ret += """
    • %s
    • """ % (project.id, project.name) - - ret += "
    " - - for project in self.projects: - ret += """
    -

    Description: %s

    -
    - - - - - - - - """ % (project.id, project.desc) - - total = 0 - if project.pot: - total = project.pot.untranslated - - for t in sorted(project.translations): - if total: - percent = "%3.1f%%" % (t.translated * 100 / total) - else: - percent = "---.-%" - - ret += """\ - - - - - - - """ % \ - (t.code, t.code, t.lang, t.translated, t.untranslated, t.fuzzy, percent) - - ret += "
    LanguageTranslatedUntranslatedFuzzyStatus
    %s%s%s%s%s%s
    " - - if project.pot: - ret += """\ -

    -
    - Template - %s strings -

    """ % project.pot.untranslated - - ret += "
    " - - ret += "
    " - return ret - -page = web.Page() -page.content = Content() -page.sidebar = web.elements.DevelopmentSidebar() -page.javascript = Javascript(1, 1) -page.javascript.write(""" - -""") diff --git a/www/releases.json b/www/releases.json new file mode 100644 index 0000000..f30f581 --- /dev/null +++ b/www/releases.json @@ -0,0 +1,87 @@ +[ + { "name" : "IPFire 2.5 - Core 34", + "status" : "stable", + "online" : 1, + "files" : [ + { + "type" : "alix", + "name" : "ipfire-2.5.1gb-ext2-scon.i586-full-core34.img.gz", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "iso", + "name" : "ipfire-2.5.i586-full-core34.iso", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "torrent", + "name" : "ipfire-2.5.i586-full-core34.iso.torrent", + "hash" : "50DC8E935D63ACAC02E5A3C21477EE59D7F1A06D" + }, + { + "type" : "usbfdd", + "name" : "ipfire-2.5-install-usb-fdd.i586-full-core34.img.gz", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "usbhdd", + "name" : "ipfire-2.5-install-usb-hdd.i586-full-core34.img.gz", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "xen", + "name" : "ipfire-2.5.xen.i586-full-core34.tar.bz2", + "sha1" : "0000000000000000000000000000000000000000" + } + ] + }, + +{ "name" : "IPFire 2.5 - Core 33", + "status" : "stable", + "online" : 1, + "files" : [ + { + "type" : "alix", + "name" : "ipfire-2.5.1gb-ext2-scon.i586-full-core33.img.gz", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "iso", + "name" : "ipfire-2.5.i586-full-core33.iso", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "torrent", + "name" : "ipfire-2.5.i586-full-core33.iso.torrent", + "hash" : "D9992ED673EC9D92774452962F4445993ECA730E" + }, + { + "type" : "usbfdd", + "name" : "ipfire-2.5-install-usb-fdd.i586-full-core33.img.gz", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "usbhdd", + "name" : "ipfire-2.5-install-usb-hdd.i586-full-core33.img.gz", + "sha1" : "0000000000000000000000000000000000000000" + }, + { + "type" : "xen", + "name" : "ipfire-2.5.xen.i586-full-core33.tar.bz2", + "sha1" : "0000000000000000000000000000000000000000" + } + ] + }, + + { "name" : "IPFire 3.0 alpha 1", + "status" : "development", + "online" : 1, + "files" : [ + { + "type" : "iso", + "name" : "ipfire-3.0-alpha1.i686.iso", + "sha1" : "0000000000000000000000000000000000000000" + } + ] + } +] diff --git a/www/include/ie6.css b/www/static/css/ie6.css similarity index 100% rename from www/include/ie6.css rename to www/static/css/ie6.css diff --git a/www/static/css/jquery.megamenu.css b/www/static/css/jquery.megamenu.css new file mode 100644 index 0000000..18ee290 --- /dev/null +++ b/www/static/css/jquery.megamenu.css @@ -0,0 +1,144 @@ +/*jQuery MegaMenu Plugin + Author: Devadatta Sahoo + Author URI: http://www.geektantra.com */ +/*body { + font-family: arial; + font-size: 12px; + height: 100%; + margin: 0px; +} +#Container { + height: 100%; + width: 960px; + margin: auto; + border-collapse: collapse; +} +a { + color: #254154; +} +ul { + text-align: left; + margin: 25px; + font-size: 16px; + list-style-type: square; +} */ +.MegaMenu { + background: #254156; + padding: 5px 7px 0px; + margin-bottom: -1px; +} +.MegaMenu a.MegaMenuLink:link, .MegaMenu a.MegaMenuLink:visited { + display: inline-block; + padding: 5px 20px 9px; + margin: 1px 2px 0px 1px; + color: #FFF; + text-decoration: none; + font-size: 15px; + outline: none; + z-index: 1000; +} +.MegaMenu a.MegaMenuLinkOff:link, .MegaMenu a.MegaMenuLinkOff:visited { + display: inline-block; + padding: 5px 20px 5px; + margin: 1px 2px 4px 1px; + color: #FFF; + text-decoration: none; + font-size: 15px; + outline: none; + z-index: 1000; +} +.MegaMenu a.MegaMenuLinkOff:hover { + background: #FFF; + color: #555; +/* margin: 0px;*/ + padding: 4px 18px 4px 17px; + border: 1px solid #9A9A9A; + padding-right: 21px; +} +.MegaMenu a.MegaMenuLinkActive:link, .MegaMenu a.MegaMenuLinkActive:visited { + background: #FFF; + color: #555; + margin: 0px; + border: 1px solid #9A9A9A; + padding-right: 21px; + border-bottom: none; +} +.MegaMenu .MegaMenuContent{ + display: none; +} +#MegaMenuContent, #MegaMenuContentShadow { + background: #FFF; + border: 1px solid #9A9A9A; + border-top: none; + padding: 10px 10px; + margin-left: 5px; + position: absolute; + z-index: 10; +} +#MegaMenuContentShadow { + background: #111; + margin-left: 8px; + margin-top: 4px; + z-index: 9; + opacity: 0.5; + -moz-opacity: 0.5; + filter:alpha(opacity=50); +} +.MegaMenuTable { + border-collapse: collapse; + border: 1px solid #FFF; +} +.MegaMenuTable th { + text-align: left; + padding: 5px 10px; + font-size: 13px; +} +.MegaMenuTable .MegaMenuHead { + padding: 0px 5px 5px; + border-bottom: 5px solid #EEE; +} +.MegaMenuTable td { + vertical-align: top; + border-right: 3px dotted #CCC; +} +.MegaMenuTable td.LastCell { + border: none; +} +.MenuFoot div { + border-top: 1px solid #CCC; + margin: 10px 10px 5px 10px; + font-size: 10px; + color: #555; + padding: 10px 0px 0px 0px; +} +.MenuFoot h2 { + padding: 0px 0px 3px 0px; + margin: 0px; + font-size: 14px; + color: #000; +} +.MegaMenuTable { + cursor: default; +} +.MegaMenuTable a { + cursor: pointer; +} +.MegaMenuTable .MegaMenuLists { + margin: 0px 15px; + padding: 0px; + color: #BBB; + list-style-type: square; + list-style-position: inside; +} +.MegaMenuLists li { + margin: 5px 0px 8px; + font-weight: bold; + font-size: 12px; +} +/*Non IE CSS Starts*/ +html>body .MegaMenu a.MegaMenuLink:link,html>body .MegaMenu a.MegaMenuLink:visited { + position: relative; +} +html>body #MegaMenuContent, html>body #MegaMenuContentShadow { +} + diff --git a/www/include/style.css b/www/static/css/style.css similarity index 87% rename from www/include/style.css rename to www/static/css/style.css index 508f990..0542dbe 100644 --- a/www/include/style.css +++ b/www/static/css/style.css @@ -33,7 +33,7 @@ body { font-family: "Verdana", "Deja-Vu Sans", "Bitstream Vera Sans", sans-serif; font-size: 0.9em; - background: #880400; /* url(/images/bg.png) repeat;*/ + background: #880400; /* url(../images/bg.png) repeat;*/ color: #585858; } @@ -131,13 +131,17 @@ p line-height: 1.5em; } +p.right { + float: right; +} + /* Header */ #header { width:100%; height:102px; -background: url('/images/bg-menu99.png') repeat-x; +background: url('../images/bg-menu99.png') repeat-x; } #header_inner @@ -236,7 +240,7 @@ float: left; #menu li { vertical-align: middle; -background: #333 url('/images/btn-break.png') center; +background: #333 url('../images/btn-break.png') center; } #menu li a { @@ -245,7 +249,7 @@ margin-right: 1px; display: block; padding: 10px 5px 0 8px; height: 26px; -background: #333 url('/images/btn-empty.png') repeat-x center; +background: #333 url('../images/btn-empty.png') repeat-x center; color: #ddd; font-weight: bolder; vertical-align: middle; @@ -255,13 +259,13 @@ text-decoration: none; #menu li a.active { -background: #CA2F2F url('/images/btn-red2.png') repeat-x center; +background: #CA2F2F url('../images/btn-red2.png') repeat-x center; color: #ddd; } #menu li a:hover { -background: #333 url('/images/btn-red2.png') repeat-x center; +background: #333 url('../images/btn-red2.png') repeat-x center; color: #fff; } @@ -269,7 +273,7 @@ color: #fff; #main { -/* background: #fff url('images/n2.gif') 0px 1px repeat-x; */ +/* background: #fff url('../images/n2.gif') 0px 1px repeat-x; */ } #main_inner p @@ -366,12 +370,12 @@ padding-left: 15px; #main_inner .post ul.post_info li.date { -background-image: url('images/n5.gif'); +background-image: url('../images/n5.gif'); } #main_inner .post ul.post_info li.comments { -background-image: url('images/n6.gif'); +background-image: url('../images/n6.gif'); margin-left: 1.1em; } @@ -390,28 +394,28 @@ table { font-size: 0.9em; } #sh-tl { - background: url(/images/sh-tl.png) no-repeat right bottom; + background: url("../images/sh-tl.png") no-repeat right bottom; } #sh-top { - background: url(/images/sh-top.png) repeat-x bottom; + background: url("../images/sh-top.png") repeat-x bottom; } #sh-tr { - background: url(/images/sh-tr.png) no-repeat left bottom; + background: url("../images/sh-tr.png") no-repeat left bottom; } #sh-lft { - background: url(/images/sh-lft.png) repeat-y right; + background: url("../images/sh-lft.png") repeat-y right; } #sh-rgt { - background: url(/images/sh-rgt.png) repeat-y left; + background: url("../images/sh-rgt.png") repeat-y left; } #sh-bl { - background: url(/images/sh-bl.png) no-repeat right top; + background: url("../images/sh-bl.png") no-repeat right top; } #sh-btn { - background: url(/images/sh-btn.png) repeat-x top; + background: url("../images/sh-btn.png") repeat-x top; } #sh-br { - background: url(/images/sh-br.png) no-repeat left top; + background: url("../images/sh-br.png") no-repeat left top; } #no-sh { background-color: #f5f5f5; @@ -481,7 +485,7 @@ clear: both; height: 26px; color: #ddd; text-align: center; -background: url(/images/ft.png) left top; +background: url("../images/ft.png") left top; margin-top: 0em; margin-bottom: 0em; padding-top: 0.5em; @@ -493,7 +497,7 @@ text-transform: lowercase; input.button { -background: #CA2F2F url('images/n3.gif') repeat-x; +background: #CA2F2F url("../images/n3.gif") repeat-x; color: #fff; border: solid 1px #A94B4B; font-weight: bold; @@ -569,7 +573,7 @@ left: 60px; /*position where enlarged image should offset horizontally */ .feed { margin-left: 3px; padding: 0 0 0 19px; - background: url("/images/feed.png") no-repeat 0 50%; + background: url("../images/feed.png") no-repeat 0 50%; } /* LAYOUT - 3 COLUMNS */ @@ -764,7 +768,7 @@ table.translate td.lang { /* Component containers */ .ui-widget-content { border: 1px solid #999/*{borderColorContent}*/; - background: #F5F5F5/*{bgColorContent}*/ 50%/*{bgContentXPos}*/ url(/images/ui-bg_flat_75_f5f5f5_40x100.png)/*{bgImgUrlDefault}*/50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; + background: #F5F5F5/*{bgColorContent}*/ 50%/*{bgContentXPos}*/ url(../images/ui-bg_flat_75_f5f5f5_40x100.png)/*{bgImgUrlDefault}*/50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } .ui-widget-content a { @@ -772,7 +776,7 @@ table.translate td.lang { } .ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; - background: #cccccc/*{bgColorHeader}*/ url(/images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; + background: #cccccc/*{bgColorHeader}*/ url(/../images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } @@ -782,7 +786,7 @@ table.translate td.lang { /* Interaction states */ .ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; - background: #e6e6e6/*{bgColorDefault}*/ url(/images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; + background: #e6e6e6/*{bgColorDefault}*/ url(../images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; outline: none; @@ -794,7 +798,7 @@ table.translate td.lang { } .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; - background: #dadada/*{bgColorHover}*/ url(/images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; + background: #dadada/*{bgColorHover}*/ url(../images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; outline: none; @@ -963,7 +967,7 @@ table.translate td.lang { /* IPFire Download Button */ .button { - background: url(/images/buttons/download_core_96x320.png); + background: url(../images/buttons/download_core_96x320.png); background-repeat: no-repeat; background-position: right; width: 700px; @@ -985,7 +989,7 @@ table.translate td.lang { /* CeBIT Button */ .cebit_button { - background: url(/images/buttons/cebit_96x320.png); + background: url(../images/buttons/cebit_96x320.png); background-repeat: no-repeat; background-position: right; width: 700px; diff --git a/www/favicon.ico b/www/static/favicon.ico similarity index 100% rename from www/favicon.ico rename to www/static/favicon.ico diff --git a/www/images/Network-1.png b/www/static/images/Network-1.png similarity index 100% rename from www/images/Network-1.png rename to www/static/images/Network-1.png diff --git a/www/images/Stats1.png b/www/static/images/Stats1.png similarity index 100% rename from www/images/Stats1.png rename to www/static/images/Stats1.png diff --git a/www/images/Stats2.png b/www/static/images/Stats2.png similarity index 100% rename from www/images/Stats2.png rename to www/static/images/Stats2.png diff --git a/www/images/art/Banner.png b/www/static/images/art/Banner.png similarity index 100% rename from www/images/art/Banner.png rename to www/static/images/art/Banner.png diff --git a/www/images/art/Banner_thumb.png b/www/static/images/art/Banner_thumb.png similarity index 100% rename from www/images/art/Banner_thumb.png rename to www/static/images/art/Banner_thumb.png diff --git a/www/images/art/CD1.png b/www/static/images/art/CD1.png similarity index 100% rename from www/images/art/CD1.png rename to www/static/images/art/CD1.png diff --git a/www/images/art/CD1_thumb.png b/www/static/images/art/CD1_thumb.png similarity index 100% rename from www/images/art/CD1_thumb.png rename to www/static/images/art/CD1_thumb.png diff --git a/www/images/art/CD2.png b/www/static/images/art/CD2.png similarity index 100% rename from www/images/art/CD2.png rename to www/static/images/art/CD2.png diff --git a/www/images/art/CD2_thumb.png b/www/static/images/art/CD2_thumb.png similarity index 100% rename from www/images/art/CD2_thumb.png rename to www/static/images/art/CD2_thumb.png diff --git a/www/images/art/Firetest1.png b/www/static/images/art/Firetest1.png similarity index 100% rename from www/images/art/Firetest1.png rename to www/static/images/art/Firetest1.png diff --git a/www/images/art/Tux.png b/www/static/images/art/Tux.png similarity index 100% rename from www/images/art/Tux.png rename to www/static/images/art/Tux.png diff --git a/www/images/art/Tux_thumb.png b/www/static/images/art/Tux_thumb.png similarity index 100% rename from www/images/art/Tux_thumb.png rename to www/static/images/art/Tux_thumb.png diff --git a/www/images/art/logo2.png b/www/static/images/art/logo2.png similarity index 100% rename from www/images/art/logo2.png rename to www/static/images/art/logo2.png diff --git a/www/images/bg-menu99.png b/www/static/images/bg-menu99.png similarity index 100% rename from www/images/bg-menu99.png rename to www/static/images/bg-menu99.png diff --git a/www/images/bg-shl.png b/www/static/images/bg-shl.png similarity index 100% rename from www/images/bg-shl.png rename to www/static/images/bg-shl.png diff --git a/www/images/bg-shr.png b/www/static/images/bg-shr.png similarity index 100% rename from www/images/bg-shr.png rename to www/static/images/bg-shr.png diff --git a/www/images/bg.png b/www/static/images/bg.png similarity index 100% rename from www/images/bg.png rename to www/static/images/bg.png diff --git a/www/images/bg1.png b/www/static/images/bg1.png similarity index 100% rename from www/images/bg1.png rename to www/static/images/bg1.png diff --git a/www/images/box_ipfire.png b/www/static/images/box_ipfire.png similarity index 100% rename from www/images/box_ipfire.png rename to www/static/images/box_ipfire.png diff --git a/www/images/btn-blue.png b/www/static/images/btn-blue.png similarity index 100% rename from www/images/btn-blue.png rename to www/static/images/btn-blue.png diff --git a/www/images/btn-break.png b/www/static/images/btn-break.png similarity index 100% rename from www/images/btn-break.png rename to www/static/images/btn-break.png diff --git a/www/images/btn-empty.png b/www/static/images/btn-empty.png similarity index 100% rename from www/images/btn-empty.png rename to www/static/images/btn-empty.png diff --git a/www/images/btn-green.png b/www/static/images/btn-green.png similarity index 100% rename from www/images/btn-green.png rename to www/static/images/btn-green.png diff --git a/www/images/btn-orange.png b/www/static/images/btn-orange.png similarity index 100% rename from www/images/btn-orange.png rename to www/static/images/btn-orange.png diff --git a/www/images/btn-red.png b/www/static/images/btn-red.png similarity index 100% rename from www/images/btn-red.png rename to www/static/images/btn-red.png diff --git a/www/images/btn-red2.png b/www/static/images/btn-red2.png similarity index 100% rename from www/images/btn-red2.png rename to www/static/images/btn-red2.png diff --git a/www/images/btn-white.png b/www/static/images/btn-white.png similarity index 100% rename from www/images/btn-white.png rename to www/static/images/btn-white.png diff --git a/www/images/btn-yellow.png b/www/static/images/btn-yellow.png similarity index 100% rename from www/images/btn-yellow.png rename to www/static/images/btn-yellow.png diff --git a/www/images/buttons/cebit_96x320.png b/www/static/images/buttons/cebit_96x320.png similarity index 100% rename from www/images/buttons/cebit_96x320.png rename to www/static/images/buttons/cebit_96x320.png diff --git a/www/images/buttons/download_core_96x320.png b/www/static/images/buttons/download_core_96x320.png similarity index 100% rename from www/images/buttons/download_core_96x320.png rename to www/static/images/buttons/download_core_96x320.png diff --git a/www/images/cebit-171px.png b/www/static/images/cebit-171px.png similarity index 100% rename from www/images/cebit-171px.png rename to www/static/images/cebit-171px.png diff --git a/www/images/cebit-177px_schatten.png b/www/static/images/cebit-177px_schatten.png similarity index 100% rename from www/images/cebit-177px_schatten.png rename to www/static/images/cebit-177px_schatten.png diff --git a/www/images/cebit2010_logo_en.png b/www/static/images/cebit2010_logo_en.png similarity index 100% rename from www/images/cebit2010_logo_en.png rename to www/static/images/cebit2010_logo_en.png diff --git a/www/images/de.gif b/www/static/images/de.gif similarity index 100% rename from www/images/de.gif rename to www/static/images/de.gif diff --git a/www/images/development.png b/www/static/images/development.png similarity index 100% rename from www/images/development.png rename to www/static/images/development.png diff --git a/www/images/download.png b/www/static/images/download.png similarity index 100% rename from www/images/download.png rename to www/static/images/download.png diff --git a/www/images/en.gif b/www/static/images/en.gif similarity index 100% rename from www/images/en.gif rename to www/static/images/en.gif diff --git a/www/images/error/403.png b/www/static/images/error/403.png similarity index 100% rename from www/images/error/403.png rename to www/static/images/error/403.png diff --git a/www/images/error/404.png b/www/static/images/error/404.png similarity index 100% rename from www/images/error/404.png rename to www/static/images/error/404.png diff --git a/www/images/error/500.png b/www/static/images/error/500.png similarity index 100% rename from www/images/error/500.png rename to www/static/images/error/500.png diff --git a/www/images/features.png b/www/static/images/features.png similarity index 100% rename from www/images/features.png rename to www/static/images/features.png diff --git a/www/images/feed.png b/www/static/images/feed.png similarity index 100% rename from www/images/feed.png rename to www/static/images/feed.png diff --git a/www/images/flags/ad.png b/www/static/images/flags/ad.png similarity index 100% rename from www/images/flags/ad.png rename to www/static/images/flags/ad.png diff --git a/www/images/flags/ae.png b/www/static/images/flags/ae.png similarity index 100% rename from www/images/flags/ae.png rename to www/static/images/flags/ae.png diff --git a/www/images/flags/af.png b/www/static/images/flags/af.png similarity index 100% rename from www/images/flags/af.png rename to www/static/images/flags/af.png diff --git a/www/images/flags/ag.png b/www/static/images/flags/ag.png similarity index 100% rename from www/images/flags/ag.png rename to www/static/images/flags/ag.png diff --git a/www/images/flags/ai.png b/www/static/images/flags/ai.png similarity index 100% rename from www/images/flags/ai.png rename to www/static/images/flags/ai.png diff --git a/www/images/flags/al.png b/www/static/images/flags/al.png similarity index 100% rename from www/images/flags/al.png rename to www/static/images/flags/al.png diff --git a/www/images/flags/am.png b/www/static/images/flags/am.png similarity index 100% rename from www/images/flags/am.png rename to www/static/images/flags/am.png diff --git a/www/images/flags/an.png b/www/static/images/flags/an.png similarity index 100% rename from www/images/flags/an.png rename to www/static/images/flags/an.png diff --git a/www/images/flags/ao.png b/www/static/images/flags/ao.png similarity index 100% rename from www/images/flags/ao.png rename to www/static/images/flags/ao.png diff --git a/www/images/flags/ar.png b/www/static/images/flags/ar.png similarity index 100% rename from www/images/flags/ar.png rename to www/static/images/flags/ar.png diff --git a/www/images/flags/as.png b/www/static/images/flags/as.png similarity index 100% rename from www/images/flags/as.png rename to www/static/images/flags/as.png diff --git a/www/images/flags/at.png b/www/static/images/flags/at.png similarity index 100% rename from www/images/flags/at.png rename to www/static/images/flags/at.png diff --git a/www/images/flags/au.png b/www/static/images/flags/au.png similarity index 100% rename from www/images/flags/au.png rename to www/static/images/flags/au.png diff --git a/www/images/flags/aw.png b/www/static/images/flags/aw.png similarity index 100% rename from www/images/flags/aw.png rename to www/static/images/flags/aw.png diff --git a/www/images/flags/ax.png b/www/static/images/flags/ax.png similarity index 100% rename from www/images/flags/ax.png rename to www/static/images/flags/ax.png diff --git a/www/images/flags/az.png b/www/static/images/flags/az.png similarity index 100% rename from www/images/flags/az.png rename to www/static/images/flags/az.png diff --git a/www/images/flags/ba.png b/www/static/images/flags/ba.png similarity index 100% rename from www/images/flags/ba.png rename to www/static/images/flags/ba.png diff --git a/www/images/flags/bb.png b/www/static/images/flags/bb.png similarity index 100% rename from www/images/flags/bb.png rename to www/static/images/flags/bb.png diff --git a/www/images/flags/bd.png b/www/static/images/flags/bd.png similarity index 100% rename from www/images/flags/bd.png rename to www/static/images/flags/bd.png diff --git a/www/images/flags/be.png b/www/static/images/flags/be.png similarity index 100% rename from www/images/flags/be.png rename to www/static/images/flags/be.png diff --git a/www/images/flags/bf.png b/www/static/images/flags/bf.png similarity index 100% rename from www/images/flags/bf.png rename to www/static/images/flags/bf.png diff --git a/www/images/flags/bg.png b/www/static/images/flags/bg.png similarity index 100% rename from www/images/flags/bg.png rename to www/static/images/flags/bg.png diff --git a/www/images/flags/bh.png b/www/static/images/flags/bh.png similarity index 100% rename from www/images/flags/bh.png rename to www/static/images/flags/bh.png diff --git a/www/images/flags/bi.png b/www/static/images/flags/bi.png similarity index 100% rename from www/images/flags/bi.png rename to www/static/images/flags/bi.png diff --git a/www/images/flags/bj.png b/www/static/images/flags/bj.png similarity index 100% rename from www/images/flags/bj.png rename to www/static/images/flags/bj.png diff --git a/www/images/flags/bm.png b/www/static/images/flags/bm.png similarity index 100% rename from www/images/flags/bm.png rename to www/static/images/flags/bm.png diff --git a/www/images/flags/bn.png b/www/static/images/flags/bn.png similarity index 100% rename from www/images/flags/bn.png rename to www/static/images/flags/bn.png diff --git a/www/images/flags/bo.png b/www/static/images/flags/bo.png similarity index 100% rename from www/images/flags/bo.png rename to www/static/images/flags/bo.png diff --git a/www/images/flags/br.png b/www/static/images/flags/br.png similarity index 100% rename from www/images/flags/br.png rename to www/static/images/flags/br.png diff --git a/www/images/flags/bs.png b/www/static/images/flags/bs.png similarity index 100% rename from www/images/flags/bs.png rename to www/static/images/flags/bs.png diff --git a/www/images/flags/bt.png b/www/static/images/flags/bt.png similarity index 100% rename from www/images/flags/bt.png rename to www/static/images/flags/bt.png diff --git a/www/images/flags/bv.png b/www/static/images/flags/bv.png similarity index 100% rename from www/images/flags/bv.png rename to www/static/images/flags/bv.png diff --git a/www/images/flags/bw.png b/www/static/images/flags/bw.png similarity index 100% rename from www/images/flags/bw.png rename to www/static/images/flags/bw.png diff --git a/www/images/flags/by.png b/www/static/images/flags/by.png similarity index 100% rename from www/images/flags/by.png rename to www/static/images/flags/by.png diff --git a/www/images/flags/bz.png b/www/static/images/flags/bz.png similarity index 100% rename from www/images/flags/bz.png rename to www/static/images/flags/bz.png diff --git a/www/images/flags/ca.png b/www/static/images/flags/ca.png similarity index 100% rename from www/images/flags/ca.png rename to www/static/images/flags/ca.png diff --git a/www/images/flags/catalonia.png b/www/static/images/flags/catalonia.png similarity index 100% rename from www/images/flags/catalonia.png rename to www/static/images/flags/catalonia.png diff --git a/www/images/flags/cc.png b/www/static/images/flags/cc.png similarity index 100% rename from www/images/flags/cc.png rename to www/static/images/flags/cc.png diff --git a/www/images/flags/cd.png b/www/static/images/flags/cd.png similarity index 100% rename from www/images/flags/cd.png rename to www/static/images/flags/cd.png diff --git a/www/images/flags/cf.png b/www/static/images/flags/cf.png similarity index 100% rename from www/images/flags/cf.png rename to www/static/images/flags/cf.png diff --git a/www/images/flags/cg.png b/www/static/images/flags/cg.png similarity index 100% rename from www/images/flags/cg.png rename to www/static/images/flags/cg.png diff --git a/www/images/flags/ch.png b/www/static/images/flags/ch.png similarity index 100% rename from www/images/flags/ch.png rename to www/static/images/flags/ch.png diff --git a/www/images/flags/ci.png b/www/static/images/flags/ci.png similarity index 100% rename from www/images/flags/ci.png rename to www/static/images/flags/ci.png diff --git a/www/images/flags/ck.png b/www/static/images/flags/ck.png similarity index 100% rename from www/images/flags/ck.png rename to www/static/images/flags/ck.png diff --git a/www/images/flags/cl.png b/www/static/images/flags/cl.png similarity index 100% rename from www/images/flags/cl.png rename to www/static/images/flags/cl.png diff --git a/www/images/flags/cm.png b/www/static/images/flags/cm.png similarity index 100% rename from www/images/flags/cm.png rename to www/static/images/flags/cm.png diff --git a/www/images/flags/cn.png b/www/static/images/flags/cn.png similarity index 100% rename from www/images/flags/cn.png rename to www/static/images/flags/cn.png diff --git a/www/images/flags/co.png b/www/static/images/flags/co.png similarity index 100% rename from www/images/flags/co.png rename to www/static/images/flags/co.png diff --git a/www/images/flags/cr.png b/www/static/images/flags/cr.png similarity index 100% rename from www/images/flags/cr.png rename to www/static/images/flags/cr.png diff --git a/www/images/flags/cs.png b/www/static/images/flags/cs.png similarity index 100% rename from www/images/flags/cs.png rename to www/static/images/flags/cs.png diff --git a/www/images/flags/cu.png b/www/static/images/flags/cu.png similarity index 100% rename from www/images/flags/cu.png rename to www/static/images/flags/cu.png diff --git a/www/images/flags/cv.png b/www/static/images/flags/cv.png similarity index 100% rename from www/images/flags/cv.png rename to www/static/images/flags/cv.png diff --git a/www/images/flags/cx.png b/www/static/images/flags/cx.png similarity index 100% rename from www/images/flags/cx.png rename to www/static/images/flags/cx.png diff --git a/www/images/flags/cy.png b/www/static/images/flags/cy.png similarity index 100% rename from www/images/flags/cy.png rename to www/static/images/flags/cy.png diff --git a/www/images/flags/cz.png b/www/static/images/flags/cz.png similarity index 100% rename from www/images/flags/cz.png rename to www/static/images/flags/cz.png diff --git a/www/images/flags/da.png b/www/static/images/flags/da.png similarity index 100% rename from www/images/flags/da.png rename to www/static/images/flags/da.png diff --git a/www/images/flags/de.png b/www/static/images/flags/de.png similarity index 100% rename from www/images/flags/de.png rename to www/static/images/flags/de.png diff --git a/www/images/flags/dj.png b/www/static/images/flags/dj.png similarity index 100% rename from www/images/flags/dj.png rename to www/static/images/flags/dj.png diff --git a/www/images/flags/dk.png b/www/static/images/flags/dk.png similarity index 100% rename from www/images/flags/dk.png rename to www/static/images/flags/dk.png diff --git a/www/images/flags/dm.png b/www/static/images/flags/dm.png similarity index 100% rename from www/images/flags/dm.png rename to www/static/images/flags/dm.png diff --git a/www/images/flags/do.png b/www/static/images/flags/do.png similarity index 100% rename from www/images/flags/do.png rename to www/static/images/flags/do.png diff --git a/www/images/flags/dz.png b/www/static/images/flags/dz.png similarity index 100% rename from www/images/flags/dz.png rename to www/static/images/flags/dz.png diff --git a/www/images/flags/ec.png b/www/static/images/flags/ec.png similarity index 100% rename from www/images/flags/ec.png rename to www/static/images/flags/ec.png diff --git a/www/images/flags/ee.png b/www/static/images/flags/ee.png similarity index 100% rename from www/images/flags/ee.png rename to www/static/images/flags/ee.png diff --git a/www/images/flags/eg.png b/www/static/images/flags/eg.png similarity index 100% rename from www/images/flags/eg.png rename to www/static/images/flags/eg.png diff --git a/www/images/flags/eh.png b/www/static/images/flags/eh.png similarity index 100% rename from www/images/flags/eh.png rename to www/static/images/flags/eh.png diff --git a/www/images/flags/england.png b/www/static/images/flags/england.png similarity index 100% rename from www/images/flags/england.png rename to www/static/images/flags/england.png diff --git a/www/images/flags/er.png b/www/static/images/flags/er.png similarity index 100% rename from www/images/flags/er.png rename to www/static/images/flags/er.png diff --git a/www/images/flags/es.png b/www/static/images/flags/es.png similarity index 100% rename from www/images/flags/es.png rename to www/static/images/flags/es.png diff --git a/www/images/flags/et.png b/www/static/images/flags/et.png similarity index 100% rename from www/images/flags/et.png rename to www/static/images/flags/et.png diff --git a/www/images/flags/europeanunion.png b/www/static/images/flags/europeanunion.png similarity index 100% rename from www/images/flags/europeanunion.png rename to www/static/images/flags/europeanunion.png diff --git a/www/images/flags/fam.png b/www/static/images/flags/fam.png similarity index 100% rename from www/images/flags/fam.png rename to www/static/images/flags/fam.png diff --git a/www/images/flags/fi.png b/www/static/images/flags/fi.png similarity index 100% rename from www/images/flags/fi.png rename to www/static/images/flags/fi.png diff --git a/www/images/flags/fj.png b/www/static/images/flags/fj.png similarity index 100% rename from www/images/flags/fj.png rename to www/static/images/flags/fj.png diff --git a/www/images/flags/fk.png b/www/static/images/flags/fk.png similarity index 100% rename from www/images/flags/fk.png rename to www/static/images/flags/fk.png diff --git a/www/images/flags/fm.png b/www/static/images/flags/fm.png similarity index 100% rename from www/images/flags/fm.png rename to www/static/images/flags/fm.png diff --git a/www/images/flags/fo.png b/www/static/images/flags/fo.png similarity index 100% rename from www/images/flags/fo.png rename to www/static/images/flags/fo.png diff --git a/www/images/flags/fr.png b/www/static/images/flags/fr.png similarity index 100% rename from www/images/flags/fr.png rename to www/static/images/flags/fr.png diff --git a/www/images/flags/ga.png b/www/static/images/flags/ga.png similarity index 100% rename from www/images/flags/ga.png rename to www/static/images/flags/ga.png diff --git a/www/images/flags/gb.png b/www/static/images/flags/gb.png similarity index 100% rename from www/images/flags/gb.png rename to www/static/images/flags/gb.png diff --git a/www/images/flags/gd.png b/www/static/images/flags/gd.png similarity index 100% rename from www/images/flags/gd.png rename to www/static/images/flags/gd.png diff --git a/www/images/flags/ge.png b/www/static/images/flags/ge.png similarity index 100% rename from www/images/flags/ge.png rename to www/static/images/flags/ge.png diff --git a/www/images/flags/gf.png b/www/static/images/flags/gf.png similarity index 100% rename from www/images/flags/gf.png rename to www/static/images/flags/gf.png diff --git a/www/images/flags/gh.png b/www/static/images/flags/gh.png similarity index 100% rename from www/images/flags/gh.png rename to www/static/images/flags/gh.png diff --git a/www/images/flags/gi.png b/www/static/images/flags/gi.png similarity index 100% rename from www/images/flags/gi.png rename to www/static/images/flags/gi.png diff --git a/www/images/flags/gl.png b/www/static/images/flags/gl.png similarity index 100% rename from www/images/flags/gl.png rename to www/static/images/flags/gl.png diff --git a/www/images/flags/gm.png b/www/static/images/flags/gm.png similarity index 100% rename from www/images/flags/gm.png rename to www/static/images/flags/gm.png diff --git a/www/images/flags/gn.png b/www/static/images/flags/gn.png similarity index 100% rename from www/images/flags/gn.png rename to www/static/images/flags/gn.png diff --git a/www/images/flags/gp.png b/www/static/images/flags/gp.png similarity index 100% rename from www/images/flags/gp.png rename to www/static/images/flags/gp.png diff --git a/www/images/flags/gq.png b/www/static/images/flags/gq.png similarity index 100% rename from www/images/flags/gq.png rename to www/static/images/flags/gq.png diff --git a/www/images/flags/gr.png b/www/static/images/flags/gr.png similarity index 100% rename from www/images/flags/gr.png rename to www/static/images/flags/gr.png diff --git a/www/images/flags/gs.png b/www/static/images/flags/gs.png similarity index 100% rename from www/images/flags/gs.png rename to www/static/images/flags/gs.png diff --git a/www/images/flags/gt.png b/www/static/images/flags/gt.png similarity index 100% rename from www/images/flags/gt.png rename to www/static/images/flags/gt.png diff --git a/www/images/flags/gu.png b/www/static/images/flags/gu.png similarity index 100% rename from www/images/flags/gu.png rename to www/static/images/flags/gu.png diff --git a/www/images/flags/gw.png b/www/static/images/flags/gw.png similarity index 100% rename from www/images/flags/gw.png rename to www/static/images/flags/gw.png diff --git a/www/images/flags/gy.png b/www/static/images/flags/gy.png similarity index 100% rename from www/images/flags/gy.png rename to www/static/images/flags/gy.png diff --git a/www/images/flags/hk.png b/www/static/images/flags/hk.png similarity index 100% rename from www/images/flags/hk.png rename to www/static/images/flags/hk.png diff --git a/www/images/flags/hm.png b/www/static/images/flags/hm.png similarity index 100% rename from www/images/flags/hm.png rename to www/static/images/flags/hm.png diff --git a/www/images/flags/hn.png b/www/static/images/flags/hn.png similarity index 100% rename from www/images/flags/hn.png rename to www/static/images/flags/hn.png diff --git a/www/images/flags/hr.png b/www/static/images/flags/hr.png similarity index 100% rename from www/images/flags/hr.png rename to www/static/images/flags/hr.png diff --git a/www/images/flags/ht.png b/www/static/images/flags/ht.png similarity index 100% rename from www/images/flags/ht.png rename to www/static/images/flags/ht.png diff --git a/www/images/flags/hu.png b/www/static/images/flags/hu.png similarity index 100% rename from www/images/flags/hu.png rename to www/static/images/flags/hu.png diff --git a/www/images/flags/id.png b/www/static/images/flags/id.png similarity index 100% rename from www/images/flags/id.png rename to www/static/images/flags/id.png diff --git a/www/images/flags/ie.png b/www/static/images/flags/ie.png similarity index 100% rename from www/images/flags/ie.png rename to www/static/images/flags/ie.png diff --git a/www/images/flags/il.png b/www/static/images/flags/il.png similarity index 100% rename from www/images/flags/il.png rename to www/static/images/flags/il.png diff --git a/www/images/flags/in.png b/www/static/images/flags/in.png similarity index 100% rename from www/images/flags/in.png rename to www/static/images/flags/in.png diff --git a/www/images/flags/io.png b/www/static/images/flags/io.png similarity index 100% rename from www/images/flags/io.png rename to www/static/images/flags/io.png diff --git a/www/images/flags/iq.png b/www/static/images/flags/iq.png similarity index 100% rename from www/images/flags/iq.png rename to www/static/images/flags/iq.png diff --git a/www/images/flags/ir.png b/www/static/images/flags/ir.png similarity index 100% rename from www/images/flags/ir.png rename to www/static/images/flags/ir.png diff --git a/www/images/flags/is.png b/www/static/images/flags/is.png similarity index 100% rename from www/images/flags/is.png rename to www/static/images/flags/is.png diff --git a/www/images/flags/it.png b/www/static/images/flags/it.png similarity index 100% rename from www/images/flags/it.png rename to www/static/images/flags/it.png diff --git a/www/images/flags/jm.png b/www/static/images/flags/jm.png similarity index 100% rename from www/images/flags/jm.png rename to www/static/images/flags/jm.png diff --git a/www/images/flags/jo.png b/www/static/images/flags/jo.png similarity index 100% rename from www/images/flags/jo.png rename to www/static/images/flags/jo.png diff --git a/www/images/flags/jp.png b/www/static/images/flags/jp.png similarity index 100% rename from www/images/flags/jp.png rename to www/static/images/flags/jp.png diff --git a/www/images/flags/ke.png b/www/static/images/flags/ke.png similarity index 100% rename from www/images/flags/ke.png rename to www/static/images/flags/ke.png diff --git a/www/images/flags/kg.png b/www/static/images/flags/kg.png similarity index 100% rename from www/images/flags/kg.png rename to www/static/images/flags/kg.png diff --git a/www/images/flags/kh.png b/www/static/images/flags/kh.png similarity index 100% rename from www/images/flags/kh.png rename to www/static/images/flags/kh.png diff --git a/www/images/flags/ki.png b/www/static/images/flags/ki.png similarity index 100% rename from www/images/flags/ki.png rename to www/static/images/flags/ki.png diff --git a/www/images/flags/km.png b/www/static/images/flags/km.png similarity index 100% rename from www/images/flags/km.png rename to www/static/images/flags/km.png diff --git a/www/images/flags/kn.png b/www/static/images/flags/kn.png similarity index 100% rename from www/images/flags/kn.png rename to www/static/images/flags/kn.png diff --git a/www/images/flags/kp.png b/www/static/images/flags/kp.png similarity index 100% rename from www/images/flags/kp.png rename to www/static/images/flags/kp.png diff --git a/www/images/flags/kr.png b/www/static/images/flags/kr.png similarity index 100% rename from www/images/flags/kr.png rename to www/static/images/flags/kr.png diff --git a/www/images/flags/kw.png b/www/static/images/flags/kw.png similarity index 100% rename from www/images/flags/kw.png rename to www/static/images/flags/kw.png diff --git a/www/images/flags/ky.png b/www/static/images/flags/ky.png similarity index 100% rename from www/images/flags/ky.png rename to www/static/images/flags/ky.png diff --git a/www/images/flags/kz.png b/www/static/images/flags/kz.png similarity index 100% rename from www/images/flags/kz.png rename to www/static/images/flags/kz.png diff --git a/www/images/flags/la.png b/www/static/images/flags/la.png similarity index 100% rename from www/images/flags/la.png rename to www/static/images/flags/la.png diff --git a/www/images/flags/lb.png b/www/static/images/flags/lb.png similarity index 100% rename from www/images/flags/lb.png rename to www/static/images/flags/lb.png diff --git a/www/images/flags/lc.png b/www/static/images/flags/lc.png similarity index 100% rename from www/images/flags/lc.png rename to www/static/images/flags/lc.png diff --git a/www/images/flags/li.png b/www/static/images/flags/li.png similarity index 100% rename from www/images/flags/li.png rename to www/static/images/flags/li.png diff --git a/www/images/flags/lk.png b/www/static/images/flags/lk.png similarity index 100% rename from www/images/flags/lk.png rename to www/static/images/flags/lk.png diff --git a/www/images/flags/lr.png b/www/static/images/flags/lr.png similarity index 100% rename from www/images/flags/lr.png rename to www/static/images/flags/lr.png diff --git a/www/images/flags/ls.png b/www/static/images/flags/ls.png similarity index 100% rename from www/images/flags/ls.png rename to www/static/images/flags/ls.png diff --git a/www/images/flags/lt.png b/www/static/images/flags/lt.png similarity index 100% rename from www/images/flags/lt.png rename to www/static/images/flags/lt.png diff --git a/www/images/flags/lu.png b/www/static/images/flags/lu.png similarity index 100% rename from www/images/flags/lu.png rename to www/static/images/flags/lu.png diff --git a/www/images/flags/lv.png b/www/static/images/flags/lv.png similarity index 100% rename from www/images/flags/lv.png rename to www/static/images/flags/lv.png diff --git a/www/images/flags/ly.png b/www/static/images/flags/ly.png similarity index 100% rename from www/images/flags/ly.png rename to www/static/images/flags/ly.png diff --git a/www/images/flags/ma.png b/www/static/images/flags/ma.png similarity index 100% rename from www/images/flags/ma.png rename to www/static/images/flags/ma.png diff --git a/www/images/flags/mc.png b/www/static/images/flags/mc.png similarity index 100% rename from www/images/flags/mc.png rename to www/static/images/flags/mc.png diff --git a/www/images/flags/md.png b/www/static/images/flags/md.png similarity index 100% rename from www/images/flags/md.png rename to www/static/images/flags/md.png diff --git a/www/images/flags/me.png b/www/static/images/flags/me.png similarity index 100% rename from www/images/flags/me.png rename to www/static/images/flags/me.png diff --git a/www/images/flags/mg.png b/www/static/images/flags/mg.png similarity index 100% rename from www/images/flags/mg.png rename to www/static/images/flags/mg.png diff --git a/www/images/flags/mh.png b/www/static/images/flags/mh.png similarity index 100% rename from www/images/flags/mh.png rename to www/static/images/flags/mh.png diff --git a/www/images/flags/mk.png b/www/static/images/flags/mk.png similarity index 100% rename from www/images/flags/mk.png rename to www/static/images/flags/mk.png diff --git a/www/images/flags/ml.png b/www/static/images/flags/ml.png similarity index 100% rename from www/images/flags/ml.png rename to www/static/images/flags/ml.png diff --git a/www/images/flags/mm.png b/www/static/images/flags/mm.png similarity index 100% rename from www/images/flags/mm.png rename to www/static/images/flags/mm.png diff --git a/www/images/flags/mn.png b/www/static/images/flags/mn.png similarity index 100% rename from www/images/flags/mn.png rename to www/static/images/flags/mn.png diff --git a/www/images/flags/mo.png b/www/static/images/flags/mo.png similarity index 100% rename from www/images/flags/mo.png rename to www/static/images/flags/mo.png diff --git a/www/images/flags/mp.png b/www/static/images/flags/mp.png similarity index 100% rename from www/images/flags/mp.png rename to www/static/images/flags/mp.png diff --git a/www/images/flags/mq.png b/www/static/images/flags/mq.png similarity index 100% rename from www/images/flags/mq.png rename to www/static/images/flags/mq.png diff --git a/www/images/flags/mr.png b/www/static/images/flags/mr.png similarity index 100% rename from www/images/flags/mr.png rename to www/static/images/flags/mr.png diff --git a/www/images/flags/ms.png b/www/static/images/flags/ms.png similarity index 100% rename from www/images/flags/ms.png rename to www/static/images/flags/ms.png diff --git a/www/images/flags/mt.png b/www/static/images/flags/mt.png similarity index 100% rename from www/images/flags/mt.png rename to www/static/images/flags/mt.png diff --git a/www/images/flags/mu.png b/www/static/images/flags/mu.png similarity index 100% rename from www/images/flags/mu.png rename to www/static/images/flags/mu.png diff --git a/www/images/flags/mv.png b/www/static/images/flags/mv.png similarity index 100% rename from www/images/flags/mv.png rename to www/static/images/flags/mv.png diff --git a/www/images/flags/mw.png b/www/static/images/flags/mw.png similarity index 100% rename from www/images/flags/mw.png rename to www/static/images/flags/mw.png diff --git a/www/images/flags/mx.png b/www/static/images/flags/mx.png similarity index 100% rename from www/images/flags/mx.png rename to www/static/images/flags/mx.png diff --git a/www/images/flags/my.png b/www/static/images/flags/my.png similarity index 100% rename from www/images/flags/my.png rename to www/static/images/flags/my.png diff --git a/www/images/flags/mz.png b/www/static/images/flags/mz.png similarity index 100% rename from www/images/flags/mz.png rename to www/static/images/flags/mz.png diff --git a/www/images/flags/na.png b/www/static/images/flags/na.png similarity index 100% rename from www/images/flags/na.png rename to www/static/images/flags/na.png diff --git a/www/images/flags/nc.png b/www/static/images/flags/nc.png similarity index 100% rename from www/images/flags/nc.png rename to www/static/images/flags/nc.png diff --git a/www/images/flags/ne.png b/www/static/images/flags/ne.png similarity index 100% rename from www/images/flags/ne.png rename to www/static/images/flags/ne.png diff --git a/www/images/flags/nf.png b/www/static/images/flags/nf.png similarity index 100% rename from www/images/flags/nf.png rename to www/static/images/flags/nf.png diff --git a/www/images/flags/ng.png b/www/static/images/flags/ng.png similarity index 100% rename from www/images/flags/ng.png rename to www/static/images/flags/ng.png diff --git a/www/images/flags/ni.png b/www/static/images/flags/ni.png similarity index 100% rename from www/images/flags/ni.png rename to www/static/images/flags/ni.png diff --git a/www/images/flags/nl.png b/www/static/images/flags/nl.png similarity index 100% rename from www/images/flags/nl.png rename to www/static/images/flags/nl.png diff --git a/www/images/flags/no.png b/www/static/images/flags/no.png similarity index 100% rename from www/images/flags/no.png rename to www/static/images/flags/no.png diff --git a/www/images/flags/np.png b/www/static/images/flags/np.png similarity index 100% rename from www/images/flags/np.png rename to www/static/images/flags/np.png diff --git a/www/images/flags/nr.png b/www/static/images/flags/nr.png similarity index 100% rename from www/images/flags/nr.png rename to www/static/images/flags/nr.png diff --git a/www/images/flags/nu.png b/www/static/images/flags/nu.png similarity index 100% rename from www/images/flags/nu.png rename to www/static/images/flags/nu.png diff --git a/www/images/flags/nz.png b/www/static/images/flags/nz.png similarity index 100% rename from www/images/flags/nz.png rename to www/static/images/flags/nz.png diff --git a/www/images/flags/om.png b/www/static/images/flags/om.png similarity index 100% rename from www/images/flags/om.png rename to www/static/images/flags/om.png diff --git a/www/images/flags/pa.png b/www/static/images/flags/pa.png similarity index 100% rename from www/images/flags/pa.png rename to www/static/images/flags/pa.png diff --git a/www/images/flags/pe.png b/www/static/images/flags/pe.png similarity index 100% rename from www/images/flags/pe.png rename to www/static/images/flags/pe.png diff --git a/www/images/flags/pf.png b/www/static/images/flags/pf.png similarity index 100% rename from www/images/flags/pf.png rename to www/static/images/flags/pf.png diff --git a/www/images/flags/pg.png b/www/static/images/flags/pg.png similarity index 100% rename from www/images/flags/pg.png rename to www/static/images/flags/pg.png diff --git a/www/images/flags/ph.png b/www/static/images/flags/ph.png similarity index 100% rename from www/images/flags/ph.png rename to www/static/images/flags/ph.png diff --git a/www/images/flags/pk.png b/www/static/images/flags/pk.png similarity index 100% rename from www/images/flags/pk.png rename to www/static/images/flags/pk.png diff --git a/www/images/flags/pl.png b/www/static/images/flags/pl.png similarity index 100% rename from www/images/flags/pl.png rename to www/static/images/flags/pl.png diff --git a/www/images/flags/pm.png b/www/static/images/flags/pm.png similarity index 100% rename from www/images/flags/pm.png rename to www/static/images/flags/pm.png diff --git a/www/images/flags/pn.png b/www/static/images/flags/pn.png similarity index 100% rename from www/images/flags/pn.png rename to www/static/images/flags/pn.png diff --git a/www/images/flags/pr.png b/www/static/images/flags/pr.png similarity index 100% rename from www/images/flags/pr.png rename to www/static/images/flags/pr.png diff --git a/www/images/flags/ps.png b/www/static/images/flags/ps.png similarity index 100% rename from www/images/flags/ps.png rename to www/static/images/flags/ps.png diff --git a/www/images/flags/pt.png b/www/static/images/flags/pt.png similarity index 100% rename from www/images/flags/pt.png rename to www/static/images/flags/pt.png diff --git a/www/images/flags/pw.png b/www/static/images/flags/pw.png similarity index 100% rename from www/images/flags/pw.png rename to www/static/images/flags/pw.png diff --git a/www/images/flags/py.png b/www/static/images/flags/py.png similarity index 100% rename from www/images/flags/py.png rename to www/static/images/flags/py.png diff --git a/www/images/flags/qa.png b/www/static/images/flags/qa.png similarity index 100% rename from www/images/flags/qa.png rename to www/static/images/flags/qa.png diff --git a/www/images/flags/re.png b/www/static/images/flags/re.png similarity index 100% rename from www/images/flags/re.png rename to www/static/images/flags/re.png diff --git a/www/images/flags/ro.png b/www/static/images/flags/ro.png similarity index 100% rename from www/images/flags/ro.png rename to www/static/images/flags/ro.png diff --git a/www/images/flags/rs.png b/www/static/images/flags/rs.png similarity index 100% rename from www/images/flags/rs.png rename to www/static/images/flags/rs.png diff --git a/www/images/flags/ru.png b/www/static/images/flags/ru.png similarity index 100% rename from www/images/flags/ru.png rename to www/static/images/flags/ru.png diff --git a/www/images/flags/rw.png b/www/static/images/flags/rw.png similarity index 100% rename from www/images/flags/rw.png rename to www/static/images/flags/rw.png diff --git a/www/images/flags/sa.png b/www/static/images/flags/sa.png similarity index 100% rename from www/images/flags/sa.png rename to www/static/images/flags/sa.png diff --git a/www/images/flags/sb.png b/www/static/images/flags/sb.png similarity index 100% rename from www/images/flags/sb.png rename to www/static/images/flags/sb.png diff --git a/www/images/flags/sc.png b/www/static/images/flags/sc.png similarity index 100% rename from www/images/flags/sc.png rename to www/static/images/flags/sc.png diff --git a/www/images/flags/scotland.png b/www/static/images/flags/scotland.png similarity index 100% rename from www/images/flags/scotland.png rename to www/static/images/flags/scotland.png diff --git a/www/images/flags/sd.png b/www/static/images/flags/sd.png similarity index 100% rename from www/images/flags/sd.png rename to www/static/images/flags/sd.png diff --git a/www/images/flags/se.png b/www/static/images/flags/se.png similarity index 100% rename from www/images/flags/se.png rename to www/static/images/flags/se.png diff --git a/www/images/flags/sg.png b/www/static/images/flags/sg.png similarity index 100% rename from www/images/flags/sg.png rename to www/static/images/flags/sg.png diff --git a/www/images/flags/sh.png b/www/static/images/flags/sh.png similarity index 100% rename from www/images/flags/sh.png rename to www/static/images/flags/sh.png diff --git a/www/images/flags/si.png b/www/static/images/flags/si.png similarity index 100% rename from www/images/flags/si.png rename to www/static/images/flags/si.png diff --git a/www/images/flags/sj.png b/www/static/images/flags/sj.png similarity index 100% rename from www/images/flags/sj.png rename to www/static/images/flags/sj.png diff --git a/www/images/flags/sk.png b/www/static/images/flags/sk.png similarity index 100% rename from www/images/flags/sk.png rename to www/static/images/flags/sk.png diff --git a/www/images/flags/sl.png b/www/static/images/flags/sl.png similarity index 100% rename from www/images/flags/sl.png rename to www/static/images/flags/sl.png diff --git a/www/images/flags/sm.png b/www/static/images/flags/sm.png similarity index 100% rename from www/images/flags/sm.png rename to www/static/images/flags/sm.png diff --git a/www/images/flags/sn.png b/www/static/images/flags/sn.png similarity index 100% rename from www/images/flags/sn.png rename to www/static/images/flags/sn.png diff --git a/www/images/flags/so.png b/www/static/images/flags/so.png similarity index 100% rename from www/images/flags/so.png rename to www/static/images/flags/so.png diff --git a/www/images/flags/sr.png b/www/static/images/flags/sr.png similarity index 100% rename from www/images/flags/sr.png rename to www/static/images/flags/sr.png diff --git a/www/images/flags/st.png b/www/static/images/flags/st.png similarity index 100% rename from www/images/flags/st.png rename to www/static/images/flags/st.png diff --git a/www/images/flags/sv.png b/www/static/images/flags/sv.png similarity index 100% rename from www/images/flags/sv.png rename to www/static/images/flags/sv.png diff --git a/www/images/flags/sy.png b/www/static/images/flags/sy.png similarity index 100% rename from www/images/flags/sy.png rename to www/static/images/flags/sy.png diff --git a/www/images/flags/sz.png b/www/static/images/flags/sz.png similarity index 100% rename from www/images/flags/sz.png rename to www/static/images/flags/sz.png diff --git a/www/images/flags/tc.png b/www/static/images/flags/tc.png similarity index 100% rename from www/images/flags/tc.png rename to www/static/images/flags/tc.png diff --git a/www/images/flags/td.png b/www/static/images/flags/td.png similarity index 100% rename from www/images/flags/td.png rename to www/static/images/flags/td.png diff --git a/www/images/flags/tf.png b/www/static/images/flags/tf.png similarity index 100% rename from www/images/flags/tf.png rename to www/static/images/flags/tf.png diff --git a/www/images/flags/tg.png b/www/static/images/flags/tg.png similarity index 100% rename from www/images/flags/tg.png rename to www/static/images/flags/tg.png diff --git a/www/images/flags/th.png b/www/static/images/flags/th.png similarity index 100% rename from www/images/flags/th.png rename to www/static/images/flags/th.png diff --git a/www/images/flags/tj.png b/www/static/images/flags/tj.png similarity index 100% rename from www/images/flags/tj.png rename to www/static/images/flags/tj.png diff --git a/www/images/flags/tk.png b/www/static/images/flags/tk.png similarity index 100% rename from www/images/flags/tk.png rename to www/static/images/flags/tk.png diff --git a/www/images/flags/tl.png b/www/static/images/flags/tl.png similarity index 100% rename from www/images/flags/tl.png rename to www/static/images/flags/tl.png diff --git a/www/images/flags/tm.png b/www/static/images/flags/tm.png similarity index 100% rename from www/images/flags/tm.png rename to www/static/images/flags/tm.png diff --git a/www/images/flags/tn.png b/www/static/images/flags/tn.png similarity index 100% rename from www/images/flags/tn.png rename to www/static/images/flags/tn.png diff --git a/www/images/flags/to.png b/www/static/images/flags/to.png similarity index 100% rename from www/images/flags/to.png rename to www/static/images/flags/to.png diff --git a/www/images/flags/tr.png b/www/static/images/flags/tr.png similarity index 100% rename from www/images/flags/tr.png rename to www/static/images/flags/tr.png diff --git a/www/images/flags/tt.png b/www/static/images/flags/tt.png similarity index 100% rename from www/images/flags/tt.png rename to www/static/images/flags/tt.png diff --git a/www/images/flags/tv.png b/www/static/images/flags/tv.png similarity index 100% rename from www/images/flags/tv.png rename to www/static/images/flags/tv.png diff --git a/www/images/flags/tw.png b/www/static/images/flags/tw.png similarity index 100% rename from www/images/flags/tw.png rename to www/static/images/flags/tw.png diff --git a/www/images/flags/tz.png b/www/static/images/flags/tz.png similarity index 100% rename from www/images/flags/tz.png rename to www/static/images/flags/tz.png diff --git a/www/images/flags/ua.png b/www/static/images/flags/ua.png similarity index 100% rename from www/images/flags/ua.png rename to www/static/images/flags/ua.png diff --git a/www/images/flags/ug.png b/www/static/images/flags/ug.png similarity index 100% rename from www/images/flags/ug.png rename to www/static/images/flags/ug.png diff --git a/www/images/flags/um.png b/www/static/images/flags/um.png similarity index 100% rename from www/images/flags/um.png rename to www/static/images/flags/um.png diff --git a/www/images/flags/us.png b/www/static/images/flags/us.png similarity index 100% rename from www/images/flags/us.png rename to www/static/images/flags/us.png diff --git a/www/images/flags/uy.png b/www/static/images/flags/uy.png similarity index 100% rename from www/images/flags/uy.png rename to www/static/images/flags/uy.png diff --git a/www/images/flags/uz.png b/www/static/images/flags/uz.png similarity index 100% rename from www/images/flags/uz.png rename to www/static/images/flags/uz.png diff --git a/www/images/flags/va.png b/www/static/images/flags/va.png similarity index 100% rename from www/images/flags/va.png rename to www/static/images/flags/va.png diff --git a/www/images/flags/vc.png b/www/static/images/flags/vc.png similarity index 100% rename from www/images/flags/vc.png rename to www/static/images/flags/vc.png diff --git a/www/images/flags/ve.png b/www/static/images/flags/ve.png similarity index 100% rename from www/images/flags/ve.png rename to www/static/images/flags/ve.png diff --git a/www/images/flags/vg.png b/www/static/images/flags/vg.png similarity index 100% rename from www/images/flags/vg.png rename to www/static/images/flags/vg.png diff --git a/www/images/flags/vi.png b/www/static/images/flags/vi.png similarity index 100% rename from www/images/flags/vi.png rename to www/static/images/flags/vi.png diff --git a/www/images/flags/vn.png b/www/static/images/flags/vn.png similarity index 100% rename from www/images/flags/vn.png rename to www/static/images/flags/vn.png diff --git a/www/images/flags/vu.png b/www/static/images/flags/vu.png similarity index 100% rename from www/images/flags/vu.png rename to www/static/images/flags/vu.png diff --git a/www/images/flags/wales.png b/www/static/images/flags/wales.png similarity index 100% rename from www/images/flags/wales.png rename to www/static/images/flags/wales.png diff --git a/www/images/flags/wf.png b/www/static/images/flags/wf.png similarity index 100% rename from www/images/flags/wf.png rename to www/static/images/flags/wf.png diff --git a/www/images/flags/ws.png b/www/static/images/flags/ws.png similarity index 100% rename from www/images/flags/ws.png rename to www/static/images/flags/ws.png diff --git a/www/images/flags/ye.png b/www/static/images/flags/ye.png similarity index 100% rename from www/images/flags/ye.png rename to www/static/images/flags/ye.png diff --git a/www/images/flags/yt.png b/www/static/images/flags/yt.png similarity index 100% rename from www/images/flags/yt.png rename to www/static/images/flags/yt.png diff --git a/www/images/flags/za.png b/www/static/images/flags/za.png similarity index 100% rename from www/images/flags/za.png rename to www/static/images/flags/za.png diff --git a/www/images/flags/zm.png b/www/static/images/flags/zm.png similarity index 100% rename from www/images/flags/zm.png rename to www/static/images/flags/zm.png diff --git a/www/images/flags/zw.png b/www/static/images/flags/zw.png similarity index 100% rename from www/images/flags/zw.png rename to www/static/images/flags/zw.png diff --git a/www/images/ft.png b/www/static/images/ft.png similarity index 100% rename from www/images/ft.png rename to www/static/images/ft.png diff --git a/www/images/icons/ipfire.png b/www/static/images/icons/ipfire.png similarity index 100% rename from www/images/icons/ipfire.png rename to www/static/images/icons/ipfire.png diff --git a/www/images/icons/ipfire_sw.png b/www/static/images/icons/ipfire_sw.png similarity index 100% rename from www/images/icons/ipfire_sw.png rename to www/static/images/icons/ipfire_sw.png diff --git a/www/static/images/ipfire_download.png b/www/static/images/ipfire_download.png new file mode 100644 index 0000000000000000000000000000000000000000..85949acedbf495ce6ca0a607861bd35704578565 GIT binary patch literal 22597 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

    V8F<7`#@>HB@>g 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 k6O5mi^DaM!{{K+^7qT"; + row += " "; + row += " " + node.arch + ""; + row += " "; + row += " "; + row += " " + node.speed + ""; + row += ""; + $("#nodes").append(row); + } + $("#" + nodeid + "_loadbar").progressBar(node.load, {showText: false}); + $("#" + nodeid + "_jobs").progressBar(node.jobcount.split("/")[0], { max: node.jobcount.split("/")[1], textFormat: 'fraction'}); + if (node.installing == true) { + $("#" + nodeid + "_hostname").html(node.hostname + " *"); + } else { + $("#" + nodeid + "_hostname").html(node.hostname); + } + }); + + $("#loadbar").progressBar(data.result.cluster.load); + $("#jobbar").progressBar(data.result.cluster.jobcount.split("/")[0], { max: data.result.cluster.jobcount.split("/")[1], textFormat: 'fraction'}); + for (var nodeid in nodes) { + if (nodes[nodeid] == false) { + $("#" + nodeid).remove(); + nodes.pop(nodeid); + } else { + nodes[nodeid] = false; + } + } + $("#count").html(count); + busy = false; + }); +} + +$(document).ready(function(){ + // Init loadbar + $("#loadbar").progressBar(); + + update(); + setInterval("update()", 2000); +}) diff --git a/www/include/correctpng.js b/www/static/js/correctpng.js similarity index 100% rename from www/include/correctpng.js rename to www/static/js/correctpng.js diff --git a/www/static/js/jquery-ui.js b/www/static/js/jquery-ui.js new file mode 100644 index 0000000..cf19f30 --- /dev/null +++ b/www/static/js/jquery-ui.js @@ -0,0 +1,298 @@ +/* + * jQuery UI 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* + * jQuery UI Draggable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger("start",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass("ui-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();this._trigger("drag",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger("stop",c);b._clear()})}else{this._trigger("stop",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.leftthis.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y=p&&n<=k)||(m>=p&&m<=k)||(nk))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(ec));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;/* + * jQuery UI Selectable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.selectable",a.extend({},a.ui.mouse,{_init:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy()},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.rightg||j.bottomd&&j.righth&&j.bottom=0;b--){this.items[b].item.removeData("sortable-item")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)f&&(e+h)m[this.floating?"width":"height"])){return g}else{return(f0?"down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.containers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?"left":"top"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?"left":"top"];if(Math.abs(f-e)this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000}})})(jQuery);;/* + * jQuery UI Accordion 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Accordion + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.accordion",{_init:function(){var d=this.options,b=this;this.running=0;if(d.collapsible==a.ui.accordion.defaults.collapsible&&d.alwaysOpen!=a.ui.accordion.defaults.alwaysOpen){d.collapsible=!d.alwaysOpen}if(d.navigation){var c=this.element.find("a").filter(d.navigationFilter);if(c.length){if(c.filter(d.header).length){this.active=c}else{this.active=c.parent().parent().prev();c.addClass("ui-accordion-content-active")}}}this.element.addClass("ui-accordion ui-widget ui-helper-reset");if(this.element[0].nodeName=="UL"){this.element.children("li").addClass("ui-accordion-li-fix")}this.headers=this.element.find(d.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){a(this).removeClass("ui-state-focus")});this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");this.active=this._findActive(this.active||d.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass("ui-accordion-content-active");a("").addClass("ui-icon "+d.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(d.icons.header).toggleClass(d.icons.headerSelected);if(a.browser.msie){this.element.find("a").css("zoom","1")}this.resize();this.element.attr("role","tablist");this.headers.attr("role","tab").bind("keydown",function(e){return b._keydown(e)}).next().attr("role","tabpanel");this.headers.not(this.active||"").attr("aria-expanded","false").attr("tabIndex","-1").next().hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex","0")}else{this.active.attr("aria-expanded","true").attr("tabIndex","0")}if(!a.browser.safari){this.headers.find("a").attr("tabIndex","-1")}if(d.event){this.headers.bind((d.event)+".accordion",function(e){return b._clickHandler.call(b,e,this)})}},destroy:function(){var c=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion").removeData("accordion");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");this.headers.find("a").removeAttr("tabindex");this.headers.children(".ui-icon").remove();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");if(c.autoHeight||c.fillHeight){b.css("height","")}},_setData:function(b,c){if(b=="alwaysOpen"){b="collapsible";c=!c}a.widget.prototype._setData.apply(this,arguments)},_keydown:function(e){var g=this.options,f=a.ui.keyCode;if(g.disabled||e.altKey||e.ctrlKey){return}var d=this.headers.length;var b=this.headers.index(e.target);var c=false;switch(e.keyCode){case f.RIGHT:case f.DOWN:c=this.headers[(b+1)%d];break;case f.LEFT:case f.UP:c=this.headers[(b-1+d)%d];break;case f.SPACE:case f.ENTER:return this._clickHandler({target:e.target},e.target)}if(c){a(e.target).attr("tabIndex","-1");a(c).attr("tabIndex","0");c.focus();return false}return true},resize:function(){var e=this.options,d;if(e.fillSpace){if(a.browser.msie){var b=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}d=this.element.parent().height();if(a.browser.msie){this.element.parent().css("overflow",b)}this.headers.each(function(){d-=a(this).outerHeight()});var c=0;this.headers.next().each(function(){c=Math.max(c,a(this).innerHeight()-a(this).height())}).height(Math.max(0,d-c)).css("overflow","auto")}else{if(e.autoHeight){d=0;this.headers.next().each(function(){d=Math.max(d,a(this).outerHeight())}).height(d)}}},activate:function(b){var c=this._findActive(b)[0];this._clickHandler({target:c},c)},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,f){var d=this.options;if(d.disabled){return false}if(!b.target&&d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var h=this.active.next(),e={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:h},c=(this.active=a([]));this._toggle(c,h,e);return false}var g=a(b.currentTarget||f);var i=g[0]==this.active[0];if(this.running||(!d.collapsible&&i)){return false}this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");if(!i){g.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);g.next().addClass("ui-accordion-content-active")}var c=g.next(),h=this.active.next(),e={options:d,newHeader:i&&d.collapsible?a([]):g,oldHeader:this.active,newContent:i&&d.collapsible?a([]):c.find("> *"),oldContent:h.find("> *")},j=this.headers.index(this.active[0])>this.headers.index(g[0]);this.active=i?a([]):g;this._toggle(c,h,e,i,j);return false},_toggle:function(b,i,g,j,k){var d=this.options,m=this;this.toShow=b;this.toHide=i;this.data=g;var c=function(){if(!m){return}return m._completed.apply(m,arguments)};this._trigger("changestart",null,this.data);this.running=i.size()===0?b.size():i.size();if(d.animated){var f={};if(d.collapsible&&j){f={toShow:a([]),toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}else{f={toShow:b,toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}if(!d.proxied){d.proxied=d.animated}if(!d.proxiedDuration){d.proxiedDuration=d.duration}d.animated=a.isFunction(d.proxied)?d.proxied(f):d.proxied;d.duration=a.isFunction(d.proxiedDuration)?d.proxiedDuration(f):d.proxiedDuration;var l=a.ui.accordion.animations,e=d.duration,h=d.animated;if(!l[h]){l[h]=function(n){this.slide(n,{easing:h,duration:e||700})}}l[h](f)}else{if(d.collapsible&&j){b.toggle()}else{i.hide();b.show()}c(true)}i.prev().attr("aria-expanded","false").attr("tabIndex","-1").blur();b.prev().attr("aria-expanded","true").attr("tabIndex","0").focus()},_completed:function(b){var c=this.options;this.running=b?0:--this.running;if(this.running){return}if(c.clearStyle){this.toShow.add(this.toHide).css({height:"",overflow:""})}this._trigger("change",null,this.data)}});a.extend(a.ui.accordion,{version:"1.7.2",defaults:{active:null,alwaysOpen:true,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase()}},animations:{slide:function(j,h){j=a.extend({easing:"swing",duration:300},j,h);if(!j.toHide.size()){j.toShow.animate({height:"show"},j);return}if(!j.toShow.size()){j.toHide.animate({height:"hide"},j);return}var c=j.toShow.css("overflow"),g,d={},f={},e=["height","paddingTop","paddingBottom"],b;var i=j.toShow;b=i[0].style.width;i.width(parseInt(i.parent().width(),10)-parseInt(i.css("paddingLeft"),10)-parseInt(i.css("paddingRight"),10)-(parseInt(i.css("borderLeftWidth"),10)||0)-(parseInt(i.css("borderRightWidth"),10)||0));a.each(e,function(k,m){f[m]="hide";var l=(""+a.css(j.toShow[0],m)).match(/^([\d+-.]+)(.*)$/);d[m]={value:l[1],unit:l[2]||"px"}});j.toShow.css({height:0,overflow:"hidden"}).show();j.toHide.filter(":hidden").each(j.complete).end().filter(":visible").animate(f,{step:function(k,l){if(l.prop=="height"){g=(l.now-l.start)/(l.end-l.start)}j.toShow[0].style[l.prop]=(g*d[l.prop].value)+d[l.prop].unit},duration:j.duration,easing:j.easing,complete:function(){if(!j.autoHeight){j.toShow.css("height","")}j.toShow.css("width",b);j.toShow.css({overflow:c});j.complete()}})},bounceslide:function(b){this.slide(b,{easing:b.down?"easeOutBounce":"swing",duration:b.down?1000:200})},easeslide:function(b){this.slide(b,{easing:"easeinout",duration:700})}}})})(jQuery);;/* + * jQuery UI Dialog 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * ui.core.js + * ui.draggable.js + * ui.resizable.js + */ +(function(c){var b={dragStart:"start.draggable",drag:"drag.draggable",dragStop:"stop.draggable",maxHeight:"maxHeight.resizable",minHeight:"minHeight.resizable",maxWidth:"maxWidth.resizable",minWidth:"minWidth.resizable",resizeStart:"start.resizable",resize:"drag.resizable",resizeStop:"stop.resizable"},a="ui-dialog ui-widget ui-widget-content ui-corner-all ";c.widget("ui.dialog",{_init:function(){this.originalTitle=this.element.attr("title");var l=this,m=this.options,j=m.title||this.originalTitle||" ",e=c.ui.dialog.getTitleId(this.element),k=(this.uiDialog=c("

    ")).appendTo(document.body).hide().addClass(a+m.dialogClass).css({position:"absolute",overflow:"hidden",zIndex:m.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(n){(m.closeOnEscape&&n.keyCode&&n.keyCode==c.ui.keyCode.ESCAPE&&l.close(n))}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(n){l.moveToTop(false,n)}),g=this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(k),f=(this.uiDialogTitlebar=c("
    ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(k),i=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){i.addClass("ui-state-hover")},function(){i.removeClass("ui-state-hover")}).focus(function(){i.addClass("ui-state-focus")}).blur(function(){i.removeClass("ui-state-focus")}).mousedown(function(n){n.stopPropagation()}).click(function(n){l.close(n);return false}).appendTo(f),h=(this.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(m.closeText).appendTo(i),d=c("").addClass("ui-dialog-title").attr("id",e).html(j).prependTo(f);f.find("*").add(f).disableSelection();(m.draggable&&c.fn.draggable&&this._makeDraggable());(m.resizable&&c.fn.resizable&&this._makeResizable());this._createButtons(m.buttons);this._isOpen=false;(m.bgiframe&&c.fn.bgiframe&&k.bgiframe());(m.autoOpen&&this.open())},destroy:function(){(this.overlay&&this.overlay.destroy());this.uiDialog.hide();this.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");this.uiDialog.remove();(this.originalTitle&&this.element.attr("title",this.originalTitle))},close:function(f){var d=this;if(false===d._trigger("beforeclose",f)){return}(d.overlay&&d.overlay.destroy());d.uiDialog.unbind("keypress.ui-dialog");(d.options.hide?d.uiDialog.hide(d.options.hide,function(){d._trigger("close",f)}):d.uiDialog.hide()&&d._trigger("close",f));c.ui.dialog.overlay.resize();d._isOpen=false;if(d.options.modal){var e=0;c(".ui-dialog").each(function(){if(this!=d.uiDialog[0]){e=Math.max(e,c(this).css("z-index"))}});c.ui.dialog.maxZ=e}},isOpen:function(){return this._isOpen},moveToTop:function(f,e){if((this.options.modal&&!f)||(!this.options.stack&&!this.options.modal)){return this._trigger("focus",e)}if(this.options.zIndex>c.ui.dialog.maxZ){c.ui.dialog.maxZ=this.options.zIndex}(this.overlay&&this.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=++c.ui.dialog.maxZ));var d={scrollTop:this.element.attr("scrollTop"),scrollLeft:this.element.attr("scrollLeft")};this.uiDialog.css("z-index",++c.ui.dialog.maxZ);this.element.attr(d);this._trigger("focus",e)},open:function(){if(this._isOpen){return}var e=this.options,d=this.uiDialog;this.overlay=e.modal?new c.ui.dialog.overlay(this):null;(d.next().length&&d.appendTo("body"));this._size();this._position(e.position);d.show(e.show);this.moveToTop(true);(e.modal&&d.bind("keypress.ui-dialog",function(h){if(h.keyCode!=c.ui.keyCode.TAB){return}var g=c(":tabbable",this),i=g.filter(":first")[0],f=g.filter(":last")[0];if(h.target==f&&!h.shiftKey){setTimeout(function(){i.focus()},1)}else{if(h.target==i&&h.shiftKey){setTimeout(function(){f.focus()},1)}}}));c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();this._trigger("open");this._isOpen=true},_createButtons:function(g){var f=this,d=false,e=c("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");this.uiDialog.find(".ui-dialog-buttonpane").remove();(typeof g=="object"&&g!==null&&c.each(g,function(){return !(d=true)}));if(d){c.each(g,function(h,i){c('').addClass("ui-state-default ui-corner-all").text(h).click(function(){i.apply(f.element[0],arguments)}).hover(function(){c(this).addClass("ui-state-hover")},function(){c(this).removeClass("ui-state-hover")}).focus(function(){c(this).addClass("ui-state-focus")}).blur(function(){c(this).removeClass("ui-state-focus")}).appendTo(e)});e.appendTo(this.uiDialog)}},_makeDraggable:function(){var d=this,f=this.options,e;this.uiDialog.draggable({cancel:".ui-dialog-content",handle:".ui-dialog-titlebar",containment:"document",start:function(){e=f.height;c(this).height(c(this).height()).addClass("ui-dialog-dragging");(f.dragStart&&f.dragStart.apply(d.element[0],arguments))},drag:function(){(f.drag&&f.drag.apply(d.element[0],arguments))},stop:function(){c(this).removeClass("ui-dialog-dragging").height(e);(f.dragStop&&f.dragStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}})},_makeResizable:function(g){g=(g===undefined?this.options.resizable:g);var d=this,f=this.options,e=typeof g=="string"?g:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",alsoResize:this.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:f.minHeight,start:function(){c(this).addClass("ui-dialog-resizing");(f.resizeStart&&f.resizeStart.apply(d.element[0],arguments))},resize:function(){(f.resize&&f.resize.apply(d.element[0],arguments))},handles:e,stop:function(){c(this).removeClass("ui-dialog-resizing");f.height=c(this).height();f.width=c(this).width();(f.resizeStop&&f.resizeStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}}).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_position:function(i){var e=c(window),f=c(document),g=f.scrollTop(),d=f.scrollLeft(),h=g;if(c.inArray(i,["center","top","right","bottom","left"])>=0){i=[i=="right"||i=="left"?i:"center",i=="top"||i=="bottom"?i:"middle"]}if(i.constructor!=Array){i=["center","middle"]}if(i[0].constructor==Number){d+=i[0]}else{switch(i[0]){case"left":d+=0;break;case"right":d+=e.width()-this.uiDialog.outerWidth();break;default:case"center":d+=(e.width()-this.uiDialog.outerWidth())/2}}if(i[1].constructor==Number){g+=i[1]}else{switch(i[1]){case"top":g+=0;break;case"bottom":g+=e.height()-this.uiDialog.outerHeight();break;default:case"middle":g+=(e.height()-this.uiDialog.outerHeight())/2}}g=Math.max(g,h);this.uiDialog.css({top:g,left:d})},_setData:function(e,f){(b[e]&&this.uiDialog.data(b[e],f));switch(e){case"buttons":this._createButtons(f);break;case"closeText":this.uiDialogTitlebarCloseText.text(f);break;case"dialogClass":this.uiDialog.removeClass(this.options.dialogClass).addClass(a+f);break;case"draggable":(f?this._makeDraggable():this.uiDialog.draggable("destroy"));break;case"height":this.uiDialog.height(f);break;case"position":this._position(f);break;case"resizable":var d=this.uiDialog,g=this.uiDialog.is(":data(resizable)");(g&&!f&&d.resizable("destroy"));(g&&typeof f=="string"&&d.resizable("option","handles",f));(g||this._makeResizable(f));break;case"title":c(".ui-dialog-title",this.uiDialogTitlebar).html(f||" ");break;case"width":this.uiDialog.width(f);break}c.widget.prototype._setData.apply(this,arguments)},_size:function(){var e=this.options;this.element.css({height:0,minHeight:0,width:"auto"});var d=this.uiDialog.css({height:"auto",width:e.width}).height();this.element.css({minHeight:Math.max(e.minHeight-d,0),height:e.height=="auto"?"auto":Math.max(e.height-d,0)})}});c.extend(c.ui.dialog,{version:"1.7.2",defaults:{autoOpen:true,bgiframe:false,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:"center",resizable:true,show:null,stack:true,title:"",width:300,zIndex:1000},getter:"isOpen",uuid:0,maxZ:0,getTitleId:function(d){return"ui-dialog-title-"+(d.attr("id")||++this.uuid)},overlay:function(d){this.$el=c.ui.dialog.overlay.create(d)}});c.extend(c.ui.dialog.overlay,{instances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(d){return d+".dialog-overlay"}).join(" "),create:function(e){if(this.instances.length===0){setTimeout(function(){if(c.ui.dialog.overlay.instances.length){c(document).bind(c.ui.dialog.overlay.events,function(f){var g=c(f.target).parents(".ui-dialog").css("zIndex")||0;return(g>c.ui.dialog.overlay.maxZ)})}},1);c(document).bind("keydown.dialog-overlay",function(f){(e.options.closeOnEscape&&f.keyCode&&f.keyCode==c.ui.keyCode.ESCAPE&&e.close(f))});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var d=c("
    ").appendTo(document.body).addClass("ui-widget-overlay").css({width:this.width(),height:this.height()});(e.options.bgiframe&&c.fn.bgiframe&&d.bgiframe());this.instances.push(d);return d},destroy:function(d){this.instances.splice(c.inArray(this.instances,d),1);if(this.instances.length===0){c([document,window]).unbind(".dialog-overlay")}d.remove();var e=0;c.each(this.instances,function(){e=Math.max(e,this.css("z-index"))});this.maxZ=e},height:function(){if(c.browser.msie&&c.browser.version<7){var e=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);var d=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(e
    ");if(!c.values){c.values=[this._valueMin(),this._valueMin()]}if(c.values.length&&c.values.length!=2){c.values=[c.values[0],c.values[0]]}}else{this.range=a("
    ")}this.range.appendTo(this.element).addClass("ui-slider-range");if(c.range=="min"||c.range=="max"){this.range.addClass("ui-slider-range-"+c.range)}this.range.addClass("ui-widget-header")}if(a(".ui-slider-handle",this.element).length==0){a('
    ').appendTo(this.element).addClass("ui-slider-handle")}if(c.values&&c.values.length){while(a(".ui-slider-handle",this.element).length').appendTo(this.element).addClass("ui-slider-handle")}}this.handles=a(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(d){d.preventDefault()}).hover(function(){if(!c.disabled){a(this).addClass("ui-state-hover")}},function(){a(this).removeClass("ui-state-hover")}).focus(function(){if(!c.disabled){a(".ui-slider .ui-state-focus").removeClass("ui-state-focus");a(this).addClass("ui-state-focus")}else{a(this).blur()}}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(d){a(this).data("index.ui-slider-handle",d)});this.handles.keydown(function(i){var f=true;var e=a(this).data("index.ui-slider-handle");if(b.options.disabled){return}switch(i.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:f=false;if(!b._keySliding){b._keySliding=true;a(this).addClass("ui-state-active");b._start(i,e)}break}var g,d,h=b._step();if(b.options.values&&b.options.values.length){g=d=b.values(e)}else{g=d=b.value()}switch(i.keyCode){case a.ui.keyCode.HOME:d=b._valueMin();break;case a.ui.keyCode.END:d=b._valueMax();break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g==b._valueMax()){return}d=g+h;break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g==b._valueMin()){return}d=g-h;break}b._slide(i,e,d);return f}).keyup(function(e){var d=a(this).data("index.ui-slider-handle");if(b._keySliding){b._stop(e,d);b._change(e,d);b._keySliding=false;a(this).removeClass("ui-state-active")}});this._refreshValue()},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy()},_mouseCapture:function(d){var e=this.options;if(e.disabled){return false}this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();var h={x:d.pageX,y:d.pageY};var j=this._normValueFromMouse(h);var c=this._valueMax()-this._valueMin()+1,f;var k=this,i;this.handles.each(function(l){var m=Math.abs(j-k.values(l));if(c>m){c=m;f=a(this);i=l}});if(e.range==true&&this.values(1)==e.min){f=a(this.handles[++i])}this._start(d,i);k._handleIndex=i;f.addClass("ui-state-active").focus();var g=f.offset();var b=!a(d.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=b?{left:0,top:0}:{left:d.pageX-g.left-(f.width()/2),top:d.pageY-g.top-(f.height()/2)-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};j=this._normValueFromMouse(h);this._slide(d,i,j);return true},_mouseStart:function(b){return true},_mouseDrag:function(d){var b={x:d.pageX,y:d.pageY};var c=this._normValueFromMouse(b);this._slide(d,this._handleIndex,c);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._handleIndex=null;this._clickOffset=null;return false},_detectOrientation:function(){this.orientation=this.options.orientation=="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(d){var c,h;if("horizontal"==this.orientation){c=this.elementSize.width;h=d.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{c=this.elementSize.height;h=d.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}var f=(h/c);if(f>1){f=1}if(f<0){f=0}if("vertical"==this.orientation){f=1-f}var e=this._valueMax()-this._valueMin(),i=f*e,b=i%this.options.step,g=this._valueMin()+i-b;if(b>(this.options.step/2)){g+=this.options.step}return parseFloat(g.toFixed(5))},_start:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("start",d,b)},_slide:function(f,e,d){var g=this.handles[e];if(this.options.values&&this.options.values.length){var b=this.values(e?0:1);if((this.options.values.length==2&&this.options.range===true)&&((e==0&&d>b)||(e==1&&d1){this.options.values[b]=e;this._refreshValue(c);if(!d){this._change(null,b)}}if(arguments.length){if(this.options.values&&this.options.values.length){return this._values(b)}else{return this.value()}}else{return this._values()}},_setData:function(b,d,c){a.widget.prototype._setData.apply(this,arguments);switch(b){case"disabled":if(d){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled")}else{this.handles.removeAttr("disabled")}case"orientation":this._detectOrientation();this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue(c);break;case"value":this._refreshValue(c);break}},_step:function(){var b=this.options.step;return b},_value:function(){var b=this.options.value;if(bthis._valueMax()){b=this._valueMax()}return b},_values:function(b){if(arguments.length){var c=this.options.values[b];if(cthis._valueMax()){c=this._valueMax()}return c}else{return this.options.values}},_valueMin:function(){var b=this.options.min;return b},_valueMax:function(){var b=this.options.max;return b},_refreshValue:function(c){var f=this.options.range,d=this.options,l=this;if(this.options.values&&this.options.values.length){var i,h;this.handles.each(function(p,n){var o=(l.values(p)-l._valueMin())/(l._valueMax()-l._valueMin())*100;var m={};m[l.orientation=="horizontal"?"left":"bottom"]=o+"%";a(this).stop(1,1)[c?"animate":"css"](m,d.animate);if(l.options.range===true){if(l.orientation=="horizontal"){(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({left:o+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({width:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}else{(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({bottom:(o)+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({height:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}}lastValPercent=o})}else{var j=this.value(),g=this._valueMin(),k=this._valueMax(),e=k!=g?(j-g)/(k-g)*100:0;var b={};b[l.orientation=="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[c?"animate":"css"](b,d.animate);(f=="min")&&(this.orientation=="horizontal")&&this.range.stop(1,1)[c?"animate":"css"]({width:e+"%"},d.animate);(f=="max")&&(this.orientation=="horizontal")&&this.range[c?"animate":"css"]({width:(100-e)+"%"},{queue:false,duration:d.animate});(f=="min")&&(this.orientation=="vertical")&&this.range.stop(1,1)[c?"animate":"css"]({height:e+"%"},d.animate);(f=="max")&&(this.orientation=="vertical")&&this.range[c?"animate":"css"]({height:(100-e)+"%"},{queue:false,duration:d.animate})}}}));a.extend(a.ui.slider,{getter:"value values",version:"1.7.2",eventPrefix:"slide",defaults:{animate:false,delay:0,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null}})})(jQuery);;/* + * jQuery UI Tabs 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.tabs",{_init:function(){if(this.options.deselectable!==undefined){this.options.collapsible=this.options.deselectable}this._tabify(true)},_setData:function(b,c){if(b=="selected"){if(this.options.collapsible&&c==this.options.selected){return}this.select(c)}else{this.options[b]=c;if(b=="deselectable"){this.options.collapsible=c}this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^A-Za-z0-9\-_:\.]/g,"")||this.options.idPrefix+a.data(b)},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+a.data(this.list[0]));return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(c,b){return{tab:c,panel:b,index:this.anchors.index(c)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(n){this.list=this.element.children("ul:first");this.lis=a("li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return a("a",this)[0]});this.panels=a([]);var p=this,d=this.options;var c=/^#.+/;this.anchors.each(function(r,o){var q=a(o).attr("href");var s=q.split("#")[0],u;if(s&&(s===location.toString().split("#")[0]||(u=a("base")[0])&&s===u.href)){q=o.hash;o.href=q}if(c.test(q)){p.panels=p.panels.add(p._sanitizeSelector(q))}else{if(q!="#"){a.data(o,"href.tabs",q);a.data(o,"load.tabs",q.replace(/#.*$/,""));var w=p._tabId(o);o.href="#"+w;var v=a("#"+w);if(!v.length){v=a(d.panelTemplate).attr("id",w).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(p.panels[r-1]||p.list);v.data("destroy.tabs",true)}p.panels=p.panels.add(v)}else{d.disabled.push(r)}}});if(n){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(d.selected===undefined){if(location.hash){this.anchors.each(function(q,o){if(o.hash==location.hash){d.selected=q;return false}})}if(typeof d.selected!="number"&&d.cookie){d.selected=parseInt(p._cookie(),10)}if(typeof d.selected!="number"&&this.lis.filter(".ui-tabs-selected").length){d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}d.selected=d.selected||0}else{if(d.selected===null){d.selected=-1}}d.selected=((d.selected>=0&&this.anchors[d.selected])||d.selected<0)?d.selected:0;d.disabled=a.unique(d.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(q,o){return p.lis.index(q)}))).sort();if(a.inArray(d.selected,d.disabled)!=-1){d.disabled.splice(a.inArray(d.selected,d.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(d.selected>=0&&this.anchors.length){this.panels.eq(d.selected).removeClass("ui-tabs-hide");this.lis.eq(d.selected).addClass("ui-tabs-selected ui-state-active");p.element.queue("tabs",function(){p._trigger("show",null,p._ui(p.anchors[d.selected],p.panels[d.selected]))});this.load(d.selected)}a(window).bind("unload",function(){p.lis.add(p.anchors).unbind(".tabs");p.lis=p.anchors=p.panels=null})}else{d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[d.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(d.cookie){this._cookie(d.selected,d.cookie)}for(var g=0,m;(m=this.lis[g]);g++){a(m)[a.inArray(g,d.disabled)!=-1&&!a(m).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(d.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(d.event!="mouseover"){var f=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var j=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){f("hover",a(this))});this.lis.bind("mouseout.tabs",function(){j("hover",a(this))});this.anchors.bind("focus.tabs",function(){f("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var b,h;if(d.fx){if(a.isArray(d.fx)){b=d.fx[0];h=d.fx[1]}else{b=h=d.fx}}function e(i,o){i.css({display:""});if(a.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var k=h?function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(h,h.duration||"normal",function(){e(o,h);p._trigger("show",null,p._ui(i,o[0]))})}:function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");p._trigger("show",null,p._ui(i,o[0]))};var l=b?function(o,i){i.animate(b,b.duration||"normal",function(){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");e(i,b);p.element.dequeue("tabs")})}:function(o,i,q){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");p.element.dequeue("tabs")};this.anchors.bind(d.event+".tabs",function(){var o=this,r=a(this).closest("li"),i=p.panels.filter(":not(.ui-tabs-hide)"),q=a(p._sanitizeSelector(this.hash));if((r.hasClass("ui-tabs-selected")&&!d.collapsible)||r.hasClass("ui-state-disabled")||r.hasClass("ui-state-processing")||p._trigger("select",null,p._ui(this,q[0]))===false){this.blur();return false}d.selected=p.anchors.index(this);p.abort();if(d.collapsible){if(r.hasClass("ui-tabs-selected")){d.selected=-1;if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){l(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this));this.blur();return false}}}if(d.cookie){p._cookie(d.selected,d.cookie)}if(q.length){if(i.length){p.element.queue("tabs",function(){l(o,i)})}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(a.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var c=a.data(this,"href.tabs");if(c){this.href=c}var d=a(this).unbind(".tabs");a.each(["href","load","cache"],function(e,f){d.removeData(f+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(a.data(this,"destroy.tabs")){a(this).remove()}else{a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(b.cookie){this._cookie(null,b.cookie)}},add:function(e,d,c){if(c===undefined){c=this.anchors.length}var b=this,g=this.options,i=a(g.tabTemplate.replace(/#\{href\}/g,e).replace(/#\{label\}/g,d)),h=!e.indexOf("#")?e.replace("#",""):this._tabId(a("a",i)[0]);i.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var f=a("#"+h);if(!f.length){f=a(g.panelTemplate).attr("id",h).data("destroy.tabs",true)}f.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(c>=this.lis.length){i.appendTo(this.list);f.appendTo(this.list[0].parentNode)}else{i.insertBefore(this.lis[c]);f.insertBefore(this.panels[c])}g.disabled=a.map(g.disabled,function(k,j){return k>=c?++k:k});this._tabify();if(this.anchors.length==1){i.addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[0],b.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[c],this.panels[c]))},remove:function(b){var d=this.options,e=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();if(e.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(b+(b+1=b?--g:g});this._tabify();this._trigger("remove",null,this._ui(e.find("a")[0],c[0]))},enable:function(b){var c=this.options;if(a.inArray(b,c.disabled)==-1){return}this.lis.eq(b).removeClass("ui-state-disabled");c.disabled=a.grep(c.disabled,function(e,d){return e!=b});this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]))},disable:function(c){var b=this,d=this.options;if(c!=d.selected){this.lis.eq(c).addClass("ui-state-disabled");d.disabled.push(c);d.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[c],this.panels[c]))}},select:function(b){if(typeof b=="string"){b=this.anchors.index(this.anchors.filter("[href$="+b+"]"))}else{if(b===null){b=-1}}if(b==-1&&this.options.collapsible){b=this.options.selected}this.anchors.eq(b).trigger(this.options.event+".tabs")},load:function(e){var c=this,g=this.options,b=this.anchors.eq(e)[0],d=a.data(b,"load.tabs");this.abort();if(!d||this.element.queue("tabs").length!==0&&a.data(b,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(e).addClass("ui-state-processing");if(g.spinner){var f=a("span",b);f.data("label.tabs",f.html()).html(g.spinner)}this.xhr=a.ajax(a.extend({},g.ajaxOptions,{url:d,success:function(i,h){a(c._sanitizeSelector(b.hash)).html(i);c._cleanup();if(g.cache){a.data(b,"cache.tabs",true)}c._trigger("load",null,c._ui(c.anchors[e],c.panels[e]));try{g.ajaxOptions.success(i,h)}catch(j){}c.element.dequeue("tabs")}}))},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup()},url:function(c,b){this.anchors.eq(c).removeData("cache.tabs").data("load.tabs",b)},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.7.2",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"
    ",spinner:"Loading…",tabTemplate:'
  • #{label}
  • '}});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(d,f){var b=this,g=this.options;var c=b._rotate||(b._rotate=function(h){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var i=g.selected;b.select(++i')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([:\[\]\.])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('
    '))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(appendText){inst.append=$(''+appendText+"");input[isRTL?"before":"after"](inst.append)}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==target){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(target)}return false})}input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst)},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst));this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,dateText,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});this._dialogInput.val(dateText);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;var browserHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",this._pos[0]+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i-1)}},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));$.datepicker._hideDatepicker(null,"");$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.rangeStart=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim")||"show";var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;if($.browser.msie&&parseInt($.browser.version,10)<7){$("iframe.ui-datepicker-cover").css({width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4})}};if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim](duration,postProcess)}if(duration==""){postProcess()}if(inst.input[0].type!="hidden"){inst.input[0].focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var dims={width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4};var self=this;inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({width:dims.width,height:dims.height}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst.input&&inst.input[0].type!="hidden"&&inst==$.datepicker._curInst){$(inst.input[0]).focus()}},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)+$(document).scrollLeft();var viewHeight=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0;offset.top-=(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(offset.top+dpHeight+inputHeight*2-viewHeight):0;return offset},_findPos:function(obj){while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj.nextSibling}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input,duration){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(inst.stayOpen){this._selectDate("#"+inst.id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))}inst.stayOpen=false;if(this._datepickerShowing){duration=(duration!=null?duration:this._get(inst,"duration"));var showAnim=this._get(inst,"showAnim");var postProcess=function(){$.datepicker._tidyDialog(inst)};if(duration!=""&&$.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(duration==""?"hide":(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide")))](duration,postProcess)}if(duration==""){this._tidyDialog(inst)}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}this._curInst=null},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if(($target.parents("#"+$.datepicker._mainDivId).length==0)&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker(null,"")}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input[0].focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;if(inst.stayOpen){inst.endDay=inst.endMonth=inst.endYear=null}this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));if(inst.stayOpen){inst.rangeStart=this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay));this._updateDatepicker(inst)}},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);inst.stayOpen=false;inst.endDay=inst.endMonth=inst.endYear=inst.rangeStart=null;this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{if(!inst.stayOpen){this._hideDatepicker(null,this._get(inst,"duration"));this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input[0].focus()}this._lastInput=null}}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getFullYear(),date.getMonth(),date.getDate());var firstMon=new Date(checkDate.getFullYear(),1-1,4);var firstDay=firstMon.getDay()||7;firstMon.setDate(firstMon.getDate()+1-firstDay);if(firstDay<4&&checkDatenew Date(checkDate.getFullYear(),12-1,28)){firstDay=new Date(checkDate.getFullYear()+1,1-1,4).getDay()||7;if(firstDay>4&&(checkDate.getDay()||7)0&&iValue="0"&&value.charAt(iValue)<="9"){num=num*10+parseInt(value.charAt(iValue++),10);size--}if(size==origSize){throw"Missing number at position "+iValue}return num};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);var size=0;for(var j=0;j0&&iValue-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TIMESTAMP:"@",W3C:"yy-mm-dd",formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1=0;m--){doy+=this._getDaysInMonth(date.getFullYear(),m)}output+=formatNumber("o",doy,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;for(var iFormat=0;iFormatmaxDate?maxDate:date);return date},_determineDate:function(date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset,getDaysInMonth){var date=new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date,this._getDaysInMonth):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,endDate){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._determineDate(date,new Date());inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if(origMonth!=inst.selectedMonth||origYear!=inst.selectedYear){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var stepBigMonths=this._get(inst,"stepBigMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-numMonths[1]+1,maxDate.getDate()));maxDraw=(minDate&&maxDrawmaxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?''+prevText+"":(hideIfNoPrevNext?"":''+prevText+""));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?''+nextText+"":(hideIfNoPrevNext?"":''+nextText+""));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'":"");var buttonPanel=(showButtonPanel)?'
    '+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'":"")+(isRTL?"":controls)+"
    ":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var endDate=inst.endDay?this._daylightSavingAdjust(new Date(inst.endYear,inst.endMonth,inst.endDay)):currentDate;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,row>0||col>0,monthNames,monthNamesShort)+'';var thead="";for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="=5?' class="ui-datepicker-week-end"':"")+'>'+dayNamesMin[day]+""}calender+=thead+"";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow";var tbody="";for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=otherMonth||!daySettings[0]||(minDate&&printDatemaxDate);tbody+='";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+""}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="
    =currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":" onclick=\"DP_jQuery.datepicker._selectDay('#"+inst.id+"',"+drawMonth+","+drawYear+', this);return false;"')+">"+(otherMonth?(showOtherMonths?printDate.getDate():" "):(unselectable?''+printDate.getDate()+"":'=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" ui-state-active":"")+'" href="#">'+printDate.getDate()+""))+"
    "+(isMultiMonth?""+((numMonths[0]>0&&col==numMonths[1]-1)?'
    ':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,secondary,monthNames,monthNamesShort){minDate=(inst.rangeStart&&minDate&&selectedDate "}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='"}if(!showMonthAfterYear){html+=monthHtml+((secondary||changeMonth||changeYear)&&(!(changeMonth&&changeYear))?" ":"")}if(secondary||!changeYear){html+=''+drawYear+""}else{var years=this._get(inst,"yearRange").split(":");var year=0;var endYear=0;if(years.length!=2){year=drawYear-10;endYear=drawYear+10}else{if(years[0].charAt(0)=="+"||years[0].charAt(0)=="-"){year=drawYear+parseInt(years[0],10);endYear=drawYear+parseInt(years[1],10)}else{year=parseInt(years[0],10);endYear=parseInt(years[1],10)}}year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='"}if(showMonthAfterYear){html+=(secondary||changeMonth||changeYear?" ":"")+monthHtml}html+="";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._daylightSavingAdjust(new Date(year,month,day));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&datemaxDate?maxDate:date);inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax,checkRange){var date=this._determineDate(this._get(inst,minMax+"Date"),null);return(!checkRange||!inst.rangeStart?date:(!date||inst.rangeStart>date?inst.rangeStart:date))},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var newMinDate=(!inst.rangeStart?null:this._daylightSavingAdjust(new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay)));newMinDate=(newMinDate&&inst.rangeStart=minDate)&&(!maxDate||date<=maxDate))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.7.2";window.DP_jQuery=$})(jQuery);;/* + * jQuery UI Progressbar 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.progressbar",{_init:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this._valueMin(),"aria-valuemax":this._valueMax(),"aria-valuenow":this._value()});this.valueDiv=a('
    ').appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow").removeData("progressbar").unbind(".progressbar");this.valueDiv.remove();a.widget.prototype.destroy.apply(this,arguments)},value:function(b){if(b===undefined){return this._value()}this._setData("value",b);return this},_setData:function(b,c){switch(b){case"value":this.options.value=c;this._refreshValue();this._trigger("change",null,{});break}a.widget.prototype._setData.apply(this,arguments)},_value:function(){var b=this.options.value;if(bthis._valueMax()){b=this._valueMax()}return b},_valueMin:function(){var b=0;return b},_valueMax:function(){var b=100;return b},_refreshValue:function(){var b=this.value();this.valueDiv[b==this._valueMax()?"addClass":"removeClass"]("ui-corner-right");this.valueDiv.width(b+"%");this.element.attr("aria-valuenow",b)}});a.extend(a.ui.progressbar,{version:"1.7.2",defaults:{value:0}})})(jQuery);;/* + * jQuery UI Effects 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/ + */ +jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(var f=0;f');var j=f.parent();if(f.css("position")=="static"){j.css({position:"relative"});f.css({position:"relative"})}else{var i=f.css("top");if(isNaN(parseInt(i,10))){i="auto"}var h=f.css("left");if(isNaN(parseInt(h,10))){h="auto"}j.css({position:f.css("position"),top:i,left:h,zIndex:f.css("z-index")}).show();f.css({position:"relative",top:0,left:0})}j.css(g);return j},removeWrapper:function(f){if(f.parent().is(".ui-effects-wrapper")){return f.parent().replaceWith(f)}return f},setTransition:function(g,i,f,h){h=h||{};d.each(i,function(k,j){unit=g.cssUnit(j);if(unit[0]>0){h[j]=unit[0]*f+unit[1]}});return h},animateClass:function(h,i,k,j){var f=(typeof k=="function"?k:(j?j:null));var g=(typeof k=="string"?k:null);return this.each(function(){var q={};var o=d(this);var p=o.attr("style")||"";if(typeof p=="object"){p=p.cssText}if(h.toggle){o.hasClass(h.toggle)?h.remove=h.toggle:h.add=h.toggle}var l=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.addClass(h.add)}if(h.remove){o.removeClass(h.remove)}var m=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.removeClass(h.add)}if(h.remove){o.addClass(h.remove)}for(var r in m){if(typeof m[r]!="function"&&m[r]&&r.indexOf("Moz")==-1&&r.indexOf("length")==-1&&m[r]!=l[r]&&(r.match(/color/i)||(!r.match(/color/i)&&!isNaN(parseInt(m[r],10))))&&(l.position!="static"||(l.position=="static"&&!r.match(/left|top|bottom|right/)))){q[r]=m[r]}}o.animate(q,i,g,function(){if(typeof d(this).attr("style")=="object"){d(this).attr("style")["cssText"]="";d(this).attr("style")["cssText"]=p}else{d(this).attr("style",p)}if(h.add){d(this).addClass(h.add)}if(h.remove){d(this).removeClass(h.remove)}if(f){f.apply(this,arguments)}})})}};function c(g,f){var i=g[1]&&g[1].constructor==Object?g[1]:{};if(f){i.mode=f}var h=g[1]&&g[1].constructor!=Object?g[1]:(i.duration?i.duration:g[2]);h=d.fx.off?0:typeof h==="number"?h:d.fx.speeds[h]||d.fx.speeds._default;var j=i.callback||(d.isFunction(g[1])&&g[1])||(d.isFunction(g[2])&&g[2])||(d.isFunction(g[3])&&g[3]);return[g[0],i,h,j]}d.fn.extend({_show:d.fn.show,_hide:d.fn.hide,__toggle:d.fn.toggle,_addClass:d.fn.addClass,_removeClass:d.fn.removeClass,_toggleClass:d.fn.toggleClass,effect:function(g,f,h,i){return d.effects[g]?d.effects[g].call(this,{method:g,options:f||{},duration:h,callback:i}):null},show:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._show.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"show"))}},hide:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._hide.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"hide"))}},toggle:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))||(d.isFunction(arguments[0])||typeof arguments[0]=="boolean")){return this.__toggle.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"toggle"))}},addClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{add:g},f,i,h]):this._addClass(g)},removeClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{remove:g},f,i,h]):this._removeClass(g)},toggleClass:function(g,f,i,h){return((typeof f!=="boolean")&&f)?d.effects.animateClass.apply(this,[{toggle:g},f,i,h]):this._toggleClass(g,f)},morph:function(f,h,g,j,i){return d.effects.animateClass.apply(this,[{add:h,remove:f},g,j,i])},switchClass:function(){return this.morph.apply(this,arguments)},cssUnit:function(f){var g=this.css(f),h=[];d.each(["em","px","%","pt"],function(j,k){if(g.indexOf(k)>0){h=[parseFloat(g),k]}});return h}});d.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(g,f){d.fx.step[f]=function(h){if(h.state==0){h.start=e(h.elem,f);h.end=b(h.end)}h.elem.style[f]="rgb("+[Math.max(Math.min(parseInt((h.pos*(h.end[0]-h.start[0]))+h.start[0],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[1]-h.start[1]))+h.start[1],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[2]-h.start[2]))+h.start[2],10),255),0)].join(",")+")"}});function b(g){var f;if(g&&g.constructor==Array&&g.length==3){return g}if(f=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(g)){return[parseInt(f[1],10),parseInt(f[2],10),parseInt(f[3],10)]}if(f=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(g)){return[parseFloat(f[1])*2.55,parseFloat(f[2])*2.55,parseFloat(f[3])*2.55]}if(f=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(g)){return[parseInt(f[1],16),parseInt(f[2],16),parseInt(f[3],16)]}if(f=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(g)){return[parseInt(f[1]+f[1],16),parseInt(f[2]+f[2],16),parseInt(f[3]+f[3],16)]}if(f=/rgba\(0, 0, 0, 0\)/.exec(g)){return a.transparent}return a[d.trim(g).toLowerCase()]}function e(h,f){var g;do{g=d.curCSS(h,f);if(g!=""&&g!="transparent"||d.nodeName(h,"body")){break}f="backgroundColor"}while(h=h.parentNode);return b(g)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};d.easing.jswing=d.easing.swing;d.extend(d.easing,{def:"easeOutQuad",swing:function(g,h,f,j,i){return d.easing[d.easing.def](g,h,f,j,i)},easeInQuad:function(g,h,f,j,i){return j*(h/=i)*h+f},easeOutQuad:function(g,h,f,j,i){return -j*(h/=i)*(h-2)+f},easeInOutQuad:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h+f}return -j/2*((--h)*(h-2)-1)+f},easeInCubic:function(g,h,f,j,i){return j*(h/=i)*h*h+f},easeOutCubic:function(g,h,f,j,i){return j*((h=h/i-1)*h*h+1)+f},easeInOutCubic:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h+f}return j/2*((h-=2)*h*h+2)+f},easeInQuart:function(g,h,f,j,i){return j*(h/=i)*h*h*h+f},easeOutQuart:function(g,h,f,j,i){return -j*((h=h/i-1)*h*h*h-1)+f},easeInOutQuart:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h+f}return -j/2*((h-=2)*h*h*h-2)+f},easeInQuint:function(g,h,f,j,i){return j*(h/=i)*h*h*h*h+f},easeOutQuint:function(g,h,f,j,i){return j*((h=h/i-1)*h*h*h*h+1)+f},easeInOutQuint:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h*h+f}return j/2*((h-=2)*h*h*h*h+2)+f},easeInSine:function(g,h,f,j,i){return -j*Math.cos(h/i*(Math.PI/2))+j+f},easeOutSine:function(g,h,f,j,i){return j*Math.sin(h/i*(Math.PI/2))+f},easeInOutSine:function(g,h,f,j,i){return -j/2*(Math.cos(Math.PI*h/i)-1)+f},easeInExpo:function(g,h,f,j,i){return(h==0)?f:j*Math.pow(2,10*(h/i-1))+f},easeOutExpo:function(g,h,f,j,i){return(h==i)?f+j:j*(-Math.pow(2,-10*h/i)+1)+f},easeInOutExpo:function(g,h,f,j,i){if(h==0){return f}if(h==i){return f+j}if((h/=i/2)<1){return j/2*Math.pow(2,10*(h-1))+f}return j/2*(-Math.pow(2,-10*--h)+2)+f},easeInCirc:function(g,h,f,j,i){return -j*(Math.sqrt(1-(h/=i)*h)-1)+f},easeOutCirc:function(g,h,f,j,i){return j*Math.sqrt(1-(h=h/i-1)*h)+f},easeInOutCirc:function(g,h,f,j,i){if((h/=i/2)<1){return -j/2*(Math.sqrt(1-h*h)-1)+f}return j/2*(Math.sqrt(1-(h-=2)*h)+1)+f},easeInElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h").css({position:"absolute",visibility:"visible",left:-d*(g/e),top:-f*(c/k)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/e,height:c/k,left:l.left+d*(g/e)+(b.options.mode=="show"?(d-Math.floor(e/2))*(g/e):0),top:l.top+f*(c/k)+(b.options.mode=="show"?(f-Math.floor(k/2))*(c/k):0),opacity:b.options.mode=="show"?0:1}).animate({left:l.left+d*(g/e)+(b.options.mode=="show"?0:(d-Math.floor(e/2))*(g/e)),top:l.top+f*(c/k)+(b.options.mode=="show"?0:(f-Math.floor(k/2))*(c/k)),opacity:b.options.mode=="show"?1:0},b.duration||500)}}setTimeout(function(){b.options.mode=="show"?h.css({visibility:"visible"}):h.css({visibility:"visible"}).hide();if(b.callback){b.callback.apply(h[0])}h.dequeue();a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);;/* + * jQuery UI Effects Fold 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.fold=function(b){return this.queue(function(){var e=a(this),k=["position","top","left"];var h=a.effects.setMode(e,b.options.mode||"hide");var o=b.options.size||15;var n=!(!b.options.horizFirst);var g=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(e,k);e.show();var d=a.effects.createWrapper(e).css({overflow:"hidden"});var i=((h=="show")!=n);var f=i?["width","height"]:["height","width"];var c=i?[d.width(),d.height()]:[d.height(),d.width()];var j=/([0-9]+)%/.exec(o);if(j){o=parseInt(j[1],10)/100*c[h=="hide"?0:1]}if(h=="show"){d.css(n?{height:0,width:o}:{height:o,width:0})}var m={},l={};m[f[0]]=h=="show"?c[0]:o;l[f[1]]=h=="show"?c[1]:0;d.animate(m,g,b.options.easing).animate(l,g,b.options.easing,function(){if(h=="hide"){e.hide()}a.effects.restore(e,k);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(e[0],arguments)}e.dequeue()})})}})(jQuery);;/* + * jQuery UI Effects Highlight 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.highlight=function(b){return this.queue(function(){var e=a(this),d=["backgroundImage","backgroundColor","opacity"];var h=a.effects.setMode(e,b.options.mode||"show");var c=b.options.color||"#ffff99";var g=e.css("backgroundColor");a.effects.save(e,d);e.show();e.css({backgroundImage:"none",backgroundColor:c});var f={backgroundColor:g};if(h=="hide"){f.opacity=0}e.animate(f,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(h=="hide"){e.hide()}a.effects.restore(e,d);if(h=="show"&&a.browser.msie){this.style.removeAttribute("filter")}if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);;/* + * jQuery UI Effects Pulsate 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.pulsate=function(b){return this.queue(function(){var d=a(this);var g=a.effects.setMode(d,b.options.mode||"show");var f=b.options.times||5;var e=b.duration?b.duration/2:a.fx.speeds._default/2;if(g=="hide"){f--}if(d.is(":hidden")){d.css("opacity",0);d.show();d.animate({opacity:1},e,b.options.easing);f=f-2}for(var c=0;c').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);; \ No newline at end of file diff --git a/www/static/js/jquery.js b/www/static/js/jquery.js new file mode 100644 index 0000000..b1ae21d --- /dev/null +++ b/www/static/js/jquery.js @@ -0,0 +1,19 @@ +/* + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
    "]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
    ","
    "]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); +/* + * Sizzle CSS Selector Engine - v0.9.3 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

    ";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
    ";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
    ").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
    ';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/www/static/js/jquery.megamenu.js b/www/static/js/jquery.megamenu.js new file mode 100644 index 0000000..2d4ea16 --- /dev/null +++ b/www/static/js/jquery.megamenu.js @@ -0,0 +1,120 @@ +/*jQuery MegaMenu Plugin + Author: Devadatta Sahoo + Author URI: http://www.geektantra.com */ +var isIE6 = navigator.userAgent.toLowerCase().indexOf('msie 6') != -1; +(function($){ + $.fn.extend({ + isChildOf: function(filter_string){ + var parents = $(this).parents().get(); + for (j = 0; j < parents.length; j++) { + if ($(parents[j]).is(filter_string)) + return true; + } + return false; + } + }); +})(jQuery); + +jQuery.fn.megamenu = function(ContentClass, Options){ + var MenuClass = $(this).attr("class").split(" ")[0]; + var ParentNodeNumber = 0; + Options = jQuery.extend({ + width: "auto", + justify: "left" + }, Options); + $(ContentClass).after(' '); + $(this).mouseover(function(){ + var MenuContent = $(this).next(ContentClass).html(); + ParentNodeNumber = $('.' + MenuClass).index(this); + MegaMenuMouseOver(ParentNodeNumber, MenuContent, "click", MenuClass, ContentClass, Options); + //setTimeout('MegaMenuMouseOver('+ParentNodeNumber+',"'+escape(MenuContent)+'","hover",\''+MenuClass+'\',\''+ContentClass+'\',\''+Options+'\')', 300); + }); + $(this).click(function(){ + var MenuContent = $(this).next('.MegaMenuContent').html(); + ParentNodeNumber = $('.' + MenuClass).index(this); + MegaMenuMouseOver(ParentNodeNumber, MenuContent, "click", MenuClass, ContentClass, Options); + }); + $(this).mouseout(function(){ + MegaMenuMouseOut(ParentNodeNumber, MenuClass, ContentClass); + }); + $(document).bind('click', function(e){ + var $clicked = $(e.target); + if ($clicked.isChildOf('#MegaMenuContent') || $clicked.is('#MegaMenuContent') || $clicked.is('.' + MenuClass)) { + } + else + MegaMenuMouseOut(ParentNodeNumber, MenuClass, ContentClass); + }); +}; + +function MegaMenuMouseOver(ParentNodeNumber, MenuContent, state, MenuLinkClass, MenuContentClass, Options){ + var MenuLinkClass = (typeof(MenuLinkClass) == 'undefined') ? ".MegaMenuLink" : MenuLinkClass; + var MenuContentClass = (typeof(MenuContentClass) == 'undefined') ? ".MegaMenuContent" : MenuContentClass; + + //var Options = eval('(' + Options + ')'); + if (state == "hover") + $('.' + MenuLinkClass).removeClass(MenuLinkClass + 'Active'); + $('.' + MenuLinkClass).eq(ParentNodeNumber).addClass(MenuLinkClass + 'Active'); + + var selfNode = new Array(); + selfNode['width'] = $('.' + MenuLinkClass).eq(ParentNodeNumber).width(); + selfNode['padding-left'] = parseInt($('.' + MenuLinkClass).eq(ParentNodeNumber).css('padding-left').replace(/px/g, '')); + selfNode['padding-right'] = parseInt($('.' + MenuLinkClass).eq(ParentNodeNumber).css('padding-right').replace(/px/g, '')); + selfNode['border-left-width'] = parseInt($('.' + MenuLinkClass).eq(ParentNodeNumber).css('border-left-width').replace(/px/g, '')); + selfNode['border-right-width'] = parseInt($('.' + MenuLinkClass).eq(ParentNodeNumber).css('border-right-width').replace(/px/g, '')); + if (isIE6) + selfNode['width'] = selfNode['width'] + 10; + + if (Options['justify'] == "left") { + var LeftPos = $('.' + MenuLinkClass).eq(ParentNodeNumber).parent().position().left; + if (Options['width'] == 'auto') + LeftPos = $('.' + MenuLinkClass).eq(ParentNodeNumber).position().left - 10; + } + else { + var RightPos = $('.' + MenuLinkClass).eq(ParentNodeNumber).parent().position().left; + if (Options['width'] == 'auto') + RightPos = $(document).width() - 10 - $('.' + MenuLinkClass).eq(ParentNodeNumber).position().left - selfNode['width'] - selfNode['padding-left'] - selfNode['padding-right'] - selfNode['border-left-width'] - selfNode['border-right-width']; + } + + var TopPos = $('.' + MenuLinkClass).eq(ParentNodeNumber).height() + $('.' + MenuLinkClass).eq(ParentNodeNumber).position().top + parseInt($('.' + MenuLinkClass).eq(ParentNodeNumber).css("padding-top").replace(/px/g, '')) + parseInt($('.' + MenuLinkClass).eq(ParentNodeNumber).css("padding-bottom").replace(/px/g, '')) + parseInt($('.' + MenuLinkClass).eq(ParentNodeNumber).css("border-top-width").replace(/px/g, '')); + + MenuContent = unescape(MenuContent); + + if (LeftPos) { + $("#MegaMenuContent").css('left', LeftPos + 'px'); + $("#MegaMenuContentShadow").css('left', (LeftPos) + 'px'); + } + else { + $("#MegaMenuContent").css('right', RightPos + 'px'); + $("#MegaMenuContentShadow").css('right', (RightPos - 4) + 'px'); + } + $("#MegaMenuContent").css('top', TopPos + 'px'); + $("#MegaMenuContentShadow").css('top', TopPos + 'px'); + if (Options['width']) { + $("#MegaMenuContent").css('width', Options['width']); + $("#MegaMenuContentShadow").css('width', Options['width']); + } + $("#MegaMenuContent").html('' + MenuContent); + $("#MegaMenuContent").slideDown("fast"); + $("#MegaMenuContentShadow").html('' + MenuContent); + $("#MegaMenuContentShadow").slideDown("fast"); + + $("#MegaMenuContent,#MegaMenuContentShadow").mouseover(function(){ + $('#MegaMenuContent').show(); + $('#MegaMenuContentShadow').show(); + + $('.' + MenuLinkClass).removeClass(MenuLinkClass + 'Active'); + $('.' + MenuLinkClass).eq(ParentNodeNumber).addClass(MenuLinkClass + 'Active'); + }); + $("#MegaMenuContent,#MegaMenuContentShadow").mouseout(function(){ + $("#MegaMenuContent").hide() + $("#MegaMenuContentShadow").hide() + $('.' + MenuLinkClass).removeClass(MenuLinkClass + 'Active'); + }); +} + +function MegaMenuMouseOut(ParentNodeNumber, MenuLinkClass, MenuContentClass){ + $('#MegaMenuContent').hide(); + $('#MegaMenuContentShadow').hide(); + var MenuLinkClass = (typeof(MenuLinkClass) == 'undefined') ? ".MegaMenuLink" : MenuLinkClass; + $('.' + MenuLinkClass).eq(ParentNodeNumber).removeClass(MenuLinkClass + 'Active'); +} diff --git a/www/include/jquery.progressbar.min.js b/www/static/js/jquery.progressbar.js similarity index 87% rename from www/include/jquery.progressbar.min.js rename to www/static/js/jquery.progressbar.js index af1b87b..54229d2 100644 --- a/www/include/jquery.progressbar.min.js +++ b/www/static/js/jquery.progressbar.js @@ -1,5 +1,5 @@ -(function($){$.extend({progressBar:new function(){this.defaults={steps:20,step_duration:20,max:100,showText:true,textFormat:'percentage',width:120,height:12,callback:null,boxImage:'/images/progressbar.gif',barImage:{0:'/images/progressbg_green.gif',30:'/images/progressbg_orange.gif',70:'/images/progressbg_red.gif'},running_value:0,value:0,image:null};this.construct=function(arg1,arg2){var argvalue=null;var argconfig=null;if(arg1!=null){if(!isNaN(arg1)){argvalue=arg1;if(arg2!=null){argconfig=arg2;}}else{argconfig=arg1;}} +(function($){$.extend({progressBar:new function(){this.defaults={steps:20,step_duration:20,max:100,showText:true,textFormat:'percentage',width:120,height:12,callback:null,boxImage:'/static/images/progressbar.gif',barImage:{0:'/static/images/progressbg_green.gif',30:'/static/images/progressbg_orange.gif',70:'/static/images/progressbg_red.gif'},running_value:0,value:0,image:null};this.construct=function(arg1,arg2){var argvalue=null;var argconfig=null;if(arg1!=null){if(!isNaN(arg1)){argvalue=arg1;if(arg2!=null){argconfig=arg2;}}else{argconfig=arg1;}} return this.each(function(child){var pb=this;var config=this.config;if(argvalue!=null&&this.bar!=null&&this.config!=null){this.config.value=argvalue if(argconfig!=null) pb.config=$.extend(this.config,argconfig);config=pb.config;}else{var $this=$(this);var config=$.extend({},$.progressBar.defaults,argconfig);config.id=$this.attr('id')?$this.attr('id'):Math.ceil(Math.random()*100000);if(argvalue==null) diff --git a/www/templates/base.html b/www/templates/base.html new file mode 100644 index 0000000..2e83bba --- /dev/null +++ b/www/templates/base.html @@ -0,0 +1,97 @@ + + + + + + {% block title %}{{ title }}{% end block %} + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + {% block content %} + {% end block %} +
    +
    +
    +
    +
    + {% block sidebar %} + {{ modules.SidebarBanner(banner) }} + {% end block %} +
    +
    +
    +
    +
    +
    + {% block javascript %}{% end block %} + + diff --git a/www/templates/builds.html b/www/templates/builds.html new file mode 100644 index 0000000..d3934c3 --- /dev/null +++ b/www/templates/builds.html @@ -0,0 +1,44 @@ +{% extends "base.html" %} + +{% block title %}{{ _("Builds") }}{% end block %} + +{% block content %} +

    {{ _("Nightly builds") }}

    + + + + {% if builds["<12h"] %} + + + + {% for build in builds["<12h"] %} + {{ modules.Build(build) }} + {% end %} + {% end %} + + {% if builds[">12h"] %} + + + + {% for build in builds[">12h"] %} + {{ modules.Build(build) }} + {% end %} + {% end %} + + {% if builds[">24h"] %} + + + + {% for build in builds[">24h"] %} + {{ modules.Build(build) }} + {% end %} + {% end %} + +
    + {{ _("Less than 12 hours ago") }} +
    + {{ _("More than 12 hours ago") }} +
    + {{ _("More than a day ago") }} +
    +{% end block %} diff --git a/www/templates/downloads-all.html b/www/templates/downloads-all.html new file mode 100644 index 0000000..816491f --- /dev/null +++ b/www/templates/downloads-all.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block content %} +
    +

    {{ _("Download IPFire") }}

    + +

    + {{ _("These are the ancient downloads of IPFire. They are just saved for historical reasons and should not be used in a productive environment.") }} +

    + +

    + {{ _("Get back to latest downloads.") }} +

    + +
    +
    + + {% for release in releases.stable %} + {% if not release == releases.latest %} + {{ modules.ReleaseItem(release) }} + {% end %} + {% end %} +{% end block %} diff --git a/www/templates/downloads-development.html b/www/templates/downloads-development.html new file mode 100644 index 0000000..cc841dc --- /dev/null +++ b/www/templates/downloads-development.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block content %} +
    +

    {{ _("Development Downloads") }}

    + +

    + NEED TO FILL IN TEXT +

    + +

    + {{ _("Get back to latest stable downloads.") }} +

    + +
    +
    + + {% for release in releases.development %} + {{ modules.ReleaseItem(release) }} + {% end %} +{% end block %} diff --git a/www/templates/downloads-torrents.html b/www/templates/downloads-torrents.html new file mode 100644 index 0000000..e256b20 --- /dev/null +++ b/www/templates/downloads-torrents.html @@ -0,0 +1,43 @@ +{% extends "base.html" %} + +{% block content %} +
    + +

    {{ _("IPFire Torrent Tracker") }}

    + +

    + {{ _("This is the latest version of the IPFire firewall distribution.") }} + Need to fill in some more text at this place. +

    + + + + + + + + + + {% for release in releases %} + + + + + + + + {% end %} +
    {{ _("Release") }}{{ _("File") }}SP 
    {{ release.name }}{{ release.torrent.file }}{{ hashes[release.torrent.hash].get("seeds", _("N/A")) }}{{ hashes[release.torrent.hash].get("peers", _("N/A")) }} + + {{ _( + +
    + +

    + {{ _("Got that information from %s within %.2f second(s).") % (tracker, request_time) }} +

    + +
    +
    + +{% end block %} diff --git a/www/templates/downloads.html b/www/templates/downloads.html new file mode 100644 index 0000000..78826df --- /dev/null +++ b/www/templates/downloads.html @@ -0,0 +1,42 @@ +{% extends "base.html" %} + +{% block content %} +
    + +

    {{ _("Download IPFire") }}

    + +

    + {{ _("This is the latest version of the IPFire firewall distribution.") }} + Need to fill in some more text at this place. +

    + +
    + {{ _("Begin download") }} + +
    + + + {% for download in release.downloads %} + + + + {% end %} +
    + {{ _(download.desc) }} +
    + +
    +
    + +
    + +

    {{ _("Other download options") }}

    + + +
    +
    +{% end block %} diff --git a/www/templates/error-404.html b/www/templates/error-404.html new file mode 100644 index 0000000..0535c63 --- /dev/null +++ b/www/templates/error-404.html @@ -0,0 +1 @@ +{% extends "error.html" %} diff --git a/www/templates/error-500.html b/www/templates/error-500.html new file mode 100644 index 0000000..a386c66 --- /dev/null +++ b/www/templates/error-500.html @@ -0,0 +1,13 @@ +{% extends "error.html" %} + +{% block explanation %} +
    + +

    {{ _("Detailed information") }}

    + + {% if lang == "de" %} + Bei der Verarbeitung der Anfrage kam es zu einem internen Problem + des Webservers.
    Sollten nähere Informationen verfügbar sein, so + sind diese untenstehend angehangen. + {% end %} +{% end block %} diff --git a/www/templates/error.html b/www/templates/error.html new file mode 100644 index 0000000..61df7c7 --- /dev/null +++ b/www/templates/error.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% block title %}{{ _("Error") }} {{ code }}{% end block %} + +{% block content %} +

    {{ code }} - {{ message }}

    + {{ _( + + {% if lang == "de" %} + Leider ist ein unerwarteter Fehler beim Laden der Seite aufgetreten. +

    + Das ist erstmal kein Grund zur Panik. +

    + Sollte dies das erstmalige Auftreten des Fehlers sein, so bitten wir + einige Zeit abzuwarten. Sollte der Fehler jedoch an dieser Stelle + regelmäßig auftreten, so würden sich die Webmaster über eine kleine + Benachrichtigung freuen. + {% else %} + en 404 + {% end %} + + {% block explanation %}{% end block %} + + {% if exception %} +
    {{ exception }}
    + {% end %} +{% end block %} diff --git a/www/templates/index.html b/www/templates/index.html new file mode 100644 index 0000000..91d603b --- /dev/null +++ b/www/templates/index.html @@ -0,0 +1,62 @@ +{% extends "base.html" %} + +{% block title %}{{ _("Home") }}{% end block %} + +{% block content %} +

    {{ _("More security for your network") }}

    + +

    + {% if lang == "de" %} + Das IPFire-System ist eine Linux-Distribution, welche + die Zielsetzung hat ein einfach zu installierendes Grundsystem zu bieten + und dabei ein hohes Sicherheitsniveau zu gewährleisten. +
    + IPFire ist komplett über sein intuitiv zu bedienendes + Webinterface zu konfigurieren und bietet sowohl Anfängern, + als auch erfahrenen Administratoren eine Fülle von + Einstellungsmöglichkeiten. Ein Schwerpunkt bei der + Weiterentwickling legen die erfahrenen Entwickler klar auf regelmäßige + System und vor allem Sicherheitsupdates. + + Durch den integrierten Paketmanager Pakfire lässt sich + der IPFire mit diversen + Addons, + bishin zu einem Server-System erweitern. + {% else %} + IPFire is a linux-distribution that focusses on easy + setup, good handling and a high niveau of security. +
    + It is operable via an intuitive webinterface, which offers a lot of + playground for beginners and even experienced + administrators. + IPFire is maintained by experienced developers, who + are really concerned about security and regulary updates to + keep it secure. + + IPFire ships with a custom built paket-manager called + Pakfire, so the system can be expanded with various + addons. + {% end %} +

    + + + +

    {{ _("News") }}

    + + {% for item in news.get(2) %} + {{ modules.NewsItem(item) }} + {% end %} + +

    + {{ _("Previous posts >>") }} +

    +{% end block %} + +{% block sidebar %} + {{ modules.SidebarRelease() }} + {{ modules.SidebarBanner(banner) }} +{% end block %} diff --git a/www/templates/modules/builds.html b/www/templates/modules/builds.html new file mode 100644 index 0000000..5b24269 --- /dev/null +++ b/www/templates/modules/builds.html @@ -0,0 +1,15 @@ + + + IPFire + + +  
    + {{ build.release }} ({{ build.arch }})
    + {{ build.date }} + + +  
    + {{ build.iso }} | {{ build.size }}
    + {{ build.pxe }}  + + diff --git a/www/templates/modules/menu-item.html b/www/templates/modules/menu-item.html new file mode 100644 index 0000000..637a456 --- /dev/null +++ b/www/templates/modules/menu-item.html @@ -0,0 +1,65 @@ +{{ item.name }} +{% if item.args.has_key("items") %} +
    + + + {% for item2 in item.items %} + + {% end %} + + + + + + + + +
    +
    + {{ item.uri }} +
    +
    +
    + Second Heading +
    +
    +
    + Third Heading +
    +
    + + + + + +
    +
    + +{% end %} diff --git a/www/templates/modules/menu.html b/www/templates/modules/menu.html new file mode 100644 index 0000000..5ca3982 --- /dev/null +++ b/www/templates/modules/menu.html @@ -0,0 +1,7 @@ + diff --git a/www/templates/modules/news-item.html b/www/templates/modules/news-item.html new file mode 100644 index 0000000..0cd5add --- /dev/null +++ b/www/templates/modules/news-item.html @@ -0,0 +1,6 @@ +
    + +

    {{ item.subject }}

    + + {{ item.content }} +
    diff --git a/www/templates/modules/release-item.html b/www/templates/modules/release-item.html new file mode 100644 index 0000000..b162a2e --- /dev/null +++ b/www/templates/modules/release-item.html @@ -0,0 +1,15 @@ +
    + +

    {{ item.name }}

    +

    + Das ist das ISO inklusive dem letzten Core Update 33. +

    + +
    + {% for download in item.downloads %} + {{ _(download.desc) }}
    + {% end %} +
    + +
    +
    diff --git a/www/templates/modules/sidebar-banner.html b/www/templates/modules/sidebar-banner.html new file mode 100644 index 0000000..fa5baa7 --- /dev/null +++ b/www/templates/modules/sidebar-banner.html @@ -0,0 +1,5 @@ +

    {{ item.title }}

    + + + {{ _( + diff --git a/www/templates/modules/sidebar-item.html b/www/templates/modules/sidebar-item.html new file mode 100644 index 0000000..7ebff07 --- /dev/null +++ b/www/templates/modules/sidebar-item.html @@ -0,0 +1,2 @@ +

    {% block heading %}{{ item.heading }}{% end block %}

    +{% block body %}{{ item.body }}{% end block %} diff --git a/www/templates/modules/sidebar-release.html b/www/templates/modules/sidebar-release.html new file mode 100644 index 0000000..0483673 --- /dev/null +++ b/www/templates/modules/sidebar-release.html @@ -0,0 +1,23 @@ +{% extends "sidebar-item.html" %} + +{% block heading %}{{ _("release information") }}{% end block %} + +{% block body %} +

    + Tux Logo +

    + +

    + {{ _("Current version") }}: +
    + {{ releases.latest.name }} +

    + + {% if releases.latest_devel %} +

    + {{ _("Current unstable") }}: +
    + {{ releases.latest_devel.name }} +

    + {% end %} +{% end block %} diff --git a/www/templates/news.html b/www/templates/news.html new file mode 100644 index 0000000..e6b98d0 --- /dev/null +++ b/www/templates/news.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} + {% for item in news.get() %} + {{ modules.NewsItem(item) }} + {% end %} +{% end block %} diff --git a/www/templates/static/cluster.html b/www/templates/static/cluster.html new file mode 100644 index 0000000..b5d4cea --- /dev/null +++ b/www/templates/static/cluster.html @@ -0,0 +1,35 @@ +{% extends "../base.html" %} + +{% block title %}{{ _("Cluster") }}{% end block %} + +{% block content %} +

    {{ _("Icecream Cluster Monitoring") }}

    + +

    {{ _("Cluster's CPU load") }}: + + - {{ _("Job load") }}: + +

    + + + + + + + + + + + + + +
    {{ _("Name") }}{{ _("Arch") }}{{ _("CPU-Load") }}{{ _("Jobs") }}{{ _("Speed") }}
    + +

     
    {{ _("Number of nodes") }}: -

    + +{% end block %} + +{% block javascript %} + + +{% end block %} diff --git a/www/templates/static/imprint.html b/www/templates/static/imprint.html new file mode 100644 index 0000000..de4a9c3 --- /dev/null +++ b/www/templates/static/imprint.html @@ -0,0 +1,109 @@ +{% extends "../base.html" %} + +{% block title %}{{ _("Imprint") }}{% end block %} + +{% block content %} +

    {{ _("Imprint") }}

    + + {% if lang == "de" %} +

    + Dieses Projekt ist ein Open-Source-Projekt und verfolgt keine kommerziellen Ziele. +

    + +

    + Verantwortliche im Sinne von § 5 TMG, § 55 RfStV: +
    + + Michael Tremer (michael@ipfire.org)
    + Gerhardstrasse 8
    + 45711 Datteln

    + + Christian Schmidt (maniacikarus@ipfire.org)
    + Mathildenstr. 25
    + 90489 Nürnberg

    + +

    + +

    Haftungsausschluss

    +

    + 1. Inhalt des Onlineangebotes
    + Der Autor übernimmt keinerlei Gewähr für die Aktualität, Korrektheit, Vollständigkeit + oder Qualität der bereitgestellten Informationen. Haftungsansprüche gegen den Autor, + welche sich auf Schäden materieller oder ideeller Art beziehen, die durch die Nutzung + oder Nichtnutzung der dargebotenen Informationen bzw. durch die Nutzung fehlerhafter + und unvollständiger Informationen verursacht wurden, sind grundsätzlich ausgeschlossen, + sofern seitens des Autors kein nachweislich vorsätzliches oder grob fahrlässiges + Verschulden vorliegt.
    + Alle Angebote sind freibleibend und unverbindlich. Der Autor behält es sich ausdrücklich vor, + Teile der Seiten oder das gesamte Angebot ohne gesonderte Ankündigung zu verändern, + zu ergänzen, zu löschen oder die Veröffentlichung zeitweise oder endgültig einzustellen. +

    + +

    + 2. Verweise und Links
    + Bei direkten oder indirekten Verweisen auf fremde Internetseiten ("Links"), + die außerhalb des Verantwortungsbereiches des Autors liegen, würde eine + Haftungsverpflichtung ausschließlich in dem Fall in Kraft treten, in dem der + Autor von den Inhalten Kenntnis hat und es ihm technisch möglich und zumutbar wäre, + die Nutzung im Falle rechtswidriger Inhalte zu verhindern.
    + Der Autor erklärt hiermit ausdrücklich, dass zum Zeitpunkt der Linksetzung keine + illegalen Inhalte auf den zu verlinkenden Seiten erkennbar waren. + Auf die aktuelle und zukünftige Gestaltung, die Inhalte oder die Urheberschaft + der gelinkten/verknüpften Seiten hat der Autor keinerlei Einfluss. Deshalb distanziert + er sich hiermit ausdrücklich von allen Inhalten aller gelinkten /verknüpften Seiten, + die nach der Linksetzung verändert wurden. Diese Feststellung gilt für alle innerhalb + des eigenen Internetangebotes gesetzten Links und Verweise sowie für Fremdeinträge + in vom Autor eingerichteten Gästebüchern, Diskussionsforen und Mailinglisten. + Für illegale, fehlerhafte oder unvollständige Inhalte und insbesondere für Schäden, + die aus der Nutzung oder Nichtnutzung solcherart dargebotener Informationen entstehen, + haftet allein der Anbieter der Seite, auf welche verwiesen wurde, nicht derjenige, + der über Links auf die jeweilige Veröffentlichung lediglich verweist. +

    + +

    + 3. Urheber- und Kennzeichenrecht
    + Der Autor ist bestrebt, in allen Publikationen die Urheberrechte der verwendeten Grafiken, + Tondokumente, Videosequenzen und Texte zu beachten, von ihm selbst erstellte Grafiken, + Tondokumente, Videosequenzen und Texte zu nutzen oder auf lizenzfreie Grafiken, Tondokumente, + Videosequenzen und Texte zurückzugreifen.
    + Alle innerhalb des Internetangebotes genannten und ggf. durch Dritte geschützten Marken- + und Warenzeichen unterliegen uneingeschränkt den Bestimmungen des jeweils gültigen Kennzeichenrechts + und den Besitzrechten der jeweiligen eingetragenen Eigentümer. Allein aufgrund der bloßen Nennung + ist nicht der Schluss zu ziehen, dass Markenzeichen nicht durch Rechte Dritter geschützt sind!
    + Das Copyright für veröffentlichte, vom Autor selbst erstellte Objekte bleibt allein beim Autor der Seiten. + Eine Vervielfältigung oder Verwendung solcher Grafiken, Tondokumente, Videosequenzen und Texte in + anderen elektronischen oder gedruckten Publikationen ist ohne ausdrückliche Zustimmung des Autors nicht gestattet. +

    + +

    + 4. Datenschutz
    + Sofern innerhalb des Internetangebotes die Möglichkeit zur Eingabe persönlicher oder geschäftlicher Daten + (Emailadressen, Namen, Anschriften) besteht, so erfolgt die Preisgabe dieser Daten seitens + des Nutzers auf ausdrücklich freiwilliger Basis. Die Inanspruchnahme und Bezahlung aller + angebotenen Dienste ist - soweit technisch möglich und zumutbar - auch ohne Angabe solcher Daten + bzw. unter Angabe anonymisierter Daten oder eines Pseudonyms gestattet. Die Nutzung der im Rahmen + des Impressums oder vergleichbarer Angaben veröffentlichten Kontaktdaten wie Postanschriften, + Telefon- und Faxnummern sowie Emailadressen durch Dritte zur Übersendung von nicht ausdrücklich + angeforderten Informationen ist nicht gestattet. Rechtliche Schritte gegen die Versender von + sogenannten Spam- Mails bei Verstössen gegen dieses Verbot sind ausdrücklich vorbehalten. +

    + +

    + 5. Rechtswirksamkeit dieses Haftungsausschlusses
    + Dieser Haftungsausschluss ist als Teil des Internetangebotes zu betrachten, von dem aus auf diese + Seite verwiesen wurde. Sofern Teile oder einzelne Formulierungen dieses Textes der geltenden + Rechtslage nicht, nicht mehr oder nicht vollständig entsprechen sollten, bleiben die übrigen + Teile des Dokumentes in ihrem Inhalt und ihrer Gültigkeit davon unberührt. +

    + +

    + Dieses Impressum gilt für alle mit dem IPFire-Projekt verbundenen Webseiten. +

    + + {% else %} + Because of the fact that the people who started this project are living + in Germany, see the german legal notes. + + {% end %} + +{% end block %} diff --git a/www/templates/static/screenshots.html b/www/templates/static/screenshots.html new file mode 100644 index 0000000..e5a4b1b --- /dev/null +++ b/www/templates/static/screenshots.html @@ -0,0 +1,28 @@ +{% extends "../base.html" %} + +{% block title %}{{ _("Screenshots") }}{% end block %} + +{% block content %} + {{ _( + +

    + {% if lang == "de" %} + Hier findet Ihr einen keinen Einblick in das IPFire Webinterface. + + {% else %} + Here you will find an insight into the IPFire webinterface. + + {% end %} +

    + +
    + +

    {{ _("System") }}

    +
    +     + {{ _( +     + {{ _( +
    +{% end block %} diff --git a/www/templates/translations.html b/www/templates/translations.html new file mode 100644 index 0000000..549abb5 --- /dev/null +++ b/www/templates/translations.html @@ -0,0 +1,55 @@ +{% extends "base.html" %} + +{% block title %}{{ _("Translations") }}{% end block %} + +{% block content %} +

    IPFire {{ _("Translation Status") }}

    + +
    + +
    + + {% for project in projects %} +
    +

    {{ _("Description") }}: {{ project.desc }}

    +
    + + + + + + + + + + {% for translation in project.translations %} + + + + + + + + {% end %} +
    {{ _("Language") }}{{ _("Translated") }}{{ _("Untranslated") }}{{ _("Fuzzy") }}{{ _("Status") }}
    {{ translation.code }}{{ translation.lang }}{{ translation.translated }}{{ translation.untranslated }}{{ translation.fuzzy }}{{ translation.percent }}
    + {% end %} + +

    + {{ _("Template") }} - {{ project.total_strings }} strings +

    +{% end block %} + +{% block javascript %} + +{% end block %} diff --git a/www/translations/de_DE.csv b/www/translations/de_DE.csv new file mode 100644 index 0000000..1762f39 --- /dev/null +++ b/www/translations/de_DE.csv @@ -0,0 +1,25 @@ +"by","von" +"imprint","Impressum" +"Home","Startseite" +"release information","Releaseinformationen" +"Current version","Aktuelle Version" +"Current unstable","Entwicklungsversion" +"File","Datei" +"Release","Release" +"Got that information from %s within %.2f second(s).","Dauer der Abfrage von %s: %.2f Sekunde(n)." +"Home","Startseite" +"Number of nodes","Anzahl der Knoten" +"Cluster's CPU load","Prozessorauslastung des Clusters" +"Job load","Job-Auslastung" +"Name","Name" +"Arch","Arch" +"Jobs","Jobs" +"CPU-Load","CPU-Auslastung" +"Template","Vorlage" +"Description","Beschreibung" +"Translation Status","Übersetzungsüberblick" +"Language","Sprache" +"Translated","Übersetzt" +"Untranslated","Nicht übersetzt" +"Fuzzy","Fuzzy" +"Status","Status" diff --git a/www/webapp.py b/www/webapp.py new file mode 100755 index 0000000..5e4d690 --- /dev/null +++ b/www/webapp.py @@ -0,0 +1,12 @@ +#!/usr/bin/python2.6 + +import tornado.httpserver +import tornado.ioloop + +from webapp import Application +application = Application() + +if __name__ == "__main__": + http_server = tornado.httpserver.HTTPServer(application) + http_server.listen(8080) + tornado.ioloop.IOLoop.instance().start() diff --git a/www/webapp/__init__.py b/www/webapp/__init__.py new file mode 100644 index 0000000..659f769 --- /dev/null +++ b/www/webapp/__init__.py @@ -0,0 +1,57 @@ +#/usr/bin/python + +import os.path + +import tornado.locale +import tornado.options +import tornado.web + +from .handlers import * +from .ui_modules import * + +BASEDIR = os.path.join(os.path.dirname(__file__), "..") + +tornado.locale.load_translations(os.path.join(BASEDIR, "translations")) +tornado.options.enable_pretty_logging() + +class Application(tornado.web.Application): + def __init__(self): + handlers = [ + # Entry sites that lead the user to index + (r"/", MainHandler), + (r"/[A-Za-z]{2}/?", MainHandler), + # + (r"/[A-Za-z]{2}/index", IndexHandler), + (r"/[A-Za-z]{2}/news", NewsHandler), + (r"/[A-Za-z]{2}/builds", BuildHandler), + (r"/[A-Za-z]{2}/translations?", TranslationHandler), + # Download sites + (r"/[A-Za-z]{2}/downloads?", DownloadHandler), + (r"/[A-Za-z]{2}/downloads?/all", DownloadAllHandler), + (r"/[A-Za-z]{2}/downloads?/development", DownloadDevelopmentHandler), + (r"/[A-Za-z]{2}/downloads?/torrents", DownloadTorrentHandler), + # API + (r"/api/cluster_info", ApiClusterInfoHandler), + # Always the last rule + (r"/[A-Za-z]{2}/(.*)", StaticHandler), + ] + + settings = dict( + cookie_secret = "aXBmaXJlY29va2llc2VjcmV0Cg==", + #debug = True, + gzip = True, + static_path = os.path.join(BASEDIR, "static"), + template_path = os.path.join(BASEDIR, "templates"), + ui_modules = { + "Build" : BuildModule, + "Menu" : MenuModule, + "MenuItem" : MenuItemModule, + "NewsItem" : NewsItemModule, + "ReleaseItem" : ReleaseItemModule, + "SidebarBanner" : SidebarBannerModule, + "SidebarItem" : SidebarItemModule, + "SidebarRelease" : SidebarReleaseModule, + }, + xsrf_cookies = True, + ) + tornado.web.Application.__init__(self, handlers, **settings) diff --git a/www/webapp/banners.py b/www/webapp/banners.py new file mode 100644 index 0000000..2c7343c --- /dev/null +++ b/www/webapp/banners.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import random +import simplejson + +from helpers import Item + +class Banners(object): + def __init__(self, filename=None): + self.items = [] + + if filename: + self.load(filename) + + def load(self, filename): + f = open(filename) + data = f.read() + f.close() + + for item in simplejson.loads(data): + self.items.append(Item(**item)) + + def get(self): + return random.choice(self.items) + + +banners = Banners("banners.json") diff --git a/www/webapp/builds.py b/www/webapp/builds.py new file mode 100644 index 0000000..496c749 --- /dev/null +++ b/www/webapp/builds.py @@ -0,0 +1,85 @@ +#!/usr/bin/python + +import os +import time + +from helpers import size + +BUILD_HOME = "/srv/anonftp/pub/nightly-builds" + +def find(): + ret = [] + for host in os.listdir(BUILD_HOME): + for build in os.listdir(os.path.join(BUILD_HOME, host)): + ret.append(Build(os.path.join(BUILD_HOME, host, build))) + + return ret + +class Build(object): + def __init__(self, path): + self.path = path + + self.__buildinfo = None + + @property + def buildinfo(self): + if not self.__buildinfo: + f = open(os.path.join(self.path, ".buildinfo")) + self.__buildinfo = f.readlines() + f.close() + return self.__buildinfo + + def get(self, key): + key = key.upper() + "=" + for line in self.buildinfo: + if line.startswith(key): + return line[len(key):].strip("\n") + + @property + def build_host(self): + return self.get("hostname") + + @property + def release(self): + return self.get("release") + + @property + def time(self): + return time.localtime(float(self.get("date"))) + + @property + def date(self): + return time.strftime("%a, %Y-%m-%d %H:%M", self.time) + + @property + def arch(self): + return self.get("arch") + + @property + def iso(self): + return self.get("iso") + + @property + def size(self): + return size(os.path.getsize(os.path.join(self.path, self.iso))) + + @property + def packages(self): + path = "%s/packages_%s" % (self.path, self.arch,) + if not os.path.exists(path): + return [] + return os.listdir(path) + + @property + def pxe(self): + dir = "/srv/www/ipfire.org/pxe" + if not os.path.isdir(dir): + return "" + + for iso in os.listdir(dir): + # Skip non-iso files + if not iso.endswith(".iso"): + continue + if os.readlink(os.path.join(dir, iso)) == os.path.join(self.path, self.iso): + return "[PXE]" + return "" diff --git a/www/webapp/cluster.py b/www/webapp/cluster.py new file mode 100644 index 0000000..7afc297 --- /dev/null +++ b/www/webapp/cluster.py @@ -0,0 +1,149 @@ +#!/usr/bin/python + +import os +import telnetlib + +class Node(object): + def __init__(self, hostname, address, arch, speed, jobcount, load, installing): + self.hostname = hostname + self.address = address + self.arch = arch + self.speed = speed + self.installing = installing + + (jobs_cur, jobs_max) = jobcount.split("/") + if jobs_cur > jobs_max: + jobs_cur = jobs_max + self.jobcount = "%s/%s" % (jobs_cur, jobs_max) + + self.load = int(load) / 10 # in percent + + self.jobs = [] + + def __str__(self): + return self.hostname + + def __repr__(self): + return "" % self.hostname + + def __cmp__(self, other): + return cmp(self.hostname, other.hostname) + + def print_node(self): + print "Hostname : %s" % self.hostname + print " Address: %s" % self.address + print " Arch : %s" % self.arch + print " Speed : %s" % self.speed + print " Jobs : %s" % self.jobcount + print " Load : %s" % self.load + +class Job(object): + def __init__(self, id, status, submitter, compiler, file): + self.id = id + self.status = status + self.submitter = submitter + self.compiler = compiler + self.file = file + + +class Cluster(object): + def __init__(self, scheduler, port=8766): + self.scheduler = scheduler + self.port = port + + self._nodes = None + + def command(self, command): + connection = telnetlib.Telnet(self.scheduler, self.port) + connection.read_until("quit.\n") + connection.write("%s\nquit\n" % command) + return connection.read_until("200 done").split("\n") + + @property + def load(self): + if not self.nodes: + return 0 + load = 0 + for node in self.nodes: + load += node.load + load /= len(self.nodes) + return load + + @property + def jobcount(self): + jobs_cur = jobs_max = 0 + for node in self.nodes: + jobs_cur += int(node.jobcount.split("/")[0]) + jobs_max += int(node.jobcount.split("/")[1]) + return "%s/%s" % (jobs_cur, jobs_max) + + @property + def nodes(self): + if self._nodes: + return self._nodes + ret = [] + data = self.command("listcs") + node = None + for line in data: + if not line.startswith(" "): + continue # does not belong to the data + + if line.startswith(" ") and node: # Job + (a, b, c, id, status, submitter, compiler, file) = line.split(" ") + submitter = submitter[4:] + compiler = compiler[3:] + file = os.path.basename(file) + job = Job(id, status, submitter, compiler, file) + node.jobs.append(job) + + elif line.startswith(" "): # Node + installing = False + a = line.split(" ") + if len(a) > 7: + installing = True + line = " ".join(a[0:7]) + + (a, hostname, address, arch, speed, jobcount, load) = line.split(" ") + address = address.strip("()") + arch = arch.strip("[]") + speed = speed[6:] + jobcount = jobcount[5:] + load = load[5:] + node = Node(hostname, address, arch, speed, jobcount, load, installing) + ret.append(node) + + self._nodes = sorted(ret) + return ret + + @property + def json(self, *args): + nodes = [] + ret = {} + for node in self.nodes: + tmp = { "hostname" : node.hostname, + "address" : node.address, + "arch" : node.arch, + "jobcount" : node.jobcount, + "load" : node.load, + "speed" : node.speed, + "installing" : node.installing,} + jobs = [] + for job in node.jobs: + jobs.append({ "id" : job.id, + "status" : job.status, + "submitter" : job.submitter, + "compiler" : job.compiler, + "file" : job.file, }) + tmp["jobs"] = jobs + nodes.append(tmp) + ret["nodes"] = nodes + ret["cluster"] = { "load" : self.load, + "jobcount" : self.jobcount, } + return ret + + +if __name__ == "__main__": + cluster = Cluster("minerva.ipfire.org") + print cluster.command("listcs") + for node in cluster.nodes: + node.print_node() diff --git a/www/webapp/handlers.py b/www/webapp/handlers.py new file mode 100644 index 0000000..b4ee0a9 --- /dev/null +++ b/www/webapp/handlers.py @@ -0,0 +1,208 @@ +#!/usr/bin/python + +import httplib +import os +import simplejson +import time +import urlparse + +import tornado.httpclient +import tornado.locale +import tornado.web + +from banners import banners +from news import news +from releases import releases + +import builds +import cluster +import translations +#import uriel + +class BaseHandler(tornado.web.RequestHandler): + def get_user_locale(self): + uri = self.request.uri.split("/") + if len(uri) > 1: + for lang in tornado.locale.get_supported_locales(None): + if lang[:2] == uri[1]: + return tornado.locale.get(lang) + + @property + def render_args(self): + return { + "banner" : banners.get(), + "lang" : self.locale.code[:2], + "langs" : [l[:2] for l in tornado.locale.get_supported_locales(None)], + "lang_link" : self.lang_link, + "link" : self.link, + "title" : "no title given", + "server" : self.request.host.replace("ipfire", "ipfire"), + "uri" : self.request.uri, + "year" : time.strftime("%Y"), + } + + def render(self, *args, **kwargs): + nargs = self.render_args + nargs.update(kwargs) + nargs["title"] = "%s - %s" % (self.request.host, nargs["title"]) + tornado.web.RequestHandler.render(self, *args, **nargs) + + def link(self, s): + return "/%s/%s" % (self.locale.code[:2], s) + + def lang_link(self, lang): + return "/%s/%s" % (lang, self.request.uri[4:]) + + def get_error_html(self, status_code, **kwargs): + if status_code in (404, 500): + render_args = self.render_args + render_args.update({ + "code" : status_code, + "exception" : kwargs.get("exception", None), + "message" : httplib.responses[status_code], + }) + return self.render_string("error-%s.html" % status_code, **render_args) + else: + return tornado.web.RequestHandler.get_error_html(self, status_code, **kwargs) + + +class MainHandler(BaseHandler): + def get(self): + lang = self.locale.code[:2] + self.redirect("/%s/index" % (lang)) + + +class DownloadHandler(BaseHandler): + def get(self): + self.render("downloads.html", release=releases.latest) + + +class DownloadAllHandler(BaseHandler): + def get(self): + self.render("downloads-all.html", releases=releases) + + +class DownloadDevelopmentHandler(BaseHandler): + def get(self): + self.render("downloads-development.html", releases=releases) + + +class DownloadTorrentHandler(BaseHandler): + tracker_url = "http://tracker.ipfire.org:6969/stats?format=txt&mode=tpbs" + + @tornado.web.asynchronous + def get(self): + http = tornado.httpclient.AsyncHTTPClient() + http.fetch(self.tracker_url, callback=self.async_callback(self.on_response)) + + def on_response(self, response): + torrents = releases.torrents + hashes = {} + if response.code == 200: + for line in response.body.split("\n"): + if not line: continue + hash, seeds, peers = line.split(":") + hash.lower() + hashes[hash] = { + "peers" : peers, + "seeds" : seeds, + } + + self.render("downloads-torrents.html", + hashes=hashes, + releases=torrents, + request_time=response.request_time, + tracker=urlparse.urlparse(response.request.url).netloc) + + +class StaticHandler(BaseHandler): + @property + def static_path(self): + return os.path.join(self.application.settings["template_path"], "static") + + @property + def static_files(self): + ret = [] + for filename in os.listdir(self.static_path): + if filename.endswith(".html"): + ret.append(filename) + return ret + + def get(self, name=None): + name = "%s.html" % name + + if not name in self.static_files: + raise tornado.web.HTTPError(404) + + self.render("static/%s" % name) + + +class IndexHandler(BaseHandler): + def get(self): + self.render("index.html", news=news) + + +class NewsHandler(BaseHandler): + def get(self): + self.render("news.html", news=news) + + +class RedirectHandler(BaseHandler): + redirects = { + "www.ipfire.org" : ( + (r"", "") + ) + } + def get(self): + pass + + +class BuildHandler(BaseHandler): + def prepare(self): + self.builds = { + "<12h" : [], + ">12h" : [], + ">24h" : [], + } + + for build in builds.find(): + if (time.time() - float(build.get("date"))) < 12*60: + self.builds["<12h"].append(build) + elif (time.time() - float(build.get("date"))) < 24*60: + self.builds[">12h"].append(build) + else: + self.builds[">24h"].append(build) + + for l in self.builds.values(): + l.sort() + + def get(self): + self.render("builds.html", builds=self.builds) + + +class UrielBaseHandler(BaseHandler): + #db = uriel.Database() + pass + +class UrielHandler(UrielBaseHandler): + def get(self): + pass + + +class ApiClusterInfoHandler(BaseHandler): + def get(self): + id = self.get_argument("id", "null") + + c = cluster.Cluster("minerva.ipfire.org") + + self.write(simplejson.dumps({ + "version": "1.1", + "id": id, + "result" : c.json, + "error" : "null", })) + self.finish() + + +class TranslationHandler(BaseHandler): + def get(self): + self.render("translations.html", projects=translations.projects) diff --git a/www/webapp/helpers.py b/www/webapp/helpers.py new file mode 100644 index 0000000..dfa1d7e --- /dev/null +++ b/www/webapp/helpers.py @@ -0,0 +1,25 @@ +#!/usr/bin/python + +class Item(object): + def __init__(self, **args): + self.args = args + + def __getattr__(self, key): + return self.args[key] + + def __getitem__(self, key): + return self.args[key] + + def __setitem__(self, key, val): + self.args[key] = val + + +def size(s): + suffixes = ["B", "K", "M", "G", "T",] + + idx = 0 + while s >= 1024 and idx < len(suffixes): + s /= 1024 + idx += 1 + + return "%.2f %s" % (s, suffixes[idx]) diff --git a/www/webapp/menu.py b/www/webapp/menu.py new file mode 100644 index 0000000..b32c3e3 --- /dev/null +++ b/www/webapp/menu.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +import simplejson + +from helpers import Item + +class Menu(object): + def __init__(self, filename=None): + self.items = [] + + if filename: + self.load(filename) + + def load(self, filename): + f = open(filename) + data = f.read() + f.close() + + for item in simplejson.loads(data): + self.items.append(MenuItem(**item)) + + +class MenuItem(Item): + def __init__(self, **args): + Item.__init__(self, **args) + self.active = False + + # Parse submenu + if self.args.has_key("subs"): + self.args["items"] = [] + for sub in self.args["subs"]: + self.args["items"].append(MenuItem(**sub)) + del self.args["subs"] + + +if __name__ == "__main__": + m = Menu("menu.json") + print [i.args for i in m.items] diff --git a/www/webapp/news.py b/www/webapp/news.py new file mode 100644 index 0000000..139e255 --- /dev/null +++ b/www/webapp/news.py @@ -0,0 +1,35 @@ +#!/usr/bin/python + +import simplejson + +from .helpers import Item + +class News(object): + def __init__(self, filename=None): + self.items = [] + + if filename: + self.load(filename) + + def load(self, filename): + f = open(filename) + data = f.read() + f.close() + + data = data.replace("\n", "").replace("\t", " ") + + json = simplejson.loads(data) + for key in sorted(json.keys()): + self.items.append(NewsItem(**json[key])) + + def get(self, limit=None): + ret = self.items[:] + ret.reverse() + if limit: + ret = ret[:limit] + return ret + + +NewsItem = Item + +news = News("news.json") diff --git a/www/webapp/releases.py b/www/webapp/releases.py new file mode 100644 index 0000000..a592730 --- /dev/null +++ b/www/webapp/releases.py @@ -0,0 +1,174 @@ +#!/usr/bin/python + +import simplejson + +from helpers import Item + +class ReleaseItem(Item): + options = { + "iso" : { + "prio" : 10, + "desc" : "Installable CD image", + "url" : "http://download.ipfire.org/iso/", + }, + "torrent" : { + "prio" : 20, + "desc" : "Torrent file", + "url" : "http://download.ipfire.org/torrent/", + }, + "alix" : { + "prio" : 40, + "desc" : "Alix image", + "url" : "http://download.ipfire.org/iso/", + }, + "usbfdd" : { + "prio" : 30, + "desc" : "USB FDD Image", + "url" : "http://download.ipfire.org/iso/", + }, + "usbhdd" : { + "prio" : 30, + "desc" : "USB HDD Image", + "url" : "http://download.ipfire.org/iso/", + }, + "xen" : { + "prio" : 50, + "desc" : "Pregenerated Xen Image", + "url" : "http://download.ipfire.org/iso/", + }, + } + + @property + def downloads(self): + ret = [] + for fileitem in self.args["files"]: + filetype = fileitem["type"] + ret.append(Item( + desc = self.options[filetype]["desc"], + file = fileitem["name"], + hash = fileitem.get("hash", None), + prio = self.options[filetype]["prio"], + sha1 = fileitem.get("sha1", None), + type = filetype, + url = self.options[filetype]["url"] + fileitem["name"], + )) + + ret.sort(lambda a, b: cmp(a.prio, b.prio)) + return ret + + for option in self.options.keys(): + if not self.args["files"].has_key(option): + continue + + ret.append(Item( + desc = self.options[option]["desc"], + file = self.args["files"][option], + prio = self.options[option]["prio"], + type = option, + url = self.options[option]["url"] + self.args["files"][option], + )) + + ret.sort(lambda a, b: cmp(a.prio, b.prio)) + return ret + + @property + def iso(self): + for download in self.downloads: + if download.type == "iso": + return download + + @property + def torrent(self): + for download in self.downloads: + if download.type == "torrent": + return download + + @property + def stable(self): + return self.status == "stable" + + @property + def development(self): + return self.status == "development" + + +class Releases(object): + def __init__(self, filename="releases.json"): + self.items = [] + + if filename: + self.load(filename) + + def load(self, filename): + f = open(filename) + data = f.read() + f.close() + + for item in simplejson.loads(data): + self.items.append(ReleaseItem(**item)) + + @property + def all(self): + return self.items + + @property + def online(self): + ret = [] + for item in self.all: + if item.online: + ret.append(item) + return ret + + @property + def offline(self): + ret = [] + for item in self.all: + if not item.online: + ret.append(item) + return ret + + @property + def latest(self): + if self.stable: + return self.stable[0] + + @property + def latest_devel(self): + if self.development: + return self.development[0] + + @property + def stable(self): + ret = [] + for item in self.online: + if item.stable: + ret.append(item) + return ret + + @property + def development(self): + ret = [] + for item in self.online: + if item.development: + ret.append(item) + return ret + + @property + def torrents(self): + ret = [] + for item in self.online: + if item.torrent: + ret.append(item) + return ret + + +releases = Releases("releases.json") + +if __name__ == "__main__": + r = Releases() + + print r.stable + print r.development + print r.latest + print r.online + print r.offline diff --git a/www/webapp/translations.py b/www/webapp/translations.py new file mode 100644 index 0000000..af44823 --- /dev/null +++ b/www/webapp/translations.py @@ -0,0 +1,102 @@ +#!/usr/bin/python + +import os + +import tornado.locale + +class Po(object): + def __init__(self, path, project): + self.path = path + self.project = project + + p = os.popen("msgfmt -v --statistics %s 2>&1" % self.path) + self.line = p.readlines()[0] + + def __cmp__(self, other): + return cmp(self.lang, other.lang) + + @property + def code2lang(self): + ret = {} + for lang in tornado.locale.LOCALE_NAMES.keys(): + ret[lang[:2]] = "%(name)s (%(name_en)s)" % tornado.locale.LOCALE_NAMES[lang] + return ret + + @property + def code(self): + return os.path.basename(self.path)[:-3] + + @property + def lang(self): + return self.code2lang.get(self.code, "Unknown (%s)" % self.code) + + @property + def translated(self): + return int(self.line.split()[0]) + + @property + def untranslated(self): + l = self.line.split() + if len(l) == 6: + return int(l[3]) + elif len(l) == 9: + return int(l[6]) + return 0 + + @property + def fuzzy(self): + l = self.line.split() + if len(l) == 9: + return l[3] + return 0 + + @property + def percent(self): + if not self.project.total_strings: + return "---.-- %" + + return "%3.1f%%" % (self.translated * 100 / self.project.total_strings) + + +class Project(object): + def __init__(self, id, path, **kwargs): + self.id = id + self.path = path + self._name = kwargs.pop("name") + self.desc = kwargs.pop("desc") + + self._translations = [] + self.pot = None + self.find_pot() + + @property + def name(self): + if self._name: + return self._name + return self.id + + @property + def translations(self): + if not self._translations: + for path in os.listdir(self.path): + if path.endswith(".po"): + self._translations.append(Po(os.path.join(self.path, path), self)) + self._translations.sort() + return self._translations + + def find_pot(self): + for path in os.listdir(self.path): + if path.endswith(".pot"): + self.pot = Po(os.path.join(self.path, path), self) + break + + @property + def total_strings(self): + if not self.pot: + return 0 + return self.pot.untranslated + +projects = [ + Project("pomona", "/srv/checkout/ipfire-3.x/src/pomona/po", + name="Pomona", desc="The pomona installer for ipfire."), +] diff --git a/www/webapp/ui_modules.py b/www/webapp/ui_modules.py new file mode 100644 index 0000000..f881bfe --- /dev/null +++ b/www/webapp/ui_modules.py @@ -0,0 +1,84 @@ +#!/usr/bin/python + +import tornado.web + +import menu +import releases + +class UIModule(tornado.web.UIModule): + def render_string(self, *args, **kwargs): + kwargs.update({ + "link" : self.handler.link, + }) + return tornado.web.UIModule.render_string(self, *args, **kwargs) + + +class MenuItemModule(UIModule): + def render(self, item): + if self.request.uri.endswith(item.link): + item.active = True + + if type(item.name) == type({}): + item.name = item.name[self.locale.code[:2]] + + return self.render_string("modules/menu-item.html", item=item) + + +class MenuModule(UIModule): + #def javascript_files(self): + # return ["js/jquery.megamenu.js",] + # + #def embedded_javascript(self): + # return """ + # $(document).ready(function(){ + # $(".MegaMenuLink").megamenu(".MegaMenuContent"); + # });""" + + def render(self, menuclass=None): + return "" # XXX + if not menuclass: + menuclass = menu.Menu("menu.json") + return self.render_string("modules/menu.html", menuitems=menuclass.items) + + +class NewsItemModule(UIModule): + def render(self, item): + for attr in ("subject", "content"): + if type(item[attr]) != type({}): + continue + item[attr] = item[attr][self.locale.code[:2]] + + return self.render_string("modules/news-item.html", item=item) + + +#class SidebarModule(UIModule): +# def render(self, sidebar): +# return self.render_string("modules/sidebar.html", items=sidebar.items) + + +class SidebarItemModule(UIModule): + def render(self): + return self.render_string("modules/sidebar-item.html") + + +class SidebarReleaseModule(UIModule): + releases = releases.Releases() + + def render(self): + return self.render_string("modules/sidebar-release.html", + releases=self.releases) + + +class ReleaseItemModule(UIModule): + def render(self, item): + return self.render_string("modules/release-item.html", item=item) + + +class SidebarBannerModule(UIModule): + def render(self, item): + return self.render_string("modules/sidebar-banner.html", item=item) + + +class BuildModule(UIModule): + def render(self, build): + return self.render_string("modules/builds.html", build=build) diff --git a/www/webapp/uriel.py b/www/webapp/uriel.py new file mode 100644 index 0000000..bf1f104 --- /dev/null +++ b/www/webapp/uriel.py @@ -0,0 +1,87 @@ +#!/usr/bin/python + +import operator +import MySQLdb as sql + +allowed_items = [ "cpu_mhz", "cpu_model", "formfactor", "lang", "model", + "ram_mb", "storage_mb", "system", "vendor", ] + +class Database(object): + _name = "uriel" + _table = "hosts" + + def __init__(self): + self.connection = sql.connect(user="uriel", db=self._name) + + self._count = None + + def cursor(self): + return self.connection.cursor() + + def table(self, item, sort=0, consolidate=0): + c = self.cursor() + c.execute("SELECT value FROM %s WHERE item = '%s'" % (self._table, item,)) + + count = 0 + results = {} + ret = [] + + if consolidate: + result = c.fetchone() + while result: + count += 1 + result = "%s" % result + + if results.has_key(result): + results[result] += 1 + else: + results[result] = 1 + + result = c.fetchone() + + for i in results.items(): + ret.append(i) + + if sort: + ret = sorted(ret, key=operator.itemgetter(1)) + ret.reverse() + + else: + result = c.fetchone() + while result: + ret.append(int("%s" % result)) + result = c.fetchone() + + if sort: + ret.sort() + + count = len(ret) + + c.close() + return (ret, count) + + def count(self): + if not self._count: + c = self.cursor() + c.execute("SELECT COUNT(DISTINCT(id)) FROM %s" % self._table) + self._count = int("%s" % c.fetchone()) + c.close() + return self._count + + def get(self, id, item): + c = self.cursor() + c.execute("SELECT value FROM %s WHERE id = '%s' AND item = '%s'" % \ + (self._table, id, item,)) + ret = c.fetchall() or None + c.close() + return ret + + def set(self, id, item, value): + c = self.cursor() + if self.get(id, item): + c.execute("UPDATE %s SET value = '%s' WHERE id = '%s' AND item = '%s'" % \ + (self._table, value, id, item,)) + else: + c.execute("INSERT INTO %s(id, item, value) VALUES('%s', '%s', '%s')" % \ + (self._table, id, item, value)) + c.close() -- 2.39.2