├── README.txt
├── kees.egg-info
├── not-zip-safe
├── top_level.txt
├── dependency_links.txt
├── entry_points.txt
├── requires.txt
├── PKG-INFO
└── SOURCES.txt
├── CHANGES.txt
├── kees
├── static
│ ├── pyramid.png
│ ├── pyramid-16x16.png
│ ├── ct.css
│ ├── theme.min.css
│ ├── theme.css
│ ├── listpoints.html
│ ├── showpoint.html
│ ├── showlevel.html
│ ├── listlevels.html
│ └── zepto.min.js
├── tests.py
├── __init__.py
├── templates
│ └── mytemplate.pt
├── views.py
└── dblayer.py
├── MANIFEST.in
├── runit.py
├── production.ini
├── tryds.py
├── setup.py
├── development.ini
└── testit.py
/README.txt:
--------------------------------------------------------------------------------
1 | kees README
2 |
--------------------------------------------------------------------------------
/kees.egg-info/not-zip-safe:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/kees.egg-info/top_level.txt:
--------------------------------------------------------------------------------
1 | kees
2 |
--------------------------------------------------------------------------------
/kees.egg-info/dependency_links.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CHANGES.txt:
--------------------------------------------------------------------------------
1 | 0.0
2 | ---
3 |
4 | - Initial version
5 |
--------------------------------------------------------------------------------
/kees.egg-info/entry_points.txt:
--------------------------------------------------------------------------------
1 | [paste.app_factory]
2 | main = kees:main
3 |
--------------------------------------------------------------------------------
/kees.egg-info/requires.txt:
--------------------------------------------------------------------------------
1 | pyramid
2 | pyramid_chameleon
3 | pyramid_debugtoolbar
4 | waitress
--------------------------------------------------------------------------------
/kees/static/pyramid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chozabu/KEES/master/kees/static/pyramid.png
--------------------------------------------------------------------------------
/kees/static/pyramid-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chozabu/KEES/master/kees/static/pyramid-16x16.png
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include *.txt *.ini *.cfg *.rst
2 | recursive-include kees *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml
3 |
--------------------------------------------------------------------------------
/kees/tests.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | from pyramid import testing
4 |
5 |
6 | class ViewTests(unittest.TestCase):
7 | def setUp(self):
8 | self.config = testing.setUp()
9 |
10 | def tearDown(self):
11 | testing.tearDown()
12 |
13 | def test_my_view(self):
14 | from .views import my_view
15 | request = testing.DummyRequest()
16 | info = my_view(request)
17 | self.assertEqual(info['project'], 'kees')
18 |
--------------------------------------------------------------------------------
/runit.py:
--------------------------------------------------------------------------------
1 | from wsgiref.simple_server import make_server
2 | import sys, os
3 |
4 | # Switch to the virtualenv if we're not already there
5 | #INTERP = os.path.expanduser("~/env/pyramid/bin/python")
6 |
7 | #if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
8 |
9 | from paste.deploy import loadapp
10 | application = loadapp(
11 | 'config:' +
12 | os.path.expanduser('/home/chozabu/git/KEES/development.ini'))
13 |
14 | server = make_server('0.0.0.0', 8080, application)
15 | server.serve_forever()
16 |
17 |
--------------------------------------------------------------------------------
/kees.egg-info/PKG-INFO:
--------------------------------------------------------------------------------
1 | Metadata-Version: 1.1
2 | Name: kees
3 | Version: 0.0
4 | Summary: kees
5 | Home-page: UNKNOWN
6 | Author: UNKNOWN
7 | Author-email: UNKNOWN
8 | License: UNKNOWN
9 | Description: kees README
10 |
11 |
12 | 0.0
13 | ---
14 |
15 | - Initial version
16 |
17 | Keywords: web pyramid pylons
18 | Platform: UNKNOWN
19 | Classifier: Programming Language :: Python
20 | Classifier: Framework :: Pyramid
21 | Classifier: Topic :: Internet :: WWW/HTTP
22 | Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
23 |
--------------------------------------------------------------------------------
/kees.egg-info/SOURCES.txt:
--------------------------------------------------------------------------------
1 | CHANGES.txt
2 | MANIFEST.in
3 | README.txt
4 | development.ini
5 | production.ini
6 | setup.py
7 | kees/__init__.py
8 | kees/dblayer.py
9 | kees/testdb.py
10 | kees/tests.py
11 | kees/views.py
12 | kees.egg-info/PKG-INFO
13 | kees.egg-info/SOURCES.txt
14 | kees.egg-info/dependency_links.txt
15 | kees.egg-info/entry_points.txt
16 | kees.egg-info/not-zip-safe
17 | kees.egg-info/requires.txt
18 | kees.egg-info/top_level.txt
19 | kees/static/pyramid-16x16.png
20 | kees/static/pyramid.png
21 | kees/static/theme.css
22 | kees/static/theme.min.css
23 | kees/templates/mytemplate.pt
--------------------------------------------------------------------------------
/kees/static/ct.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: e9f5f1;
3 | color: #222222;
4 | text-shadow: rgba(250,250,255, .4) 0em 0em 4px;
5 | font: 12pt Ubuntu, Verdana, Arial, Helvetica, sans-serif;
6 | margin: 10px;
7 | }
8 |
9 | #chatout {
10 | margin-left: 520px;
11 | }
12 |
13 | .PIPanel, body > ul > li {
14 | background: white;
15 | padding: 5px 10px;
16 | border: #bbbbbb 1px solid;
17 | text-align: left;
18 | margin: 5px;
19 | border-radius: 5px;
20 | box-shadow: 2px 2px 2px #bbbbbb;
21 | }
22 |
23 | .PIPanel:hover {
24 | border: gray 1px solid;
25 | border-color: #666666;
26 | }
27 |
28 | .PIPanel > span {
29 | font-size: 10pt;
30 | }
31 |
32 | .PIPanel > div {
33 | margin-top: 10px;
34 | }
35 |
36 | span.postname {
37 | font-weight: bold;
38 | }
39 |
40 | span.postid {
41 | font-size: 8pt;
42 | float: right;
43 | }
44 |
45 | body > ul {
46 | margin: 0px;
47 | padding: 0px;
48 | list-style-type: none;
49 | text-align: left;
50 | float: left;
51 | width: 480px;
52 | }
53 |
--------------------------------------------------------------------------------
/production.ini:
--------------------------------------------------------------------------------
1 | ###
2 | # app configuration
3 | # http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/environment.html
4 | ###
5 |
6 | [app:main]
7 | use = egg:kees
8 |
9 | pyramid.reload_templates = false
10 | pyramid.debug_authorization = false
11 | pyramid.debug_notfound = false
12 | pyramid.debug_routematch = false
13 | pyramid.default_locale_name = en
14 |
15 | ###
16 | # wsgi server configuration
17 | ###
18 |
19 | [server:main]
20 | use = egg:waitress#main
21 | host = 0.0.0.0
22 | port = 6543
23 |
24 | ###
25 | # logging configuration
26 | # http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/logging.html
27 | ###
28 |
29 | [loggers]
30 | keys = root, kees
31 |
32 | [handlers]
33 | keys = console
34 |
35 | [formatters]
36 | keys = generic
37 |
38 | [logger_root]
39 | level = WARN
40 | handlers = console
41 |
42 | [logger_kees]
43 | level = WARN
44 | handlers =
45 | qualname = kees
46 |
47 | [handler_console]
48 | class = StreamHandler
49 | args = (sys.stderr,)
50 | level = NOTSET
51 | formatter = generic
52 |
53 | [formatter_generic]
54 | format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
55 |
--------------------------------------------------------------------------------
/tryds.py:
--------------------------------------------------------------------------------
1 |
2 | import dataset
3 |
4 | #db = dataset.connect('sqlite:///:memory:')
5 | db = dataset.connect('sqlite:///mydatabase.db')
6 |
7 | table = db['sometable']
8 | table.insert(dict(name='John Doe', age=37))
9 | table.insert(dict(name='Jane Doe', age=34, gender='female'))
10 |
11 | john = table.find_one(name='John Doe')
12 |
13 | print john
14 |
15 | def newAccount(request, username, password):
16 | username = username.replace(".","")
17 | eUser = database.users.find_one({"_id":username})
18 | if(eUser):
19 | print "dupe account creation attempt on name: " + username
20 | return {"result":"fail", "message":"name taken"}
21 | newUser = {}
22 | newUser['createdAt'] = time.time()
23 | newUser['lastTouch'] = time.time()
24 | newUser['salt'] = uuid.uuid4().get_hex()
25 | newUser['_id'] = username
26 | makeImage(username)
27 | newUser['username'] = username
28 | newUser['groups'] = []
29 | newUser['password'] = hashlib.sha512(password + newUser['salt']).hexdigest()
30 | database.users.insert(newUser)
31 | print {"result":"sucess", "message":"account " + username + " created"}
32 | return {"result":"sucess", "message":"account " + username + " created"}
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from setuptools import setup, find_packages
4 |
5 | here = os.path.abspath(os.path.dirname(__file__))
6 | with open(os.path.join(here, 'README.txt')) as f:
7 | README = f.read()
8 | with open(os.path.join(here, 'CHANGES.txt')) as f:
9 | CHANGES = f.read()
10 |
11 | requires = [
12 | 'pyramid',
13 | 'pyramid_chameleon',
14 | 'pyramid_debugtoolbar',
15 | 'waitress',
16 | ]
17 |
18 | setup(name='kees',
19 | version='0.0',
20 | description='kees',
21 | long_description=README + '\n\n' + CHANGES,
22 | classifiers=[
23 | "Programming Language :: Python",
24 | "Framework :: Pyramid",
25 | "Topic :: Internet :: WWW/HTTP",
26 | "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
27 | ],
28 | author='',
29 | author_email='',
30 | url='',
31 | keywords='web pyramid pylons',
32 | packages=find_packages(),
33 | include_package_data=True,
34 | zip_safe=False,
35 | install_requires=requires,
36 | tests_require=requires,
37 | test_suite="kees",
38 | entry_points="""\
39 | [paste.app_factory]
40 | main = kees:main
41 | """,
42 | )
43 |
--------------------------------------------------------------------------------
/kees/__init__.py:
--------------------------------------------------------------------------------
1 | from pyramid.config import Configurator
2 |
3 |
4 | def main(global_config, **settings):
5 | """ This function returns a Pyramid WSGI application.
6 | """
7 | config = Configurator(settings=settings)
8 | config.include('pyramid_chameleon')
9 | config.add_static_view('static', 'static', cache_max_age=3600)
10 | config.add_static_view('pplevels', 'pplevels', cache_max_age=3600)
11 | config.add_static_view('thumbs', 'thumbs', cache_max_age=3600)
12 | config.add_route('home', '/')
13 | config.add_route('store_mp3_view', '/store_mp3_view')
14 | config.add_route('uploadLevel', '/uploadLevel')
15 | config.add_route('query_levels', '/query_levels')
16 | config.add_route('add_point', '/add_point')
17 | config.add_route('add_vote', '/add_vote')
18 | config.add_route('query_points', '/query_points')
19 | config.add_route('get_point', '/get_point')
20 | config.add_route('get_level', '/get_level')
21 | config.add_route('get_tags', '/get_tags')
22 | config.add_route('login', '/login')
23 | config.add_route('new_user', '/new_user')
24 | config.add_route('uploadCrash', '/uploadCrash')
25 | config.add_route('crashLogs', '/crashLogs')
26 | config.scan()
27 | return config.make_wsgi_app()
28 |
--------------------------------------------------------------------------------
/development.ini:
--------------------------------------------------------------------------------
1 | ###
2 | # app configuration
3 | # http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/environment.html
4 | ###
5 |
6 | [app:main]
7 | use = egg:kees
8 |
9 | pyramid.reload_templates = true
10 | pyramid.debug_authorization = false
11 | pyramid.debug_notfound = false
12 | pyramid.debug_routematch = false
13 | pyramid.default_locale_name = en
14 | pyramid.includes =
15 | pyramid_debugtoolbar
16 |
17 | # By default, the toolbar only appears for clients from IP addresses
18 | # '127.0.0.1' and '::1'.
19 | # debugtoolbar.hosts = 127.0.0.1 ::1
20 |
21 | ###
22 | # wsgi server configuration
23 | ###
24 |
25 | [server:main]
26 | use = egg:waitress#main
27 | host = 0.0.0.0
28 | port = 6543
29 |
30 | ###
31 | # logging configuration
32 | # http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/logging.html
33 | ###
34 |
35 | [loggers]
36 | keys = root, kees
37 |
38 | [handlers]
39 | keys = console
40 |
41 | [formatters]
42 | keys = generic
43 |
44 | [logger_root]
45 | level = INFO
46 | handlers = console
47 |
48 | [logger_kees]
49 | level = DEBUG
50 | handlers =
51 | qualname = kees
52 |
53 | [handler_console]
54 | class = StreamHandler
55 | args = (sys.stderr,)
56 | level = NOTSET
57 | formatter = generic
58 |
59 | [formatter_generic]
60 | format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
61 |
--------------------------------------------------------------------------------
/testit.py:
--------------------------------------------------------------------------------
1 |
2 | import requests
3 |
4 | server = 'http://0.0.0.0:8080/'
5 |
6 |
7 | print ""
8 | print "Create user"
9 | params = {'username': "chozabu", 'password': "asd"}#open('otherthing.txt', 'rb')}
10 | r = requests.post(server+'new_user', data=params)
11 | print r.text
12 |
13 | print ""
14 | print "login user"
15 | params = {'username': "chozabu", 'password': "asd"}#open('otherthing.txt', 'rb')}
16 | r = requests.post(server+'login', data=params)
17 | print r.text
18 | session = r.json()['session']
19 |
20 |
21 | print ""
22 | print "add_point"
23 | files = {'session':session, 'name': "apoint", 'text': "blah blah blah"}#open('otherthing.txt', 'rb')}
24 | r = requests.post(server+'add_point', data=files)
25 | print r.text
26 |
27 |
28 | print ""
29 | print "query points"
30 | params = {'sortKey': "rating", 'cursor': 0, 'limit':8}#open('otherthing.txt', 'rb')}
31 | r = requests.post(server+'query_points', data=params)
32 | print r.text
33 | #print r
34 | #print dir(r)
35 | '''
36 | print ""
37 | print "upload level"
38 | files = {'session':session, 'author': "chozabu", 'name': "ICERUN", "leveldata":"someleveldata", 'sshot':'apicture'}#open('otherthing.txt', 'rb')}
39 | r = requests.post(server+'uploadLevel', files=files)
40 | print r.text
41 |
42 |
43 | print ""
44 | print "query levels"
45 | params = {'sortKey': "filename", 'cursor': 0, 'limit':8}#open('otherthing.txt', 'rb')}
46 | r = requests.post(server+'query_levels', data=params)
47 | print r.text
48 | #print r
49 | #print dir(r)
50 | '''
--------------------------------------------------------------------------------
/kees/static/theme.min.css:
--------------------------------------------------------------------------------
1 | @import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);body{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300;color:#fff;background:#bc2131}h1,h2,h3,h4,h5,h6{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300}p{font-weight:300}.font-normal{font-weight:400}.font-semi-bold{font-weight:600}.font-bold{font-weight:700}.starter-template{margin-top:250px}.starter-template .content{margin-left:10px}.starter-template .content h1{margin-top:10px;font-size:60px}.starter-template .content h1 .smaller{font-size:40px;color:#f2b7bd}.starter-template .content .lead{font-size:25px;color:#f2b7bd}.starter-template .content .lead .font-normal{color:#fff}.starter-template .links{float:right;right:0;margin-top:125px}.starter-template .links ul{display:block;padding:0;margin:0}.starter-template .links ul li{list-style:none;display:inline;margin:0 10px}.starter-template .links ul li:first-child{margin-left:0}.starter-template .links ul li:last-child{margin-right:0}.starter-template .links ul li.current-version{color:#f2b7bd;font-weight:400}.starter-template .links ul li a{color:#fff}.starter-template .links ul li a:hover{text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.9em;color:#f2b7bd;text-transform:lowercase;float:right;right:0}@media (max-width:1199px){.starter-template .content h1{font-size:45px}.starter-template .content h1 .smaller{font-size:30px}.starter-template .content .lead{font-size:20px}}@media (max-width:991px){.starter-template{margin-top:0}.starter-template .logo{margin:40px auto}.starter-template .content{margin-left:0;text-align:center}.starter-template .content h1{margin-bottom:20px}.starter-template .links{float:none;text-align:center;margin-top:60px}.starter-template .copyright{float:none;text-align:center}}@media (max-width:767px){.starter-template .content h1 .smaller{font-size:25px;display:block}.starter-template .content .lead{font-size:16px}.starter-template .links{margin-top:40px}.starter-template .links ul li{display:block;margin:0}.starter-template .links ul li .icon-muted{display:none}.starter-template .copyright{margin-top:20px}}
--------------------------------------------------------------------------------
/kees/static/theme.css:
--------------------------------------------------------------------------------
1 | @import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);
2 | body {
3 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
4 | font-weight: 300;
5 | color: #ffffff;
6 | background: #bc2131;
7 | }
8 | h1,
9 | h2,
10 | h3,
11 | h4,
12 | h5,
13 | h6 {
14 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
15 | font-weight: 300;
16 | }
17 | p {
18 | font-weight: 300;
19 | }
20 | .font-normal {
21 | font-weight: 400;
22 | }
23 | .font-semi-bold {
24 | font-weight: 600;
25 | }
26 | .font-bold {
27 | font-weight: 700;
28 | }
29 | .starter-template {
30 | margin-top: 250px;
31 | }
32 | .starter-template .content {
33 | margin-left: 10px;
34 | }
35 | .starter-template .content h1 {
36 | margin-top: 10px;
37 | font-size: 60px;
38 | }
39 | .starter-template .content h1 .smaller {
40 | font-size: 40px;
41 | color: #f2b7bd;
42 | }
43 | .starter-template .content .lead {
44 | font-size: 25px;
45 | color: #f2b7bd;
46 | }
47 | .starter-template .content .lead .font-normal {
48 | color: #ffffff;
49 | }
50 | .starter-template .links {
51 | float: right;
52 | right: 0;
53 | margin-top: 125px;
54 | }
55 | .starter-template .links ul {
56 | display: block;
57 | padding: 0;
58 | margin: 0;
59 | }
60 | .starter-template .links ul li {
61 | list-style: none;
62 | display: inline;
63 | margin: 0 10px;
64 | }
65 | .starter-template .links ul li:first-child {
66 | margin-left: 0;
67 | }
68 | .starter-template .links ul li:last-child {
69 | margin-right: 0;
70 | }
71 | .starter-template .links ul li.current-version {
72 | color: #f2b7bd;
73 | font-weight: 400;
74 | }
75 | .starter-template .links ul li a {
76 | color: #ffffff;
77 | }
78 | .starter-template .links ul li a:hover {
79 | text-decoration: underline;
80 | }
81 | .starter-template .links ul li .icon-muted {
82 | color: #eb8b95;
83 | margin-right: 5px;
84 | }
85 | .starter-template .links ul li:hover .icon-muted {
86 | color: #ffffff;
87 | }
88 | .starter-template .copyright {
89 | margin-top: 10px;
90 | font-size: 0.9em;
91 | color: #f2b7bd;
92 | text-transform: lowercase;
93 | float: right;
94 | right: 0;
95 | }
96 | @media (max-width: 1199px) {
97 | .starter-template .content h1 {
98 | font-size: 45px;
99 | }
100 | .starter-template .content h1 .smaller {
101 | font-size: 30px;
102 | }
103 | .starter-template .content .lead {
104 | font-size: 20px;
105 | }
106 | }
107 | @media (max-width: 991px) {
108 | .starter-template {
109 | margin-top: 0;
110 | }
111 | .starter-template .logo {
112 | margin: 40px auto;
113 | }
114 | .starter-template .content {
115 | margin-left: 0;
116 | text-align: center;
117 | }
118 | .starter-template .content h1 {
119 | margin-bottom: 20px;
120 | }
121 | .starter-template .links {
122 | float: none;
123 | text-align: center;
124 | margin-top: 60px;
125 | }
126 | .starter-template .copyright {
127 | float: none;
128 | text-align: center;
129 | }
130 | }
131 | @media (max-width: 767px) {
132 | .starter-template .content h1 .smaller {
133 | font-size: 25px;
134 | display: block;
135 | }
136 | .starter-template .content .lead {
137 | font-size: 16px;
138 | }
139 | .starter-template .links {
140 | margin-top: 40px;
141 | }
142 | .starter-template .links ul li {
143 | display: block;
144 | margin: 0;
145 | }
146 | .starter-template .links ul li .icon-muted {
147 | display: none;
148 | }
149 | .starter-template .copyright {
150 | margin-top: 20px;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/kees/templates/mytemplate.pt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Starter Scaffold for The Pyramid Web Framework
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
71 |
72 |
73 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/kees/static/listpoints.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | KivEnt Server
4 |
5 |
6 |
7 | KivEntEd Points
8 |
9 |
15 |
16 |
22 |
23 |
41 |
42 |
46 |
47 |
48 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/kees/static/showpoint.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | KivEnt Server
4 |
5 |
6 |
7 | KivEntEd Point
8 |
9 |
15 |
16 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/kees/static/showlevel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | KivEnt Server
4 |
5 |
6 |
7 | KivEntEd Level
8 |
9 |
15 |
16 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
196 |
197 |
198 |
--------------------------------------------------------------------------------
/kees/views.py:
--------------------------------------------------------------------------------
1 | from pyramid.view import view_config
2 |
3 | import os
4 | import uuid
5 | import string
6 | import dblayer
7 | import datetime
8 | from pyramid.response import Response
9 |
10 |
11 | if not os.path.exists("kees/pplevels"):os.makedirs("kees/pplevels")
12 | if not os.path.exists("kees/thumbs"):os.makedirs("kees/thumbs")
13 | if not os.path.exists("kees/crashs"):os.makedirs("kees/crashs")
14 |
15 | def pythonicVarName(field):
16 | firstLetter = True
17 | for word in field.split(' '):
18 | if firstLetter == False:
19 | wordCapped = str(word[0]).upper() + word[1:]
20 | id = id + wordCapped
21 | else:
22 | id = word.lower()
23 | firstLetter = False
24 | for i in string.punctuation:
25 | if i in id:
26 | id = id.replace(i, "")
27 | return id
28 |
29 | def write_a_file(file_path, input_file):
30 | temp_file_path = file_path + '~'
31 | output_file = open(temp_file_path, 'wb')
32 |
33 | # Finally write the data to a temporary file
34 | input_file.seek(0)
35 | while True:
36 | data = input_file.read(2<<16)
37 | if not data:
38 | break
39 | output_file.write(data)
40 |
41 | # If your data is really critical you may want to force it to disk first
42 | # using output_file.flush(); os.fsync(output_file.fileno())
43 |
44 | output_file.close()
45 |
46 | # Now that we know the file has been fully saved to disk move it into place.
47 |
48 | os.rename(temp_file_path, file_path)
49 | def write_some_data(file_path, input_data):
50 | temp_file_path = file_path + '~'
51 | output_file = open(temp_file_path, 'wb')
52 |
53 | # Finally write the data to a temporary file
54 | output_file.write(input_data)
55 |
56 | # If your data is really critical you may want to force it to disk first
57 | # using output_file.flush(); os.fsync(output_file.fileno())
58 |
59 | output_file.close()
60 |
61 | # Now that we know the file has been fully saved to disk move it into place.
62 |
63 | os.rename(temp_file_path, file_path)
64 |
65 | @view_config(route_name='home', renderer='templates/mytemplate.pt')
66 | def my_view(request):
67 | return {'project': 'kees'}
68 |
69 |
70 | #@view_config(route_name='home', renderer='json')
71 | #def my_view(request):
72 | # return {"text":"hello"}
73 |
74 | @view_config(route_name='new_user', renderer='json')
75 | def new_user(request):
76 | i = request.POST
77 | username = i['username']
78 | print username
79 | password = i['password']
80 | return dblayer.new_user(username,password)
81 | @view_config(route_name='login', renderer='json')
82 | def login(request):
83 | i = request.POST
84 | username = i['username']
85 | password = i['password']
86 | return dblayer.login(username,password)
87 |
88 | @view_config(route_name='query_levels', renderer='json')
89 | def query_levels(request):
90 | i = request.POST
91 | sortKey = str(i['sortKey'])
92 | cursor = int(i['cursor'])
93 | limit = int(i['limit'])
94 | levels = dblayer.query_levels(sortKey,cursor,limit)
95 | #return Response("OK")
96 | return levels
97 |
98 | @view_config(route_name='query_points', renderer='json')
99 | def query_points(request):
100 | print "points"
101 | i = request.POST
102 | sortKey = str(i['sortKey'])
103 | cursor = int(i['cursor'])
104 | limit = int(i['limit'])
105 | points = dblayer.query_points(sortKey,cursor,limit)
106 | print points
107 | return points
108 |
109 | @view_config(route_name='get_tags', renderer='json')
110 | def get_tags(request):
111 | print "TAGS"
112 | i = request.POST
113 | print i
114 | docid = i['id']
115 | print "requesting: ", docid
116 | tags = dblayer.get_tags(docid)
117 | print tags
118 | return tags
119 |
120 | @view_config(route_name='get_point', renderer='json')
121 | def get_point(request):
122 | print "HELLO"
123 | i = request.POST
124 | print i
125 | docid = i['id']
126 | dbid = 'points'#i['dbid']
127 | print "docid=",docid
128 | point = dblayer.get_one(dbid, uid=docid)
129 | print point
130 | return point
131 |
132 | @view_config(route_name='get_level', renderer='json')
133 | def get_level(request):
134 | print "HELLO"
135 | i = request.POST
136 | print i
137 | docid = i['id']
138 | dbid = 'pplevels'#i['dbid']
139 | print "docid=",docid
140 | point = dblayer.get_one(dbid, uid=docid)
141 | print point
142 | return point
143 |
144 | @view_config(route_name='add_vote', renderer='json')
145 | def add_vote(request):
146 | i = request.POST
147 | print i
148 | dbid = str(i['dbid'])
149 | print dbid
150 | if dbid not in ['points', 'pplevels']:
151 | print "db not accepted"
152 | return {"status":"fail"}
153 | print "db accepted"
154 | session = str(i['session'])
155 | print "session=", session
156 | val = float(i['val'])
157 | print "val=", val
158 | docid = str(i['docid'])
159 | print "docid=", docid
160 | tag = i.get('tag', None)
161 |
162 | return dblayer.add_vote(session,val,docid,dbid,tag=tag)
163 |
164 | @view_config(route_name='add_point', renderer='json')
165 | def add_point(request):
166 | i = request.POST
167 | session = i['session']
168 | print session
169 | name = i['name']
170 | text = i['text']
171 | return dblayer.add_point(session, name, text)
172 |
173 | @view_config(route_name='uploadLevel', renderer='json')
174 | def uploadLevel(request):
175 | i = request.POST
176 | session = i['session'].file.read()
177 | print session
178 | author = i['author'].file.read()
179 | name = i['name'].file.read()
180 | leveldata = i['leveldata'].file
181 | sshot = i['sshot'].file
182 | fullname = pythonicVarName(author+name)
183 | tags = i.get("tags_str").file.read()
184 | if dblayer.add_level(session, name, author, fullname, tags):
185 |
186 |
187 | namepath = "kees/pplevels/" + fullname
188 | write_a_file(namepath, leveldata)
189 |
190 | namepath = "kees/thumbs/" + fullname+".png"
191 | write_a_file(namepath, sshot)
192 |
193 | return {"result":"OK"}
194 | return {"result":"FAIL","dta":[session,author,name], "insessions":session in dblayer.sessions}
195 | #return Response("OK")
196 |
197 |
198 |
199 | @view_config(route_name='uploadCrash', renderer='json')
200 | def uploadCrash(request):
201 | i = request.POST
202 | print "POST uploading crash"
203 |
204 | now = str(datetime.datetime.now())
205 | crashData = i['crashData']
206 |
207 | namepath = "kees/crashs/" + now+"--" + str(i['version'])
208 | write_some_data(namepath, crashData)
209 |
210 | return {"result":"OK"}
211 |
212 | @view_config(route_name='crashLogs', renderer='json')
213 | def crashLogs(request):
214 | files = os.listdir('kees/crashs')
215 | #result = "".join(''+f+'
' for f in files)
216 | result = "".join(''+f+'
' for f in files)
217 | return Response(body=result,headerlist=[('Content-Type', 'text/html')])
218 |
219 |
220 | @view_config(route_name='store_mp3_view', renderer='json')
221 | def store_mp3_view(request):
222 | # ``filename`` contains the name of the file in string format.
223 | #
224 | # WARNING: this example does not deal with the fact that IE sends an
225 | # absolute file *path* as the filename. This example is naive; it
226 | # trusts user input.
227 |
228 | filename = request.POST['mp3'].filename
229 |
230 | # ``input_file`` contains the actual file data which needs to be
231 | # stored somewhere.
232 |
233 | input_file = request.POST['mp3'].file
234 |
235 | # Note that we are generating our own filename instead of trusting
236 | # the incoming filename since that might result in insecure paths.
237 | # Please note that in a real application you would not use /tmp,
238 | # and if you write to an untrusted location you will need to do
239 | # some extra work to prevent symlink attacks.
240 |
241 | file_path = os.path.join('/tmp', '%s.mp3' % uuid.uuid4())
242 |
243 | # We first write to a temporary file to prevent incomplete files from
244 | # being used.
245 |
246 | temp_file_path = file_path + '~'
247 | output_file = open(temp_file_path, 'wb')
248 |
249 | # Finally write the data to a temporary file
250 | input_file.seek(0)
251 | while True:
252 | data = input_file.read(2<<16)
253 | if not data:
254 | break
255 | output_file.write(data)
256 |
257 | # If your data is really critical you may want to force it to disk first
258 | # using output_file.flush(); os.fsync(output_file.fileno())
259 |
260 | output_file.close()
261 |
262 | # Now that we know the file has been fully saved to disk move it into place.
263 |
264 | os.rename(temp_file_path, file_path)
265 |
266 | return Response('OK')
--------------------------------------------------------------------------------
/kees/dblayer.py:
--------------------------------------------------------------------------------
1 | import datetime, time
2 | import dataset
3 | import uuid, hashlib
4 |
5 | #db = dataset.connect('sqlite:///:memory:')
6 | sessions = {}
7 | db = dataset.connect('sqlite:///mydatabase.db')
8 | '''database=db
9 |
10 | table = db['sometable']
11 | table.insert(dict(name='John Doe', age=37))
12 | table.insert(dict(name='Jane Doe', age=34, gender='female'))
13 |
14 | john = table.find_one(name='John Doe')
15 |
16 | print john
17 | '''
18 |
19 | def add_vote(session, val, docid, dbid='pplevels', tag=None):
20 | sRef = getsession(session)
21 | if not sRef:
22 | return False
23 | print val, docid, dbid, tag
24 | levelstable = db[dbid]
25 | for l in levelstable:
26 | print l
27 | record = levelstable.find_one(uid=docid)
28 | print docid
29 | print record, record==None
30 | if record == None:
31 | return {'result':'fail', 'reason':'voteable item not found'}
32 | username = sRef['username']
33 |
34 | istag = tag!=None
35 |
36 | votes_stable = db['votes']
37 | # votes_meta_table = db['votes_meta']
38 | # vote_meta = votes_meta_table.find_one(docid=docid)
39 | # if not vote_meta:
40 | # vote_meta = dict(docid=docid, votenum=1, rating=val, heat=1.)
41 | # else:
42 | if not istag:
43 | votenum=record['ratingCount']
44 | rating=record['rating']
45 | print "RATING working directly on record"
46 | else:
47 | print "TAG - working on meta"
48 | votes_group_table = db['vote_groups']
49 | vote_group = votes_group_table.find_one(dbid=dbid, docid=docid, tag=tag)
50 | if not vote_group:
51 | vote_group = new_vote_group(docid=docid, dbid=dbid, tag=tag)
52 | votenum=vote_group['ratingCount']
53 | rating=vote_group['rating']
54 | print "Rating was, ", rating
55 | print username,docid
56 | vote = votes_stable.find_one(user=username, docid=docid)
57 | print "-------------"
58 | print "vote=",vote
59 | print "val=", val
60 | print ""
61 | if not vote:
62 | vp1=float(votenum+1.)
63 | print "vp1=",vp1
64 | rating=rating/vp1*votenum+val/(vp1)
65 | votenum=vp1
66 | print "new vote, rating now, ", rating
67 | else:
68 | oldval=vote['value']
69 | print oldval, votenum
70 | if votenum<1:
71 | rating=val
72 | else:
73 | rating=rating-oldval/votenum+val/votenum
74 | print "re-vote, rating now, ", rating
75 |
76 | if not istag:
77 | vote_meta = dict(uid=docid, ratingCount=votenum, rating=rating)
78 | levelstable.update(vote_meta,['uid'])
79 | else:
80 | vote_group['ratingCount']=votenum
81 | vote_group['rating']=rating
82 | votes_group_table.upsert(vote_group, ['uid'])
83 | for v in votes_group_table:
84 | print v
85 |
86 | newVote = {"user":username, "value":val, "time":time.time(), "docid":docid}
87 | votes_stable.upsert(newVote,['user', 'docid'])
88 | print "xoxoxoxoxoxoxoxoxoxoxox"
89 | for v in votes_stable:
90 | print v
91 | return True
92 |
93 | def get_tags(docid):
94 | votes_group_table = db['vote_groups']
95 | for v in votes_group_table:
96 | print v['docid']
97 | rawtags = votes_group_table.find(docid=docid)
98 | tags = [x for x in rawtags]
99 | print "tags=", tags
100 | return tags
101 |
102 | def new_voteable(name, author):
103 | newLevel = {}
104 | newLevel['uid'] = uuid.uuid4().get_hex()
105 | newLevel['name'] = name
106 | newLevel['author'] = author
107 | nowStamp = time.time()
108 | newLevel['rating'] = .5
109 | newLevel['ratingCount'] = 0
110 | newLevel['dateAdded'] = nowStamp
111 | newLevel['dateModified'] = nowStamp
112 | return newLevel
113 |
114 | def new_vote_group(docid, dbid, tag):
115 | newLevel = {}
116 | newLevel['uid'] = uuid.uuid4().get_hex()
117 | newLevel['docid'] = docid
118 | newLevel['dbid'] = dbid
119 | newLevel['tag'] = tag
120 | nowStamp = time.time()
121 | newLevel['rating'] = .5
122 | newLevel['ratingCount'] = 0
123 | newLevel['dateAdded'] = nowStamp
124 | newLevel['dateModified'] = nowStamp
125 | return newLevel
126 |
127 | def add_level(session, name, author, fullname, tags_str=None, tags=[]):
128 | ses = getsession(session)
129 | if not ses:
130 | return False
131 | isNew = True
132 | levelstable = db['pplevels']
133 | record = levelstable.find_one(filename=fullname)
134 | print record, record==None
135 | if record != None:
136 | isNew = False
137 | print "not new"
138 | else:
139 | print "new"
140 | if (isNew):
141 | record = new_voteable(name,author)
142 | record['filename'] = fullname
143 | record['downloads'] = 0
144 | else:
145 | nowStamp = time.time()
146 | record['dateModified'] = nowStamp
147 | record['description'] = "description"
148 | #db.ppLevels[fullname] = newLevel
149 | levelstable.upsert(record,['filename'])
150 | print "tags_str:", tags_str
151 | if tags_str:
152 | tags = tags_str.split()
153 | print "tags:", tags
154 | if tags:
155 | for t in tags:
156 | print "adding tag:", t
157 | add_vote(session, 1, record['uid'], 'pplevels', tag=t)
158 | return True
159 |
160 | def add_point(session, name, text):
161 | ses = getsession(session)
162 | if not ses:
163 | return False
164 | author = ses['username']
165 | isNew = True
166 | levelstable = db['points']
167 | #record = levelstable.find_one(filename=fullname)
168 | record = new_voteable(name,author)
169 | #record['filename'] = fullname
170 | #record['downloads'] = 0
171 | record['text'] = text
172 | #db.ppLevels[fullname] = newLevel
173 | levelstable.insert(record)
174 | return record
175 | def query_levels(sortKey, cursor=0, limit=8, **_filter):
176 | levelstable = db['pplevels']
177 | print limit, cursor, sortKey
178 | a= levelstable.find(_limit=limit, _offset=cursor, order_by=sortKey, **_filter)
179 | return [x for x in a]
180 | def query_points(sortKey, cursor=0, limit=8, **_filter):
181 | levelstable = db['points']
182 | print limit, cursor, sortKey
183 | a= levelstable.find(_limit=limit, _offset=cursor, order_by=sortKey, **_filter)
184 | return [x for x in a]
185 | def get_one(dbid, **_filter):
186 | print "get_one"
187 | print dbid
188 | levelstable = db[dbid]
189 | print levelstable
190 | a= levelstable.find_one(**_filter)
191 | print a
192 | return a
193 |
194 | def getsession(session):
195 | if sessions.has_key(session) == False:
196 | return False
197 | sRef = sessions[session]
198 | sRef['lastTouch'] = time.time()
199 | return sRef
200 |
201 | def newSession(username, userRef):
202 | timeNow = time.time()
203 | session = {}
204 | session['_id'] = uuid.uuid4().get_hex()
205 | session['startTime'] = timeNow
206 | session['lastTouch'] = timeNow
207 | session['info'] = {}
208 | sessions[session['_id']] = session
209 | session['username'] = username
210 | # TODO CHECK FOR TIMED OUT SESSIONS elsewhere
211 | checkTimedOutSessions()
212 | return session
213 |
214 | def checkTimedOutSessions():
215 | texpire = time.time()-1000*60*60#*24*7
216 | remsessions = []
217 | for sid in sessions:
218 | sRef = sessions[sid]
219 | if sRef['lastTouch'] < texpire:
220 | remsessions.append(sid)
221 | #sessions.pop(sid)
222 | for s in remsessions:
223 | sessions.pop(s)
224 |
225 | def login(username, password):
226 | username = username.replace(".","")
227 | usertable = db['users']
228 | eUser = usertable.find_one(username=username)
229 | if(eUser):
230 | # makeImage(username)
231 | if hashlib.sha512(password + eUser['salt']).hexdigest() == eUser['password']:
232 | session = newSession(username, eUser)
233 | eUser['lastTouch'] = time.time()
234 | usertable.update(eUser,['username'])
235 | returnInfo = {"result":"OK", "session":session['_id'], "message":"logged in", "username":username, "_id":username, "noteCount":eUser['noteCount']}
236 | print returnInfo
237 | return returnInfo
238 | wrongpass = {"result":"fail", "message":"incorrect password"}
239 | print wrongpass
240 | return wrongpass
241 | wrongUser = {"result":"fail", "message":"user not found"}
242 | print wrongUser
243 | return wrongUser
244 |
245 | def new_user(username, password):
246 | username = username.replace(".","")
247 | usertable = db['users']
248 | #eUser = database.users.find_one({"_id":username})
249 | eUser = usertable.find_one(username=username)
250 | print eUser
251 | if(eUser):
252 | print "dupe account creation attempt on name: " + username
253 | return login(username, password)
254 | return {"result":"fail", "message":"name taken"}
255 | newUser = {}
256 | newUser['createdAt'] = time.time()
257 | newUser['lastTouch'] = time.time()
258 | salt = newUser['salt'] = uuid.uuid4().get_hex()
259 | #newUser['_id'] = username
260 | #makeImage(username)
261 | newUser['username'] = username
262 | newUser['noteCount'] = 0
263 | #newUser['groups'] = []
264 | newUser['password'] = hashlib.sha512(password + salt).hexdigest()
265 | usertable.insert(newUser)
266 | #database.users.insert(newUser)
267 | print {"result":"OK", "message":"account " + username + " created"}
--------------------------------------------------------------------------------
/kees/static/listlevels.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | KivEnt Server
4 |
5 |
6 |
7 | KivEntEd Levels
8 |
26 |
27 |
31 |
32 |
33 |
238 |
239 |
240 |
--------------------------------------------------------------------------------
/kees/static/zepto.min.js:
--------------------------------------------------------------------------------
1 | /* Zepto v1.0-1-ga3cab6c - polyfill zepto detect event ajax form fx - zeptojs.com/license */
2 | (function(a){String.prototype.trim===a&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),Array.prototype.reduce===a&&(Array.prototype.reduce=function(b){if(this===void 0||this===null)throw new TypeError;var c=Object(this),d=c.length>>>0,e=0,f;if(typeof b!="function")throw new TypeError;if(d==0&&arguments.length==1)throw new TypeError;if(arguments.length>=2)f=arguments[1];else do{if(e in c){f=c[e++];break}if(++e>=d)throw new TypeError}while(!0);while(e0?c.fn.concat.apply([],a):a}function O(a){return a.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function P(a){return a in j?j[a]:j[a]=new RegExp("(^|\\s)"+a+"(\\s|$)")}function Q(a,b){return typeof b=="number"&&!l[O(a)]?b+"px":b}function R(a){var b,c;return i[a]||(b=h.createElement(a),h.body.appendChild(b),c=k(b,"").getPropertyValue("display"),b.parentNode.removeChild(b),c=="none"&&(c="block"),i[a]=c),i[a]}function S(a){return"children"in a?f.call(a.children):c.map(a.childNodes,function(a){if(a.nodeType==1)return a})}function T(c,d,e){for(b in d)e&&(J(d[b])||K(d[b]))?(J(d[b])&&!J(c[b])&&(c[b]={}),K(d[b])&&!K(c[b])&&(c[b]=[]),T(c[b],d[b],e)):d[b]!==a&&(c[b]=d[b])}function U(b,d){return d===a?c(b):c(b).filter(d)}function V(a,b,c,d){return F(b)?b.call(a,c,d):b}function W(a,b,c){c==null?a.removeAttribute(b):a.setAttribute(b,c)}function X(b,c){var d=b.className,e=d&&d.baseVal!==a;if(c===a)return e?d.baseVal:d;e?d.baseVal=c:b.className=c}function Y(a){var b;try{return a?a=="true"||(a=="false"?!1:a=="null"?null:isNaN(b=Number(a))?/^[\[\{]/.test(a)?c.parseJSON(a):a:b):a}catch(d){return a}}function Z(a,b){b(a);for(var c in a.childNodes)Z(a.childNodes[c],b)}var a,b,c,d,e=[],f=e.slice,g=e.filter,h=window.document,i={},j={},k=h.defaultView.getComputedStyle,l={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},m=/^\s*<(\w+|!)[^>]*>/,n=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,o=/^(?:body|html)$/i,p=["val","css","html","text","data","width","height","offset"],q=["after","prepend","before","append"],r=h.createElement("table"),s=h.createElement("tr"),t={tr:h.createElement("tbody"),tbody:r,thead:r,tfoot:r,td:s,th:s,"*":h.createElement("div")},u=/complete|loaded|interactive/,v=/^\.([\w-]+)$/,w=/^#([\w-]*)$/,x=/^[\w-]+$/,y={},z=y.toString,A={},B,C,D=h.createElement("div");return A.matches=function(a,b){if(!a||a.nodeType!==1)return!1;var c=a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.matchesSelector;if(c)return c.call(a,b);var d,e=a.parentNode,f=!e;return f&&(e=D).appendChild(a),d=~A.qsa(e,b).indexOf(a),f&&D.removeChild(a),d},B=function(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():""})},C=function(a){return g.call(a,function(b,c){return a.indexOf(b)==c})},A.fragment=function(b,d,e){b.replace&&(b=b.replace(n,"<$1>$2>")),d===a&&(d=m.test(b)&&RegExp.$1),d in t||(d="*");var g,h,i=t[d];return i.innerHTML=""+b,h=c.each(f.call(i.childNodes),function(){i.removeChild(this)}),J(e)&&(g=c(h),c.each(e,function(a,b){p.indexOf(a)>-1?g[a](b):g.attr(a,b)})),h},A.Z=function(a,b){return a=a||[],a.__proto__=c.fn,a.selector=b||"",a},A.isZ=function(a){return a instanceof A.Z},A.init=function(b,d){if(!b)return A.Z();if(F(b))return c(h).ready(b);if(A.isZ(b))return b;var e;if(K(b))e=M(b);else if(I(b))e=[J(b)?c.extend({},b):b],b=null;else if(m.test(b))e=A.fragment(b.trim(),RegExp.$1,d),b=null;else{if(d!==a)return c(d).find(b);e=A.qsa(h,b)}return A.Z(e,b)},c=function(a,b){return A.init(a,b)},c.extend=function(a){var b,c=f.call(arguments,1);return typeof a=="boolean"&&(b=a,a=c.shift()),c.forEach(function(c){T(a,c,b)}),a},A.qsa=function(a,b){var c;return H(a)&&w.test(b)?(c=a.getElementById(RegExp.$1))?[c]:[]:a.nodeType!==1&&a.nodeType!==9?[]:f.call(v.test(b)?a.getElementsByClassName(RegExp.$1):x.test(b)?a.getElementsByTagName(b):a.querySelectorAll(b))},c.contains=function(a,b){return a!==b&&a.contains(b)},c.type=E,c.isFunction=F,c.isWindow=G,c.isArray=K,c.isPlainObject=J,c.isEmptyObject=function(a){var b;for(b in a)return!1;return!0},c.inArray=function(a,b,c){return e.indexOf.call(b,a,c)},c.camelCase=B,c.trim=function(a){return a.trim()},c.uuid=0,c.support={},c.expr={},c.map=function(a,b){var c,d=[],e,f;if(L(a))for(e=0;e=0?b:b+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){this.parentNode!=null&&this.parentNode.removeChild(this)})},each:function(a){return e.every.call(this,function(b,c){return a.call(b,c,b)!==!1}),this},filter:function(a){return F(a)?this.not(this.not(a)):c(g.call(this,function(b){return A.matches(b,a)}))},add:function(a,b){return c(C(this.concat(c(a,b))))},is:function(a){return this.length>0&&A.matches(this[0],a)},not:function(b){var d=[];if(F(b)&&b.call!==a)this.each(function(a){b.call(this,a)||d.push(this)});else{var e=typeof b=="string"?this.filter(b):L(b)&&F(b.item)?f.call(b):c(b);this.forEach(function(a){e.indexOf(a)<0&&d.push(a)})}return c(d)},has:function(a){return this.filter(function(){return I(a)?c.contains(this,a):c(this).find(a).size()})},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){var a=this[0];return a&&!I(a)?a:c(a)},last:function(){var a=this[this.length-1];return a&&!I(a)?a:c(a)},find:function(a){var b,d=this;return typeof a=="object"?b=c(a).filter(function(){var a=this;return e.some.call(d,function(b){return c.contains(b,a)})}):this.length==1?b=c(A.qsa(this[0],a)):b=this.map(function(){return A.qsa(this,a)}),b},closest:function(a,b){var d=this[0],e=!1;typeof a=="object"&&(e=c(a));while(d&&!(e?e.indexOf(d)>=0:A.matches(d,a)))d=d!==b&&!H(d)&&d.parentNode;return c(d)},parents:function(a){var b=[],d=this;while(d.length>0)d=c.map(d,function(a){if((a=a.parentNode)&&!H(a)&&b.indexOf(a)<0)return b.push(a),a});return U(b,a)},parent:function(a){return U(C(this.pluck("parentNode")),a)},children:function(a){return U(this.map(function(){return S(this)}),a)},contents:function(){return this.map(function(){return f.call(this.childNodes)})},siblings:function(a){return U(this.map(function(a,b){return g.call(S(b.parentNode),function(a){return a!==b})}),a)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(a){return c.map(this,function(b){return b[a]})},show:function(){return this.each(function(){this.style.display=="none"&&(this.style.display=null),k(this,"").getPropertyValue("display")=="none"&&(this.style.display=R(this.nodeName))})},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){var b=F(a);if(this[0]&&!b)var d=c(a).get(0),e=d.parentNode||this.length>1;return this.each(function(f){c(this).wrapAll(b?a.call(this,f):e?d.cloneNode(!0):d)})},wrapAll:function(a){if(this[0]){c(this[0]).before(a=c(a));var b;while((b=a.children()).length)a=b.first();c(a).append(this)}return this},wrapInner:function(a){var b=F(a);return this.each(function(d){var e=c(this),f=e.contents(),g=b?a.call(this,d):a;f.length?f.wrapAll(g):e.append(g)})},unwrap:function(){return this.parent().each(function(){c(this).replaceWith(c(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(b){return this.each(function(){var d=c(this);(b===a?d.css("display")=="none":b)?d.show():d.hide()})},prev:function(a){return c(this.pluck("previousElementSibling")).filter(a||"*")},next:function(a){return c(this.pluck("nextElementSibling")).filter(a||"*")},html:function(b){return b===a?this.length>0?this[0].innerHTML:null:this.each(function(a){var d=this.innerHTML;c(this).empty().append(V(this,b,a,d))})},text:function(b){return b===a?this.length>0?this[0].textContent:null:this.each(function(){this.textContent=b})},attr:function(c,d){var e;return typeof c=="string"&&d===a?this.length==0||this[0].nodeType!==1?a:c=="value"&&this[0].nodeName=="INPUT"?this.val():!(e=this[0].getAttribute(c))&&c in this[0]?this[0][c]:e:this.each(function(a){if(this.nodeType!==1)return;if(I(c))for(b in c)W(this,b,c[b]);else W(this,c,V(this,d,a,this.getAttribute(c)))})},removeAttr:function(a){return this.each(function(){this.nodeType===1&&W(this,a)})},prop:function(b,c){return c===a?this[0]&&this[0][b]:this.each(function(a){this[b]=V(this,c,a,this[b])})},data:function(b,c){var d=this.attr("data-"+O(b),c);return d!==null?Y(d):a},val:function(b){return b===a?this[0]&&(this[0].multiple?c(this[0]).find("option").filter(function(a){return this.selected}).pluck("value"):this[0].value):this.each(function(a){this.value=V(this,b,a,this.value)})},offset:function(a){if(a)return this.each(function(b){var d=c(this),e=V(this,a,b,d.offset()),f=d.offsetParent().offset(),g={top:e.top-f.top,left:e.left-f.left};d.css("position")=="static"&&(g.position="relative"),d.css(g)});if(this.length==0)return null;var b=this[0].getBoundingClientRect();return{left:b.left+window.pageXOffset,top:b.top+window.pageYOffset,width:Math.round(b.width),height:Math.round(b.height)}},css:function(a,c){if(arguments.length<2&&typeof a=="string")return this[0]&&(this[0].style[B(a)]||k(this[0],"").getPropertyValue(a));var d="";if(E(a)=="string")!c&&c!==0?this.each(function(){this.style.removeProperty(O(a))}):d=O(a)+":"+Q(a,c);else for(b in a)!a[b]&&a[b]!==0?this.each(function(){this.style.removeProperty(O(b))}):d+=O(b)+":"+Q(b,a[b])+";";return this.each(function(){this.style.cssText+=";"+d})},index:function(a){return a?this.indexOf(c(a)[0]):this.parent().children().indexOf(this[0])},hasClass:function(a){return e.some.call(this,function(a){return this.test(X(a))},P(a))},addClass:function(a){return this.each(function(b){d=[];var e=X(this),f=V(this,a,b,e);f.split(/\s+/g).forEach(function(a){c(this).hasClass(a)||d.push(a)},this),d.length&&X(this,e+(e?" ":"")+d.join(" "))})},removeClass:function(b){return this.each(function(c){if(b===a)return X(this,"");d=X(this),V(this,b,c,d).split(/\s+/g).forEach(function(a){d=d.replace(P(a)," ")}),X(this,d.trim())})},toggleClass:function(b,d){return this.each(function(e){var f=c(this),g=V(this,b,e,X(this));g.split(/\s+/g).forEach(function(b){(d===a?!f.hasClass(b):d)?f.addClass(b):f.removeClass(b)})})},scrollTop:function(){if(!this.length)return;return"scrollTop"in this[0]?this[0].scrollTop:this[0].scrollY},position:function(){if(!this.length)return;var a=this[0],b=this.offsetParent(),d=this.offset(),e=o.test(b[0].nodeName)?{top:0,left:0}:b.offset();return d.top-=parseFloat(c(a).css("margin-top"))||0,d.left-=parseFloat(c(a).css("margin-left"))||0,e.top+=parseFloat(c(b[0]).css("border-top-width"))||0,e.left+=parseFloat(c(b[0]).css("border-left-width"))||0,{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||h.body;while(a&&!o.test(a.nodeName)&&c(a).css("position")=="static")a=a.offsetParent;return a})}},c.fn.detach=c.fn.remove,["width","height"].forEach(function(b){c.fn[b]=function(d){var e,f=this[0],g=b.replace(/./,function(a){return a[0].toUpperCase()});return d===a?G(f)?f["inner"+g]:H(f)?f.documentElement["offset"+g]:(e=this.offset())&&e[b]:this.each(function(a){f=c(this),f.css(b,V(this,d,a,f[b]()))})}}),q.forEach(function(a,b){var d=b%2;c.fn[a]=function(){var a,e=c.map(arguments,function(b){return a=E(b),a=="object"||a=="array"||b==null?b:A.fragment(b)}),f,g=this.length>1;return e.length<1?this:this.each(function(a,h){f=d?h:h.parentNode,h=b==0?h.nextSibling:b==1?h.firstChild:b==2?h:null,e.forEach(function(a){if(g)a=a.cloneNode(!0);else if(!f)return c(a).remove();Z(f.insertBefore(a,h),function(a){a.nodeName!=null&&a.nodeName.toUpperCase()==="SCRIPT"&&(!a.type||a.type==="text/javascript")&&!a.src&&window.eval.call(window,a.innerHTML)})})})},c.fn[d?a+"To":"insert"+(b?"Before":"After")]=function(b){return c(b)[a](this),this}}),A.Z.prototype=c.fn,A.uniq=C,A.deserializeValue=Y,c.zepto=A,c}();window.Zepto=Zepto,"$"in window||(window.$=Zepto),function(a){function b(a){var b=this.os={},c=this.browser={},d=a.match(/WebKit\/([\d.]+)/),e=a.match(/(Android)\s+([\d.]+)/),f=a.match(/(iPad).*OS\s([\d_]+)/),g=!f&&a.match(/(iPhone\sOS)\s([\d_]+)/),h=a.match(/(webOS|hpwOS)[\s\/]([\d.]+)/),i=h&&a.match(/TouchPad/),j=a.match(/Kindle\/([\d.]+)/),k=a.match(/Silk\/([\d._]+)/),l=a.match(/(BlackBerry).*Version\/([\d.]+)/),m=a.match(/(BB10).*Version\/([\d.]+)/),n=a.match(/(RIM\sTablet\sOS)\s([\d.]+)/),o=a.match(/PlayBook/),p=a.match(/Chrome\/([\d.]+)/)||a.match(/CriOS\/([\d.]+)/),q=a.match(/Firefox\/([\d.]+)/);if(c.webkit=!!d)c.version=d[1];e&&(b.android=!0,b.version=e[2]),g&&(b.ios=b.iphone=!0,b.version=g[2].replace(/_/g,".")),f&&(b.ios=b.ipad=!0,b.version=f[2].replace(/_/g,".")),h&&(b.webos=!0,b.version=h[2]),i&&(b.touchpad=!0),l&&(b.blackberry=!0,b.version=l[2]),m&&(b.bb10=!0,b.version=m[2]),n&&(b.rimtabletos=!0,b.version=n[2]),o&&(c.playbook=!0),j&&(b.kindle=!0,b.version=j[1]),k&&(c.silk=!0,c.version=k[1]),!k&&b.android&&a.match(/Kindle Fire/)&&(c.silk=!0),p&&(c.chrome=!0,c.version=p[1]),q&&(c.firefox=!0,c.version=q[1]),b.tablet=!!(f||o||e&&!a.match(/Mobile/)||q&&a.match(/Tablet/)),b.phone=!b.tablet&&!!(e||g||h||l||m||p&&a.match(/Android/)||p&&a.match(/CriOS\/([\d.]+)/)||q&&a.match(/Mobile/))}b.call(a,navigator.userAgent),a.__detect=b}(Zepto),function(a){function g(a){return a._zid||(a._zid=d++)}function h(a,b,d,e){b=i(b);if(b.ns)var f=j(b.ns);return(c[g(a)]||[]).filter(function(a){return a&&(!b.e||a.e==b.e)&&(!b.ns||f.test(a.ns))&&(!d||g(a.fn)===g(d))&&(!e||a.sel==e)})}function i(a){var b=(""+a).split(".");return{e:b[0],ns:b.slice(1).sort().join(" ")}}function j(a){return new RegExp("(?:^| )"+a.replace(" "," .* ?")+"(?: |$)")}function k(b,c,d){a.type(b)!="string"?a.each(b,d):b.split(/\s/).forEach(function(a){d(a,c)})}function l(a,b){return a.del&&(a.e=="focus"||a.e=="blur")||!!b}function m(a){return f[a]||a}function n(b,d,e,h,j,n){var o=g(b),p=c[o]||(c[o]=[]);k(d,e,function(c,d){var e=i(c);e.fn=d,e.sel=h,e.e in f&&(d=function(b){var c=b.relatedTarget;if(!c||c!==this&&!a.contains(this,c))return e.fn.apply(this,arguments)}),e.del=j&&j(d,c);var g=e.del||d;e.proxy=function(a){var c=g.apply(b,[a].concat(a.data));return c===!1&&(a.preventDefault(),a.stopPropagation()),c},e.i=p.length,p.push(e),b.addEventListener(m(e.e),e.proxy,l(e,n))})}function o(a,b,d,e,f){var i=g(a);k(b||"",d,function(b,d){h(a,b,d,e).forEach(function(b){delete c[i][b.i],a.removeEventListener(m(b.e),b.proxy,l(b,f))})})}function t(b){var c,d={originalEvent:b};for(c in b)!r.test(c)&&b[c]!==undefined&&(d[c]=b[c]);return a.each(s,function(a,c){d[a]=function(){return this[c]=p,b[a].apply(b,arguments)},d[c]=q}),d}function u(a){if(!("defaultPrevented"in a)){a.defaultPrevented=!1;var b=a.preventDefault;a.preventDefault=function(){this.defaultPrevented=!0,b.call(this)}}}var b=a.zepto.qsa,c={},d=1,e={},f={mouseenter:"mouseover",mouseleave:"mouseout"};e.click=e.mousedown=e.mouseup=e.mousemove="MouseEvents",a.event={add:n,remove:o},a.proxy=function(b,c){if(a.isFunction(b)){var d=function(){return b.apply(c,arguments)};return d._zid=g(b),d}if(typeof c=="string")return a.proxy(b[c],b);throw new TypeError("expected function")},a.fn.bind=function(a,b){return this.each(function(){n(this,a,b)})},a.fn.unbind=function(a,b){return this.each(function(){o(this,a,b)})},a.fn.one=function(a,b){return this.each(function(c,d){n(this,a,b,null,function(a,b){return function(){var c=a.apply(d,arguments);return o(d,b,a),c}})})};var p=function(){return!0},q=function(){return!1},r=/^([A-Z]|layer[XY]$)/,s={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};a.fn.delegate=function(b,c,d){return this.each(function(e,f){n(f,c,d,b,function(c){return function(d){var e,g=a(d.target).closest(b,f).get(0);if(g)return e=a.extend(t(d),{currentTarget:g,liveFired:f}),c.apply(g,[e].concat([].slice.call(arguments,1)))}})})},a.fn.undelegate=function(a,b,c){return this.each(function(){o(this,b,c,a)})},a.fn.live=function(b,c){return a(document.body).delegate(this.selector,b,c),this},a.fn.die=function(b,c){return a(document.body).undelegate(this.selector,b,c),this},a.fn.on=function(b,c,d){return!c||a.isFunction(c)?this.bind(b,c||d):this.delegate(c,b,d)},a.fn.off=function(b,c,d){return!c||a.isFunction(c)?this.unbind(b,c||d):this.undelegate(c,b,d)},a.fn.trigger=function(b,c){if(typeof b=="string"||a.isPlainObject(b))b=a.Event(b);return u(b),b.data=c,this.each(function(){"dispatchEvent"in this&&this.dispatchEvent(b)})},a.fn.triggerHandler=function(b,c){var d,e;return this.each(function(f,g){d=t(typeof b=="string"?a.Event(b):b),d.data=c,d.target=g,a.each(h(g,b.type||b),function(a,b){e=b.proxy(d);if(d.isImmediatePropagationStopped())return!1})}),e},"focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(b){a.fn[b]=function(a){return a?this.bind(b,a):this.trigger(b)}}),["focus","blur"].forEach(function(b){a.fn[b]=function(a){return a?this.bind(b,a):this.each(function(){try{this[b]()}catch(a){}}),this}}),a.Event=function(a,b){typeof a!="string"&&(b=a,a=b.type);var c=document.createEvent(e[a]||"Events"),d=!0;if(b)for(var f in b)f=="bubbles"?d=!!b[f]:c[f]=b[f];return c.initEvent(a,d,!0,null,null,null,null,null,null,null,null,null,null,null,null),c.isDefaultPrevented=function(){return this.defaultPrevented},c}}(Zepto),function($){function triggerAndReturn(a,b,c){var d=$.Event(b);return $(a).trigger(d,c),!d.defaultPrevented}function triggerGlobal(a,b,c,d){if(a.global)return triggerAndReturn(b||document,c,d)}function ajaxStart(a){a.global&&$.active++===0&&triggerGlobal(a,null,"ajaxStart")}function ajaxStop(a){a.global&&!--$.active&&triggerGlobal(a,null,"ajaxStop")}function ajaxBeforeSend(a,b){var c=b.context;if(b.beforeSend.call(c,a,b)===!1||triggerGlobal(b,c,"ajaxBeforeSend",[a,b])===!1)return!1;triggerGlobal(b,c,"ajaxSend",[a,b])}function ajaxSuccess(a,b,c){var d=c.context,e="success";c.success.call(d,a,e,b),triggerGlobal(c,d,"ajaxSuccess",[b,c,a]),ajaxComplete(e,b,c)}function ajaxError(a,b,c,d){var e=d.context;d.error.call(e,c,b,a),triggerGlobal(d,e,"ajaxError",[c,d,a]),ajaxComplete(b,c,d)}function ajaxComplete(a,b,c){var d=c.context;c.complete.call(d,b,a),triggerGlobal(c,d,"ajaxComplete",[b,c]),ajaxStop(c)}function empty(){}function mimeToDataType(a){return a&&(a=a.split(";",2)[0]),a&&(a==htmlType?"html":a==jsonType?"json":scriptTypeRE.test(a)?"script":xmlTypeRE.test(a)&&"xml")||"text"}function appendQuery(a,b){return(a+"&"+b).replace(/[&?]{1,2}/,"?")}function serializeData(a){a.processData&&a.data&&$.type(a.data)!="string"&&(a.data=$.param(a.data,a.traditional)),a.data&&(!a.type||a.type.toUpperCase()=="GET")&&(a.url=appendQuery(a.url,a.data))}function parseArguments(a,b,c,d){var e=!$.isFunction(b);return{url:a,data:e?b:undefined,success:e?$.isFunction(c)?c:undefined:b,dataType:e?d||c:c}}function serialize(a,b,c,d){var e,f=$.isArray(b);$.each(b,function(b,g){e=$.type(g),d&&(b=c?d:d+"["+(f?"":b)+"]"),!d&&f?a.add(g.name,g.value):e=="array"||!c&&e=="object"?serialize(a,g,c,b):a.add(b,g)})}var jsonpID=0,document=window.document,key,name,rscript=/