From 6a2977830e14dba526d01a4f77b3e9c01f8b2d34 Mon Sep 17 00:00:00 2001 From: Lyc-heng <18087603176@163.com> Date: Tue, 24 Jul 2018 22:17:07 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E7=94=B5=E8=84=91=E9=87=8D=E8=A3=85?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E6=96=B0=E5=88=9D=E5=A7=8B=E5=8C=96=E4=BB=93?= =?UTF-8?q?=E5=BA=93=EF=BC=8C=E5=9C=A8=E4=B9=8B=E5=89=8D=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=9A=84=E5=9F=BA=E7=A1=80=E4=B8=8A=E5=A2=9E=E5=8A=A0=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E8=A1=A8=E5=8D=95=E6=94=B9=E7=94=A8ajax=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=EF=BC=8Chash=E5=AD=98=E5=82=A8=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E4=BA=86sha512=E7=AE=97=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + app.py | 98 +++++++++- database.py | 25 +++ file.py | 56 +++++- forms/signin_form.py | 16 ++ forms/signup_form.py | 12 ++ forms/upload_form.py | 8 + models.py | 20 ++ signinup.py | 51 +++++ static/css/download.css | 31 ++++ static/css/login.css | 39 ++++ static/images/cloud10.png | Bin 0 -> 58580 bytes static/js/RequestAnimationFrame.js | 22 +++ static/js/ThreeExtras.js | 175 ++++++++++++++++++ static/js/ThreeWebGL.js | 286 +++++++++++++++++++++++++++++ static/js/checkPassword.js | 114 ++++++++++++ static/js/lanrenzhijia.js | 60 ++++++ static/js/lib/jquery-3.3.1.min.js | 2 + static/js/lib/sha512.min.js | 9 + templates/csrf/csrf_error.html | 3 + templates/index.html | 237 ++++++++++++++++++++++++ templates/login/signin.html | 46 +++++ templates/login/signup.html | 51 +++++ templates/upload/download.html | 17 ++ templates/upload/upload.html | 30 +++ 25 files changed, 1401 insertions(+), 11 deletions(-) create mode 100644 database.py create mode 100644 forms/signin_form.py create mode 100644 forms/signup_form.py create mode 100644 forms/upload_form.py create mode 100644 models.py create mode 100644 signinup.py create mode 100644 static/css/download.css create mode 100644 static/css/login.css create mode 100644 static/images/cloud10.png create mode 100644 static/js/RequestAnimationFrame.js create mode 100644 static/js/ThreeExtras.js create mode 100644 static/js/ThreeWebGL.js create mode 100644 static/js/checkPassword.js create mode 100644 static/js/lanrenzhijia.js create mode 100644 static/js/lib/jquery-3.3.1.min.js create mode 100644 static/js/lib/sha512.min.js create mode 100644 templates/csrf/csrf_error.html create mode 100644 templates/index.html create mode 100644 templates/login/signin.html create mode 100644 templates/login/signup.html create mode 100644 templates/upload/download.html create mode 100644 templates/upload/upload.html diff --git a/.gitignore b/.gitignore index d4d1bdc..f6eb7a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .idea/ __pycache__/ config.py +forms/__pycache__/ +instance +templates/login/debug.log +templates/upload/debug.log \ No newline at end of file diff --git a/app.py b/app.py index 4a13921..1814d08 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,84 @@ from flask import Flask, request import mail import file +from flask import render_template, redirect, url_for, request +from forms.signin_form import LoginForm +from forms.signup_form import RegisterForm +from flask_wtf.csrf import CSRFProtect, CSRFError +from werkzeug.exceptions import HTTPException, NotFound +from flask_login import LoginManager, login_required, login_user, logout_user -app = Flask(__name__) +import os +import config + +from database import create_app, add_user +from models import User +import signinup + +app = create_app() +# 防止跨站脚本攻击 +app.secret_key = config.secretinfo['secret_key'] +# app.config['WTF_CSRF_SECRET_KEY'] = 'CSRFTokenGeneratorSecretKey2018' # CSRF Token生成器的签发密钥 +# app.config['WTF_CSRF_TIME_LIMIT'] = 10 # 表单提交限时1分钟,超时则触发CSRF Token校验失败错误 +csrf = CSRFProtect(app) + +# Add LoginManager +login_manager = LoginManager() +login_manager.session_protection = config.secretinfo['login_manager_session_protection'] +login_manager.login_view = config.secretinfo['login_manager_login_view'] +login_manager.login_message = config.secretinfo['login_manager_login_message'] +login_manager.login_message_category = config.secretinfo['login_manager_login_message_category'] +login_manager.init_app(app) + + +@login_manager.user_loader +def load_user(userid): + return User.query.get(int(userid)) + + +@app.route('/') +def index(): + return render_template('index.html') + + +# ------------------------------------------------------退出登录部分代码---------------------------- +@app.route('/signoff') +@login_required +def signoff(): + logout_user() + return 'Logged out successfully!' + + +# ----------------------------------------------------注册部分的代码----------------------------------- +@app.route('/signin', methods=['GET']) +def signin(): + form = LoginForm() + return render_template('./login/signup.html', form=form) + + +@app.route('/signin', methods=['POST']) +def do_signin(): + html = signinup.signin_User() + return html + + +# --------------------------------------------登陆部分的代码------------------------------------------- +@app.route('/signup', methods=['GET']) +def signup(): + form = RegisterForm() + return render_template('./login/signin.html', form=form) + + +@app.route('/signup', methods=['POST']) +def do_signup(): + html = signinup.signup_User() + return html + + +@csrf.exempt +@app.errorhandler(CSRFError) +def handle_csrf_error(e): + return render_template('./csrf/csrf_error.html', reason=e.description), 400 @app.route('/test_mail') @@ -11,21 +87,27 @@ def test_mail(): return mail.test_mail(email) -@app.route('/upload_file', methods=['POST']) +@app.route('/upload_file', methods=['GET', 'POST']) +@login_required def upload_file(): - # f = 要上传的文件 - # file.upload_file(f) - pass + return file.upload_file() + +# ======= +@app.route('/upload', methods=['GET', 'POST']) +def upload(): + f = file.upload_file() + return f -@app.route('/file_list') +@app.route('/file_list', methods=['GET', 'POST']) def file_list(): - file.file_list() - pass + filelist = file.file_list() + return file.download_file(filelist) def main(): mail.init(app) + file.init(app) app.run(host='zlbweb.cn', port=443, ssl_context=('cert.pem', 'key.pem')) diff --git a/database.py b/database.py new file mode 100644 index 0000000..be84280 --- /dev/null +++ b/database.py @@ -0,0 +1,25 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy + +import config + +db = SQLAlchemy() + + +def create_app(): + app = Flask(__name__) + app.config['SQLALCHEMY_DATABASE_URI'] = config.secretinfo['SQLALCHEMY_DATABASE_URI'] + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = config.secretinfo['SQLALCHEMY_TRACK_MODIFICATIONS'] + db.init_app(app) + + with app.app_context(): + from models import User + db.create_all() + db.session.merge(User(id=0,username="lycheng", email='anjing@cuc.edu.cn', password='aB8')) + db.session.commit() + return app + +def add_user(user,userID): + from models import User + db.session.add(User(id=userID,username=user.userName.data, email=user.email.data, password=user.password.data)) + db.session.commit() diff --git a/file.py b/file.py index 7a60b11..49a0a7b 100644 --- a/file.py +++ b/file.py @@ -1,6 +1,56 @@ +from flask import render_template, redirect, url_for, flash +from forms.upload_form import CheckFile +import os + +app = None +upload_dir = None # 文件上传/下载路径 +filelist = None + +ALLOWED_EXTENSIONS = ['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'rtf', 'txt', + 'pdf', 'png', 'bmp', 'jpg'] # 允许上传的文件格式 +ALLOWED_FILE_SIZE = 10 * 1024 * 1024 # 允许上传的文件大小MB + + +def init(_app): + global app + global upload_dir + app = _app + upload_dir = os.path.join( + app.instance_path, 'upload' + ) # 将文件上传到项目的upload文件夹下 + if not os.path.exists(upload_dir): + os.makedirs(upload_dir) + # upload_dir = r'D:\Users\蛮小白\Desktop\test\upload' + + +def allowed_file(filename): # 检查文件格式是否合法 + return '.' in filename and \ + filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS + + +def allowed_size(size): # 检查文件大小是否合法 + return size <= ALLOWED_FILE_SIZE + + def upload_file(): - pass + form = CheckFile() + if form.validate_on_submit(): + f = form.image.data + size = len(f.read()) + if allowed_file(f.filename): + if allowed_size(size): + f.seek(0) + f.save(os.path.join(upload_dir, f.filename)) + flash('Upload success。') + return redirect(url_for('upload')) + else: + flash('上传失败,文件大小:<=10M') + else: + flash('上传失败,允许上传的文件类型:office文档、常见图片类型') + return render_template('./upload/upload.html', form=form) -def file_list(): - pass +def file_list(): # 文件下载 + for parent, dirname, filenames in os.walk(upload_dir): + filelist = filenames + return filelist diff --git a/forms/signin_form.py b/forms/signin_form.py new file mode 100644 index 0000000..7c72fba --- /dev/null +++ b/forms/signin_form.py @@ -0,0 +1,16 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField +from wtforms.validators import DataRequired, Email, Length, Regexp, EqualTo + + +class LoginForm(FlaskForm): + userName = StringField('userName', validators=[DataRequired(), + Regexp('^[A-Za-z0-9\u4e00-\u9fa5]+$', 0, + message="用户名字只能包含中文,英文字母,数字")]) + email = StringField('email', validators=[DataRequired(), Email(message="邮箱格式有误")]) + # 密码必须包含大写、小写、数字,且至少出现一次 + password = PasswordField('password', validators=[DataRequired(), Length(min=8, max=32), + Regexp('^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$', 0, + "密码长度限制在3~36之间且密码不能为弱密码"), + EqualTo('confirmpassword', message='Passwords must match')], ) + confirmpassword = PasswordField('confirmpassword') \ No newline at end of file diff --git a/forms/signup_form.py b/forms/signup_form.py new file mode 100644 index 0000000..ac8fc36 --- /dev/null +++ b/forms/signup_form.py @@ -0,0 +1,12 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField +from wtforms.validators import DataRequired, Email, Length + + +class RegisterForm(FlaskForm): + email = StringField('email', validators=[DataRequired(), Email()]) + password = PasswordField('password', validators=[DataRequired()]) + + + + diff --git a/forms/upload_form.py b/forms/upload_form.py new file mode 100644 index 0000000..9e36dd3 --- /dev/null +++ b/forms/upload_form.py @@ -0,0 +1,8 @@ +from flask_wtf import FlaskForm +from wtforms import StringField +from wtforms.validators import DataRequired +from flask_wtf.file import FileField, FileRequired + + +class CheckFile(FlaskForm): + image = FileField('image', validators=[FileRequired()]) diff --git a/models.py b/models.py new file mode 100644 index 0000000..70bd310 --- /dev/null +++ b/models.py @@ -0,0 +1,20 @@ +from flask_login import UserMixin + +from database import db + + +# user models +class User(db.Model, UserMixin): + __tablename__ = 'Users' + + id = db.Column(db.INT) + username = db.Column(db.String(45)) + email = db.Column(db.String(128), primary_key=True) + password = db.Column(db.String(512)) + access_token = db.Column(db.String(128)) + + def verify_password(self, password): + return self.password == password + + def __repr__(self): + return '' % self.username diff --git a/signinup.py b/signinup.py new file mode 100644 index 0000000..424b324 --- /dev/null +++ b/signinup.py @@ -0,0 +1,51 @@ +from flask import render_template, redirect, url_for, request +from forms.signin_form import LoginForm +from forms.signup_form import RegisterForm +from flask_login import LoginManager, login_required, login_user, logout_user + +from database import create_app, add_user +from models import User +import hashlib + +# 注册新用户 +def signin_User(): + form = LoginForm() + if form.validate_on_submit(): + user = User.query.filter_by(email=form.email.data).first() + print(user) + if user is not None: + # next = request.args.get('next') + # return redirect(next or url_for('welcome')) + return render_template('./login/signup.html', form=form, message="该邮箱已被注册") + else: + # login_user(user) + + # #使用sha512进行hash + hash = hashlib.sha512() + hash.update(form.password.data.encode('utf-8')) + form.password.data = hash.hexdigest() + + id = (User.query.order_by((User.id).desc()).first()).id + 1 + add_user(form, id) + next = request.args.get('next') + return redirect(next or url_for('upload')) + # return render_template('welcome.html', form=form, userName=form.userName.data) + else: + return render_template('./login/signup.html', form=form, message=list(form.errors.values())[0][0]) + +# 用户登录 +def signup_User(): + form = RegisterForm() + if form.validate_on_submit(): + user = User.query.filter_by(email=form.email.data).first() + if user is not None and user.verify_password(form.password.data): + # 启动用户登录 + current_user = User() + current_user.id = user.id + login_user(current_user) + next = request.args.get('next') + return redirect(next or url_for('upload')) + else: + return render_template('./login/signin.html', form=form, message='账户或者密码错误') + else: + return render_template('./login/signin.html', form=form, message='账户或者密码错误') \ No newline at end of file diff --git a/static/css/download.css b/static/css/download.css new file mode 100644 index 0000000..f109c4f --- /dev/null +++ b/static/css/download.css @@ -0,0 +1,31 @@ +body{ + padding: 0 ; + margin: 0 auto; +} + +#title{ + background: white; + height: 70px; + width:100%; + background-position: top; + margin: 0 auto; + padding: 0 ; + border-width: 0; + background-color: red; +} + +#title p{ + display: block; + font-size:30px; + padding-left: 10%; + padding-top:0; +} + +#showimage{ + padding: 0; + margin: 0; + display: inline-block; + width:100%; + height: 100%; + background-color: yellow; +} \ No newline at end of file diff --git a/static/css/login.css b/static/css/login.css new file mode 100644 index 0000000..cbf1686 --- /dev/null +++ b/static/css/login.css @@ -0,0 +1,39 @@ +#title{ + background: white; + height: 70px; + width:100%; + background-position: top; + margin: 0 auto; + padding: 0 ; + border-width: 0; +} + +#title p{ + display: block; + font-size:30px; + padding-left: 10%; + padding-top:0; +} + +#showimage { + width:50%; + margin: 0 ; + padding: 0 ; + display:inline-block ; + /*background-color:red;*/ + height: 300px; + float: top; +} + +#login { + width:40%; + margin: 0 ; + padding: 0 ; + display:inline-block ; + /*background-color: yellow;*/ +} + +body{ + margin: 0 auto; + padding: 0 ; +} diff --git a/static/images/cloud10.png b/static/images/cloud10.png new file mode 100644 index 0000000000000000000000000000000000000000..2d87a4de62677622872109e71331d57107ef23ea GIT binary patch literal 58580 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 TydeO~00000NkvXXu0mjfCpdpb literal 0 HcmV?d00001 diff --git a/static/js/RequestAnimationFrame.js b/static/js/RequestAnimationFrame.js new file mode 100644 index 0000000..77f85c5 --- /dev/null +++ b/static/js/RequestAnimationFrame.js @@ -0,0 +1,22 @@ +/** + * Provides requestAnimationFrame in a cross browser way. + * http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + */ + +if ( !window.requestAnimationFrame ) { + + window.requestAnimationFrame = ( function() { + + return window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) { + + window.setTimeout( callback, 1000 / 60 ); + + }; + + } )(); + +} diff --git a/static/js/ThreeExtras.js b/static/js/ThreeExtras.js new file mode 100644 index 0000000..3a6ccd6 --- /dev/null +++ b/static/js/ThreeExtras.js @@ -0,0 +1,175 @@ +// ThreeExtras.js r39 - http://github.com/mrdoob/three.js +THREE.AnimationHandler=function(){var a=[],d={},b={};b.update=function(c){for(var f=0;f1){console.log("THREE.Animation.update: Warning! Scale out of bounds:"+e+" on bone "+o);e=e<0?0:1}if(b==="pos"){b=a.position;if(this.interpolationType===THREE.AnimationHandler.LINEAR){b.x=c[0]+(f[0]-c[0])*e;b.y=c[1]+(f[1]-c[1])*e;b.z=c[2]+(f[2]-c[2])*e}else if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD){this.points[0]= +this.getPrevKeyWith("pos",o,g.index-1).pos;this.points[1]=c;this.points[2]=f;this.points[3]=this.getNextKeyWith("pos",o,h.index+1).pos;e=e*0.33+0.33;c=this.interpolateCatmullRom(this.points,e);b.x=c[0];b.y=c[1];b.z=c[2];if(this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD){e=this.interpolateCatmullRom(this.points,e*1.01);this.target.set(e[0],e[1],e[2]);this.target.subSelf(b);this.target.y=0;this.target.normalize();e=Math.atan2(this.target.x,this.target.z);a.rotation.set(0,e,0)}}}else if(b=== +"rot")THREE.Quaternion.slerp(c,f,a.quaternion,e);else if(b==="scl"){b=a.scale;b.x=c[0]+(f[0]-c[0])*e;b.y=c[1]+(f[1]-c[1])*e;b.z=c[2]+(f[2]-c[2])*e}}}}if(this.JITCompile&&k[0][l]===undefined){this.hierarchy[0].update(undefined,!0);for(o=0;oa.length-2?f:f+1;b[3]=f>a.length-3?f:f+2;f=a[b[0]];h=a[b[1]];j=a[b[2]];l=a[b[3]];b=c*c;g=c*b;e[0]=this.interpolate(f[0],h[0],j[0],l[0],c,b,g);e[1]=this.interpolate(f[1],h[1],j[1],l[1],c,b,g);e[2]=this.interpolate(f[2],h[2],j[2],l[2],c,b,g);return e}; +THREE.Animation.prototype.interpolate=function(a,d,b,e,c,f,g){a=(b-a)*0.5;e=(e-d)*0.5;return(2*(d-b)+a+e)*g+(-3*(d-b)-2*a-e)*f+a*c+d};THREE.Animation.prototype.getNextKeyWith=function(a,d,b){var e=this.data.hierarchy[d].keys;if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)b=b0?b:0:b>=0?b:b+e.length;b>=0;b--)if(e[b][a]!==undefined)return e[b];return this.data.hierarchy[d].keys[e.length-1]}; +var GeometryUtils={merge:function(a,d){var b=d instanceof THREE.Mesh,e=a.vertices.length,c=b?d.geometry:d,f=a.vertices,g=c.vertices,h=a.faces,j=c.faces,l=a.faceVertexUvs[0];c=c.faceVertexUvs[0];b&&d.matrixAutoUpdate&&d.updateMatrix();for(var k=0,m=g.length;k= 0.0 )\npointSpecularWeight = specularTex.r * pow( pointDotNormalHalf, uShininess );\npointDiffuse += vec4( uDiffuseColor, 1.0 ) * pointDiffuseWeight;\npointSpecular += vec4( uSpecularColor, 1.0 ) * pointSpecularWeight * pointDiffuseWeight;\nvec4 dirDiffuse = vec4( 0.0, 0.0, 0.0, 0.0 );\nvec4 dirSpecular = vec4( 0.0, 0.0, 0.0, 0.0 );\nvec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nvec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );\nfloat dirDotNormalHalf = dot( normal, dirHalfVector );\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\nfloat dirSpecularWeight = 0.0;\nif ( dirDotNormalHalf >= 0.0 )\ndirSpecularWeight = specularTex.r * pow( dirDotNormalHalf, uShininess );\ndirDiffuse += vec4( uDiffuseColor, 1.0 ) * dirDiffuseWeight;\ndirSpecular += vec4( uSpecularColor, 1.0 ) * dirSpecularWeight * dirDiffuseWeight;\nvec4 totalLight = vec4( uAmbientLightColor * uAmbientColor, 1.0 );\ntotalLight += vec4( uDirLightColor, 1.0 ) * ( dirDiffuse + dirSpecular );\ntotalLight += vec4( uPointLightColor, 1.0 ) * ( pointDiffuse + pointSpecular );\ngl_FragColor = vec4( totalLight.xyz * aoTex * diffuseTex, 1.0 );\n}", +vertexShader:"attribute vec4 tangent;\nuniform vec3 uPointLightPos;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vPointLightVector;\nvarying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvNormal = normalize( normalMatrix * normal );\nvTangent = normalize( normalMatrix * tangent.xyz );\nvBinormal = cross( vNormal, vTangent ) * tangent.w;\nvBinormal = normalize( vBinormal );\nvUv = uv;\nvec4 lPosition = viewMatrix * vec4( uPointLightPos, 1.0 );\nvPointLightVector = normalize( lPosition.xyz - mvPosition.xyz );\n#ifdef VERTEX_TEXTURES\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\nvec4 displacedPosition = vec4( vNormal.xyz * df, 0.0 ) + mvPosition;\ngl_Position = projectionMatrix * displacedPosition;\n#else\ngl_Position = projectionMatrix * mvPosition;\n#endif\n}"}, +cube:{uniforms:{tCube:{type:"t",value:1,texture:null}},vertexShader:"varying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nvarying vec3 vViewPosition;\nvoid main() {\nvec3 wPos = cameraPosition - vViewPosition;\ngl_FragColor = textureCube( tCube, vec3( - wPos.x, wPos.yz ) );\n}"},convolution:{uniforms:{tDiffuse:{type:"t", +value:0,texture:null},uImageIncrement:{type:"v2",value:new THREE.Vector2(0.001953125,0)},cKernel:{type:"fv1",value:[]}},vertexShader:"varying vec2 vUv;\nuniform vec2 uImageIncrement;\nvoid main(void) {\nvUv = uv - ((KERNEL_SIZE - 1.0) / 2.0) * uImageIncrement;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform vec2 uImageIncrement;\nuniform float cKernel[KERNEL_SIZE];\nvoid main(void) {\nvec2 imageCoord = vUv;\nvec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );\nfor( int i=0; i25&&(f=25);c=(f-1)*0.5;b=Array(f);for(d=e=0;d +this.heightMax?this.heightMax:this.position.y)-this.heightMin)*this.heightCoef:0;(this.moveForward||this.autoForward&&!this.moveBackward)&&this.translateZ(-(this.movementSpeed+this.autoSpeedFactor));this.moveBackward&&this.translateZ(this.movementSpeed);this.moveLeft&&this.translateX(-this.movementSpeed);this.moveRight&&this.translateX(this.movementSpeed);var b=this.lookSpeed;this.activeLook||(b=0);this.lon+=this.mouseX*b;this.lookVertical&&(this.lat-=this.mouseY*b);this.lat=Math.max(-85,Math.min(85, +this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;var e=this.target.position,c=this.position;e.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);e.y=c.y+100*Math.cos(this.phi);e.z=c.z+100*Math.sin(this.phi)*Math.sin(this.theta)}this.lon+=this.mouseX*b;this.lookVertical&&(this.lat-=this.mouseY*b);this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;if(this.constrainVertical)this.phi=(this.phi-0)*(this.verticalMax- +this.verticalMin)/3.14+this.verticalMin;e=this.target.position;c=this.position;e.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);e.y=c.y+100*Math.cos(this.phi);e.z=c.z+100*Math.sin(this.phi)*Math.sin(this.theta);this.supr.update.call(this)};this.domElement.addEventListener("contextmenu",function(b){b.preventDefault()},!1);this.domElement.addEventListener("mousemove",d(this,this.onMouseMove),!1);this.domElement.addEventListener("mousedown",d(this,this.onMouseDown),!1);this.domElement.addEventListener("mouseup", +d(this,this.onMouseUp),!1);this.domElement.addEventListener("keydown",d(this,this.onKeyDown),!1);this.domElement.addEventListener("keyup",d(this,this.onKeyUp),!1)};THREE.QuakeCamera.prototype=new THREE.Camera;THREE.QuakeCamera.prototype.constructor=THREE.QuakeCamera;THREE.QuakeCamera.prototype.supr=THREE.Camera.prototype;THREE.QuakeCamera.prototype.translate=function(a,d){this.matrix.rotateAxis(d);if(this.noFly)d.y=0;this.position.addSelf(d.multiplyScalar(a));this.target.position.addSelf(d.multiplyScalar(a))}; +THREE.PathCamera=function(a){function d(l,k,m,p){var o={name:m,fps:0.6,length:p,hierarchy:[]},x,w=k.getControlPointsArray(),u=k.getLength(),B=w.length,z=0;x=B-1;k={parent:-1,keys:[]};k.keys[0]={time:0,pos:w[0],rot:[0,0,0,1],scl:[1,1,1]};k.keys[x]={time:p,pos:w[x],rot:[0,0,0,1],scl:[1,1,1]};for(x=1;x=0?p:p+c;p=this.verticalAngleMap.srcRange;o=this.verticalAngleMap.dstRange; +this.phi=(this.phi-p[0])*(o[1]-o[0])/(p[1]-p[0])+o[0];p=this.horizontalAngleMap.srcRange;o=this.horizontalAngleMap.dstRange;this.theta=(this.theta-p[0])*(o[1]-o[0])/(p[1]-p[0])+o[0];p=this.target.position;p.x=100*Math.sin(this.phi)*Math.cos(this.theta);p.y=100*Math.cos(this.phi);p.z=100*Math.sin(this.phi)*Math.sin(this.theta);this.supr.update.call(this,l,k,m)};this.onMouseMove=function(l){this.mouseX=l.clientX-this.windowHalfX;this.mouseY=l.clientY-this.windowHalfY};this.spline=new THREE.Spline;this.spline.initFromArray(this.waypoints); +this.useConstantSpeed&&this.spline.reparametrizeByArcLength(this.resamplingCoef);if(this.createDebugDummy){a=new THREE.MeshLambertMaterial({color:30719});var g=new THREE.MeshLambertMaterial({color:65280}),h=new THREE.Cube(10,10,20),j=new THREE.Cube(2,2,10);this.animationParent=new THREE.Mesh(h,a);a=new THREE.Mesh(j,g);a.position.set(0,10,0);this.animation=d(this.animationParent,this.spline,this.id,this.duration);this.animationParent.addChild(this);this.animationParent.addChild(this.target);this.animationParent.addChild(a)}else{this.animation= +d(this.animationParent,this.spline,this.id,this.duration);this.animationParent.addChild(this.target);this.animationParent.addChild(this)}this.createDebugPath&&e(this.debugPath,this.spline);this.domElement.addEventListener("mousemove",function(l,k){return function(){k.apply(l,arguments)}}(this,this.onMouseMove),!1)};THREE.PathCamera.prototype=new THREE.Camera;THREE.PathCamera.prototype.constructor=THREE.PathCamera;THREE.PathCamera.prototype.supr=THREE.Camera.prototype;THREE.PathCameraIdCounter=0; +THREE.FlyCamera=function(a){function d(b,e){return function(){e.apply(b,arguments)}}THREE.Camera.call(this,a.fov,a.aspect,a.near,a.far,a.target);this.tmpQuaternion=new THREE.Quaternion;this.tdiff=0;this.movementSpeed=1;this.rollSpeed=0.0050;this.dragToLook=!1;this.autoForward=!1;this.domElement=document;if(a){if(a.movementSpeed!==undefined)this.movementSpeed=a.movementSpeed;if(a.rollSpeed!==undefined)this.rollSpeed=a.rollSpeed;if(a.dragToLook!==undefined)this.dragToLook=a.dragToLook;if(a.autoForward!== +undefined)this.autoForward=a.autoForward;if(a.domElement!==undefined)this.domElement=a.domElement}this.useTarget=!1;this.useQuaternion=!0;this.mouseStatus=0;this.moveState={up:0,down:0,left:0,right:0,forward:0,back:0,pitchUp:0,pitchDown:0,yawLeft:0,yawRight:0,rollLeft:0,rollRight:0};this.moveVector=new THREE.Vector3(0,0,0);this.rotationVector=new THREE.Vector3(0,0,0);this.lastUpdate=(new Date).getTime();this.handleEvent=function(b){if(typeof this[b.type]=="function")this[b.type](b)};this.keydown= +function(b){if(!b.altKey){switch(b.keyCode){case 16:this.movementSpeedMultiplier=0.1;break;case 87:this.moveState.forward=1;break;case 83:this.moveState.back=1;break;case 65:this.moveState.left=1;break;case 68:this.moveState.right=1;break;case 82:this.moveState.up=1;break;case 70:this.moveState.down=1;break;case 38:this.moveState.pitchUp=1;break;case 40:this.moveState.pitchDown=1;break;case 37:this.moveState.yawLeft=1;break;case 39:this.moveState.yawRight=1;break;case 81:this.moveState.rollLeft=1; +break;case 69:this.moveState.rollRight=1}this.updateMovementVector();this.updateRotationVector()}};this.keyup=function(b){switch(b.keyCode){case 16:this.movementSpeedMultiplier=1;break;case 87:this.moveState.forward=0;break;case 83:this.moveState.back=0;break;case 65:this.moveState.left=0;break;case 68:this.moveState.right=0;break;case 82:this.moveState.up=0;break;case 70:this.moveState.down=0;break;case 38:this.moveState.pitchUp=0;break;case 40:this.moveState.pitchDown=0;break;case 37:this.moveState.yawLeft= +0;break;case 39:this.moveState.yawRight=0;break;case 81:this.moveState.rollLeft=0;break;case 69:this.moveState.rollRight=0}this.updateMovementVector();this.updateRotationVector()};this.mousedown=function(b){b.preventDefault();b.stopPropagation();if(this.dragToLook)this.mouseStatus++;else switch(b.button){case 0:this.moveForward=!0;break;case 2:this.moveBackward=!0}};this.mousemove=function(b){if(!this.dragToLook||this.mouseStatus>0){var e=this.getContainerDimensions(),c=e.size[0]/2,f=e.size[1]/2; +this.moveState.yawLeft=-(b.clientX-e.offset[0]-c)/c;this.moveState.pitchDown=(b.clientY-e.offset[1]-f)/f;this.updateRotationVector()}};this.mouseup=function(b){b.preventDefault();b.stopPropagation();if(this.dragToLook){this.mouseStatus--;this.moveState.yawLeft=this.moveState.pitchDown=0}else switch(b.button){case 0:this.moveForward=!1;break;case 2:this.moveBackward=!1}this.updateRotationVector()};this.update=function(){var b=(new Date).getTime();this.tdiff=(b-this.lastUpdate)/1E3;this.lastUpdate= +b;b=this.tdiff*this.movementSpeed;var e=this.tdiff*this.rollSpeed;this.translateX(this.moveVector.x*b);this.translateY(this.moveVector.y*b);this.translateZ(this.moveVector.z*b);this.tmpQuaternion.set(this.rotationVector.x*e,this.rotationVector.y*e,this.rotationVector.z*e,1).normalize();this.quaternion.multiplySelf(this.tmpQuaternion);this.matrix.setPosition(this.position);this.matrix.setRotationFromQuaternion(this.quaternion);this.matrixWorldNeedsUpdate=!0;this.supr.update.call(this)};this.updateMovementVector= +function(){var b=this.moveState.forward||this.autoForward&&!this.moveState.back?1:0;this.moveVector.x=-this.moveState.left+this.moveState.right;this.moveVector.y=-this.moveState.down+this.moveState.up;this.moveVector.z=-b+this.moveState.back};this.updateRotationVector=function(){this.rotationVector.x=-this.moveState.pitchDown+this.moveState.pitchUp;this.rotationVector.y=-this.moveState.yawRight+this.moveState.yawLeft;this.rotationVector.z=-this.moveState.rollRight+this.moveState.rollLeft};this.getContainerDimensions= +function(){return this.domElement!=document?{size:[this.domElement.offsetWidth,this.domElement.offsetHeight],offset:[this.domElement.offsetLeft,this.domElement.offsetTop]}:{size:[window.innerWidth,window.innerHeight],offset:[0,0]}};this.domElement.addEventListener("mousemove",d(this,this.mousemove),!1);this.domElement.addEventListener("mousedown",d(this,this.mousedown),!1);this.domElement.addEventListener("mouseup",d(this,this.mouseup),!1);window.addEventListener("keydown",d(this,this.keydown),!1); +window.addEventListener("keyup",d(this,this.keyup),!1);this.updateMovementVector();this.updateRotationVector()};THREE.FlyCamera.prototype=new THREE.Camera;THREE.FlyCamera.prototype.constructor=THREE.FlyCamera;THREE.FlyCamera.prototype.supr=THREE.Camera.prototype; +THREE.Cube=function(a,d,b,e,c,f,g,h,j){function l(u,B,z,n,y,C,G,K){var J,I,E=e||1,L=c||1,P=y/2,Q=C/2,R=k.vertices.length;if(u=="x"&&B=="y"||u=="y"&&B=="x")J="z";else if(u=="x"&&B=="z"||u=="z"&&B=="x"){J="y";L=f||1}else if(u=="z"&&B=="y"||u=="y"&&B=="z"){J="x";E=f||1}var M=E+1,F=L+1;y/=E;var N=C/L;for(I=0;I0){g(0,0,-k-(f||0));for(j=a;j0){g(0,0,k+(c||0)); +for(j=a+a/2;j<2*a;j++)h.faces.push(new THREE.Face4(2*a+1,(2*j-2*a+2)%a+a,(2*j-2*a+1)%a+a,(2*j-2*a)%a+a))}j=0;for(a=this.faces.length;j0||(k=this.vertices.push(new THREE.Vertex(new THREE.Vector3(m,h,p)))-1);l.push(k)}d.push(l)}var o,x,w;c=d.length;for(b=0;b0)for(e=0;e1){o=this.vertices[g].position.clone(); +x=this.vertices[j].position.clone();w=this.vertices[l].position.clone();o.normalize();x.normalize();w.normalize();this.faces.push(new THREE.Face3(g,j,l,[new THREE.Vector3(o.x,o.y,o.z),new THREE.Vector3(x.x,x.y,x.z),new THREE.Vector3(w.x,w.y,w.z)]));this.faceVertexUvs[0].push([k,m,u])}}}this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals();this.boundingSphere={radius:a}};THREE.Sphere.prototype=new THREE.Geometry;THREE.Sphere.prototype.constructor=THREE.Sphere; +THREE.Torus=function(a,d,b,e){THREE.Geometry.call(this);this.radius=a||100;this.tube=d||40;this.segmentsR=b||8;this.segmentsT=e||6;a=[];for(d=0;d<=this.segmentsR;++d)for(b=0;b<=this.segmentsT;++b){e=b/this.segmentsT*2*Math.PI;var c=d/this.segmentsR*2*Math.PI;this.vertices.push(new THREE.Vertex(new THREE.Vector3((this.radius+this.tube*Math.cos(c))*Math.cos(e),(this.radius+this.tube*Math.cos(c))*Math.sin(e),this.tube*Math.sin(c))));a.push([b/this.segmentsT,1-d/this.segmentsR])}for(d=1;d<=this.segmentsR;++d)for(b= +1;b<=this.segmentsT;++b){e=(this.segmentsT+1)*d+b;c=(this.segmentsT+1)*d+b-1;var f=(this.segmentsT+1)*(d-1)+b-1,g=(this.segmentsT+1)*(d-1)+b;this.faces.push(new THREE.Face4(e,c,f,g));this.faceVertexUvs[0].push([new THREE.UV(a[e][0],a[e][1]),new THREE.UV(a[c][0],a[c][1]),new THREE.UV(a[f][0],a[f][1]),new THREE.UV(a[g][0],a[g][1])])}delete a;this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.Torus.prototype=new THREE.Geometry;THREE.Torus.prototype.constructor=THREE.Torus; +THREE.TorusKnot=function(a,d,b,e,c,f,g){function h(m,p,o,x,w,u){p=o/x*m;o=Math.cos(p);return new THREE.Vector3(w*(2+o)*0.5*Math.cos(m),w*(2+o)*Math.sin(m)*0.5,u*w*Math.sin(p)*0.5)}THREE.Geometry.call(this);this.radius=a||200;this.tube=d||40;this.segmentsR=b||64;this.segmentsT=e||8;this.p=c||2;this.q=f||3;this.heightScale=g||1;this.grid=Array(this.segmentsR);b=new THREE.Vector3;e=new THREE.Vector3;f=new THREE.Vector3;for(a=0;a>7)-127;A|=(H&127)<<16|D<<8;if(A==0&&V==-127)return 0;return(1-2*(S>>7))*(1+A*Math.pow(2,-23))*Math.pow(2,V)}function h(t,v){var A=k(t,v),D=k(t,v+1),H=k(t,v+2);return(k(t,v+3)<<24)+(H<<16)+(D<<8)+A}function j(t,v){var A=k(t,v);return(k(t,v+1)<<8)+A}function l(t,v){var A=k(t,v);return A>127?A-256:A}function k(t, +v){return t.charCodeAt(v)&255}function m(t){var v,A,D;v=h(a,t);A=h(a,t+G);D=h(a,t+K);t=j(a,t+J);THREE.BinaryLoader.prototype.f3(B,v,A,D,t)}function p(t){var v,A,D,H,S,V;v=h(a,t);A=h(a,t+G);D=h(a,t+K);H=j(a,t+J);S=h(a,t+I);V=h(a,t+E);t=h(a,t+L);THREE.BinaryLoader.prototype.f3n(B,y,v,A,D,H,S,V,t)}function o(t){var v,A,D,H;v=h(a,t);A=h(a,t+P);D=h(a,t+Q);H=h(a,t+R);t=j(a,t+M);THREE.BinaryLoader.prototype.f4(B,v,A,D,H,t)}function x(t){var v,A,D,H,S,V,ca,da;v=h(a,t);A=h(a,t+P);D=h(a,t+Q);H=h(a,t+R);S=j(a, +t+M);V=h(a,t+F);ca=h(a,t+N);da=h(a,t+O);t=h(a,t+T);THREE.BinaryLoader.prototype.f4n(B,y,v,A,D,H,S,V,ca,da,t)}function w(t){var v,A;v=h(a,t);A=h(a,t+U);t=h(a,t+X);THREE.BinaryLoader.prototype.uv3(B.faceVertexUvs[0],C[v*2],C[v*2+1],C[A*2],C[A*2+1],C[t*2],C[t*2+1])}function u(t){var v,A,D;v=h(a,t);A=h(a,t+ea);D=h(a,t+fa);t=h(a,t+ga);THREE.BinaryLoader.prototype.uv4(B.faceVertexUvs[0],C[v*2],C[v*2+1],C[A*2],C[A*2+1],C[D*2],C[D*2+1],C[t*2],C[t*2+1])}var B=this,z=0,n,y=[],C=[],G,K,J,I,E,L,P,Q,R,M,F,N,O, +T,U,X,ea,fa,ga,Y,Z,$,aa,ba,W;THREE.Geometry.call(this);THREE.Loader.prototype.init_materials(B,e,f);n={signature:a.substr(z,8),header_bytes:k(a,z+8),vertex_coordinate_bytes:k(a,z+9),normal_coordinate_bytes:k(a,z+10),uv_coordinate_bytes:k(a,z+11),vertex_index_bytes:k(a,z+12),normal_index_bytes:k(a,z+13),uv_index_bytes:k(a,z+14),material_index_bytes:k(a,z+15),nvertices:h(a,z+16),nnormals:h(a,z+16+4),nuvs:h(a,z+16+8),ntri_flat:h(a,z+16+12),ntri_smooth:h(a,z+16+16),ntri_flat_uv:h(a,z+16+20),ntri_smooth_uv:h(a, +z+16+24),nquad_flat:h(a,z+16+28),nquad_smooth:h(a,z+16+32),nquad_flat_uv:h(a,z+16+36),nquad_smooth_uv:h(a,z+16+40)};z+=n.header_bytes;G=n.vertex_index_bytes;K=n.vertex_index_bytes*2;J=n.vertex_index_bytes*3;I=n.vertex_index_bytes*3+n.material_index_bytes;E=n.vertex_index_bytes*3+n.material_index_bytes+n.normal_index_bytes;L=n.vertex_index_bytes*3+n.material_index_bytes+n.normal_index_bytes*2;P=n.vertex_index_bytes;Q=n.vertex_index_bytes*2;R=n.vertex_index_bytes*3;M=n.vertex_index_bytes*4;F=n.vertex_index_bytes* +4+n.material_index_bytes;N=n.vertex_index_bytes*4+n.material_index_bytes+n.normal_index_bytes;O=n.vertex_index_bytes*4+n.material_index_bytes+n.normal_index_bytes*2;T=n.vertex_index_bytes*4+n.material_index_bytes+n.normal_index_bytes*3;U=n.uv_index_bytes;X=n.uv_index_bytes*2;ea=n.uv_index_bytes;fa=n.uv_index_bytes*2;ga=n.uv_index_bytes*3;f=n.vertex_index_bytes*3+n.material_index_bytes;W=n.vertex_index_bytes*4+n.material_index_bytes;Y=n.ntri_flat*f;Z=n.ntri_smooth*(f+n.normal_index_bytes*3);$=n.ntri_flat_uv* +(f+n.uv_index_bytes*3);aa=n.ntri_smooth_uv*(f+n.normal_index_bytes*3+n.uv_index_bytes*3);ba=n.nquad_flat*W;f=n.nquad_smooth*(W+n.normal_index_bytes*4);W=n.nquad_flat_uv*(W+n.uv_index_bytes*4);z+=function(t){for(var v,A,D,H=n.vertex_coordinate_bytes*3,S=t+n.nvertices*H;t=this.maxCount-3&&h(this)};this.begin= +function(){this.count=0;this.hasPos=!1;this.hasNormal=!1};this.end=function(b){if(this.count!=0){for(var e=this.count*3;ethis.size-1&&(j=this.size-1);var p=Math.floor(l-h);p<1&&(p=1);l=Math.floor(l+h);l>this.size-1&&(l=this.size-1);var o=Math.floor(k-h);o<1&&(o=1);h=Math.floor(k+h); +h>this.size-1&&(h=this.size-1);for(var x,w,u,B,z,n;m0&&(this.field[u+x]+=B)}}}};this.addPlaneX=function(b,e){var c,f,g,h,j,l=this.size,k=this.yd,m=this.zd,p=this.field,o=l*Math.sqrt(b/e);o>l&&(o=l);for(c=0;c0)for(f=0;fk&&(x=k);for(f=0;f0){j=f*m;for(c=0;csize&&(dist=size);for(g=0;g0){j=zd*g;for(f=0;ff?this.hits.push(c):this.hits.unshift(c);f=e}}return this.hits}; +THREE.CollisionSystem.prototype.rayCastNearest=function(a){var d=this.rayCastAll(a);if(d.length==0)return null;for(var b=0;d[b]instanceof THREE.MeshCollider;){var e=this.rayMesh(a,d[b]);if(ed.length)return null;return d[b]}; +THREE.CollisionSystem.prototype.rayCast=function(a,d){if(d instanceof THREE.PlaneCollider)return this.rayPlane(a,d);else if(d instanceof THREE.SphereCollider)return this.raySphere(a,d);else if(d instanceof THREE.BoxCollider)return this.rayBox(a,d);else if(d instanceof THREE.MeshCollider&&d.box)return this.rayBox(a,d.box)}; +THREE.CollisionSystem.prototype.rayMesh=function(a,d){for(var b=this.makeRayLocal(a,d.mesh),e=Number.MAX_VALUE,c=0;c=h*f))return Number.MAX_VALUE;g/=h;h=THREE.CollisionSystem.__v3;h.copy(a.direction);h.multiplyScalar(g);h.addSelf(a.origin);if(Math.abs(c.x)>Math.abs(c.y))if(Math.abs(c.x)>Math.abs(c.z)){a=h.y-d.y;c=b.y-d.y;f=e.y-d.y; +h=h.z-d.z;b=b.z-d.z;e=e.z-d.z}else{a=h.x-d.x;c=b.x-d.x;f=e.x-d.x;h=h.y-d.y;b=b.y-d.y;e=e.y-d.y}else if(Math.abs(c.y)>Math.abs(c.z)){a=h.x-d.x;c=b.x-d.x;f=e.x-d.x;h=h.z-d.z;b=b.z-d.z;e=e.z-d.z}else{a=h.x-d.x;c=b.x-d.x;f=e.x-d.x;h=h.y-d.y;b=b.y-d.y;e=e.y-d.y}d=c*e-b*f;if(d==0)return Number.MAX_VALUE;d=1/d;e=(a*e-h*f)*d;if(!(e>=0))return Number.MAX_VALUE;d*=c*h-b*a;if(!(d>=0))return Number.MAX_VALUE;if(!(1-e-d>=0))return Number.MAX_VALUE;return g}; +THREE.CollisionSystem.prototype.makeRayLocal=function(a,d){var b=new THREE.Ray(a.origin.clone(),a.direction.clone()),e=THREE.Matrix4.makeInvert(d.matrixWorld);e.multiplyVector3(b.origin);e.rotateAxis(b.direction);b.direction.normalize();return b}; +THREE.CollisionSystem.prototype.rayBox=function(a,d){var b;b=d.dynamic&&d.mesh&&d.mesh.matrixWorld?this.makeRayLocal(a,d.mesh):new THREE.Ray(a.origin.clone(),a.direction.clone());var e=0,c=0,f=0,g=0,h=0,j=0,l=!0;if(b.origin.xd.max.x){e=d.max.x-b.origin.x;e/=b.direction.x;l=!1;g=1}if(b.origin.yd.max.y){c=d.max.y-b.origin.y;c/=b.direction.y;l=!1;h= +1}if(b.origin.zd.max.z){f=d.max.z-b.origin.z;f/=b.direction.z;l=!1;j=1}if(l)return-1;l=0;if(c>e){l=1;e=c}if(f>e){l=2;e=f}switch(l){case 0:h=b.origin.y+b.direction.y*e;if(hd.max.y)return Number.MAX_VALUE;b=b.origin.z+b.direction.z*e;if(bd.max.z)return Number.MAX_VALUE;d.normal=new THREE.Vector3(g,0,0);break;case 1:g=b.origin.x+b.direction.x*e;if(gd.max.x)return Number.MAX_VALUE;b=b.origin.z+ +b.direction.z*e;if(bd.max.z)return Number.MAX_VALUE;d.normal=new THREE.Vector3(0,h,0);break;case 2:g=b.origin.x+b.direction.x*e;if(gd.max.x)return Number.MAX_VALUE;h=b.origin.y+b.direction.y*e;if(hd.max.y)return Number.MAX_VALUE;d.normal=new THREE.Vector3(0,0,j)}return e};THREE.CollisionSystem.prototype.rayPlane=function(a,d){var b=a.direction.dot(d.normal),e=d.point.dot(d.normal);if(b<0)b=(e-a.origin.dot(d.normal))/b;else return Number.MAX_VALUE;return b>0?b:Number.MAX_VALUE}; +THREE.CollisionSystem.prototype.raySphere=function(a,d){var b=d.center.clone().subSelf(a.origin);if(b.lengthSq=0)return Math.abs(e)-Math.sqrt(b);return Number.MAX_VALUE};THREE.CollisionSystem.__v1=new THREE.Vector3;THREE.CollisionSystem.__v2=new THREE.Vector3;THREE.CollisionSystem.__v3=new THREE.Vector3;THREE.CollisionUtils={}; +THREE.CollisionUtils.MeshOBB=function(a){a.geometry.computeBoundingBox();var d=a.geometry.boundingBox,b=new THREE.Vector3(d.x[0],d.y[0],d.z[0]);d=new THREE.Vector3(d.x[1],d.y[1],d.z[1]);b=new THREE.BoxCollider(b,d);b.mesh=a;return b};THREE.CollisionUtils.MeshAABB=function(a){var d=THREE.CollisionUtils.MeshOBB(a);d.min.addSelf(a.position);d.max.addSelf(a.position);d.dynamic=!1;return d}; +THREE.CollisionUtils.MeshColliderWBox=function(a){for(var d=a.geometry.vertices,b=d.length,e=a.geometry.faces,c=e.length,f=[],g=[],h=[],j=0;j>16&255)/255;this.g=(this.hex>>8&255)/255;this.b=(this.hex&255)/255},updateStyleString:function(){this.__styleString="rgb("+~~(this.r*255)+","+~~(this.g* +255)+","+~~(this.b*255)+")"},clone:function(){return new THREE.Color(this.hex)}};THREE.Vector2=function(b,d){this.set(b||0,d||0)}; +THREE.Vector2.prototype={set:function(b,d){this.x=b;this.y=d;return this},copy:function(b){this.set(b.x,b.y);return this},addSelf:function(b){this.set(this.x+b.x,this.y+b.y);return this},add:function(b,d){this.set(b.x+d.x,b.y+d.y);return this},subSelf:function(b){this.set(this.x-b.x,this.y-b.y);return this},sub:function(b,d){this.set(b.x-d.x,b.y-d.y);return this},multiplyScalar:function(b){this.set(this.x*b,this.y*b);return this},negate:function(){this.set(-this.x,-this.y);return this},unit:function(){this.multiplyScalar(1/ +this.length());return this},length:function(){return Math.sqrt(this.lengthSq())},lengthSq:function(){return this.x*this.x+this.y*this.y},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(b,d,e){this.set(b||0,d||0,e||0)}; +THREE.Vector3.prototype={set:function(b,d,e){this.x=b;this.y=d;this.z=e;return this},copy:function(b){this.set(b.x,b.y,b.z);return this},add:function(b,d){this.set(b.x+d.x,b.y+d.y,b.z+d.z);return this},addSelf:function(b){this.set(this.x+b.x,this.y+b.y,this.z+b.z);return this},addScalar:function(b){this.set(this.x+b,this.y+b,this.z+b);return this},sub:function(b,d){this.set(b.x-d.x,b.y-d.y,b.z-d.z);return this},subSelf:function(b){this.set(this.x-b.x,this.y-b.y,this.z-b.z);return this},cross:function(b, +d){this.set(b.y*d.z-b.z*d.y,b.z*d.x-b.x*d.z,b.x*d.y-b.y*d.x);return this},crossSelf:function(b){var d=this.x,e=this.y,g=this.z;this.set(e*b.z-g*b.y,g*b.x-d*b.z,d*b.y-e*b.x);return this},multiply:function(b,d){this.set(b.x*d.x,b.y*d.y,b.z*d.z);return this},multiplySelf:function(b){this.set(this.x*b.x,this.y*b.y,this.z*b.z);return this},multiplyScalar:function(b){this.set(this.x*b,this.y*b,this.z*b);return this},divideSelf:function(b){this.set(this.x/b.x,this.y/b.y,this.z/b.z);return this},divideScalar:function(b){this.set(this.x/ +b,this.y/b,this.z/b);return this},negate:function(){this.set(-this.x,-this.y,-this.z);return this},dot:function(b){return this.x*b.x+this.y*b.y+this.z*b.z},distanceTo:function(b){return Math.sqrt(this.distanceToSquared(b))},distanceToSquared:function(b){var d=this.x-b.x,e=this.y-b.y;b=this.z-b.z;return d*d+e*e+b*b},length:function(){return Math.sqrt(this.lengthSq())},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},lengthManhattan:function(){return this.x+this.y+this.z},normalize:function(){var b= +this.length();b>0?this.multiplyScalar(1/b):this.set(0,0,0);return this},setPositionFromMatrix:function(b){this.x=b.n14;this.y=b.n24;this.z=b.n34},setRotationFromMatrix:function(b){this.y=Math.asin(b.n13);var d=Math.cos(this.y);if(Math.abs(d)>1.0E-5){this.x=Math.atan2(-b.n23/d,b.n33/d);this.z=Math.atan2(-b.n13/d,b.n11/d)}else{this.x=0;this.z=Math.atan2(b.n21,b.n22)}},setLength:function(b){return this.normalize().multiplyScalar(b)},isZero:function(){return Math.abs(this.x)<1.0E-4&&Math.abs(this.y)< +1.0E-4&&Math.abs(this.z)<1.0E-4},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}};THREE.Vector4=function(b,d,e,g){this.set(b||0,d||0,e||0,g||1)}; +THREE.Vector4.prototype={set:function(b,d,e,g){this.x=b;this.y=d;this.z=e;this.w=g;return this},copy:function(b){this.set(b.x,b.y,b.z,b.w||1);return this},add:function(b,d){this.set(b.x+d.x,b.y+d.y,b.z+d.z,b.w+d.w);return this},addSelf:function(b){this.set(this.x+b.x,this.y+b.y,this.z+b.z,this.w+b.w);return this},sub:function(b,d){this.set(b.x-d.x,b.y-d.y,b.z-d.z,b.w-d.w);return this},subSelf:function(b){this.set(this.x-b.x,this.y-b.y,this.z-b.z,this.w-b.w);return this},multiplyScalar:function(b){this.set(this.x* +b,this.y*b,this.z*b,this.w*b);return this},divideScalar:function(b){this.set(this.x/b,this.y/b,this.z/b,this.w/b);return this},lerpSelf:function(b,d){this.set(this.x+(b.x-this.x)*d,this.y+(b.y-this.y)*d,this.z+(b.z-this.z)*d,this.w+(b.w-this.w)*d)},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Ray=function(b,d){this.origin=b||new THREE.Vector3;this.direction=d||new THREE.Vector3}; +THREE.Ray.prototype={intersectScene:function(b){var d,e,g=b.objects,h=[];b=0;for(d=g.length;b0&&V>0&&Z+V< +1}var e,g,h,o,n,p,q,v,E,F,H,I=b.geometry,M=I.vertices,N=[];e=0;for(g=I.faces.length;e0:E<0)){v=v.dot((new THREE.Vector3).sub(o, +F))/E;F=F.addSelf(H.multiplyScalar(v));if(h instanceof THREE.Face3){if(d(F,o,n,p)){h={distance:this.origin.distanceTo(F),point:F,face:h,object:b};N.push(h)}}else if(h instanceof THREE.Face4&&(d(F,o,n,q)||d(F,n,p,q))){h={distance:this.origin.distanceTo(F),point:F,face:h,object:b};N.push(h)}}}return N}}; +THREE.Rectangle=function(){function b(){o=g-d;n=h-e}var d,e,g,h,o,n,p=!0;this.getX=function(){return d};this.getY=function(){return e};this.getWidth=function(){return o};this.getHeight=function(){return n};this.getLeft=function(){return d};this.getTop=function(){return e};this.getRight=function(){return g};this.getBottom=function(){return h};this.set=function(q,v,E,F){p=!1;d=q;e=v;g=E;h=F;b()};this.addPoint=function(q,v){if(p){p=!1;d=q;e=v;g=q;h=v}else{d=dq?g:q;h=h>v?h:v}b()}; +this.add3Points=function(q,v,E,F,H,I){if(p){p=!1;d=qE?q>H?q:H:E>H?E:H;h=v>F?v>I?v:I:F>I?F:I}else{d=qE?q>H?q>g?q:g:H>g?H:g:E>H?E>g?E:g:H>g?H:g;h=v>F?v>I?v>h?v:h:I>h?I:h:F>I?F>h?F:h:I>h?I:h}b()};this.addRectangle=function(q){if(p){p=!1;d=q.getLeft();e=q.getTop();g=q.getRight();h=q.getBottom()}else{d=dq.getRight()? +g:q.getRight();h=h>q.getBottom()?h:q.getBottom()}b()};this.inflate=function(q){d-=q;e-=q;g+=q;h+=q;b()};this.minSelf=function(q){d=d>q.getLeft()?d:q.getLeft();e=e>q.getTop()?e:q.getTop();g=g=0&&Math.min(h,q.getBottom())-Math.max(e,q.getTop())>=0};this.empty=function(){p=!0;h=g=e=d=0;b()};this.isEmpty=function(){return p}}; +THREE.Matrix3=function(){this.m=[]};THREE.Matrix3.prototype={transpose:function(){var b,d=this.m;b=d[1];d[1]=d[3];d[3]=b;b=d[2];d[2]=d[6];d[6]=b;b=d[5];d[5]=d[7];d[7]=b;return this},transposeIntoArray:function(b){var d=this.m;b[0]=d[0];b[1]=d[3];b[2]=d[6];b[3]=d[1];b[4]=d[4];b[5]=d[7];b[6]=d[2];b[7]=d[5];b[8]=d[8];return this}}; +THREE.Matrix4=function(b,d,e,g,h,o,n,p,q,v,E,F,H,I,M,N){this.set(b||1,d||0,e||0,g||0,h||0,o||1,n||0,p||0,q||0,v||0,E||1,F||0,H||0,I||0,M||0,N||1);this.flat=Array(16);this.m33=new THREE.Matrix3}; +THREE.Matrix4.prototype={set:function(b,d,e,g,h,o,n,p,q,v,E,F,H,I,M,N){this.n11=b;this.n12=d;this.n13=e;this.n14=g;this.n21=h;this.n22=o;this.n23=n;this.n24=p;this.n31=q;this.n32=v;this.n33=E;this.n34=F;this.n41=H;this.n42=I;this.n43=M;this.n44=N;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(b){this.set(b.n11,b.n12,b.n13,b.n14,b.n21,b.n22,b.n23,b.n24,b.n31,b.n32,b.n33,b.n34,b.n41,b.n42,b.n43,b.n44);return this},lookAt:function(b,d,e){var g=THREE.Matrix4.__v1, +h=THREE.Matrix4.__v2,o=THREE.Matrix4.__v3;o.sub(b,d).normalize();if(o.length()===0)o.z=1;g.cross(e,o).normalize();if(g.length()===0){o.x+=1.0E-4;g.cross(e,o).normalize()}h.cross(o,g).normalize();this.n11=g.x;this.n12=h.x;this.n13=o.x;this.n21=g.y;this.n22=h.y;this.n23=o.y;this.n31=g.z;this.n32=h.z;this.n33=o.z;return this},multiplyVector3:function(b){var d=b.x,e=b.y,g=b.z,h=1/(this.n41*d+this.n42*e+this.n43*g+this.n44);b.x=(this.n11*d+this.n12*e+this.n13*g+this.n14)*h;b.y=(this.n21*d+this.n22*e+this.n23* +g+this.n24)*h;b.z=(this.n31*d+this.n32*e+this.n33*g+this.n34)*h;return b},multiplyVector4:function(b){var d=b.x,e=b.y,g=b.z,h=b.w;b.x=this.n11*d+this.n12*e+this.n13*g+this.n14*h;b.y=this.n21*d+this.n22*e+this.n23*g+this.n24*h;b.z=this.n31*d+this.n32*e+this.n33*g+this.n34*h;b.w=this.n41*d+this.n42*e+this.n43*g+this.n44*h;return b},rotateAxis:function(b){var d=b.x,e=b.y,g=b.z;b.x=d*this.n11+e*this.n12+g*this.n13;b.y=d*this.n21+e*this.n22+g*this.n23;b.z=d*this.n31+e*this.n32+g*this.n33;b.normalize(); +return b},crossVector:function(b){var d=new THREE.Vector4;d.x=this.n11*b.x+this.n12*b.y+this.n13*b.z+this.n14*b.w;d.y=this.n21*b.x+this.n22*b.y+this.n23*b.z+this.n24*b.w;d.z=this.n31*b.x+this.n32*b.y+this.n33*b.z+this.n34*b.w;d.w=b.w?this.n41*b.x+this.n42*b.y+this.n43*b.z+this.n44*b.w:1;return d},multiply:function(b,d){var e=b.n11,g=b.n12,h=b.n13,o=b.n14,n=b.n21,p=b.n22,q=b.n23,v=b.n24,E=b.n31,F=b.n32,H=b.n33,I=b.n34,M=b.n41,N=b.n42,V=b.n43,L=b.n44,sa=d.n11,da=d.n12,oa=d.n13,Z=d.n14,K=d.n21,Ia=d.n22, +ca=d.n23,Ea=d.n24,fa=d.n31,c=d.n32,S=d.n33,pa=d.n34;this.n11=e*sa+g*K+h*fa;this.n12=e*da+g*Ia+h*c;this.n13=e*oa+g*ca+h*S;this.n14=e*Z+g*Ea+h*pa+o;this.n21=n*sa+p*K+q*fa;this.n22=n*da+p*Ia+q*c;this.n23=n*oa+p*ca+q*S;this.n24=n*Z+p*Ea+q*pa+v;this.n31=E*sa+F*K+H*fa;this.n32=E*da+F*Ia+H*c;this.n33=E*oa+F*ca+H*S;this.n34=E*Z+F*Ea+H*pa+I;this.n41=M*sa+N*K+V*fa;this.n42=M*da+N*Ia+V*c;this.n43=M*oa+N*ca+V*S;this.n44=M*Z+N*Ea+V*pa+L;return this},multiplyToArray:function(b,d,e){this.multiply(b,d);e[0]=this.n11; +e[1]=this.n21;e[2]=this.n31;e[3]=this.n41;e[4]=this.n12;e[5]=this.n22;e[6]=this.n32;e[7]=this.n42;e[8]=this.n13;e[9]=this.n23;e[10]=this.n33;e[11]=this.n43;e[12]=this.n14;e[13]=this.n24;e[14]=this.n34;e[15]=this.n44;return this},multiplySelf:function(b){this.multiply(this,b);return this},multiplyScalar:function(b){this.n11*=b;this.n12*=b;this.n13*=b;this.n14*=b;this.n21*=b;this.n22*=b;this.n23*=b;this.n24*=b;this.n31*=b;this.n32*=b;this.n33*=b;this.n34*=b;this.n41*=b;this.n42*=b;this.n43*=b;this.n44*= +b;return this},determinant:function(){var b=this.n11,d=this.n12,e=this.n13,g=this.n14,h=this.n21,o=this.n22,n=this.n23,p=this.n24,q=this.n31,v=this.n32,E=this.n33,F=this.n34,H=this.n41,I=this.n42,M=this.n43,N=this.n44;return g*n*v*H-e*p*v*H-g*o*E*H+d*p*E*H+e*o*F*H-d*n*F*H-g*n*q*I+e*p*q*I+g*h*E*I-b*p*E*I-e*h*F*I+b*n*F*I+g*o*q*M-d*p*q*M-g*h*v*M+b*p*v*M+d*h*F*M-b*o*F*M-e*o*q*N+d*n*q*N+e*h*v*N-b*n*v*N-d*h*E*N+b*o*E*N},transpose:function(){var b;b=this.n21;this.n21=this.n12;this.n12=b;b=this.n31;this.n31= +this.n13;this.n13=b;b=this.n32;this.n32=this.n23;this.n23=b;b=this.n41;this.n41=this.n14;this.n14=b;b=this.n42;this.n42=this.n24;this.n24=b;b=this.n43;this.n43=this.n34;this.n43=b;return this},clone:function(){var b=new THREE.Matrix4;b.n11=this.n11;b.n12=this.n12;b.n13=this.n13;b.n14=this.n14;b.n21=this.n21;b.n22=this.n22;b.n23=this.n23;b.n24=this.n24;b.n31=this.n31;b.n32=this.n32;b.n33=this.n33;b.n34=this.n34;b.n41=this.n41;b.n42=this.n42;b.n43=this.n43;b.n44=this.n44;return b},flatten:function(){this.flat[0]= +this.n11;this.flat[1]=this.n21;this.flat[2]=this.n31;this.flat[3]=this.n41;this.flat[4]=this.n12;this.flat[5]=this.n22;this.flat[6]=this.n32;this.flat[7]=this.n42;this.flat[8]=this.n13;this.flat[9]=this.n23;this.flat[10]=this.n33;this.flat[11]=this.n43;this.flat[12]=this.n14;this.flat[13]=this.n24;this.flat[14]=this.n34;this.flat[15]=this.n44;return this.flat},flattenToArray:function(b){b[0]=this.n11;b[1]=this.n21;b[2]=this.n31;b[3]=this.n41;b[4]=this.n12;b[5]=this.n22;b[6]=this.n32;b[7]=this.n42; +b[8]=this.n13;b[9]=this.n23;b[10]=this.n33;b[11]=this.n43;b[12]=this.n14;b[13]=this.n24;b[14]=this.n34;b[15]=this.n44;return b},flattenToArrayOffset:function(b,d){b[d]=this.n11;b[d+1]=this.n21;b[d+2]=this.n31;b[d+3]=this.n41;b[d+4]=this.n12;b[d+5]=this.n22;b[d+6]=this.n32;b[d+7]=this.n42;b[d+8]=this.n13;b[d+9]=this.n23;b[d+10]=this.n33;b[d+11]=this.n43;b[d+12]=this.n14;b[d+13]=this.n24;b[d+14]=this.n34;b[d+15]=this.n44;return b},setTranslation:function(b,d,e){this.set(1,0,0,b,0,1,0,d,0,0,1,e,0,0, +0,1);return this},setScale:function(b,d,e){this.set(b,0,0,0,0,d,0,0,0,0,e,0,0,0,0,1);return this},setRotationX:function(b){var d=Math.cos(b);b=Math.sin(b);this.set(1,0,0,0,0,d,-b,0,0,b,d,0,0,0,0,1);return this},setRotationY:function(b){var d=Math.cos(b);b=Math.sin(b);this.set(d,0,b,0,0,1,0,0,-b,0,d,0,0,0,0,1);return this},setRotationZ:function(b){var d=Math.cos(b);b=Math.sin(b);this.set(d,-b,0,0,b,d,0,0,0,0,1,0,0,0,0,1);return this},setRotationAxis:function(b,d){var e=Math.cos(d),g=Math.sin(d),h= +1-e,o=b.x,n=b.y,p=b.z,q=h*o,v=h*n;this.set(q*o+e,q*n-g*p,q*p+g*n,0,q*n+g*p,v*n+e,v*p-g*o,0,q*p-g*n,v*p+g*o,h*p*p+e,0,0,0,0,1);return this},setPosition:function(b){this.n14=b.x;this.n24=b.y;this.n34=b.z;return this},setRotationFromEuler:function(b){var d=b.x,e=b.y,g=b.z;b=Math.cos(d);d=Math.sin(d);var h=Math.cos(e);e=Math.sin(e);var o=Math.cos(g);g=Math.sin(g);var n=b*e,p=d*e;this.n11=h*o;this.n12=-h*g;this.n13=e;this.n21=p*o+b*g;this.n22=-p*g+b*o;this.n23=-d*h;this.n31=-n*o+d*g;this.n32=n*g+d*o;this.n33= +b*h;return this},setRotationFromQuaternion:function(b){var d=b.x,e=b.y,g=b.z,h=b.w,o=d+d,n=e+e,p=g+g;b=d*o;var q=d*n;d*=p;var v=e*n;e*=p;g*=p;o*=h;n*=h;h*=p;this.n11=1-(v+g);this.n12=q-h;this.n13=d+n;this.n21=q+h;this.n22=1-(b+g);this.n23=e-o;this.n31=d-n;this.n32=e+o;this.n33=1-(b+v);return this},scale:function(b){var d=b.x,e=b.y;b=b.z;this.n11*=d;this.n12*=e;this.n13*=b;this.n21*=d;this.n22*=e;this.n23*=b;this.n31*=d;this.n32*=e;this.n33*=b;this.n41*=d;this.n42*=e;this.n43*=b;return this},extractPosition:function(b){this.n14= +b.n14;this.n24=b.n24;this.n34=b.n34},extractRotation:function(b,d){var e=1/d.x,g=1/d.y,h=1/d.z;this.n11=b.n11*e;this.n21=b.n21*e;this.n31=b.n31*e;this.n12=b.n12*g;this.n22=b.n22*g;this.n32=b.n32*g;this.n13=b.n13*h;this.n23=b.n23*h;this.n33=b.n33*h}}; +THREE.Matrix4.makeInvert=function(b,d){var e=b.n11,g=b.n12,h=b.n13,o=b.n14,n=b.n21,p=b.n22,q=b.n23,v=b.n24,E=b.n31,F=b.n32,H=b.n33,I=b.n34,M=b.n41,N=b.n42,V=b.n43,L=b.n44;d===undefined&&(d=new THREE.Matrix4);d.n11=q*I*N-v*H*N+v*F*V-p*I*V-q*F*L+p*H*L;d.n12=o*H*N-h*I*N-o*F*V+g*I*V+h*F*L-g*H*L;d.n13=h*v*N-o*q*N+o*p*V-g*v*V-h*p*L+g*q*L;d.n14=o*q*F-h*v*F-o*p*H+g*v*H+h*p*I-g*q*I;d.n21=v*H*M-q*I*M-v*E*V+n*I*V+q*E*L-n*H*L;d.n22=h*I*M-o*H*M+o*E*V-e*I*V-h*E*L+e*H*L;d.n23=o*q*M-h*v*M-o*n*V+e*v*V+h*n*L-e*q*L; +d.n24=h*v*E-o*q*E+o*n*H-e*v*H-h*n*I+e*q*I;d.n31=p*I*M-v*F*M+v*E*N-n*I*N-p*E*L+n*F*L;d.n32=o*F*M-g*I*M-o*E*N+e*I*N+g*E*L-e*F*L;d.n33=h*v*M-o*p*M+o*n*N-e*v*N-g*n*L+e*p*L;d.n34=o*p*E-g*v*E-o*n*F+e*v*F+g*n*I-e*p*I;d.n41=q*F*M-p*H*M-q*E*N+n*H*N+p*E*V-n*F*V;d.n42=g*H*M-h*F*M+h*E*N-e*H*N-g*E*V+e*F*V;d.n43=h*p*M-g*q*M-h*n*N+e*q*N+g*n*V-e*p*V;d.n44=g*q*E-h*p*E+h*n*F-e*q*F-g*n*H+e*p*H;d.multiplyScalar(1/b.determinant());return d}; +THREE.Matrix4.makeInvert3x3=function(b){var d=b.m33,e=d.m,g=b.n33*b.n22-b.n32*b.n23,h=-b.n33*b.n21+b.n31*b.n23,o=b.n32*b.n21-b.n31*b.n22,n=-b.n33*b.n12+b.n32*b.n13,p=b.n33*b.n11-b.n31*b.n13,q=-b.n32*b.n11+b.n31*b.n12,v=b.n23*b.n12-b.n22*b.n13,E=-b.n23*b.n11+b.n21*b.n13,F=b.n22*b.n11-b.n21*b.n12;b=b.n11*g+b.n21*n+b.n31*v;if(b==0)throw"matrix not invertible";b=1/b;e[0]=b*g;e[1]=b*h;e[2]=b*o;e[3]=b*n;e[4]=b*p;e[5]=b*q;e[6]=b*v;e[7]=b*E;e[8]=b*F;return d}; +THREE.Matrix4.makeFrustum=function(b,d,e,g,h,o){var n;n=new THREE.Matrix4;n.n11=2*h/(d-b);n.n12=0;n.n13=(d+b)/(d-b);n.n14=0;n.n21=0;n.n22=2*h/(g-e);n.n23=(g+e)/(g-e);n.n24=0;n.n31=0;n.n32=0;n.n33=-(o+h)/(o-h);n.n34=-2*o*h/(o-h);n.n41=0;n.n42=0;n.n43=-1;n.n44=0;return n};THREE.Matrix4.makePerspective=function(b,d,e,g){var h;b=e*Math.tan(b*Math.PI/360);h=-b;return THREE.Matrix4.makeFrustum(h*d,b*d,h,b,e,g)}; +THREE.Matrix4.makeOrtho=function(b,d,e,g,h,o){var n,p,q,v;n=new THREE.Matrix4;p=d-b;q=e-g;v=o-h;n.n11=2/p;n.n12=0;n.n13=0;n.n14=-((d+b)/p);n.n21=0;n.n22=2/q;n.n23=0;n.n24=-((e+g)/q);n.n31=0;n.n32=0;n.n33=-2/v;n.n34=-((o+h)/v);n.n41=0;n.n42=0;n.n43=0;n.n44=1;return n};THREE.Matrix4.__v1=new THREE.Vector3;THREE.Matrix4.__v2=new THREE.Vector3;THREE.Matrix4.__v3=new THREE.Vector3; +THREE.Object3D=function(){this.parent=undefined;this.children=[];this.up=new THREE.Vector3(0,1,0);this.position=new THREE.Vector3;this.rotation=new THREE.Vector3;this.scale=new THREE.Vector3(1,1,1);this.rotationAutoUpdate=!0;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixRotationWorld=new THREE.Matrix4;this.matrixAutoUpdate=!0;this.matrixWorldNeedsUpdate=!0;this.quaternion=new THREE.Quaternion;this.useQuaternion=!1;this.boundRadius=0;this.boundRadiusScale=1;this.visible= +!0;this._vector=new THREE.Vector3}; +THREE.Object3D.prototype={translate:function(b,d){this.matrix.rotateAxis(d);this.position.addSelf(d.multiplyScalar(b))},translateX:function(b){this.translate(b,this._vector.set(1,0,0))},translateY:function(b){this.translate(b,this._vector.set(0,1,0))},translateZ:function(b){this.translate(b,this._vector.set(0,0,1))},lookAt:function(b){this.matrix.lookAt(this.position,b,this.up);this.rotationAutoUpdate&&this.rotation.setRotationFromMatrix(this.matrix)},addChild:function(b){if(this.children.indexOf(b)===-1){b.parent!== +undefined&&b.parent.removeChild(b);b.parent=this;this.children.push(b);for(var d=this;d instanceof THREE.Scene===!1&&d!==undefined;)d=d.parent;d!==undefined&&d.addChildRecurse(b)}},removeChild:function(b){var d=this.children.indexOf(b);if(d!==-1){b.parent=undefined;this.children.splice(d,1)}},updateMatrix:function(){this.matrix.setPosition(this.position);this.useQuaternion?this.matrix.setRotationFromQuaternion(this.quaternion):this.matrix.setRotationFromEuler(this.rotation);if(this.scale.x!==1||this.scale.y!== +1||this.scale.z!==1){this.matrix.scale(this.scale);this.boundRadiusScale=Math.max(this.scale.x,Math.max(this.scale.y,this.scale.z))}this.matrixWorldNeedsUpdate=!0},update:function(b,d,e){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||d){b?this.matrixWorld.multiply(b,this.matrix):this.matrixWorld.copy(this.matrix);this.matrixRotationWorld.extractRotation(this.matrixWorld,this.scale);this.matrixWorldNeedsUpdate=!1;d=!0}b=0;for(var g=this.children.length;b=1){e.w=b.w;e.x=b.x;e.y=b.y;e.z=b.z;return e}var o=Math.acos(h),n=Math.sqrt(1-h*h);if(Math.abs(n)<0.0010){e.w=0.5*(b.w+d.w);e.x=0.5*(b.x+d.x);e.y=0.5*(b.y+d.y);e.z=0.5*(b.z+d.z);return e}h=Math.sin((1-g)*o)/n;g=Math.sin(g*o)/n;e.w=b.w*h+d.w*g;e.x=b.x*h+d.x*g;e.y=b.y*h+d.y*g;e.z=b.z*h+d.z*g;return e};THREE.Vertex=function(b){this.position=b||new THREE.Vector3}; +THREE.Face3=function(b,d,e,g,h,o){this.a=b;this.b=d;this.c=e;this.normal=g instanceof THREE.Vector3?g:new THREE.Vector3;this.vertexNormals=g instanceof Array?g:[];this.color=h instanceof THREE.Color?h:new THREE.Color;this.vertexColors=h instanceof Array?h:[];this.vertexTangents=[];this.materials=o instanceof Array?o:[o];this.centroid=new THREE.Vector3}; +THREE.Face4=function(b,d,e,g,h,o,n){this.a=b;this.b=d;this.c=e;this.d=g;this.normal=h instanceof THREE.Vector3?h:new THREE.Vector3;this.vertexNormals=h instanceof Array?h:[];this.color=o instanceof THREE.Color?o:new THREE.Color;this.vertexColors=o instanceof Array?o:[];this.vertexTangents=[];this.materials=n instanceof Array?n:[n];this.centroid=new THREE.Vector3};THREE.UV=function(b,d){this.set(b||0,d||0)}; +THREE.UV.prototype={set:function(b,d){this.u=b;this.v=d;return this},copy:function(b){this.set(b.u,b.v);return this}};THREE.Geometry=function(){this.id="Geometry"+THREE.GeometryIdCounter++;this.vertices=[];this.colors=[];this.faces=[];this.edges=[];this.faceUvs=[[]];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphColors=[];this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.hasTangents=!1}; +THREE.Geometry.prototype={computeCentroids:function(){var b,d,e;b=0;for(d=this.faces.length;b0){this.boundingBox={x:[this.vertices[0].position.x,this.vertices[0].position.x],y:[this.vertices[0].position.y,this.vertices[0].position.y],z:[this.vertices[0].position.z,this.vertices[0].position.z]};for(var d=1,e=this.vertices.length;dthis.boundingBox.x[1])this.boundingBox.x[1]=b.position.x; +if(b.position.ythis.boundingBox.y[1])this.boundingBox.y[1]=b.position.y;if(b.position.zthis.boundingBox.z[1])this.boundingBox.z[1]=b.position.z}}},computeBoundingSphere:function(){for(var b=this.boundingSphere===null?0:this.boundingSphere.radius,d=0,e=this.vertices.length;d1){b=e.matrixWorldInverse;b=-(b.n31*this.position.x+b.n32*this.position.y+b.n33*this.position.z+b.n34);this.LODs[0].object3D.visible=!0;for(var g=1;g=this.LODs[g].visibleAtDistance){this.LODs[g-1].object3D.visible= +!1;this.LODs[g].object3D.visible=!0}else break;for(;gF){e=E;E=F;F=e}}else if(EI){e=H;H=I;I=e}}else if(H=0&&ta>=0&&aa>=0&&ma>=0)return!0;else if(Fa<0&&ta<0||aa<0&&ma<0)return!1;else{if(Fa<0)pa=Math.max(pa,Fa/(Fa-ta));else ta<0&&(ra=Math.min(ra,Fa/(Fa-ta)));if(aa<0)pa=Math.max(pa,aa/(aa-ma));else ma<0&&(ra=Math.min(ra,aa/(aa-ma)));if(raFa&&n.positionScreen.z0&&Z.z<1){Pa=da[sa]=da[sa]||new THREE.RenderableParticle;sa++;L=Pa;L.x=Z.x/Z.w;L.y=Z.y/Z.w;L.z=Z.z;L.rotation=$.rotation.z;L.scale.x=$.scale.x*Math.abs(L.x-(Z.x+S.projectionMatrix.n11)/(Z.w+S.projectionMatrix.n14));L.scale.y=$.scale.y*Math.abs(L.y-(Z.y+S.projectionMatrix.n22)/(Z.w+S.projectionMatrix.n24));L.materials=$.materials;ra.push(L)}}}}pa&&ra.sort(d);return ra}}; +THREE.SoundRenderer=function(){this.volume=1;this.domElement=document.createElement("div");this.domElement.id="THREESound";this.cameraPosition=new THREE.Vector3;this.soundPosition=new THREE.Vector3;this.render=function(b,d,e){e&&b.update(undefined,!1,d);e=b.sounds;var g,h=e.length;for(g=0;g 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#ifdef PHONG\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif", +lights_vertex:"if ( !enableLighting ) {\nvLightWeighting = vec3( 1.0 );\n} else {\nvLightWeighting = ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nfloat directionalLightWeighting = max( dot( transformedNormal, normalize( lDirection.xyz ) ), 0.0 );\nvLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat pointLightWeighting = max( dot( transformedNormal, lVector ), 0.0 );\nvLightWeighting += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef PHONG\nvPointLight[ i ] = vec4( lVector, lDistance );\n#endif\n}\n#endif\n}", +lights_pars_fragment:"#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",lights_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\nvec4 mColor = vec4( diffuse, opacity );\nvec4 mSpecular = vec4( specular, opacity );\n#if MAX_POINT_LIGHTS > 0\nvec4 pointDiffuse = vec4( 0.0 );\nvec4 pointSpecular = vec4( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec3 pointVector = normalize( vPointLight[ i ].xyz );\nvec3 pointHalfVector = normalize( vPointLight[ i ].xyz + vViewPosition );\nfloat pointDistance = vPointLight[ i ].w;\nfloat pointDotNormalHalf = dot( normal, pointHalfVector );\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\nfloat pointSpecularWeight = 0.0;\nif ( pointDotNormalHalf >= 0.0 )\npointSpecularWeight = pow( pointDotNormalHalf, shininess );\npointDiffuse += mColor * pointDiffuseWeight * pointDistance;\npointSpecular += mSpecular * pointSpecularWeight * pointDistance;\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec4 dirDiffuse = vec4( 0.0 );\nvec4 dirSpecular = vec4( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nvec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );\nfloat dirDotNormalHalf = dot( normal, dirHalfVector );\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\nfloat dirSpecularWeight = 0.0;\nif ( dirDotNormalHalf >= 0.0 )\ndirSpecularWeight = pow( dirDotNormalHalf, shininess );\ndirDiffuse += mColor * dirDiffuseWeight;\ndirSpecular += mSpecular * dirSpecularWeight;\n}\n#endif\nvec4 totalLight = vec4( ambient, opacity );\n#if MAX_DIR_LIGHTS > 0\ntotalLight += dirDiffuse + dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalLight += pointDiffuse + pointSpecular;\n#endif\ngl_FragColor = gl_FragColor * totalLight;", +color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, opacity );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\nvColor = color;\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\n#endif",skinning_vertex:"#ifdef USE_SKINNING\ngl_Position = ( boneGlobalMatrices[ int( skinIndex.x ) ] * skinVertexA ) * skinWeight.x;\ngl_Position += ( boneGlobalMatrices[ int( skinIndex.y ) ] * skinVertexB ) * skinWeight.y;\ngl_Position = projectionMatrix * viewMatrix * objectMatrix * gl_Position;\n#endif", +morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\nuniform float morphTargetInfluences[ 8 ];\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0, 0.0, 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\nmorphed += position;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( morphed, 1.0 );\n#endif", +default_vertex:"#ifndef USE_MORPHTARGETS\n#ifndef USE_SKINNING\ngl_Position = projectionMatrix * mvPosition;\n#endif\n#endif"};THREE.UniformsUtils={merge:function(b){var d,e,g,h={};for(d=0;dt){y=z;t=A[y]}c.bindBuffer(c.ARRAY_BUFFER,m.__webglMorphTargetsBuffers[y]);c.vertexAttribPointer(s["morphTarget"+j],3,c.FLOAT,!1,0,0);w.__webglMorphTargetInfluences[j]=t;u[y]=1;t=-1;j++}}c.uniform1fv(k.program.uniforms.morphTargetInfluences, +w.__webglMorphTargetInfluences)}else{c.bindBuffer(c.ARRAY_BUFFER,m.__webglVertexBuffer);c.vertexAttribPointer(f.position,3,c.FLOAT,!1,0,0)}if(m.__webglCustomAttributes)for(x in m.__webglCustomAttributes)if(f[x]>=0){s=m.__webglCustomAttributes[x];c.bindBuffer(c.ARRAY_BUFFER,s.buffer);c.vertexAttribPointer(f[x],s.size,c.FLOAT,!1,0,0)}if(f.color>=0){c.bindBuffer(c.ARRAY_BUFFER,m.__webglColorBuffer);c.vertexAttribPointer(f.color,3,c.FLOAT,!1,0,0)}if(f.normal>=0){c.bindBuffer(c.ARRAY_BUFFER,m.__webglNormalBuffer); +c.vertexAttribPointer(f.normal,3,c.FLOAT,!1,0,0)}if(f.tangent>=0){c.bindBuffer(c.ARRAY_BUFFER,m.__webglTangentBuffer);c.vertexAttribPointer(f.tangent,4,c.FLOAT,!1,0,0)}if(f.uv>=0)if(m.__webglUVBuffer){c.bindBuffer(c.ARRAY_BUFFER,m.__webglUVBuffer);c.vertexAttribPointer(f.uv,2,c.FLOAT,!1,0,0);c.enableVertexAttribArray(f.uv)}else c.disableVertexAttribArray(f.uv);if(f.uv2>=0)if(m.__webglUV2Buffer){c.bindBuffer(c.ARRAY_BUFFER,m.__webglUV2Buffer);c.vertexAttribPointer(f.uv2,2,c.FLOAT,!1,0,0);c.enableVertexAttribArray(f.uv2)}else c.disableVertexAttribArray(f.uv2); +if(k.skinning&&f.skinVertexA>=0&&f.skinVertexB>=0&&f.skinIndex>=0&&f.skinWeight>=0){c.bindBuffer(c.ARRAY_BUFFER,m.__webglSkinVertexABuffer);c.vertexAttribPointer(f.skinVertexA,4,c.FLOAT,!1,0,0);c.bindBuffer(c.ARRAY_BUFFER,m.__webglSkinVertexBBuffer);c.vertexAttribPointer(f.skinVertexB,4,c.FLOAT,!1,0,0);c.bindBuffer(c.ARRAY_BUFFER,m.__webglSkinIndicesBuffer);c.vertexAttribPointer(f.skinIndex,4,c.FLOAT,!1,0,0);c.bindBuffer(c.ARRAY_BUFFER,m.__webglSkinWeightsBuffer);c.vertexAttribPointer(f.skinWeight, +4,c.FLOAT,!1,0,0)}if(w instanceof THREE.Mesh)if(k.wireframe){c.lineWidth(k.wireframeLinewidth);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,m.__webglLineBuffer);c.drawElements(c.LINES,m.__webglLineCount,c.UNSIGNED_SHORT,0)}else{c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,m.__webglFaceBuffer);c.drawElements(c.TRIANGLES,m.__webglFaceCount,c.UNSIGNED_SHORT,0)}else if(w instanceof THREE.Line){w=w.type==THREE.LineStrip?c.LINE_STRIP:c.LINES;c.lineWidth(k.linewidth);c.drawArrays(w,0,m.__webglLineCount)}else if(w instanceof +THREE.ParticleSystem)c.drawArrays(c.POINTS,0,m.__webglParticleCount);else w instanceof THREE.Ribbon&&c.drawArrays(c.TRIANGLE_STRIP,0,m.__webglVertexCount)}}function h(f,s,j){if(!f.__webglVertexBuffer)f.__webglVertexBuffer=c.createBuffer();if(!f.__webglNormalBuffer)f.__webglNormalBuffer=c.createBuffer();if(f.hasPos){c.bindBuffer(c.ARRAY_BUFFER,f.__webglVertexBuffer);c.bufferData(c.ARRAY_BUFFER,f.positionArray,c.DYNAMIC_DRAW);c.enableVertexAttribArray(s.attributes.position);c.vertexAttribPointer(s.attributes.position, +3,c.FLOAT,!1,0,0)}if(f.hasNormal){c.bindBuffer(c.ARRAY_BUFFER,f.__webglNormalBuffer);if(j==THREE.FlatShading){var k,m,w,x,u,A,t,y,z,D,B=f.count*3;for(D=0;D0&&W[0]0&&W[1]0.0010&&u.scale>0.0010){O[0]=u.x;O[1]=u.y;O[2]=u.z;D=u.size*u.scale/za;B[0]=D*t;B[1]=D;c.uniform3fv(P.screenPosition,O);c.uniform2fv(P.scale,B);c.uniform1f(P.rotation,u.rotation);c.uniform1f(P.opacity,u.opacity);oa(u.blending);K(u.texture,1);c.drawElements(c.TRIANGLES,6,c.UNSIGNED_SHORT, +0)}}}}c.enable(c.CULL_FACE);c.enable(c.DEPTH_TEST);c.depthMask(ta)}function V(f,s){f._modelViewMatrix.multiplyToArray(s.matrixWorldInverse,f.matrixWorld,f._modelViewMatrixArray);THREE.Matrix4.makeInvert3x3(f._modelViewMatrix).transposeIntoArray(f._normalMatrixArray)}function L(f){var s,j,k,m,w;if(f instanceof THREE.Mesh){j=f.geometry;for(s in j.geometryGroups){k=j.geometryGroups[s];w=!1;for(m in k.__webglCustomAttributes)if(k.__webglCustomAttributes[m].needsUpdate){w=!0;break}if(j.__dirtyVertices|| +j.__dirtyMorphTargets||j.__dirtyElements||j.__dirtyUvs||j.__dirtyNormals||j.__dirtyColors||j.__dirtyTangents||w){w=c.DYNAMIC_DRAW;var x=void 0,u=void 0,A=void 0,t=void 0;A=void 0;var y=void 0,z=void 0,D=void 0,B=void 0,O=void 0,W=void 0,P=void 0,X=void 0,Ga=void 0,T=void 0,Q=void 0,U=void 0,ua=void 0;z=void 0;D=void 0;t=void 0;B=void 0;t=void 0;var r=void 0,G=void 0;z=void 0;r=void 0;G=void 0;var i=void 0,Ka=void 0;r=void 0;G=void 0;i=void 0;Ka=void 0;r=void 0;G=void 0;i=void 0;Ka=void 0;r=void 0; +G=void 0;i=void 0;t=void 0;B=void 0;y=void 0;A=void 0;A=void 0;r=void 0;G=void 0;i=void 0;var Va=void 0,va=0,Aa=0,Za=0,$a=0,Ja=0,La=0,ea=0,Ma=0,xa=0,C=0,Ba=0;G=r=0;var Ca=k.__vertexArray,fb=k.__uvArray,gb=k.__uv2Array,Qa=k.__normalArray,ha=k.__tangentArray,Da=k.__colorArray,ia=k.__skinVertexAArray,ja=k.__skinVertexBArray,ka=k.__skinIndexArray,la=k.__skinWeightArray,hb=k.__morphTargetsArrays,Ra=k.__webglCustomAttributes;i=void 0;var Na=k.__faceArray,Oa=k.__lineArray,qb=k.__needsSmoothNormals;W=k.__vertexColorType; +O=k.__uvType;P=k.__normalType;var Ha=f.geometry,ib=Ha.__dirtyVertices,jb=Ha.__dirtyElements,eb=Ha.__dirtyUvs,kb=Ha.__dirtyNormals,lb=Ha.__dirtyTangents,mb=Ha.__dirtyColors,nb=Ha.__dirtyMorphTargets,ab=Ha.vertices,rb=k.faces,ub=Ha.faces,sb=Ha.faceVertexUvs[0],tb=Ha.faceVertexUvs[1],bb=Ha.skinVerticesA,cb=Ha.skinVerticesB,db=Ha.skinIndices,Wa=Ha.skinWeights,Ya=f instanceof THREE.ShadowVolume?Ha.edgeFaces:undefined;morphTargets=Ha.morphTargets;if(Ra)for(Va in Ra){Ra[Va].offset=0;Ra[Va].offsetSrc=0}x= +0;for(u=rb.length;x0){c.bindBuffer(c.ARRAY_BUFFER,k.__webglColorBuffer);c.bufferData(c.ARRAY_BUFFER,Da,w)}if(kb){c.bindBuffer(c.ARRAY_BUFFER,k.__webglNormalBuffer);c.bufferData(c.ARRAY_BUFFER,Qa,w)}if(lb&&Ha.hasTangents){c.bindBuffer(c.ARRAY_BUFFER,k.__webglTangentBuffer);c.bufferData(c.ARRAY_BUFFER,ha,w)}if(eb&&Za>0){c.bindBuffer(c.ARRAY_BUFFER,k.__webglUVBuffer);c.bufferData(c.ARRAY_BUFFER,fb,w)}if(eb&& +$a>0){c.bindBuffer(c.ARRAY_BUFFER,k.__webglUV2Buffer);c.bufferData(c.ARRAY_BUFFER,gb,w)}if(jb){c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,k.__webglFaceBuffer);c.bufferData(c.ELEMENT_ARRAY_BUFFER,Na,w);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,k.__webglLineBuffer);c.bufferData(c.ELEMENT_ARRAY_BUFFER,Oa,w)}if(C>0){c.bindBuffer(c.ARRAY_BUFFER,k.__webglSkinVertexABuffer);c.bufferData(c.ARRAY_BUFFER,ia,w);c.bindBuffer(c.ARRAY_BUFFER,k.__webglSkinVertexBBuffer);c.bufferData(c.ARRAY_BUFFER,ja,w);c.bindBuffer(c.ARRAY_BUFFER, +k.__webglSkinIndicesBuffer);c.bufferData(c.ARRAY_BUFFER,ka,w);c.bindBuffer(c.ARRAY_BUFFER,k.__webglSkinWeightsBuffer);c.bufferData(c.ARRAY_BUFFER,la,w)}}}j.__dirtyVertices=!1;j.__dirtyMorphTargets=!1;j.__dirtyElements=!1;j.__dirtyUvs=!1;j.__dirtyNormals=!1;j.__dirtyTangents=!1;j.__dirtyColors=!1}else if(f instanceof THREE.Ribbon){j=f.geometry;if(j.__dirtyVertices||j.__dirtyColors){f=j;s=c.DYNAMIC_DRAW;W=f.vertices;k=f.colors;P=W.length;w=k.length;X=f.__vertexArray;x=f.__colorArray;Ga=f.__dirtyColors; +if(f.__dirtyVertices){for(u=0;u65535){y[A].counter+=1;t=y[A].hash+"_"+y[A].counter;f.geometryGroups[t]==undefined&&(f.geometryGroups[t]={faces:[],materials:u,vertices:0,numMorphTargets:z})}f.geometryGroups[t].faces.push(m);f.geometryGroups[t].vertices+=x}}function da(f,s,j){f.push({buffer:s,object:j,opaque:{list:[],count:0},transparent:{list:[],count:0}})}function oa(f){if(f!= +ga){switch(f){case THREE.AdditiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.SRC_ALPHA,c.ONE);break;case THREE.SubtractiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ZERO,c.ONE_MINUS_SRC_COLOR);break;case THREE.MultiplyBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ZERO,c.SRC_COLOR);break;default:c.blendEquationSeparate(c.FUNC_ADD,c.FUNC_ADD);c.blendFuncSeparate(c.SRC_ALPHA,c.ONE_MINUS_SRC_ALPHA,c.ONE,c.ONE_MINUS_SRC_ALPHA)}ga=f}}function Z(f,s,j){if((j.width&j.width-1)==0&&(j.height& +j.height-1)==0){c.texParameteri(f,c.TEXTURE_WRAP_S,fa(s.wrapS));c.texParameteri(f,c.TEXTURE_WRAP_T,fa(s.wrapT));c.texParameteri(f,c.TEXTURE_MAG_FILTER,fa(s.magFilter));c.texParameteri(f,c.TEXTURE_MIN_FILTER,fa(s.minFilter));c.generateMipmap(f)}else{c.texParameteri(f,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE);c.texParameteri(f,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE);c.texParameteri(f,c.TEXTURE_MAG_FILTER,Ea(s.magFilter));c.texParameteri(f,c.TEXTURE_MIN_FILTER,Ea(s.minFilter))}}function K(f,s){if(f.needsUpdate){if(f.__webglInit){c.bindTexture(c.TEXTURE_2D, +f.__webglTexture);c.texSubImage2D(c.TEXTURE_2D,0,0,0,c.RGBA,c.UNSIGNED_BYTE,f.image)}else{f.__webglTexture=c.createTexture();c.bindTexture(c.TEXTURE_2D,f.__webglTexture);c.texImage2D(c.TEXTURE_2D,0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,f.image);f.__webglInit=!0}Z(c.TEXTURE_2D,f,f.image);c.bindTexture(c.TEXTURE_2D,null);f.needsUpdate=!1}c.activeTexture(c.TEXTURE0+s);c.bindTexture(c.TEXTURE_2D,f.__webglTexture)}function Ia(f){if(f&&!f.__webglFramebuffer){if(f.depthBuffer===undefined)f.depthBuffer=!0;if(f.stencilBuffer=== +undefined)f.stencilBuffer=!0;f.__webglFramebuffer=c.createFramebuffer();f.__webglRenderbuffer=c.createRenderbuffer();f.__webglTexture=c.createTexture();c.bindTexture(c.TEXTURE_2D,f.__webglTexture);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,fa(f.wrapS));c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,fa(f.wrapT));c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,fa(f.magFilter));c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,fa(f.minFilter));c.texImage2D(c.TEXTURE_2D,0,fa(f.format),f.width,f.height, +0,fa(f.format),fa(f.type),null);c.bindRenderbuffer(c.RENDERBUFFER,f.__webglRenderbuffer);c.bindFramebuffer(c.FRAMEBUFFER,f.__webglFramebuffer);c.framebufferTexture2D(c.FRAMEBUFFER,c.COLOR_ATTACHMENT0,c.TEXTURE_2D,f.__webglTexture,0);if(f.depthBuffer&&!f.stencilBuffer){c.renderbufferStorage(c.RENDERBUFFER,c.DEPTH_COMPONENT16,f.width,f.height);c.framebufferRenderbuffer(c.FRAMEBUFFER,c.DEPTH_ATTACHMENT,c.RENDERBUFFER,f.__webglRenderbuffer)}else if(f.depthBuffer&&f.stencilBuffer){c.renderbufferStorage(c.RENDERBUFFER, +c.DEPTH_STENCIL,f.width,f.height);c.framebufferRenderbuffer(c.FRAMEBUFFER,c.DEPTH_STENCIL_ATTACHMENT,c.RENDERBUFFER,f.__webglRenderbuffer)}else c.renderbufferStorage(c.RENDERBUFFER,c.RGBA4,f.width,f.height);c.bindTexture(c.TEXTURE_2D,null);c.bindRenderbuffer(c.RENDERBUFFER,null);c.bindFramebuffer(c.FRAMEBUFFER,null)}var s,j;if(f){s=f.__webglFramebuffer;j=f.width;f=f.height}else{s=null;j=ya;f=za}if(s!=Fa){c.bindFramebuffer(c.FRAMEBUFFER,s);c.viewport(wa,qa,j,f);Fa=s}}function ca(f,s){var j;if(f=="fragment")j= +c.createShader(c.FRAGMENT_SHADER);else f=="vertex"&&(j=c.createShader(c.VERTEX_SHADER));c.shaderSource(j,s);c.compileShader(j);if(!c.getShaderParameter(j,c.COMPILE_STATUS)){console.error(c.getShaderInfoLog(j));console.error(s);return null}return j}function Ea(f){switch(f){case THREE.NearestFilter:case THREE.NearestMipMapNearestFilter:case THREE.NearestMipMapLinearFilter:return c.NEAREST;default:return c.LINEAR}}function fa(f){switch(f){case THREE.RepeatWrapping:return c.REPEAT;case THREE.ClampToEdgeWrapping:return c.CLAMP_TO_EDGE; +case THREE.MirroredRepeatWrapping:return c.MIRRORED_REPEAT;case THREE.NearestFilter:return c.NEAREST;case THREE.NearestMipMapNearestFilter:return c.NEAREST_MIPMAP_NEAREST;case THREE.NearestMipMapLinearFilter:return c.NEAREST_MIPMAP_LINEAR;case THREE.LinearFilter:return c.LINEAR;case THREE.LinearMipMapNearestFilter:return c.LINEAR_MIPMAP_NEAREST;case THREE.LinearMipMapLinearFilter:return c.LINEAR_MIPMAP_LINEAR;case THREE.ByteType:return c.BYTE;case THREE.UnsignedByteType:return c.UNSIGNED_BYTE;case THREE.ShortType:return c.SHORT; +case THREE.UnsignedShortType:return c.UNSIGNED_SHORT;case THREE.IntType:return c.INT;case THREE.UnsignedShortType:return c.UNSIGNED_INT;case THREE.FloatType:return c.FLOAT;case THREE.AlphaFormat:return c.ALPHA;case THREE.RGBFormat:return c.RGB;case THREE.RGBAFormat:return c.RGBA;case THREE.LuminanceFormat:return c.LUMINANCE;case THREE.LuminanceAlphaFormat:return c.LUMINANCE_ALPHA}return 0}var c,S=document.createElement("canvas"),pa=[],ra=null,Fa=null,ta=!0,aa=this,ma=null,na=null,ga=null,Y=null,wa= +0,qa=0,ya=0,za=0,$=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4],Pa=new THREE.Matrix4,Ta=new Float32Array(16),Xa=new Float32Array(16),Ua=new THREE.Vector4,Sa={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]}};b=b||{};stencil=b.stencil!==undefined?b.stencil:!0;antialias=b.antialias!==undefined?b.antialias:!1;clearColor=b.clearColor!==undefined?new THREE.Color(b.clearColor): +new THREE.Color(0);clearAlpha=b.clearAlpha!==undefined?b.clearAlpha:0;this.maxMorphTargets=8;this.domElement=S;this.autoClear=!0;this.sortObjects=!0;(function(f,s,j,k){try{if(!(c=S.getContext("experimental-webgl",{antialias:f,stencil:k})))throw"Error creating WebGL context.";}catch(m){console.error(m)}console.log(navigator.userAgent+" | "+c.getParameter(c.VERSION)+" | "+c.getParameter(c.VENDOR)+" | "+c.getParameter(c.RENDERER)+" | "+c.getParameter(c.SHADING_LANGUAGE_VERSION));c.clearColor(0,0,0,1); +c.clearDepth(1);c.enable(c.DEPTH_TEST);c.depthFunc(c.LEQUAL);c.frontFace(c.CCW);c.cullFace(c.BACK);c.enable(c.CULL_FACE);c.enable(c.BLEND);c.blendEquation(c.FUNC_ADD);c.blendFunc(c.SRC_ALPHA,c.ONE_MINUS_SRC_ALPHA);c.clearColor(s.r,s.g,s.b,j)})(antialias,clearColor,clearAlpha,stencil);this.context=c;if(stencil){var R={};R.vertices=new Float32Array(12);R.faces=new Uint16Array(6);R.darkness=0.5;R.vertices[0]=-20;R.vertices[1]=-20;R.vertices[2]=-1;R.vertices[3]=20;R.vertices[4]=-20;R.vertices[5]=-1;R.vertices[6]= +20;R.vertices[7]=20;R.vertices[8]=-1;R.vertices[9]=-20;R.vertices[10]=20;R.vertices[11]=-1;R.faces[0]=0;R.faces[1]=1;R.faces[2]=2;R.faces[3]=0;R.faces[4]=2;R.faces[5]=3;R.vertexBuffer=c.createBuffer();R.elementBuffer=c.createBuffer();c.bindBuffer(c.ARRAY_BUFFER,R.vertexBuffer);c.bufferData(c.ARRAY_BUFFER,R.vertices,c.STATIC_DRAW);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,R.elementBuffer);c.bufferData(c.ELEMENT_ARRAY_BUFFER,R.faces,c.STATIC_DRAW);R.program=c.createProgram();c.attachShader(R.program,ca("fragment", +THREE.ShaderLib.shadowPost.fragmentShader));c.attachShader(R.program,ca("vertex",THREE.ShaderLib.shadowPost.vertexShader));c.linkProgram(R.program);R.vertexLocation=c.getAttribLocation(R.program,"position");R.projectionLocation=c.getUniformLocation(R.program,"projectionMatrix");R.darknessLocation=c.getUniformLocation(R.program,"darkness")}var J={};J.vertices=new Float32Array(16);J.faces=new Uint16Array(6);b=0;J.vertices[b++]=-1;J.vertices[b++]=-1;J.vertices[b++]=0;J.vertices[b++]=0;J.vertices[b++]= +1;J.vertices[b++]=-1;J.vertices[b++]=1;J.vertices[b++]=0;J.vertices[b++]=1;J.vertices[b++]=1;J.vertices[b++]=1;J.vertices[b++]=1;J.vertices[b++]=-1;J.vertices[b++]=1;J.vertices[b++]=0;J.vertices[b++]=1;b=0;J.faces[b++]=0;J.faces[b++]=1;J.faces[b++]=2;J.faces[b++]=0;J.faces[b++]=2;J.faces[b++]=3;J.vertexBuffer=c.createBuffer();J.elementBuffer=c.createBuffer();J.tempTexture=c.createTexture();J.occlusionTexture=c.createTexture();c.bindBuffer(c.ARRAY_BUFFER,J.vertexBuffer);c.bufferData(c.ARRAY_BUFFER, +J.vertices,c.STATIC_DRAW);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,J.elementBuffer);c.bufferData(c.ELEMENT_ARRAY_BUFFER,J.faces,c.STATIC_DRAW);c.bindTexture(c.TEXTURE_2D,J.tempTexture);c.texImage2D(c.TEXTURE_2D,0,c.RGB,16,16,0,c.RGB,c.UNSIGNED_BYTE,null);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.NEAREST);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.NEAREST);c.bindTexture(c.TEXTURE_2D, +J.occlusionTexture);c.texImage2D(c.TEXTURE_2D,0,c.RGBA,16,16,0,c.RGBA,c.UNSIGNED_BYTE,null);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.NEAREST);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.NEAREST);if(c.getParameter(c.MAX_VERTEX_TEXTURE_IMAGE_UNITS)<=0){J.hasVertexTexture=!1;J.program=c.createProgram();c.attachShader(J.program,ca("fragment",THREE.ShaderLib.lensFlare.fragmentShader)); +c.attachShader(J.program,ca("vertex",THREE.ShaderLib.lensFlare.vertexShader))}else{J.hasVertexTexture=!0;J.program=c.createProgram();c.attachShader(J.program,ca("fragment",THREE.ShaderLib.lensFlareVertexTexture.fragmentShader));c.attachShader(J.program,ca("vertex",THREE.ShaderLib.lensFlareVertexTexture.vertexShader))}c.linkProgram(J.program);J.attributes={};J.uniforms={};J.attributes.vertex=c.getAttribLocation(J.program,"position");J.attributes.uv=c.getAttribLocation(J.program,"UV");J.uniforms.renderType= +c.getUniformLocation(J.program,"renderType");J.uniforms.map=c.getUniformLocation(J.program,"map");J.uniforms.occlusionMap=c.getUniformLocation(J.program,"occlusionMap");J.uniforms.opacity=c.getUniformLocation(J.program,"opacity");J.uniforms.scale=c.getUniformLocation(J.program,"scale");J.uniforms.rotation=c.getUniformLocation(J.program,"rotation");J.uniforms.screenPosition=c.getUniformLocation(J.program,"screenPosition");var pb=!1;_sprite={};_sprite.vertices=new Float32Array(16);_sprite.faces=new Uint16Array(6); +b=0;_sprite.vertices[b++]=-1;_sprite.vertices[b++]=-1;_sprite.vertices[b++]=0;_sprite.vertices[b++]=0;_sprite.vertices[b++]=1;_sprite.vertices[b++]=-1;_sprite.vertices[b++]=1;_sprite.vertices[b++]=0;_sprite.vertices[b++]=1;_sprite.vertices[b++]=1;_sprite.vertices[b++]=1;_sprite.vertices[b++]=1;_sprite.vertices[b++]=-1;_sprite.vertices[b++]=1;_sprite.vertices[b++]=0;_sprite.vertices[b++]=1;b=0;_sprite.faces[b++]=0;_sprite.faces[b++]=1;_sprite.faces[b++]=2;_sprite.faces[b++]=0;_sprite.faces[b++]=2; +_sprite.faces[b++]=3;_sprite.vertexBuffer=c.createBuffer();_sprite.elementBuffer=c.createBuffer();c.bindBuffer(c.ARRAY_BUFFER,_sprite.vertexBuffer);c.bufferData(c.ARRAY_BUFFER,_sprite.vertices,c.STATIC_DRAW);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,_sprite.elementBuffer);c.bufferData(c.ELEMENT_ARRAY_BUFFER,_sprite.faces,c.STATIC_DRAW);_sprite.program=c.createProgram();c.attachShader(_sprite.program,ca("fragment",THREE.ShaderLib.sprite.fragmentShader));c.attachShader(_sprite.program,ca("vertex",THREE.ShaderLib.sprite.vertexShader)); +c.linkProgram(_sprite.program);_sprite.attributes={};_sprite.uniforms={};_sprite.attributes.position=c.getAttribLocation(_sprite.program,"position");_sprite.attributes.uv=c.getAttribLocation(_sprite.program,"uv");_sprite.uniforms.uvOffset=c.getUniformLocation(_sprite.program,"uvOffset");_sprite.uniforms.uvScale=c.getUniformLocation(_sprite.program,"uvScale");_sprite.uniforms.rotation=c.getUniformLocation(_sprite.program,"rotation");_sprite.uniforms.scale=c.getUniformLocation(_sprite.program,"scale"); +_sprite.uniforms.alignment=c.getUniformLocation(_sprite.program,"alignment");_sprite.uniforms.map=c.getUniformLocation(_sprite.program,"map");_sprite.uniforms.opacity=c.getUniformLocation(_sprite.program,"opacity");_sprite.uniforms.useScreenCoordinates=c.getUniformLocation(_sprite.program,"useScreenCoordinates");_sprite.uniforms.affectedByDistance=c.getUniformLocation(_sprite.program,"affectedByDistance");_sprite.uniforms.screenPosition=c.getUniformLocation(_sprite.program,"screenPosition");_sprite.uniforms.modelViewMatrix= +c.getUniformLocation(_sprite.program,"modelViewMatrix");_sprite.uniforms.projectionMatrix=c.getUniformLocation(_sprite.program,"projectionMatrix");var ob=!1;this.setSize=function(f,s){S.width=f;S.height=s;this.setViewport(0,0,S.width,S.height)};this.setViewport=function(f,s,j,k){wa=f;qa=s;ya=j;za=k;c.viewport(wa,qa,ya,za)};this.setScissor=function(f,s,j,k){c.scissor(f,s,j,k)};this.enableScissorTest=function(f){f?c.enable(c.SCISSOR_TEST):c.disable(c.SCISSOR_TEST)};this.enableDepthBufferWrite=function(f){ta= +f;c.depthMask(f)};this.setClearColorHex=function(f,s){var j=new THREE.Color(f);c.clearColor(j.r,j.g,j.b,s)};this.setClearColor=function(f,s){c.clearColor(f.r,f.g,f.b,s)};this.clear=function(){c.clear(c.COLOR_BUFFER_BIT|c.DEPTH_BUFFER_BIT|c.STENCIL_BUFFER_BIT)};this.setStencilShadowDarkness=function(f){R.darkness=f};this.initMaterial=function(f,s,j,k){var m,w,x;if(f instanceof THREE.MeshDepthMaterial)x="depth";else if(f instanceof THREE.ShadowVolumeDynamicMaterial)x="shadowVolumeDynamic";else if(f instanceof +THREE.MeshNormalMaterial)x="normal";else if(f instanceof THREE.MeshBasicMaterial)x="basic";else if(f instanceof THREE.MeshLambertMaterial)x="lambert";else if(f instanceof THREE.MeshPhongMaterial)x="phong";else if(f instanceof THREE.LineBasicMaterial)x="basic";else f instanceof THREE.ParticleBasicMaterial&&(x="particle_basic");if(x){var u=THREE.ShaderLib[x];f.uniforms=THREE.UniformsUtils.clone(u.uniforms);f.vertexShader=u.vertexShader;f.fragmentShader=u.fragmentShader}var A,t,y;A=y=u=0;for(t=s.length;A< +t;A++){w=s[A];w instanceof THREE.DirectionalLight&&y++;w instanceof THREE.PointLight&&u++}if(u+y<=4)s=y;else{s=Math.ceil(4*y/(u+y));u=4-s}w={directional:s,point:u};y=50;if(k!==undefined&&k instanceof THREE.SkinnedMesh)y=k.bones.length;var z;a:{A=f.fragmentShader;t=f.vertexShader;u=f.uniforms;s=f.attributes;j={map:!!f.map,envMap:!!f.envMap,lightMap:!!f.lightMap,vertexColors:f.vertexColors,fog:j,sizeAttenuation:f.sizeAttenuation,skinning:f.skinning,morphTargets:f.morphTargets,maxMorphTargets:this.maxMorphTargets, +maxDirLights:w.directional,maxPointLights:w.point,maxBones:y};var D;w=[];if(x)w.push(x);else{w.push(A);w.push(t)}for(D in j){w.push(D);w.push(j[D])}x=w.join();D=0;for(w=pa.length;D0?"#define VERTEX_TEXTURES":"","#define MAX_DIR_LIGHTS "+j.maxDirLights,"#define MAX_POINT_LIGHTS "+j.maxPointLights,"#define MAX_BONES "+j.maxBones,j.map?"#define USE_MAP":"",j.envMap?"#define USE_ENVMAP":"",j.lightMap?"#define USE_LIGHTMAP":"",j.vertexColors? +"#define USE_COLOR":"",j.skinning?"#define USE_SKINNING":"",j.morphTargets?"#define USE_MORPHTARGETS":"",j.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nuniform mat4 cameraInverseMatrix;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n"); +c.attachShader(D,ca("fragment",prefix_fragment+A));c.attachShader(D,ca("vertex",prefix_vertex+t));c.linkProgram(D);c.getProgramParameter(D,c.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+c.getProgramParameter(D,c.VALIDATE_STATUS)+", gl error ["+c.getError()+"]");D.uniforms={};D.attributes={};var B;A=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition","cameraInverseMatrix","boneGlobalMatrices","morphTargetInfluences"];for(B in u)A.push(B); +B=A;u=0;for(A=B.length;u=0&&c.enableVertexAttribArray(z.color);z.normal>= +0&&c.enableVertexAttribArray(z.normal);z.tangent>=0&&c.enableVertexAttribArray(z.tangent);if(f.skinning&&z.skinVertexA>=0&&z.skinVertexB>=0&&z.skinIndex>=0&&z.skinWeight>=0){c.enableVertexAttribArray(z.skinVertexA);c.enableVertexAttribArray(z.skinVertexB);c.enableVertexAttribArray(z.skinIndex);c.enableVertexAttribArray(z.skinWeight)}for(m in f.attributes)z[m]>=0&&c.enableVertexAttribArray(z[m]);if(f.morphTargets){f.numSupportedMorphTargets=0;if(z.morphTarget0>=0){c.enableVertexAttribArray(z.morphTarget0); +f.numSupportedMorphTargets++}if(z.morphTarget1>=0){c.enableVertexAttribArray(z.morphTarget1);f.numSupportedMorphTargets++}if(z.morphTarget2>=0){c.enableVertexAttribArray(z.morphTarget2);f.numSupportedMorphTargets++}if(z.morphTarget3>=0){c.enableVertexAttribArray(z.morphTarget3);f.numSupportedMorphTargets++}if(z.morphTarget4>=0){c.enableVertexAttribArray(z.morphTarget4);f.numSupportedMorphTargets++}if(z.morphTarget5>=0){c.enableVertexAttribArray(z.morphTarget5);f.numSupportedMorphTargets++}if(z.morphTarget6>= +0){c.enableVertexAttribArray(z.morphTarget6);f.numSupportedMorphTargets++}if(z.morphTarget7>=0){c.enableVertexAttribArray(z.morphTarget7);f.numSupportedMorphTargets++}k.__webglMorphTargetInfluences=new Float32Array(this.maxMorphTargets);f=0;for(m=this.maxMorphTargets;f0||D.faceVertexUvs.length>0)x.__uvArray=new Float32Array(A*2);if(D.faceUvs.length>1||D.faceVertexUvs.length>1)x.__uv2Array=new Float32Array(A*2)}if(u.geometry.skinWeights.length&&u.geometry.skinIndices.length){x.__skinVertexAArray=new Float32Array(A* +4);x.__skinVertexBArray=new Float32Array(A*4);x.__skinIndexArray=new Float32Array(A*4);x.__skinWeightArray=new Float32Array(A*4)}x.__faceArray=new Uint16Array(O*3+(u.geometry.edgeFaces?u.geometry.edgeFaces.length*6:0));x.__lineArray=new Uint16Array(W*2);if(x.numMorphTargets){x.__morphTargetsArrays=[];D=0;for(B=x.numMorphTargets;D=0;m--){k=j.__webglObjects[m].object;if(s==k){j.__webglObjects.splice(m,1);break}}f.__objectsRemoved.splice(0,1)}s=0;for(j=f.__webglObjects.length;s0}}; +THREE.WebGLRenderTarget=function(b,d,e){this.width=b;this.height=d;e=e||{};this.wrapS=e.wrapS!==undefined?e.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=e.wrapT!==undefined?e.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=e.magFilter!==undefined?e.magFilter:THREE.LinearFilter;this.minFilter=e.minFilter!==undefined?e.minFilter:THREE.LinearMipMapLinearFilter;this.format=e.format!==undefined?e.format:THREE.RGBAFormat;this.type=e.type!==undefined?e.type:THREE.UnsignedByteType;this.depthBuffer=e.depthBuffer!== +undefined?e.depthBuffer:!0;this.stencilBuffer=e.stencilBuffer!==undefined?e.stencilBuffer:!0}; diff --git a/static/js/checkPassword.js b/static/js/checkPassword.js new file mode 100644 index 0000000..d72cb64 --- /dev/null +++ b/static/js/checkPassword.js @@ -0,0 +1,114 @@ +// 检测用户输入的信息是否符合要求,若符合则发送给后端 +function beforeSubmit() { + + var username = document.getElementById('userName').value; + var email = document.getElementById('email').value; + var password = document.getElementById('password').value; + var confirmpassword = document.getElementById('confirmpassword').value; + + var reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/; + + if(username == ""){ + alert("用户名不能为空"); + return false; + } + if(email == ""){ + alert("邮箱不能为空"); + return false; + } + if(password == ""){ + alert("密码不能为空"); + return false; + } + if(confirmpassword == ""){ + alert("请再次输入密码"); + return false; + } + //确认两次输入的密码相同 + if (password != confirmpassword) { + alert("两次输入的密码必须相同"); + return false; + } + + + if (password.length < 8 || password.length > 32) { + alert("密码长度限制在8位~32位"); + return false; + } + + if ((password).match(reg) == null) { + alert("密码必须同时包含大写小写数字"); + return false; + } + + // 创建一个FormData对象,直接把表单传进去 + var formData = new FormData(document.forms.namedItem("login_form")); + + // 通过jquery发送出去 + $.ajax({ + url: "/signin", + type: "POST", + data: formData, + processData: false, // 告诉jQuery不要去处理发送的数据 + contentType: false, // 告诉jQuery不要去设置Content-Type请求头 + success:function (data) { //成功回调 + document.open(); + document.write(data); //根据python返回的模板更新当前页面 + document.close(); + } + }).done(function(resp) { + alert('success!'); + }).fail(function(err) { + alert('fail!') + }); + + + return true; + +} + +//将password使用sha512后发送给后端 +function hashPassword(){ + var email = document.getElementById('email').value; + var password = document.getElementById('password').value; + + if(email == ""){ + alert("邮箱不能为空"); + return false; + } + if(password == ""){ + alert("密码不能为空"); + return false; + } + + var formData = new FormData(document.forms.namedItem("login_form")); + + // sha512加密过程 + var hash = sha512.create(); + hash.update(password); + afterhash = hash.hex(); + + //表单中password的值用hash值代替 + formData.set('password',afterhash); + + // 通过jquery发送出去 + $.ajax({ + url: "/signup", + type: "POST", + data: formData, + processData: false, // 告诉jQuery不要去处理发送的数据 + contentType: false, // 告诉jQuery不要去设置Content-Type请求头 + success:function (data) { //成功回调 + document.open(); + document.write(data); //根据python返回的模板更新当前页面 + document.close(); + } + }).done(function(resp) { + alert('success!'); + }).fail(function(err) { + alert('fail!') + }); + + + return true; +} \ No newline at end of file diff --git a/static/js/lanrenzhijia.js b/static/js/lanrenzhijia.js new file mode 100644 index 0000000..a05edd3 --- /dev/null +++ b/static/js/lanrenzhijia.js @@ -0,0 +1,60 @@ +/** + * @author alteredq / http://alteredqualia.com/ + * @author mr.doob / http://mrdoob.com/ + */ + +Detector = { + + canvas : !! window.CanvasRenderingContext2D, + webgl : ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(), + workers : !! window.Worker, + fileapi : window.File && window.FileReader && window.FileList && window.Blob, + + getWebGLErrorMessage : function () { + + var domElement = document.createElement( 'div' ); + + domElement.style.fontFamily = 'monospace'; + domElement.style.fontSize = '13px'; + domElement.style.textAlign = 'center'; + domElement.style.background = '#eee'; + domElement.style.color = '#000'; + domElement.style.padding = '1em'; + domElement.style.width = '475px'; + domElement.style.margin = '5em auto 0'; + + if ( ! this.webgl ) { + + domElement.innerHTML = window.WebGLRenderingContext ? [ + 'Sorry, your graphics card doesn\'t support WebGL' + ].join( '\n' ) : [ + 'Sorry, your browser doesn\'t support WebGL
', + 'Please try with', + 'Chrome 10, ', + 'Firefox 4 or', + 'Safari 6' + ].join( '\n' ); + + } + + return domElement; + + }, + + addGetWebGLMessage : function ( parameters ) { + + var parent, id, domElement; + + parameters = parameters || {}; + + parent = parameters.parent !== undefined ? parameters.parent : document.body; + id = parameters.id !== undefined ? parameters.id : 'oldie'; + + domElement = Detector.getWebGLErrorMessage(); + domElement.id = id; + + parent.appendChild( domElement ); + + } + +}; diff --git a/static/js/lib/jquery-3.3.1.min.js b/static/js/lib/jquery-3.3.1.min.js new file mode 100644 index 0000000..4d9b3a2 --- /dev/null +++ b/static/js/lib/jquery-3.3.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,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":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" + + + + +
+
+ 注册
+ 登陆 +
+
+ + + + + + + diff --git a/templates/login/signin.html b/templates/login/signin.html new file mode 100644 index 0000000..ca20df3 --- /dev/null +++ b/templates/login/signin.html @@ -0,0 +1,46 @@ + + + + + + + + + 登陆界面 + + +
+

夏季小学期实践

+
+ +
+ +
+

预留区域

+
+ +
+ {% if message %} +

{{ message }}

+ {% endif %} + +
+ + Sign Up: + + 邮箱:
+ 密码:
+ + +

{{ form.csrf_token }}

+ + +
+ +
+ +
+ + + \ No newline at end of file diff --git a/templates/login/signup.html b/templates/login/signup.html new file mode 100644 index 0000000..5d425fa --- /dev/null +++ b/templates/login/signup.html @@ -0,0 +1,51 @@ + + + + + + + + 用户注册界面 + + + + +
+

夏季小学期实践

+
+ +
+ +
+

预留区域

+
+ +
+ {% if message %} +

{{ message }}

+ {% endif %} + +
+ + Sign In: + + 用户名:
+ 邮箱:
+ 密码:
+ 再次确认密码: + + +

{{ form.csrf_token }}

+ + +
+ +
+ +
+ + + \ No newline at end of file diff --git a/templates/upload/download.html b/templates/upload/download.html new file mode 100644 index 0000000..b03bc54 --- /dev/null +++ b/templates/upload/download.html @@ -0,0 +1,17 @@ + + + + + + 文件下载页面 + + +
+

选择你要下载的页面

+
+ +
+

title

+
+ + \ No newline at end of file diff --git a/templates/upload/upload.html b/templates/upload/upload.html new file mode 100644 index 0000000..ecd14ab --- /dev/null +++ b/templates/upload/upload.html @@ -0,0 +1,30 @@ + + + + + 上传文件页面 + + + +

选择要上传的文件

+ +{% with messages = get_flashed_messages() %} +{% if messages %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+{% endif %} +{% endwith %} +
+

{{ form.watermark }}

+

File: {{ form.image }}

+

{{ form.csrf_token }}

+ + +
+Sign Off + + + \ No newline at end of file From 613aa2adfe9b65b505c24c2d7e138b8016877ca9 Mon Sep 17 00:00:00 2001 From: Lyc-heng <18087603176@163.com> Date: Thu, 26 Jul 2018 00:17:32 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD(=E4=BB=85=E5=87=BD=E6=95=B0?= =?UTF-8?q?=EF=BC=8C=E8=BF=98=E6=B2=A1=E6=9C=89=E4=B8=8A=E4=BC=A0=E7=9A=84?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=BF=9B=E8=A1=8C=E6=B5=8B=E8=AF=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- database.py | 5 --- encryption.py | 87 ++++++++++++++++++++++++++++++++++++++++++++ file.py | 8 ++-- forms/signin_form.py | 2 +- signinup.py | 2 +- 6 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 encryption.py diff --git a/.gitignore b/.gitignore index f6eb7a4..d275988 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ config.py forms/__pycache__/ instance templates/login/debug.log -templates/upload/debug.log \ No newline at end of file +templates/upload/debug.log +static/secret/ \ No newline at end of file diff --git a/database.py b/database.py index be84280..76dd3ee 100644 --- a/database.py +++ b/database.py @@ -12,11 +12,6 @@ def create_app(): app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = config.secretinfo['SQLALCHEMY_TRACK_MODIFICATIONS'] db.init_app(app) - with app.app_context(): - from models import User - db.create_all() - db.session.merge(User(id=0,username="lycheng", email='anjing@cuc.edu.cn', password='aB8')) - db.session.commit() return app def add_user(user,userID): diff --git a/encryption.py b/encryption.py new file mode 100644 index 0000000..313e95c --- /dev/null +++ b/encryption.py @@ -0,0 +1,87 @@ + +import sys +from Crypto.Cipher import AES +from binascii import b2a_hex, a2b_hex +import rsa + +class prpcrypt(): + def __init__(self, key): + self.key = key + self.mode = AES.MODE_CBC + + # 加密函数,如果text不是16的倍数【加密文本text必须为16的倍数!】,那就补足为16的倍数 + def encrypt(self, text): + cryptor = AES.new(self.key, self.mode, self.key) + + length = 16 + count = len(text) + if (count % length != 0): + add = length - (count % length) + else: + add = 0 + text = text + ('\0' * add).encode() + self.ciphertext = cryptor.encrypt(text) + # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题 + # 所以这里统一把加密后的字符串转化为16进制字符串 + return b2a_hex(self.ciphertext) + + # 解密后,去掉补足的空格用strip() 去掉 + def decrypt(self, text): + cryptor = AES.new(self.key, self.mode, self.key) + plain_text = cryptor.decrypt(a2b_hex(text)) + return plain_text.rstrip(('\0').encode()) + +def encryption_file(filepath): + with open('./static/secret/publickey.txt', 'rb') as f: # 以二进制写类型打开 + publicKey = (f.read()).decode() + + # 将获取得到的字符串转化为公钥所需参数(n,e) + para1 = publicKey[10:-8] + para2 = publicKey[-6:-1] + + #公钥初始化 + publicKey = rsa.key.PublicKey(int(para1),int(para2)) + + + with open('./static/secret/privatekey.txt', 'rb') as f: # 以二进制写类型打开 + privateKey = (f.read()).decode() + + # 解析字符串转换为私钥所需的五个参数(n,e,d,p,q) + para3 = privateKey[len(para1)+len(para2)+15:-1] + para4 = para3[:-908] + para3 = para3[-906:] + para3,para4 = para4,para3 + para5 = para4[:480] + para4 = para4[482:] + para4,para5 = para5,para4 + + #私钥初始化 + privateKey = rsa.key.PrivateKey(int(para1),int(para2),int(para3),int(para4),int(para5)) + + + # 获得对称密钥 + with open('./static/secret/symmetrickey.txt', 'rb') as f: # 以二进制写类型打开 + secretkey = f.read() + message = rsa.decrypt(secretkey, privateKey) + + + #采用AES_CBC模式加密 + secretkey = message + pc = prpcrypt(secretkey) # 初始化密钥 + + # 加密操作 + file = open('E:/大学/大二下/更新操作.PNG', 'rb').read() + e = pc.encrypt(file) + with open('E:/大学/大二下/1.PNG', 'wb') as f: # 以二进制写类型打开 + f.write(e) # 写入文件 + + # # 解密操作 + # file = open('E:/大学/大二下/1.PNG', 'rb').read() + # d = pc.decrypt(file) + # with open('E:/大学/大二下/2.PNG', 'wb') as f: # 以二进制写类型打开 + # f.write(d) # 写入文件 + +if __name__ == '__main__': + encryption_file("d") + + diff --git a/file.py b/file.py index 49a0a7b..a9a396f 100644 --- a/file.py +++ b/file.py @@ -1,14 +1,14 @@ from flask import render_template, redirect, url_for, flash from forms.upload_form import CheckFile import os +import config app = None upload_dir = None # 文件上传/下载路径 filelist = None -ALLOWED_EXTENSIONS = ['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'rtf', 'txt', - 'pdf', 'png', 'bmp', 'jpg'] # 允许上传的文件格式 -ALLOWED_FILE_SIZE = 10 * 1024 * 1024 # 允许上传的文件大小MB +ALLOWED_EXTENSIONS = config.ALLOWED_EXTENSIONS # 允许上传的文件格式 +ALLOWED_FILE_SIZE = config.ALLOWED_FILE_SIZE # 允许上传的文件大小MB def init(_app): @@ -52,5 +52,5 @@ def upload_file(): def file_list(): # 文件下载 for parent, dirname, filenames in os.walk(upload_dir): - filelist = filenames + filelist = next(os.walk(upload_dir))[-1] return filelist diff --git a/forms/signin_form.py b/forms/signin_form.py index 7c72fba..e2e8a78 100644 --- a/forms/signin_form.py +++ b/forms/signin_form.py @@ -11,6 +11,6 @@ class LoginForm(FlaskForm): # 密码必须包含大写、小写、数字,且至少出现一次 password = PasswordField('password', validators=[DataRequired(), Length(min=8, max=32), Regexp('^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$', 0, - "密码长度限制在3~36之间且密码不能为弱密码"), + "密码长度限制在8~36之间且密码不能为弱密码"), EqualTo('confirmpassword', message='Passwords must match')], ) confirmpassword = PasswordField('confirmpassword') \ No newline at end of file diff --git a/signinup.py b/signinup.py index 424b324..f53b454 100644 --- a/signinup.py +++ b/signinup.py @@ -22,7 +22,7 @@ def signin_User(): # #使用sha512进行hash hash = hashlib.sha512() - hash.update(form.password.data.encode('utf-8')) + hash.update(form.password.data.encode()) form.password.data = hash.hexdigest() id = (User.query.order_by((User.id).desc()).first()).id + 1 From 3cb5d3fbc76bcdda4739301ec30c091880050785 Mon Sep 17 00:00:00 2001 From: Lyc-heng <18087603176@163.com> Date: Thu, 26 Jul 2018 15:02:42 +0800 Subject: [PATCH 3/6] =?UTF-8?q?1.=E5=90=8E=E7=AB=AF=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E4=BF=9D=E5=AD=98=E6=96=87=E4=BB=B6=E7=BB=99?= =?UTF-8?q?=E5=89=8D=E7=AB=AF2.=E6=96=B0=E5=BB=BA=E6=96=87=E4=BB=B6hash?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 5 ++++- database.py | 17 +++++++++++++-- encryption.py | 38 +++++++++++++++------------------- file.py | 14 +++++++++---- models.py | 7 +++++++ signinup.py | 6 +++++- templates/upload/download.html | 4 +++- templates/upload/upload.html | 1 + 8 files changed, 62 insertions(+), 30 deletions(-) diff --git a/app.py b/app.py index 1814d08..c7d1f6d 100644 --- a/app.py +++ b/app.py @@ -102,8 +102,11 @@ def upload(): @app.route('/file_list', methods=['GET', 'POST']) def file_list(): filelist = file.file_list() - return file.download_file(filelist) + return filelist +@app.route('/download/', methods=['GET', 'POST']) +def download(filename): + return file.download(filename) def main(): mail.init(app) diff --git a/database.py b/database.py index 76dd3ee..bab671d 100644 --- a/database.py +++ b/database.py @@ -12,9 +12,22 @@ def create_app(): app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = config.secretinfo['SQLALCHEMY_TRACK_MODIFICATIONS'] db.init_app(app) + with app.app_context(): + from models import User + db.create_all() + # db.session.merge(User(id=0, username="lycheng", email='anjing@cuc.edu.cn', password='aB8')) + db.session.commit() + return app -def add_user(user,userID): + +def add_user(user, userID): from models import User - db.session.add(User(id=userID,username=user.userName.data, email=user.email.data, password=user.password.data)) + db.session.add(User(id=userID, username=user.userName.data, email=user.email.data, password=user.password.data)) + db.session.commit() + + +def add_filehash(pfilename, phash): + from models import FileHash + db.session.merge(FileHash(filename=pfilename, hash=phash)) db.session.commit() diff --git a/encryption.py b/encryption.py index 313e95c..2040e3e 100644 --- a/encryption.py +++ b/encryption.py @@ -1,9 +1,9 @@ - import sys from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex import rsa + class prpcrypt(): def __init__(self, key): self.key = key @@ -31,7 +31,8 @@ def decrypt(self, text): plain_text = cryptor.decrypt(a2b_hex(text)) return plain_text.rstrip(('\0').encode()) -def encryption_file(filepath): + +def encryption_file(filedata): with open('./static/secret/publickey.txt', 'rb') as f: # 以二进制写类型打开 publicKey = (f.read()).decode() @@ -39,41 +40,40 @@ def encryption_file(filepath): para1 = publicKey[10:-8] para2 = publicKey[-6:-1] - #公钥初始化 - publicKey = rsa.key.PublicKey(int(para1),int(para2)) - + # 公钥初始化 + publicKey = rsa.key.PublicKey(int(para1), int(para2)) with open('./static/secret/privatekey.txt', 'rb') as f: # 以二进制写类型打开 privateKey = (f.read()).decode() # 解析字符串转换为私钥所需的五个参数(n,e,d,p,q) - para3 = privateKey[len(para1)+len(para2)+15:-1] + para3 = privateKey[len(para1) + len(para2) + 15:-1] para4 = para3[:-908] para3 = para3[-906:] - para3,para4 = para4,para3 + para3, para4 = para4, para3 para5 = para4[:480] para4 = para4[482:] - para4,para5 = para5,para4 - - #私钥初始化 - privateKey = rsa.key.PrivateKey(int(para1),int(para2),int(para3),int(para4),int(para5)) + para4, para5 = para5, para4 + # 私钥初始化 + privateKey = rsa.key.PrivateKey(int(para1), int(para2), int(para3), int(para4), int(para5)) # 获得对称密钥 with open('./static/secret/symmetrickey.txt', 'rb') as f: # 以二进制写类型打开 secretkey = f.read() message = rsa.decrypt(secretkey, privateKey) - - #采用AES_CBC模式加密 + # 采用AES_CBC模式加密 secretkey = message pc = prpcrypt(secretkey) # 初始化密钥 # 加密操作 - file = open('E:/大学/大二下/更新操作.PNG', 'rb').read() - e = pc.encrypt(file) - with open('E:/大学/大二下/1.PNG', 'wb') as f: # 以二进制写类型打开 - f.write(e) # 写入文件 + return pc.encrypt(filedata) + + # file = open('E:/大学/大二下/更新操作.PNG', 'rb').read() + # e = pc.encrypt(file) + # with open('E:/大学/大二下/1.PNG', 'wb') as f: # 以二进制写类型打开 + # f.write(e) # 写入文件 # # 解密操作 # file = open('E:/大学/大二下/1.PNG', 'rb').read() @@ -81,7 +81,3 @@ def encryption_file(filepath): # with open('E:/大学/大二下/2.PNG', 'wb') as f: # 以二进制写类型打开 # f.write(d) # 写入文件 -if __name__ == '__main__': - encryption_file("d") - - diff --git a/file.py b/file.py index a9a396f..3876186 100644 --- a/file.py +++ b/file.py @@ -2,6 +2,8 @@ from forms.upload_form import CheckFile import os import config +import encryption +import database app = None upload_dir = None # 文件上传/下载路径 @@ -34,6 +36,7 @@ def allowed_size(size): # 检查文件大小是否合法 def upload_file(): form = CheckFile() + # database.add_filehash("test","lycheng") if form.validate_on_submit(): f = form.image.data size = len(f.read()) @@ -49,8 +52,11 @@ def upload_file(): flash('上传失败,允许上传的文件类型:office文档、常见图片类型') return render_template('./upload/upload.html', form=form) - -def file_list(): # 文件下载 +def file_list(): # 返回已经上传的文件列表 + name='' for parent, dirname, filenames in os.walk(upload_dir): - filelist = next(os.walk(upload_dir))[-1] - return filelist + filelist = filenames + return render_template('./upload/download.html', message=filelist) + +def download(filename): + return send_from_directory(upload_dir, filename, mimetype='application/octet-stream') \ No newline at end of file diff --git a/models.py b/models.py index 70bd310..0a02452 100644 --- a/models.py +++ b/models.py @@ -18,3 +18,10 @@ def verify_password(self, password): def __repr__(self): return '' % self.username + +class FileHash(db.Model,UserMixin): + __tablename__ = 'FileHash' + + filename = db.Column(db.String(50), primary_key=True) + hash = db.Column(db.String(512)) + diff --git a/signinup.py b/signinup.py index f53b454..5a8e0ac 100644 --- a/signinup.py +++ b/signinup.py @@ -25,7 +25,11 @@ def signin_User(): hash.update(form.password.data.encode()) form.password.data = hash.hexdigest() - id = (User.query.order_by((User.id).desc()).first()).id + 1 + try: + id = (User.query.order_by((User.id).desc()).first()).id + 1 + except AttributeError: + id = 0 + add_user(form, id) next = request.args.get('next') return redirect(next or url_for('upload')) diff --git a/templates/upload/download.html b/templates/upload/download.html index b03bc54..8e4891e 100644 --- a/templates/upload/download.html +++ b/templates/upload/download.html @@ -11,7 +11,9 @@
-

title

+ {% if message %} +

{{ message }}

+ {% endif %}
\ No newline at end of file diff --git a/templates/upload/upload.html b/templates/upload/upload.html index ecd14ab..0792b60 100644 --- a/templates/upload/upload.html +++ b/templates/upload/upload.html @@ -24,6 +24,7 @@

选择要上传的文件

+Download
Sign Off From 75b428d36c2ff9c32239a4e8d8d53180913625d9 Mon Sep 17 00:00:00 2001 From: Lyc-heng <18087603176@163.com> Date: Sat, 28 Jul 2018 15:08:14 +0800 Subject: [PATCH 4/6] =?UTF-8?q?1.=E5=AE=8C=E6=88=90=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E5=B9=B6=E9=AA=8C=E8=AF=81=E7=9A=84=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?2.=E5=A2=9E=E5=8A=A0=E5=89=8D=E7=AB=AF=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E7=AB=AF=E6=89=80=E6=9C=89=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E5=8A=9F=E8=83=BD=203.=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 18 ++++-- encryption.py | 112 +++++++++++++++++++++++++++++++++ file.py | 19 ++++-- forms/dowmload_form.py | 7 +++ static/css/download.css | 15 +++++ templates/login/signin.html | 2 +- templates/login/signup.html | 2 +- templates/upload/download.html | 45 +++++++++++-- templates/upload/upload.html | 2 +- 9 files changed, 206 insertions(+), 16 deletions(-) create mode 100644 forms/dowmload_form.py diff --git a/app.py b/app.py index c7d1f6d..ff99d90 100644 --- a/app.py +++ b/app.py @@ -4,6 +4,7 @@ from flask import render_template, redirect, url_for, request from forms.signin_form import LoginForm from forms.signup_form import RegisterForm +from forms.dowmload_form import DownloadForm from flask_wtf.csrf import CSRFProtect, CSRFError from werkzeug.exceptions import HTTPException, NotFound from flask_login import LoginManager, login_required, login_user, logout_user @@ -99,13 +100,22 @@ def upload(): f = file.upload_file() return f -@app.route('/file_list', methods=['GET', 'POST']) -def file_list(): +# 文件下载页面 +@app.route('/filedownload', methods=['GET']) +def filedownload(): + form = DownloadForm() + return render_template('./upload/download.html',form=form) + +@app.route('/filelist', methods=['GET','POST']) +def filelist(): filelist = file.file_list() return filelist -@app.route('/download/', methods=['GET', 'POST']) -def download(filename): + +@app.route('/download', methods=['GET', 'POST']) +def download(): + form = DownloadForm() + filename = form.filename.data return file.download(filename) def main(): diff --git a/encryption.py b/encryption.py index 2040e3e..6a3fff6 100644 --- a/encryption.py +++ b/encryption.py @@ -2,6 +2,7 @@ from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex import rsa +import os class prpcrypt(): @@ -81,3 +82,114 @@ def encryption_file(filedata): # with open('E:/大学/大二下/2.PNG', 'wb') as f: # 以二进制写类型打开 # f.write(d) # 写入文件 + +def decryption_file(filedata): + with open('./static/secret/publickey.txt', 'rb') as f: # 以二进制写类型打开 + publicKey = (f.read()).decode() + + # 将获取得到的字符串转化为公钥所需参数(n,e) + para1 = publicKey[10:-8] + para2 = publicKey[-6:-1] + + # 公钥初始化 + publicKey = rsa.key.PublicKey(int(para1), int(para2)) + + with open('./static/secret/privatekey.txt', 'rb') as f: # 以二进制写类型打开 + privateKey = (f.read()).decode() + + # 解析字符串转换为私钥所需的五个参数(n,e,d,p,q) + para3 = privateKey[len(para1) + len(para2) + 15:-1] + para4 = para3[:-908] + para3 = para3[-906:] + para3, para4 = para4, para3 + para5 = para4[:480] + para4 = para4[482:] + para4, para5 = para5, para4 + + # 私钥初始化 + privateKey = rsa.key.PrivateKey(int(para1), int(para2), int(para3), int(para4), int(para5)) + + # 获得对称密钥 + with open('./static/secret/symmetrickey.txt', 'rb') as f: # 以二进制写类型打开 + secretkey = f.read() + message = rsa.decrypt(secretkey, privateKey) + + # 采用AES_CBC模式加密 + secretkey = message + pc = prpcrypt(secretkey) # 初始化密钥 + + # 解密操作 + file = open(filedata, 'rb').read() + return pc.decrypt(file) + + +# 对加密后的数据进行签名,参数为已经加密但未签名的文件 +def sign_file(filedata): + with open('./static/secret/publickey.txt', 'rb') as f: # 以二进制写类型打开 + publicKey = (f.read()).decode() + + # 将获取得到的字符串转化为公钥所需参数(n,e) + para1 = publicKey[10:-8] + para2 = publicKey[-6:-1] + + # 公钥初始化 + publicKey = rsa.key.PublicKey(int(para1), int(para2)) + + with open('./static/secret/privatekey.txt', 'rb') as f: # 以二进制写类型打开 + privateKey = (f.read()).decode() + + # 解析字符串转换为私钥所需的五个参数(n,e,d,p,q) + para3 = privateKey[len(para1) + len(para2) + 15:-1] + para4 = para3[:-908] + para3 = para3[-906:] + para3, para4 = para4, para3 + para5 = para4[:480] + para4 = para4[482:] + para4, para5 = para5, para4 + + # 私钥初始化 + privateKey = rsa.key.PrivateKey(int(para1), int(para2), int(para3), int(para4), int(para5)) + + # 获得对称密钥 + with open('./static/secret/symmetrickey.txt', 'rb') as f: # 以二进制写类型打开 + secretkey = f.read() + message = rsa.decrypt(secretkey, privateKey) + + # 采用AES_CBC模式加密 + secretkey = message + pc = prpcrypt(secretkey) # 初始化密钥 + + # 使用对称密钥加密数据 + endata = pc.encrypt(filedata) + # 对加密的数据进行签名 + return rsa.sign(endata, privateKey, 'SHA-1') + + +# 验证签名,参数为签名后的文件和未签名的文件 +def verify_file(signfile, filedata): + with open('./static/secret/publickey.txt', 'rb') as f: # 以二进制写类型打开 + publicKey = (f.read()).decode() + + # 将获取得到的字符串转化为公钥所需参数(n,e) + para1 = publicKey[10:-8] + para2 = publicKey[-6:-1] + + # 公钥初始化 + publicKey = rsa.key.PublicKey(int(para1), int(para2)) + + with open('./static/secret/privatekey.txt', 'rb') as f: # 以二进制写类型打开 + privateKey = (f.read()).decode() + + # 解析字符串转换为私钥所需的五个参数(n,e,d,p,q) + para3 = privateKey[len(para1) + len(para2) + 15:-1] + para4 = para3[:-908] + para3 = para3[-906:] + para3, para4 = para4, para3 + para5 = para4[:480] + para4 = para4[482:] + para4, para5 = para5, para4 + + # 私钥初始化 + privateKey = rsa.key.PrivateKey(int(para1), int(para2), int(para3), int(para4), int(para5)) + + return rsa.verify(filedata, signfile, publicKey) diff --git a/file.py b/file.py index 3876186..d5eedbb 100644 --- a/file.py +++ b/file.py @@ -39,11 +39,16 @@ def upload_file(): # database.add_filehash("test","lycheng") if form.validate_on_submit(): f = form.image.data - size = len(f.read()) + path = os.path.join(upload_dir, f.filename) + data=f.read() + size = len(data) if allowed_file(f.filename): if allowed_size(size): - f.seek(0) - f.save(os.path.join(upload_dir, f.filename)) + data_encryption=encryption.encryption_file(data) + file=open(path,'w') + file.write(data_encryption.decode()) + file.close() + #f.save(os.path.join(upload_dir, f.filename)) flash('Upload success。') return redirect(url_for('upload')) else: @@ -56,7 +61,11 @@ def file_list(): # 返回已经上传的文件列表 name='' for parent, dirname, filenames in os.walk(upload_dir): filelist = filenames - return render_template('./upload/download.html', message=filelist) + return str(filelist) def download(filename): - return send_from_directory(upload_dir, filename, mimetype='application/octet-stream') \ No newline at end of file + path=os.path.join(upload_dir,filename) + d=encryption.decryption_file(path) + with open(os.path.join('./instance/download',filename),'wb') as file: + file.write(d) + return send_from_directory('./instance/download', filename, mimetype='application/octet-stream') diff --git a/forms/dowmload_form.py b/forms/dowmload_form.py new file mode 100644 index 0000000..8657505 --- /dev/null +++ b/forms/dowmload_form.py @@ -0,0 +1,7 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField +from wtforms.validators import DataRequired, Email, Length, Regexp, EqualTo + + +class DownloadForm(FlaskForm): + filename = StringField('filename',validators=[DataRequired()]) diff --git a/static/css/download.css b/static/css/download.css index f109c4f..a245250 100644 --- a/static/css/download.css +++ b/static/css/download.css @@ -3,6 +3,12 @@ body{ margin: 0 auto; } +p{ + padding: 0; + margin: 0; +} + + #title{ background: white; height: 70px; @@ -28,4 +34,13 @@ body{ width:100%; height: 100%; background-color: yellow; +} + +#downloadfile{ + padding: 0; + margin: 0; + display: inline-block; + background-color: blue; + width:100%; + } \ No newline at end of file diff --git a/templates/login/signin.html b/templates/login/signin.html index ca20df3..ecc845c 100644 --- a/templates/login/signin.html +++ b/templates/login/signin.html @@ -41,6 +41,6 @@

预留区域

- + Download
\ No newline at end of file diff --git a/templates/login/signup.html b/templates/login/signup.html index 5d425fa..3964860 100644 --- a/templates/login/signup.html +++ b/templates/login/signup.html @@ -46,6 +46,6 @@

预留区域

- + Download
\ No newline at end of file diff --git a/templates/upload/download.html b/templates/upload/download.html index 8e4891e..f7dcf87 100644 --- a/templates/upload/download.html +++ b/templates/upload/download.html @@ -3,17 +3,54 @@ + 文件下载页面 +
-

选择你要下载的页面

+

选择你要下载的文件

+ +
+
+ + File Name: + +

文件名:{{ form.filename(placeholder='filename') }}

+ +

{{ form.csrf_token }}

+ +

+
+
+
- {% if message %} -

{{ message }}

- {% endif %} + + +
+ +
+
\ No newline at end of file diff --git a/templates/upload/upload.html b/templates/upload/upload.html index 0792b60..4d4d0e2 100644 --- a/templates/upload/upload.html +++ b/templates/upload/upload.html @@ -24,7 +24,7 @@

选择要上传的文件

-Download
+Download
Sign Off From c639e9b2e876f703cb62f14c6b4301b48f57ed6e Mon Sep 17 00:00:00 2001 From: Lyc-heng <18087603176@163.com> Date: Mon, 3 Sep 2018 12:04:05 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E5=8F=8D=E9=A6=88=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9B=90=E5=80=BC+=E5=AF=86=E7=A0=81=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E8=BF=9B=E8=A1=8Chash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- app.py | 27 ++++++-------- database.py | 2 +- encryption.py | 29 +++++---------- file.py | 68 ++++++++++++++++++++++++++-------- forms/signin_form.py | 4 +- models.py | 15 ++++++++ signinup.py | 27 +++++++++----- static/js/checkPassword.js | 12 +++--- templates/upload/download.html | 1 - templates/upload/upload.html | 2 +- 11 files changed, 120 insertions(+), 70 deletions(-) diff --git a/.gitignore b/.gitignore index d275988..48fce70 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ forms/__pycache__/ instance templates/login/debug.log templates/upload/debug.log -static/secret/ \ No newline at end of file +static/secret/ +example.db diff --git a/app.py b/app.py index ff99d90..22b06d6 100644 --- a/app.py +++ b/app.py @@ -6,10 +6,7 @@ from forms.signup_form import RegisterForm from forms.dowmload_form import DownloadForm from flask_wtf.csrf import CSRFProtect, CSRFError -from werkzeug.exceptions import HTTPException, NotFound -from flask_login import LoginManager, login_required, login_user, logout_user - -import os +from flask_login import LoginManager, login_required, login_user, logout_user,current_user import config from database import create_app, add_user @@ -19,6 +16,7 @@ app = create_app() # 防止跨站脚本攻击 app.secret_key = config.secretinfo['secret_key'] +app.config['MAX_CONTENT_LENGTH'] = 20 * 1024 * 1024 # 20MB # app.config['WTF_CSRF_SECRET_KEY'] = 'CSRFTokenGeneratorSecretKey2018' # CSRF Token生成器的签发密钥 # app.config['WTF_CSRF_TIME_LIMIT'] = 10 # 表单提交限时1分钟,超时则触发CSRF Token校验失败错误 csrf = CSRFProtect(app) @@ -31,10 +29,10 @@ login_manager.login_message_category = config.secretinfo['login_manager_login_message_category'] login_manager.init_app(app) - @login_manager.user_loader def load_user(userid): - return User.query.get(int(userid)) + #return User.query.get(int(userid)) + return User.query.filter_by(id=userid).first() @app.route('/') @@ -47,7 +45,7 @@ def index(): @login_required def signoff(): logout_user() - return 'Logged out successfully!' + return redirect(url_for('index')) # ----------------------------------------------------注册部分的代码----------------------------------- @@ -91,15 +89,11 @@ def test_mail(): @app.route('/upload_file', methods=['GET', 'POST']) @login_required def upload_file(): - return file.upload_file() - - -# ======= -@app.route('/upload', methods=['GET', 'POST']) -def upload(): - f = file.upload_file() + print(current_user.is_anonymous) + f=file.upload_file() return f + # 文件下载页面 @app.route('/filedownload', methods=['GET']) def filedownload(): @@ -116,7 +110,10 @@ def filelist(): def download(): form = DownloadForm() filename = form.filename.data - return file.download(filename) + print(current_user.is_authenticated) + if current_user.is_authenticated: + return file.download(filename) + return file.download_anonmity(filename) def main(): mail.init(app) diff --git a/database.py b/database.py index bab671d..352480b 100644 --- a/database.py +++ b/database.py @@ -23,7 +23,7 @@ def create_app(): def add_user(user, userID): from models import User - db.session.add(User(id=userID, username=user.userName.data, email=user.email.data, password=user.password.data)) + db.session.add(User(id=userID, username=user.userName.data, email=user.email.data, password=user.password.data, salt=user.salt.encode())) db.session.commit() diff --git a/encryption.py b/encryption.py index 6a3fff6..7b311f7 100644 --- a/encryption.py +++ b/encryption.py @@ -71,17 +71,6 @@ def encryption_file(filedata): # 加密操作 return pc.encrypt(filedata) - # file = open('E:/大学/大二下/更新操作.PNG', 'rb').read() - # e = pc.encrypt(file) - # with open('E:/大学/大二下/1.PNG', 'wb') as f: # 以二进制写类型打开 - # f.write(e) # 写入文件 - - # # 解密操作 - # file = open('E:/大学/大二下/1.PNG', 'rb').read() - # d = pc.decrypt(file) - # with open('E:/大学/大二下/2.PNG', 'wb') as f: # 以二进制写类型打开 - # f.write(d) # 写入文件 - def decryption_file(filedata): with open('./static/secret/publickey.txt', 'rb') as f: # 以二进制写类型打开 @@ -119,8 +108,9 @@ def decryption_file(filedata): pc = prpcrypt(secretkey) # 初始化密钥 # 解密操作 - file = open(filedata, 'rb').read() - return pc.decrypt(file) + with open(filedata, 'rb') as file: + d = pc.decrypt(file.read()) + return d # 对加密后的数据进行签名,参数为已经加密但未签名的文件 @@ -156,13 +146,15 @@ def sign_file(filedata): message = rsa.decrypt(secretkey, privateKey) # 采用AES_CBC模式加密 - secretkey = message - pc = prpcrypt(secretkey) # 初始化密钥 + # secretkey = message + # pc = prpcrypt(secretkey) # 初始化密钥 # 使用对称密钥加密数据 - endata = pc.encrypt(filedata) + # endata = pc.encrypt(filedata) + print('filedata=',len(filedata)) + print('endata=',len(filedata)) # 对加密的数据进行签名 - return rsa.sign(endata, privateKey, 'SHA-1') + return rsa.sign(filedata, privateKey, 'SHA-1') # 验证签名,参数为签名后的文件和未签名的文件 @@ -191,5 +183,4 @@ def verify_file(signfile, filedata): # 私钥初始化 privateKey = rsa.key.PrivateKey(int(para1), int(para2), int(para3), int(para4), int(para5)) - - return rsa.verify(filedata, signfile, publicKey) + return rsa.verify(filedata, signfile, publicKey) diff --git a/file.py b/file.py index d5eedbb..6963704 100644 --- a/file.py +++ b/file.py @@ -3,10 +3,14 @@ import os import config import encryption -import database - +from forms.dowmload_form import DownloadForm +from flask import send_from_directory +from io import BytesIO +import zipfile app = None upload_dir = None # 文件上传/下载路径 +download_dir=None #下载路径 +sign_dir=None #签名路径 filelist = None ALLOWED_EXTENSIONS = config.ALLOWED_EXTENSIONS # 允许上传的文件格式 @@ -15,14 +19,25 @@ def init(_app): global app - global upload_dir + global upload_dir,download_dir,sign_dir app = _app upload_dir = os.path.join( app.instance_path, 'upload' ) # 将文件上传到项目的upload文件夹下 + download_dir=os.path.join( + app.instance_path,'download' + ) + sign_dir=os.path.join( + app.instance_path,'sign' + ) + if not os.path.exists(upload_dir): os.makedirs(upload_dir) - # upload_dir = r'D:\Users\蛮小白\Desktop\test\upload' + if not os.path.exists(download_dir): + os.makedirs(download_dir) + if not os.path.exists(sign_dir): + os.makedirs(sign_dir) + def allowed_file(filename): # 检查文件格式是否合法 @@ -39,18 +54,22 @@ def upload_file(): # database.add_filehash("test","lycheng") if form.validate_on_submit(): f = form.image.data - path = os.path.join(upload_dir, f.filename) + file_path = os.path.join(upload_dir, f.filename) + sign_path=os.path.join(sign_dir,f.filename.split('.')[-2]) + if f.filename in file_list(): + flash('file exists') + return redirect(url_for('upload_file')) data=f.read() size = len(data) if allowed_file(f.filename): if allowed_size(size): - data_encryption=encryption.encryption_file(data) - file=open(path,'w') - file.write(data_encryption.decode()) - file.close() - #f.save(os.path.join(upload_dir, f.filename)) + data_encryption = encryption.encryption_file(data) + with open(file_path, 'wb') as file: + file.write(data_encryption) + with open(sign_path,'wb') as file: + file.write(encryption.sign_file(data_encryption)) flash('Upload success。') - return redirect(url_for('upload')) + return redirect(url_for('upload_file')) else: flash('上传失败,文件大小:<=10M') else: @@ -58,14 +77,31 @@ def upload_file(): return render_template('./upload/upload.html', form=form) def file_list(): # 返回已经上传的文件列表 - name='' for parent, dirname, filenames in os.walk(upload_dir): filelist = filenames return str(filelist) def download(filename): path=os.path.join(upload_dir,filename) - d=encryption.decryption_file(path) - with open(os.path.join('./instance/download',filename),'wb') as file: - file.write(d) - return send_from_directory('./instance/download', filename, mimetype='application/octet-stream') + sign_path=os.path.join(sign_dir,filename.split('.')[-2]) + with open(sign_path,'rb') as file: #获取签名 + signdata=file.read() + with open(path,'rb') as file: #获取加密后数据 + filedata=file.read() + sign=encryption.verify_file(signdata,filedata) + if sign: + d=encryption.decryption_file(path) + with open(os.path.join(download_dir,filename),'wb') as file: + file.write(d+b'\x00\x00\x00\x00') + flash('success') + return send_from_directory(download_dir, filename,mimetype='application/octet-stream') + flash('verification failed') + return redirect(url_for('filedownload')) + + +def download_anonmity(filename): + dl_name = '{}.zip'.format(filename.split('.')[-2]) + with zipfile.ZipFile(os.path.join(download_dir,dl_name), 'w', zipfile.ZIP_DEFLATED) as f: + f.write(os.path.join(upload_dir, filename),filename) + f.write(os.path.join(sign_dir,filename.split('.')[-2]),filename.split('.')[-2]) + return send_from_directory(download_dir, dl_name, mimetype='application/octet-stream') \ No newline at end of file diff --git a/forms/signin_form.py b/forms/signin_form.py index e2e8a78..ecdc1d0 100644 --- a/forms/signin_form.py +++ b/forms/signin_form.py @@ -1,6 +1,7 @@ from flask_wtf import FlaskForm from wtforms import StringField, PasswordField from wtforms.validators import DataRequired, Email, Length, Regexp, EqualTo +from os import urandom class LoginForm(FlaskForm): @@ -13,4 +14,5 @@ class LoginForm(FlaskForm): Regexp('^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$', 0, "密码长度限制在8~36之间且密码不能为弱密码"), EqualTo('confirmpassword', message='Passwords must match')], ) - confirmpassword = PasswordField('confirmpassword') \ No newline at end of file + confirmpassword = PasswordField('confirmpassword') + salt = (urandom(64)).decode("utf8","ignore") \ No newline at end of file diff --git a/models.py b/models.py index 0a02452..7909e56 100644 --- a/models.py +++ b/models.py @@ -11,14 +11,29 @@ class User(db.Model, UserMixin): username = db.Column(db.String(45)) email = db.Column(db.String(128), primary_key=True) password = db.Column(db.String(512)) + salt = db.Column(db.String(64)) access_token = db.Column(db.String(128)) + def is_authenticated(self): + return True + + def is_active(self): + return True + + def is_anonymous(self): + return False + + def get_id(self): + return self.id + def verify_password(self, password): return self.password == password def __repr__(self): return '' % self.username + + class FileHash(db.Model,UserMixin): __tablename__ = 'FileHash' diff --git a/signinup.py b/signinup.py index 5a8e0ac..8273e89 100644 --- a/signinup.py +++ b/signinup.py @@ -1,8 +1,7 @@ -from flask import render_template, redirect, url_for, request +from flask import render_template, redirect, url_for, request,g from forms.signin_form import LoginForm from forms.signup_form import RegisterForm -from flask_login import LoginManager, login_required, login_user, logout_user - +from flask_login import login_user from database import create_app, add_user from models import User import hashlib @@ -12,7 +11,6 @@ def signin_User(): form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(email=form.email.data).first() - print(user) if user is not None: # next = request.args.get('next') # return redirect(next or url_for('welcome')) @@ -20,9 +18,11 @@ def signin_User(): else: # login_user(user) - # #使用sha512进行hash + # 使用sha512进行hash hash = hashlib.sha512() - hash.update(form.password.data.encode()) + # 将盐值和密码进行拼接 + hashpassword = form.salt.encode() + form.password.data.encode() + hash.update(hashpassword) form.password.data = hash.hexdigest() try: @@ -32,7 +32,7 @@ def signin_User(): add_user(form, id) next = request.args.get('next') - return redirect(next or url_for('upload')) + return redirect(next or url_for('upload_file')) # return render_template('welcome.html', form=form, userName=form.userName.data) else: return render_template('./login/signup.html', form=form, message=list(form.errors.values())[0][0]) @@ -42,13 +42,22 @@ def signup_User(): form = RegisterForm() if form.validate_on_submit(): user = User.query.filter_by(email=form.email.data).first() - if user is not None and user.verify_password(form.password.data): + + # 检测密码是否正确 + hash = hashlib.sha512() + # 将盐值和密码进行拼接 + hashpassword = user.salt + form.password.data.encode() + hash.update(hashpassword) + resulthash = hash.hexdigest() + + if user is not None and user.verify_password(resulthash): # 启动用户登录 + current_user = User() current_user.id = user.id login_user(current_user) next = request.args.get('next') - return redirect(next or url_for('upload')) + return redirect(next or url_for('upload_file')) else: return render_template('./login/signin.html', form=form, message='账户或者密码错误') else: diff --git a/static/js/checkPassword.js b/static/js/checkPassword.js index d72cb64..e0ff242 100644 --- a/static/js/checkPassword.js +++ b/static/js/checkPassword.js @@ -83,13 +83,13 @@ function hashPassword(){ var formData = new FormData(document.forms.namedItem("login_form")); - // sha512加密过程 - var hash = sha512.create(); - hash.update(password); - afterhash = hash.hex(); + // // sha512加密过程 + // var hash = sha512.create(); + // hash.update(password); + // afterhash = hash.hex(); - //表单中password的值用hash值代替 - formData.set('password',afterhash); + // //表单中password的值用hash值代替 + // formData.set('password',afterhash); // 通过jquery发送出去 $.ajax({ diff --git a/templates/upload/download.html b/templates/upload/download.html index f7dcf87..11f339f 100644 --- a/templates/upload/download.html +++ b/templates/upload/download.html @@ -26,7 +26,6 @@

选择你要下载的文件

-
diff --git a/templates/upload/upload.html b/templates/upload/upload.html index 4d4d0e2..4facd64 100644 --- a/templates/upload/upload.html +++ b/templates/upload/upload.html @@ -17,7 +17,7 @@

选择要上传的文件

{% endif %} {% endwith %} - +

{{ form.watermark }}

File: {{ form.image }}

{{ form.csrf_token }}

From 790d0da75983c1ed302ce4d3415007af5cef12ed Mon Sep 17 00:00:00 2001 From: Lyc-heng <18087603176@163.com> Date: Mon, 3 Sep 2018 17:34:36 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E9=83=A8=E5=88=86=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- file.py | 96 ++++++++++++++++++++++++++++++++++++++++++++--------- signinup.py | 14 ++++---- 3 files changed, 89 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 48fce70..075675a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ instance templates/login/debug.log templates/upload/debug.log static/secret/ -example.db +example.db \ No newline at end of file diff --git a/file.py b/file.py index 6963704..f74fcaf 100644 --- a/file.py +++ b/file.py @@ -7,11 +7,13 @@ from flask import send_from_directory from io import BytesIO import zipfile +import hashlib app = None upload_dir = None # 文件上传/下载路径 download_dir=None #下载路径 sign_dir=None #签名路径 -filelist = None +hash_dir=None +filelist = [] ALLOWED_EXTENSIONS = config.ALLOWED_EXTENSIONS # 允许上传的文件格式 ALLOWED_FILE_SIZE = config.ALLOWED_FILE_SIZE # 允许上传的文件大小MB @@ -19,7 +21,7 @@ def init(_app): global app - global upload_dir,download_dir,sign_dir + global upload_dir,download_dir,sign_dir,hash_dir app = _app upload_dir = os.path.join( app.instance_path, 'upload' @@ -30,6 +32,9 @@ def init(_app): sign_dir=os.path.join( app.instance_path,'sign' ) + hash_dir = os.path.join( + app.instance_path, 'hash' + ) if not os.path.exists(upload_dir): os.makedirs(upload_dir) @@ -37,32 +42,82 @@ def init(_app): os.makedirs(download_dir) if not os.path.exists(sign_dir): os.makedirs(sign_dir) - - + if not os.path.exists(hash_dir): + os.makedirs(hash_dir) def allowed_file(filename): # 检查文件格式是否合法 return '.' in filename and \ filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS - def allowed_size(size): # 检查文件大小是否合法 return size <= ALLOWED_FILE_SIZE +def getMd5(filedata,filename): + '''将字典的键设为每个文件的md5,值为不同用户上传的文件名''' + myhash=hashlib.md5() + myhash.update(filedata) + with open(os.path.join(hash_dir,'hash'),'r')as file: + my_dict = file.read() + my_dict=dict(my_dict) if my_dict=='' else eval(my_dict) + if my_dict.get(myhash.hexdigest())==None: + return False + if filename not in my_dict[myhash.hexdigest()]: + my_dict[myhash.hexdigest()].append(filename) + with open(os.path.join(hash_dir,'hash'),'w')as file: + file.write(str(my_dict)) + return True + +def saveMd5(filedata,filename): + '''第一次被上传的文件建立键值对,{md5:filename}''' + myhash=hashlib.md5() + myhash.update(filedata) + with open(os.path.join(hash_dir,'hash'),'r')as file: + my_dict=file.read() + my_dict=dict(my_dict) if my_dict=='' else eval(my_dict) + my_dict[myhash.hexdigest()]=[filename] + with open(os.path.join(hash_dir,'hash'),'w')as file: + file.write(str(my_dict)) + +def file_list(): # 返回已经上传的文件列表 + global filelist + with open(os.path.join(hash_dir,'hash'),'r')as file: + my_dict = file.read() + my_dict=dict(my_dict) if my_dict=='' else eval(my_dict) + for i in my_dict: + filelist.extend(list(my_dict[i])) + return str(filelist) + +def get_name(filename): + '''不同用户上传/下载相同文件时用的文件名不同,但服务器只保存一次该文件, + 此处通过用户输入的文件名获取服务器保存的该文件的真实文件名''' + with open(os.path.join(hash_dir,'hash'),'r')as file: + my_dict = file.read() + my_dict=dict(my_dict) if my_dict=='' else eval(my_dict) + for i in my_dict: + if filename in my_dict[i]: + return my_dict[i][0] + return False def upload_file(): + + '''上传文件,限制文件大小,格式并对文件加密保存''' form = CheckFile() # database.add_filehash("test","lycheng") if form.validate_on_submit(): f = form.image.data file_path = os.path.join(upload_dir, f.filename) sign_path=os.path.join(sign_dir,f.filename.split('.')[-2]) - if f.filename in file_list(): - flash('file exists') - return redirect(url_for('upload_file')) data=f.read() size = len(data) if allowed_file(f.filename): if allowed_size(size): + if getMd5(data, f.filename): # 如果返回True,表示该文件已经上传过,可以秒传 + flash('Upload success。') + return redirect(url_for('upload_file')) + if f.filename in file_list(): # 如果为真,表示服务器已存在同名(不同内容)文件,需改名 + flash('服务器存在同名文件,请重试') + return redirect(url_for('upload_file')) + saveMd5(data,f.filename)#保存文件的md5 data_encryption = encryption.encryption_file(data) with open(file_path, 'wb') as file: file.write(data_encryption) @@ -76,12 +131,14 @@ def upload_file(): flash('上传失败,允许上传的文件类型:office文档、常见图片类型') return render_template('./upload/upload.html', form=form) -def file_list(): # 返回已经上传的文件列表 - for parent, dirname, filenames in os.walk(upload_dir): - filelist = filenames - return str(filelist) - -def download(filename): +def download(name): + '''下载服务器端保存的文件''' + if get_name(name): + filename=get_name(name) + else: + print('file name error') + flash('file name error') + return redirect(url_for('filedownload')) path=os.path.join(upload_dir,filename) sign_path=os.path.join(sign_dir,filename.split('.')[-2]) with open(sign_path,'rb') as file: #获取签名 @@ -94,14 +151,21 @@ def download(filename): with open(os.path.join(download_dir,filename),'wb') as file: file.write(d+b'\x00\x00\x00\x00') flash('success') - return send_from_directory(download_dir, filename,mimetype='application/octet-stream') + return send_from_directory(download_dir, filename, as_attachment=True) flash('verification failed') return redirect(url_for('filedownload')) -def download_anonmity(filename): +def download_anonmity(name): + if get_name(name): + filename=get_name(name) + else: + print('file name error') + flash('file name error') + return redirect(url_for('filedownload')) dl_name = '{}.zip'.format(filename.split('.')[-2]) with zipfile.ZipFile(os.path.join(download_dir,dl_name), 'w', zipfile.ZIP_DEFLATED) as f: f.write(os.path.join(upload_dir, filename),filename) f.write(os.path.join(sign_dir,filename.split('.')[-2]),filename.split('.')[-2]) + return send_from_directory(download_dir, dl_name, mimetype='application/octet-stream') \ No newline at end of file diff --git a/signinup.py b/signinup.py index 8273e89..6614870 100644 --- a/signinup.py +++ b/signinup.py @@ -43,12 +43,14 @@ def signup_User(): if form.validate_on_submit(): user = User.query.filter_by(email=form.email.data).first() - # 检测密码是否正确 - hash = hashlib.sha512() - # 将盐值和密码进行拼接 - hashpassword = user.salt + form.password.data.encode() - hash.update(hashpassword) - resulthash = hash.hexdigest() + resulthash = "" + if user is not None: + # 检测密码是否正确 + hash = hashlib.sha512() + # 将盐值和密码进行拼接 + hashpassword = user.salt + form.password.data.encode() + hash.update(hashpassword) + resulthash = hash.hexdigest() if user is not None and user.verify_password(resulthash): # 启动用户登录