diff --git a/Math.uuid.js b/Math.uuid.js new file mode 100644 index 0000000..7538e67 --- /dev/null +++ b/Math.uuid.js @@ -0,0 +1,92 @@ +/*! +Math.uuid.js (v1.4) +http://www.broofa.com +mailto:robert@broofa.com + +Copyright (c) 2010 Robert Kieffer +Dual licensed under the MIT and GPL licenses. +*/ + +/* + * Generate a random uuid. + * + * USAGE: Math.uuid(length, radix) + * length - the desired number of characters + * radix - the number of allowable values for each character. + * + * EXAMPLES: + * // No arguments - returns RFC4122, version 4 ID + * >>> Math.uuid() + * "92329D39-6F5C-4520-ABFC-AAB64544E172" + * + * // One argument - returns ID of the specified length + * >>> Math.uuid(15) // 15 character ID (default base=62) + * "VcydxgltxrVZSTV" + * + * // Two arguments - returns ID of the specified length, and radix. (Radix must be <= 62) + * >>> Math.uuid(8, 2) // 8 character ID (base=2) + * "01001010" + * >>> Math.uuid(8, 10) // 8 character ID (base=10) + * "47473046" + * >>> Math.uuid(8, 16) // 8 character ID (base=16) + * "098F4D35" + */ +(function() { + // Private array of chars to use + var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + + Math.uuid = function (len, radix) { + var chars = CHARS, uuid = [], i; + radix = radix || chars.length; + + if (len) { + // Compact form + for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix]; + } else { + // rfc4122, version 4 form + var r; + + // rfc4122 requires these characters + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + + // Fill in random data. At i==19 set the high bits of clock sequence as + // per rfc4122, sec. 4.1.5 + for (i = 0; i < 36; i++) { + if (!uuid[i]) { + r = 0 | Math.random()*16; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + } + } + } + + return uuid.join(''); + }; + + // A more performant, but slightly bulkier, RFC4122v4 solution. We boost performance + // by minimizing calls to random() + Math.uuidFast = function() { + var chars = CHARS, uuid = new Array(36), rnd=0, r; + for (var i = 0; i < 36; i++) { + if (i==8 || i==13 || i==18 || i==23) { + uuid[i] = '-'; + } else if (i==14) { + uuid[i] = '4'; + } else { + if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + } + } + return uuid.join(''); + }; + + // A more compact, but less performant, RFC4122v4 solution: + Math.uuidCompact = function() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); + }; +})(); diff --git a/README.md b/README.md deleted file mode 100644 index 9471dc2..0000000 --- a/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# OpenJsCad - -Enthousiastic about OpenSCAD but somewhat frustrated by the limitations of its language, here is an alternative using Javascript. It's free, completely open source, still seriously under construction, based on Evan Wallace's CSG.js library and can be used from within the Chrome browser. - -Launch your Chrome browser and go to: http://joostn.github.com/OpenJsCad/ - -The benefits over openSCAD are mainly in the language itself: you can use dynamic arrays for example, and solids can be stored in variables. - -# Contribute - -Contributions are welcome, fork me on GitHub! - -The only content here is the 'GUI' part (i.e. index.html) in the gh-pages branch at https://github.com/joostn/OpenJsCad/tree/gh-pages - -The actual CSG engine is in csg.js. Don't fork the copy of csg.js here, but instead create a fork of this branch: -https://github.com/joostn/csg.js - -# License - -Copyright (c) 2012 Joost Nieuwenhuijse (joost@newhouse.nl), under the [MIT license](http://www.opensource.org/licenses/mit-license.php). -Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the [MIT license](http://www.opensource.org/licenses/mit-license.php). diff --git a/coffee-script.js b/coffee-script.js new file mode 100644 index 0000000..7b4871c --- /dev/null +++ b/coffee-script.js @@ -0,0 +1,8 @@ +/** + * CoffeeScript Compiler v1.2.0 + * http://coffeescript.org + * + * Copyright 2011, Jeremy Ashkenas + * Released under the MIT License + */ +(function(root){var CoffeeScript=function(){function require(a){return require[a]}require["./helpers"]=new function(){var a=this;(function(){var b,c;a.starts=function(a,b,c){return b===a.substr(c,b.length)},a.ends=function(a,b,c){var d;d=b.length;return b===a.substr(a.length-d-(c||0),d)},a.compact=function(a){var b,c,d,e;e=[];for(c=0,d=a.length;c=0)f+=1;else if(j=g[0],t.call(d,j)>=0)f-=1;a+=1}return a-1},a.prototype.removeLeadingNewlines=function(){var a,b,c,d;d=this.tokens;for(a=0,c=d.length;a=0)))return 1;d.splice(b,1);return 0})},a.prototype.closeOpenCalls=function(){var a,b;b=function(a,b){var c;return(c=a[0])===")"||c==="CALL_END"||a[0]==="OUTDENT"&&this.tag(b-1)===")"},a=function(a,b){return this.tokens[a[0]==="OUTDENT"?b-1:b][0]="CALL_END"};return this.scanTokens(function(c,d){c[0]==="CALL_START"&&this.detectEnd(d+1,b,a);return 1})},a.prototype.closeOpenIndexes=function(){var a,b;b=function(a,b){var c;return(c=a[0])==="]"||c==="INDEX_END"},a=function(a,b){return a[0]="INDEX_END"};return this.scanTokens(function(c,d){c[0]==="INDEX_START"&&this.detectEnd(d+1,b,a);return 1})},a.prototype.addImplicitBraces=function(){var a,b,c,f,g,i,j;f=[],g=null,j=null,c=!0,i=0,b=function(a,b){var d,e,f,g,i,k;i=this.tokens.slice(b+1,b+3+1||9e9),d=i[0],g=i[1],f=i[2];if("HERECOMMENT"===(d!=null?d[0]:void 0))return!1;e=a[0],t.call(l,e)>=0&&(c=!1);return(e==="TERMINATOR"||e==="OUTDENT"||t.call(h,e)>=0&&c)&&(!j&&this.tag(b-1)!==","||(g!=null?g[0]:void 0)!==":"&&((d!=null?d[0]:void 0)!=="@"||(f!=null?f[0]:void 0)!==":"))||e===","&&d&&(k=d[0])!=="IDENTIFIER"&&k!=="NUMBER"&&k!=="STRING"&&k!=="@"&&k!=="TERMINATOR"&&k!=="OUTDENT"},a=function(a,b){var c;c=["}","}",a[2]],c.generated=!0;return this.tokens.splice(b,0,c)};return this.scanTokens(function(h,i,k){var m,n,o,p,q,r,s,u;if(s=p=h[0],t.call(e,s)>=0){f.push([p==="INDENT"&&this.tag(i-1)==="{"?"{":p,i]);return 1}if(t.call(d,p)>=0){g=f.pop();return 1}if(p!==":"||(m=this.tag(i-2))!==":"&&((u=f[f.length-1])!=null?u[0]:void 0)==="{")return 1;c=!0,f.push(["{"]),n=m==="@"?i-2:i-1;while(this.tag(n-2)==="HERECOMMENT")n-=2;o=this.tag(n-1),j=!o||t.call(l,o)>=0,r=new String("{"),r.generated=!0,q=["{",r,h[2]],q.generated=!0,k.splice(n,0,q),this.detectEnd(i+2,b,a);return 2})},a.prototype.addImplicitParentheses=function(){var a,b,c,d,e;c=e=d=!1,b=function(a,b){var c,g,i,j;g=a[0];if(!e&&a.fromThen)return!0;if(g==="IF"||g==="ELSE"||g==="CATCH"||g==="->"||g==="=>"||g==="CLASS")e=!0;if(g==="IF"||g==="ELSE"||g==="SWITCH"||g==="TRY"||g==="=")d=!0;if((g==="."||g==="?."||g==="::")&&this.tag(b-1)==="OUTDENT")return!0;return!a.generated&&this.tag(b-1)!==","&&(t.call(h,g)>=0||g==="INDENT"&&!d)&&(g!=="INDENT"||(i=this.tag(b-2))!=="CLASS"&&i!=="EXTENDS"&&(j=this.tag(b-1),t.call(f,j)<0)&&(!(c=this.tokens[b+1])||!c.generated||c[0]!=="{"))},a=function(a,b){return this.tokens.splice(b,0,["CALL_END",")",a[2]])};return this.scanTokens(function(f,h,k){var m,n,o,p,q,r,s,u;q=f[0];if(q==="CLASS"||q==="IF")c=!0;r=k.slice(h-1,h+1+1||9e9),p=r[0],n=r[1],o=r[2],m=!c&&q==="INDENT"&&o&&o.generated&&o[0]==="{"&&p&&(s=p[0],t.call(i,s)>=0),e=!1,d=!1,t.call(l,q)>=0&&(c=!1),p&&!p.spaced&&q==="?"&&(f.call=!0);if(f.fromThen)return 1;if(!(m||(p!=null?p.spaced:void 0)&&(p.call||(u=p[0],t.call(i,u)>=0))&&(t.call(g,q)>=0||!f.spaced&&!f.newLine&&t.call(j,q)>=0)))return 1;k.splice(h,0,["CALL_START","(",f[2]]),this.detectEnd(h+1,b,a),p[0]==="?"&&(p[0]="FUNC_EXIST");return 2})},a.prototype.addImplicitIndentation=function(){var a,b,c,d,e;e=c=d=null,b=function(a,b){var c;return a[1]!==";"&&(c=a[0],t.call(m,c)>=0)&&(a[0]!=="ELSE"||e==="IF"||e==="THEN")},a=function(a,b){return this.tokens.splice(this.tag(b-1)===","?b-1:b,0,d)};return this.scanTokens(function(f,g,h){var i,j,k;i=f[0];if(i==="TERMINATOR"&&this.tag(g+1)==="THEN"){h.splice(g,1);return 0}if(i==="ELSE"&&this.tag(g-1)!=="OUTDENT"){h.splice.apply(h,[g,0].concat(u.call(this.indentation(f))));return 2}if(i==="CATCH"&&((j=this.tag(g+2))==="OUTDENT"||j==="TERMINATOR"||j==="FINALLY")){h.splice.apply(h,[g+2,0].concat(u.call(this.indentation(f))));return 4}if(t.call(n,i)>=0&&this.tag(g+1)!=="INDENT"&&(i!=="ELSE"||this.tag(g+1)!=="IF")){e=i,k=this.indentation(f),c=k[0],d=k[1],e==="THEN"&&(c.fromThen=!0),c.generated=d.generated=!0,h.splice(g+1,0,c),this.detectEnd(g+2,b,a),i==="THEN"&&h.splice(g,1);return 1}return 1})},a.prototype.tagPostfixConditionals=function(){var a,b,c;c=null,b=function(a,b){var c;return(c=a[0])==="TERMINATOR"||c==="INDENT"},a=function(a,b){if(a[0]!=="INDENT"||a.generated&&!a.fromThen)return c[0]="POST_"+c[0]};return this.scanTokens(function(d,e){if(d[0]!=="IF")return 1;c=d,this.detectEnd(e+1,b,a);return 1})},a.prototype.indentation=function(a){return[["INDENT",2,a[2]],["OUTDENT",2,a[2]]]},a.prototype.tag=function(a){var b;return(b=this.tokens[a])!=null?b[0]:void 0};return a}(),b=[["(",")"],["[","]"],["{","}"],["INDENT","OUTDENT"],["CALL_START","CALL_END"],["PARAM_START","PARAM_END"],["INDEX_START","INDEX_END"]],a.INVERSES=k={},e=[],d=[];for(q=0,r=b.length;q","=>","[","(","{","--","++"],j=["+","-"],f=["->","=>","{","[",","],h=["POST_IF","FOR","WHILE","UNTIL","WHEN","BY","LOOP","TERMINATOR"],n=["ELSE","->","=>","TRY","FINALLY","THEN"],m=["TERMINATOR","CATCH","FINALLY","ELSE","OUTDENT","LEADING_WHEN"],l=["TERMINATOR","INDENT","OUTDENT"]}).call(this)},require["./lexer"]=new function(){var a=this;(function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W=Array.prototype.indexOf||function(a){for(var b=0,c=this.length;b=0||W.call(g,c)>=0)&&(j=c.toUpperCase(),j==="WHEN"&&(l=this.tag(),W.call(v,l)>=0)?j="LEADING_WHEN":j==="FOR"?this.seenFor=!0:j==="UNLESS"?j="IF":W.call(N,j)>=0?j="UNARY":W.call(H,j)>=0&&(j!=="INSTANCEOF"&&this.seenFor?(j="FOR"+j,this.seenFor=!1):(j="RELATION",this.value()==="!"&&(this.tokens.pop(),c="!"+c)))),W.call(["eval","arguments"].concat(t),c)>=0&&(b?(j="IDENTIFIER",c=new String(c),c.reserved=!0):W.call(I,c)>=0&&this.error('reserved word "'+c+'"')),b||(W.call(e,c)>=0&&(c=f[c]),j=function(){switch(c){case"!":return"UNARY";case"==":case"!=":return"COMPARE";case"&&":case"||":return"LOGIC";case"true":case"false":case"null":case"undefined":return"BOOL";case"break":case"continue":return"STATEMENT";default:return j}}()),this.token(j,c),a&&this.token(":",":");return d.length},a.prototype.numberToken=function(){var a,b,c,d;if(!(c=E.exec(this.chunk)))return 0;d=c[0],b=d.length;if(a=/0b([01]+)/.exec(d))d=parseInt(a[1],2).toString();this.token("NUMBER",d);return b},a.prototype.stringToken=function(){var a,b;switch(this.chunk.charAt(0)){case"'":if(!(a=L.exec(this.chunk)))return 0;this.token("STRING",(b=a[0]).replace(A,"\\\n"));break;case'"':if(!(b=this.balancedString(this.chunk,'"')))return 0;0=0))return 0;if(!(c=G.exec(this.chunk)))return 0;g=c,c=g[0],e=g[1],a=g[2],e.slice(0,2)==="/*"&&this.error("regular expressions cannot begin with `*`"),e==="//"&&(e="/(?:)/"),this.token("REGEX",""+e+a);return c.length},a.prototype.heregexToken=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n;d=a[0],b=a[1],c=a[2];if(0>b.indexOf("#{")){e=b.replace(o,"").replace(/\//g,"\\/"),e.match(/^\*/)&&this.error("regular expressions cannot begin with `*`"),this.token("REGEX","/"+(e||"(?:)")+"/"+c);return d.length}this.token("IDENTIFIER","RegExp"),this.tokens.push(["CALL_START","("]),g=[],k=this.interpolateString(b,{regex:!0});for(i=0,j=k.length;ithis.indent){if(d){this.indebt=f-this.indent,this.suppressNewlines();return b.length}a=f-this.indent+this.outdebt,this.token("INDENT",a),this.indents.push(a),this.ends.push("OUTDENT"),this.outdebt=this.indebt=0}else this.indebt=0,this.outdentToken(this.indent-f,d);this.indent=f;return b.length},a.prototype.outdentToken=function(a,b){var c,d;while(a>0)d=this.indents.length-1,this.indents[d]===void 0?a=0:this.indents[d]===this.outdebt?(a-=this.outdebt,this.outdebt=0):this.indents[d]=0)&&this.error('reserved word "'+this.value()+"\" can't be assigned");if((h=b[1])==="||"||h==="&&"){b[0]="COMPOUND_ASSIGN",b[1]+="=";return f.length}}if(f===";")this.seenFor=!1,e="TERMINATOR";else if(W.call(z,f)>=0)e="MATH";else if(W.call(i,f)>=0)e="COMPARE";else if(W.call(j,f)>=0)e="COMPOUND_ASSIGN";else if(W.call(N,f)>=0)e="UNARY";else if(W.call(K,f)>=0)e="SHIFT";else if(W.call(x,f)>=0||f==="?"&&(b!=null?b.spaced:void 0))e="LOGIC";else if(b&&!b.spaced)if(f==="("&&(k=b[0],W.call(c,k)>=0))b[0]==="?"&&(b[0]="FUNC_EXIST"),e="CALL_START";else if(f==="["&&(l=b[0],W.call(q,l)>=0)){e="INDEX_START";switch(b[0]){case"?":b[0]="INDEX_SOAK"}}switch(f){case"(":case"{":case"[":this.ends.push(r[f]);break;case")":case"}":case"]":this.pair(f)}this.token(e,f);return f.length},a.prototype.sanitizeHeredoc=function(a,b){var c,d,e,f,g;e=b.indent,d=b.herecomment;if(d){l.test(a)&&this.error('block comment cannot contain "*/", starting');if(a.indexOf("\n")<=0)return a}else while(f=m.exec(a)){c=f[1];if(e===null||0<(g=c.length)&&gh;1<=h?c++:c--){switch(d=a.charAt(c)){case"\\":c++;continue;case b:g.pop();if(!g.length)return a.slice(0,c+1);b=g[g.length-1];continue}b!=="}"||d!=='"'&&d!=="'"?b==="}"&&d==="/"&&(e=n.exec(a.slice(c))||G.exec(a.slice(c)))?c+=e[0].length-1:b==="}"&&d==="{"?g.push(b="}"):b==='"'&&f==="#"&&d==="{"&&g.push(b="}"):g.push(b=d),f=d}return this.error("missing "+g.pop()+", starting")},a.prototype.interpolateString=function(b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t;c==null&&(c={}),e=c.heredoc,m=c.regex,o=[],l=0,f=-1;while(j=b.charAt(f+=1)){if(j==="\\"){f+=1;continue}if(j!=="#"||b.charAt(f+1)!=="{"||!(d=this.balancedString(b.slice(f+1),"}")))continue;l1&&(k.unshift(["(","(",this.line]),k.push([")",")",this.line])),o.push(["TOKENS",k])}f+=d.length,l=f+1}f>l&&l1)&&this.token("(","(");for(f=0,q=o.length;f|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/,O=/^[^\n\S]+/,h=/^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/,d=/^[-=]>/,B=/^(?:\n[^\n\S]*)+/,L=/^'[^\\']*(?:\\.[^\\']*)*'/,s=/^`[^\\`]*(?:\\.[^\\`]*)*`/,G=/^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/,n=/^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/,o=/\s+(?:#.*)?/g,A=/\n/g,m=/\n+([^\n\S]*)/g,l=/\*\//,w=/^\s*(?:,|\??\.(?![.\d])|::)/,M=/\s+$/,j=["-=","+=","/=","*=","%=","||=","&&=","?=","<<=",">>=",">>>=","&=","^=","|="],N=["!","~","NEW","TYPEOF","DELETE","DO"],x=["&&","||","&","|","^"],K=["<<",">>",">>>"],i=["==","!=","<",">","<=",">="],z=["*","/","%"],H=["IN","OF","INSTANCEOF"],b=["TRUE","FALSE","NULL","UNDEFINED"],C=["NUMBER","REGEX","BOOL","++","--","]"],D=C.concat(")","}","THIS","IDENTIFIER","STRING"),c=["IDENTIFIER","STRING","REGEX",")","]","}","?","::","@","THIS","SUPER"],q=c.concat("NUMBER","BOOL"),v=["INDENT","OUTDENT","TERMINATOR"]}).call(this)},require["./parser"]=new function(){var a=this,b=function(){var a={trace:function(){},yy:{},symbols_:{error:2,Root:3,Body:4,Block:5,TERMINATOR:6,Line:7,Expression:8,Statement:9,Return:10,Comment:11,STATEMENT:12,Value:13,Invocation:14,Code:15,Operation:16,Assign:17,If:18,Try:19,While:20,For:21,Switch:22,Class:23,Throw:24,INDENT:25,OUTDENT:26,Identifier:27,IDENTIFIER:28,AlphaNumeric:29,NUMBER:30,STRING:31,Literal:32,JS:33,REGEX:34,DEBUGGER:35,BOOL:36,Assignable:37,"=":38,AssignObj:39,ObjAssignable:40,":":41,ThisProperty:42,RETURN:43,HERECOMMENT:44,PARAM_START:45,ParamList:46,PARAM_END:47,FuncGlyph:48,"->":49,"=>":50,OptComma:51,",":52,Param:53,ParamVar:54,"...":55,Array:56,Object:57,Splat:58,SimpleAssignable:59,Accessor:60,Parenthetical:61,Range:62,This:63,".":64,"?.":65,"::":66,Index:67,INDEX_START:68,IndexValue:69,INDEX_END:70,INDEX_SOAK:71,Slice:72,"{":73,AssignList:74,"}":75,CLASS:76,EXTENDS:77,OptFuncExist:78,Arguments:79,SUPER:80,FUNC_EXIST:81,CALL_START:82,CALL_END:83,ArgList:84,THIS:85,"@":86,"[":87,"]":88,RangeDots:89,"..":90,Arg:91,SimpleArgs:92,TRY:93,Catch:94,FINALLY:95,CATCH:96,THROW:97,"(":98,")":99,WhileSource:100,WHILE:101,WHEN:102,UNTIL:103,Loop:104,LOOP:105,ForBody:106,FOR:107,ForStart:108,ForSource:109,ForVariables:110,OWN:111,ForValue:112,FORIN:113,FOROF:114,BY:115,SWITCH:116,Whens:117,ELSE:118,When:119,LEADING_WHEN:120,IfBlock:121,IF:122,POST_IF:123,UNARY:124,"-":125,"+":126,"--":127,"++":128,"?":129,MATH:130,SHIFT:131,COMPARE:132,LOGIC:133,RELATION:134,COMPOUND_ASSIGN:135,$accept:0,$end:1},terminals_:{2:"error",6:"TERMINATOR",12:"STATEMENT",25:"INDENT",26:"OUTDENT",28:"IDENTIFIER",30:"NUMBER",31:"STRING",33:"JS",34:"REGEX",35:"DEBUGGER",36:"BOOL",38:"=",41:":",43:"RETURN",44:"HERECOMMENT",45:"PARAM_START",47:"PARAM_END",49:"->",50:"=>",52:",",55:"...",64:".",65:"?.",66:"::",68:"INDEX_START",70:"INDEX_END",71:"INDEX_SOAK",73:"{",75:"}",76:"CLASS",77:"EXTENDS",80:"SUPER",81:"FUNC_EXIST",82:"CALL_START",83:"CALL_END",85:"THIS",86:"@",87:"[",88:"]",90:"..",93:"TRY",95:"FINALLY",96:"CATCH",97:"THROW",98:"(",99:")",101:"WHILE",102:"WHEN",103:"UNTIL",105:"LOOP",107:"FOR",111:"OWN",113:"FORIN",114:"FOROF",115:"BY",116:"SWITCH",118:"ELSE",120:"LEADING_WHEN",122:"IF",123:"POST_IF",124:"UNARY",125:"-",126:"+",127:"--",128:"++",129:"?",130:"MATH",131:"SHIFT",132:"COMPARE",133:"LOGIC",134:"RELATION",135:"COMPOUND_ASSIGN"},productions_:[0,[3,0],[3,1],[3,2],[4,1],[4,3],[4,2],[7,1],[7,1],[9,1],[9,1],[9,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[5,2],[5,3],[27,1],[29,1],[29,1],[32,1],[32,1],[32,1],[32,1],[32,1],[17,3],[17,4],[17,5],[39,1],[39,3],[39,5],[39,1],[40,1],[40,1],[40,1],[10,2],[10,1],[11,1],[15,5],[15,2],[48,1],[48,1],[51,0],[51,1],[46,0],[46,1],[46,3],[53,1],[53,2],[53,3],[54,1],[54,1],[54,1],[54,1],[58,2],[59,1],[59,2],[59,2],[59,1],[37,1],[37,1],[37,1],[13,1],[13,1],[13,1],[13,1],[13,1],[60,2],[60,2],[60,2],[60,1],[60,1],[67,3],[67,2],[69,1],[69,1],[57,4],[74,0],[74,1],[74,3],[74,4],[74,6],[23,1],[23,2],[23,3],[23,4],[23,2],[23,3],[23,4],[23,5],[14,3],[14,3],[14,1],[14,2],[78,0],[78,1],[79,2],[79,4],[63,1],[63,1],[42,2],[56,2],[56,4],[89,1],[89,1],[62,5],[72,3],[72,2],[72,2],[84,1],[84,3],[84,4],[84,4],[84,6],[91,1],[91,1],[92,1],[92,3],[19,2],[19,3],[19,4],[19,5],[94,3],[24,2],[61,3],[61,5],[100,2],[100,4],[100,2],[100,4],[20,2],[20,2],[20,2],[20,1],[104,2],[104,2],[21,2],[21,2],[21,2],[106,2],[106,2],[108,2],[108,3],[112,1],[112,1],[112,1],[110,1],[110,3],[109,2],[109,2],[109,4],[109,4],[109,4],[109,6],[109,6],[22,5],[22,7],[22,4],[22,6],[117,1],[117,2],[119,3],[119,4],[121,3],[121,5],[18,1],[18,3],[18,3],[18,3],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,5],[16,3]],performAction:function(a,b,c,d,e,f,g){var h=f.length-1;switch(e){case 1:return this.$=new d.Block;case 2:return this.$=f[h];case 3:return this.$=f[h-1];case 4:this.$=d.Block.wrap([f[h]]);break;case 5:this.$=f[h-2].push(f[h]);break;case 6:this.$=f[h-1];break;case 7:this.$=f[h];break;case 8:this.$=f[h];break;case 9:this.$=f[h];break;case 10:this.$=f[h];break;case 11:this.$=new d.Literal(f[h]);break;case 12:this.$=f[h];break;case 13:this.$=f[h];break;case 14:this.$=f[h];break;case 15:this.$=f[h];break;case 16:this.$=f[h];break;case 17:this.$=f[h];break;case 18:this.$=f[h];break;case 19:this.$=f[h];break;case 20:this.$=f[h];break;case 21:this.$=f[h];break;case 22:this.$=f[h];break;case 23:this.$=f[h];break;case 24:this.$=new d.Block;break;case 25:this.$=f[h-1];break;case 26:this.$=new d.Literal(f[h]);break;case 27:this.$=new d.Literal(f[h]);break;case 28:this.$=new d.Literal(f[h]);break;case 29:this.$=f[h];break;case 30:this.$=new d.Literal(f[h]);break;case 31:this.$=new d.Literal(f[h]);break;case 32:this.$=new d.Literal(f[h]);break;case 33:this.$=function(){var a;a=new d.Literal(f[h]),f[h]==="undefined"&&(a.isUndefined=!0);return a}();break;case 34:this.$=new d.Assign(f[h-2],f[h]);break;case 35:this.$=new d.Assign(f[h-3],f[h]);break;case 36:this.$=new d.Assign(f[h-4],f[h-1]);break;case 37:this.$=new d.Value(f[h]);break;case 38:this.$=new d.Assign(new d.Value(f[h-2]),f[h],"object");break;case 39:this.$=new d.Assign(new d.Value(f[h-4]),f[h-1],"object");break;case 40:this.$=f[h];break;case 41:this.$=f[h];break;case 42:this.$=f[h];break;case 43:this.$=f[h];break;case 44:this.$=new d.Return(f[h]);break;case 45:this.$=new d.Return;break;case 46:this.$=new d.Comment(f[h]);break;case 47:this.$=new d.Code(f[h-3],f[h],f[h-1]);break;case 48:this.$=new d.Code([],f[h],f[h-1]);break;case 49:this.$="func";break;case 50:this.$="boundfunc";break;case 51:this.$=f[h];break;case 52:this.$=f[h];break;case 53:this.$=[];break;case 54:this.$=[f[h]];break;case 55:this.$=f[h-2].concat(f[h]);break;case 56:this.$=new d.Param(f[h]);break;case 57:this.$=new d.Param(f[h-1],null,!0);break;case 58:this.$=new d.Param(f[h-2],f[h]);break;case 59:this.$=f[h];break;case 60:this.$=f[h];break;case 61:this.$=f[h];break;case 62:this.$=f[h];break;case 63:this.$=new d.Splat(f[h-1]);break;case 64:this.$=new d.Value(f[h]);break;case 65:this.$=f[h-1].add(f[h]);break;case 66:this.$=new d.Value(f[h-1],[].concat(f[h]));break;case 67:this.$=f[h];break;case 68:this.$=f[h];break;case 69:this.$=new d.Value(f[h]);break;case 70:this.$=new d.Value(f[h]);break;case 71:this.$=f[h];break;case 72:this.$=new d.Value(f[h]);break;case 73:this.$=new d.Value(f[h]);break;case 74:this.$=new d.Value(f[h]);break;case 75:this.$=f[h];break;case 76:this.$=new d.Access(f[h]);break;case 77:this.$=new d.Access(f[h],"soak");break;case 78:this.$=[new d.Access(new d.Literal("prototype")),new d.Access(f[h])];break;case 79:this.$=new d.Access(new d.Literal("prototype"));break;case 80:this.$=f[h];break;case 81:this.$=f[h-1];break;case 82:this.$=d.extend(f[h],{soak:!0});break;case 83:this.$=new d.Index(f[h]);break;case 84:this.$=new d.Slice(f[h]);break;case 85:this.$=new d.Obj(f[h-2],f[h-3].generated);break;case 86:this.$=[];break;case 87:this.$=[f[h]];break;case 88:this.$=f[h-2].concat(f[h]);break;case 89:this.$=f[h-3].concat(f[h]);break;case 90:this.$=f[h-5].concat(f[h-2]);break;case 91:this.$=new d.Class;break;case 92:this.$=new d.Class(null,null,f[h]);break;case 93:this.$=new d.Class(null,f[h]);break;case 94:this.$=new d.Class(null,f[h-1],f[h]);break;case 95:this.$=new d.Class(f[h]);break;case 96:this.$=new d.Class(f[h-1],null,f[h]);break;case 97:this.$=new d.Class(f[h-2],f[h]);break;case 98:this.$=new d.Class(f[h-3],f[h-1],f[h]);break;case 99:this.$=new d.Call(f[h-2],f[h],f[h-1]);break;case 100:this.$=new d.Call(f[h-2],f[h],f[h-1]);break;case 101:this.$=new d.Call("super",[new d.Splat(new d.Literal("arguments"))]);break;case 102:this.$=new d.Call("super",f[h]);break;case 103:this.$=!1;break;case 104:this.$=!0;break;case 105:this.$=[];break;case 106:this.$=f[h-2];break;case 107:this.$=new d.Value(new d.Literal("this"));break;case 108:this.$=new d.Value(new d.Literal("this"));break;case 109:this.$=new d.Value(new d.Literal("this"),[new d.Access(f[h])],"this");break;case 110:this.$=new d.Arr([]);break;case 111:this.$=new d.Arr(f[h-2]);break;case 112:this.$="inclusive";break;case 113:this.$="exclusive";break;case 114:this.$=new d.Range(f[h-3],f[h-1],f[h-2]);break;case 115:this.$=new d.Range(f[h-2],f[h],f[h-1]);break;case 116:this.$=new d.Range(f[h-1],null,f[h]);break;case 117:this.$=new d.Range(null,f[h],f[h-1]);break;case 118:this.$=[f[h]];break;case 119:this.$=f[h-2].concat(f[h]);break;case 120:this.$=f[h-3].concat(f[h]);break;case 121:this.$=f[h-2];break;case 122:this.$=f[h-5].concat(f[h-2]);break;case 123:this.$=f[h];break;case 124:this.$=f[h];break;case 125:this.$=f[h];break;case 126:this.$=[].concat(f[h-2],f[h]);break;case 127:this.$=new d.Try(f[h]);break;case 128:this.$=new d.Try(f[h-1],f[h][0],f[h][1]);break;case 129:this.$=new d.Try(f[h-2],null,null,f[h]);break;case 130:this.$=new d.Try(f[h-3],f[h-2][0],f[h-2][1],f[h]);break;case 131:this.$=[f[h-1],f[h]];break;case 132:this.$=new d.Throw(f[h]);break;case 133:this.$=new d.Parens(f[h-1]);break;case 134:this.$=new d.Parens(f[h-2]);break;case 135:this.$=new d.While(f[h]);break;case 136:this.$=new d.While(f[h-2],{guard:f[h]});break;case 137:this.$=new d.While(f[h],{invert:!0});break;case 138:this.$=new d.While(f[h-2],{invert:!0,guard:f[h]});break;case 139:this.$=f[h-1].addBody(f[h]);break;case 140:this.$=f[h].addBody(d.Block.wrap([f[h-1]]));break;case 141:this.$=f[h].addBody(d.Block.wrap([f[h-1]]));break;case 142:this.$=f[h];break;case 143:this.$=(new d.While(new d.Literal("true"))).addBody(f[h]);break;case 144:this.$=(new d.While(new d.Literal("true"))).addBody(d.Block.wrap([f[h]]));break;case 145:this.$=new d.For(f[h-1],f[h]);break;case 146:this.$=new d.For(f[h-1],f[h]);break;case 147:this.$=new d.For(f[h],f[h-1]);break;case 148:this.$={source:new d.Value(f[h])};break;case 149:this.$=function(){f[h].own=f[h-1].own,f[h].name=f[h-1][0],f[h].index=f[h-1][1];return f[h]}();break;case 150:this.$=f[h];break;case 151:this.$=function(){f[h].own=!0;return f[h]}();break;case 152:this.$=f[h];break;case 153:this.$=new d.Value(f[h]);break;case 154:this.$=new d.Value(f[h]);break;case 155:this.$=[f[h]];break;case 156:this.$=[f[h-2],f[h]];break;case 157:this.$={source:f[h]};break;case 158:this.$={source:f[h],object:!0};break;case 159:this.$={source:f[h-2],guard:f[h]};break;case 160:this.$={source:f[h-2],guard:f[h],object:!0};break;case 161:this.$={source:f[h-2],step:f[h]};break;case 162:this.$={source:f[h-4],guard:f[h-2],step:f[h]};break;case 163:this.$={source:f[h-4],step:f[h-2],guard:f[h]};break;case 164:this.$=new d.Switch(f[h-3],f[h-1]);break;case 165:this.$=new d.Switch(f[h-5],f[h-3],f[h-1]);break;case 166:this.$=new d.Switch(null,f[h-1]);break;case 167:this.$=new d.Switch(null,f[h-3],f[h-1]);break;case 168:this.$=f[h];break;case 169:this.$=f[h-1].concat(f[h]);break;case 170:this.$=[[f[h-1],f[h]]];break;case 171:this.$=[[f[h-2],f[h-1]]];break;case 172:this.$=new d.If(f[h-1],f[h],{type:f[h-2]});break;case 173:this.$=f[h-4].addElse(new d.If(f[h-1],f[h],{type:f[h-2]}));break;case 174:this.$=f[h];break;case 175:this.$=f[h-2].addElse(f[h]);break;case 176:this.$=new d.If(f[h],d.Block.wrap([f[h-2]]),{type:f[h-1],statement:!0});break;case 177:this.$=new d.If(f[h],d.Block.wrap([f[h-2]]),{type:f[h-1],statement:!0});break;case 178:this.$=new d.Op(f[h-1],f[h]);break;case 179:this.$=new d.Op("-",f[h]);break;case 180:this.$=new d.Op("+",f[h]);break;case 181:this.$=new d.Op("--",f[h]);break;case 182:this.$=new d.Op("++",f[h]);break;case 183:this.$=new d.Op("--",f[h-1],null,!0);break;case 184:this.$=new d.Op("++",f[h-1],null,!0);break;case 185:this.$=new d.Existence(f[h-1]);break;case 186:this.$=new d.Op("+",f[h-2],f[h]);break;case 187:this.$=new d.Op("-",f[h-2],f[h]);break;case 188:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 189:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 190:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 191:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 192:this.$=function(){return f[h-1].charAt(0)==="!"?(new d.Op(f[h-1].slice(1),f[h-2],f[h])).invert():new d.Op(f[h-1],f[h-2],f[h])}();break;case 193:this.$=new d.Assign(f[h-2],f[h],f[h-1]);break;case 194:this.$=new d.Assign(f[h-4],f[h-1],f[h-3]);break;case 195:this.$=new d.Extends(f[h-2],f[h])}},table:[{1:[2,1],3:1,4:2,5:3,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[3]},{1:[2,2],6:[1,72]},{6:[1,73]},{1:[2,4],6:[2,4],26:[2,4],99:[2,4]},{4:75,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[1,74],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,7],6:[2,7],26:[2,7],99:[2,7],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,8],6:[2,8],26:[2,8],99:[2,8],100:88,101:[1,63],103:[1,64],106:89,107:[1,66],108:67,123:[1,87]},{1:[2,12],6:[2,12],25:[2,12],26:[2,12],47:[2,12],52:[2,12],55:[2,12],60:91,64:[1,93],65:[1,94],66:[1,95],67:96,68:[1,97],70:[2,12],71:[1,98],75:[2,12],78:90,81:[1,92],82:[2,103],83:[2,12],88:[2,12],90:[2,12],99:[2,12],101:[2,12],102:[2,12],103:[2,12],107:[2,12],115:[2,12],123:[2,12],125:[2,12],126:[2,12],129:[2,12],130:[2,12],131:[2,12],132:[2,12],133:[2,12],134:[2,12]},{1:[2,13],6:[2,13],25:[2,13],26:[2,13],47:[2,13],52:[2,13],55:[2,13],60:100,64:[1,93],65:[1,94],66:[1,95],67:96,68:[1,97],70:[2,13],71:[1,98],75:[2,13],78:99,81:[1,92],82:[2,103],83:[2,13],88:[2,13],90:[2,13],99:[2,13],101:[2,13],102:[2,13],103:[2,13],107:[2,13],115:[2,13],123:[2,13],125:[2,13],126:[2,13],129:[2,13],130:[2,13],131:[2,13],132:[2,13],133:[2,13],134:[2,13]},{1:[2,14],6:[2,14],25:[2,14],26:[2,14],47:[2,14],52:[2,14],55:[2,14],70:[2,14],75:[2,14],83:[2,14],88:[2,14],90:[2,14],99:[2,14],101:[2,14],102:[2,14],103:[2,14],107:[2,14],115:[2,14],123:[2,14],125:[2,14],126:[2,14],129:[2,14],130:[2,14],131:[2,14],132:[2,14],133:[2,14],134:[2,14]},{1:[2,15],6:[2,15],25:[2,15],26:[2,15],47:[2,15],52:[2,15],55:[2,15],70:[2,15],75:[2,15],83:[2,15],88:[2,15],90:[2,15],99:[2,15],101:[2,15],102:[2,15],103:[2,15],107:[2,15],115:[2,15],123:[2,15],125:[2,15],126:[2,15],129:[2,15],130:[2,15],131:[2,15],132:[2,15],133:[2,15],134:[2,15]},{1:[2,16],6:[2,16],25:[2,16],26:[2,16],47:[2,16],52:[2,16],55:[2,16],70:[2,16],75:[2,16],83:[2,16],88:[2,16],90:[2,16],99:[2,16],101:[2,16],102:[2,16],103:[2,16],107:[2,16],115:[2,16],123:[2,16],125:[2,16],126:[2,16],129:[2,16],130:[2,16],131:[2,16],132:[2,16],133:[2,16],134:[2,16]},{1:[2,17],6:[2,17],25:[2,17],26:[2,17],47:[2,17],52:[2,17],55:[2,17],70:[2,17],75:[2,17],83:[2,17],88:[2,17],90:[2,17],99:[2,17],101:[2,17],102:[2,17],103:[2,17],107:[2,17],115:[2,17],123:[2,17],125:[2,17],126:[2,17],129:[2,17],130:[2,17],131:[2,17],132:[2,17],133:[2,17],134:[2,17]},{1:[2,18],6:[2,18],25:[2,18],26:[2,18],47:[2,18],52:[2,18],55:[2,18],70:[2,18],75:[2,18],83:[2,18],88:[2,18],90:[2,18],99:[2,18],101:[2,18],102:[2,18],103:[2,18],107:[2,18],115:[2,18],123:[2,18],125:[2,18],126:[2,18],129:[2,18],130:[2,18],131:[2,18],132:[2,18],133:[2,18],134:[2,18]},{1:[2,19],6:[2,19],25:[2,19],26:[2,19],47:[2,19],52:[2,19],55:[2,19],70:[2,19],75:[2,19],83:[2,19],88:[2,19],90:[2,19],99:[2,19],101:[2,19],102:[2,19],103:[2,19],107:[2,19],115:[2,19],123:[2,19],125:[2,19],126:[2,19],129:[2,19],130:[2,19],131:[2,19],132:[2,19],133:[2,19],134:[2,19]},{1:[2,20],6:[2,20],25:[2,20],26:[2,20],47:[2,20],52:[2,20],55:[2,20],70:[2,20],75:[2,20],83:[2,20],88:[2,20],90:[2,20],99:[2,20],101:[2,20],102:[2,20],103:[2,20],107:[2,20],115:[2,20],123:[2,20],125:[2,20],126:[2,20],129:[2,20],130:[2,20],131:[2,20],132:[2,20],133:[2,20],134:[2,20]},{1:[2,21],6:[2,21],25:[2,21],26:[2,21],47:[2,21],52:[2,21],55:[2,21],70:[2,21],75:[2,21],83:[2,21],88:[2,21],90:[2,21],99:[2,21],101:[2,21],102:[2,21],103:[2,21],107:[2,21],115:[2,21],123:[2,21],125:[2,21],126:[2,21],129:[2,21],130:[2,21],131:[2,21],132:[2,21],133:[2,21],134:[2,21]},{1:[2,22],6:[2,22],25:[2,22],26:[2,22],47:[2,22],52:[2,22],55:[2,22],70:[2,22],75:[2,22],83:[2,22],88:[2,22],90:[2,22],99:[2,22],101:[2,22],102:[2,22],103:[2,22],107:[2,22],115:[2,22],123:[2,22],125:[2,22],126:[2,22],129:[2,22],130:[2,22],131:[2,22],132:[2,22],133:[2,22],134:[2,22]},{1:[2,23],6:[2,23],25:[2,23],26:[2,23],47:[2,23],52:[2,23],55:[2,23],70:[2,23],75:[2,23],83:[2,23],88:[2,23],90:[2,23],99:[2,23],101:[2,23],102:[2,23],103:[2,23],107:[2,23],115:[2,23],123:[2,23],125:[2,23],126:[2,23],129:[2,23],130:[2,23],131:[2,23],132:[2,23],133:[2,23],134:[2,23]},{1:[2,9],6:[2,9],26:[2,9],99:[2,9],101:[2,9],103:[2,9],107:[2,9],123:[2,9]},{1:[2,10],6:[2,10],26:[2,10],99:[2,10],101:[2,10],103:[2,10],107:[2,10],123:[2,10]},{1:[2,11],6:[2,11],26:[2,11],99:[2,11],101:[2,11],103:[2,11],107:[2,11],123:[2,11]},{1:[2,71],6:[2,71],25:[2,71],26:[2,71],38:[1,101],47:[2,71],52:[2,71],55:[2,71],64:[2,71],65:[2,71],66:[2,71],68:[2,71],70:[2,71],71:[2,71],75:[2,71],81:[2,71],82:[2,71],83:[2,71],88:[2,71],90:[2,71],99:[2,71],101:[2,71],102:[2,71],103:[2,71],107:[2,71],115:[2,71],123:[2,71],125:[2,71],126:[2,71],129:[2,71],130:[2,71],131:[2,71],132:[2,71],133:[2,71],134:[2,71]},{1:[2,72],6:[2,72],25:[2,72],26:[2,72],47:[2,72],52:[2,72],55:[2,72],64:[2,72],65:[2,72],66:[2,72],68:[2,72],70:[2,72],71:[2,72],75:[2,72],81:[2,72],82:[2,72],83:[2,72],88:[2,72],90:[2,72],99:[2,72],101:[2,72],102:[2,72],103:[2,72],107:[2,72],115:[2,72],123:[2,72],125:[2,72],126:[2,72],129:[2,72],130:[2,72],131:[2,72],132:[2,72],133:[2,72],134:[2,72]},{1:[2,73],6:[2,73],25:[2,73],26:[2,73],47:[2,73],52:[2,73],55:[2,73],64:[2,73],65:[2,73],66:[2,73],68:[2,73],70:[2,73],71:[2,73],75:[2,73],81:[2,73],82:[2,73],83:[2,73],88:[2,73],90:[2,73],99:[2,73],101:[2,73],102:[2,73],103:[2,73],107:[2,73],115:[2,73],123:[2,73],125:[2,73],126:[2,73],129:[2,73],130:[2,73],131:[2,73],132:[2,73],133:[2,73],134:[2,73]},{1:[2,74],6:[2,74],25:[2,74],26:[2,74],47:[2,74],52:[2,74],55:[2,74],64:[2,74],65:[2,74],66:[2,74],68:[2,74],70:[2,74],71:[2,74],75:[2,74],81:[2,74],82:[2,74],83:[2,74],88:[2,74],90:[2,74],99:[2,74],101:[2,74],102:[2,74],103:[2,74],107:[2,74],115:[2,74],123:[2,74],125:[2,74],126:[2,74],129:[2,74],130:[2,74],131:[2,74],132:[2,74],133:[2,74],134:[2,74]},{1:[2,75],6:[2,75],25:[2,75],26:[2,75],47:[2,75],52:[2,75],55:[2,75],64:[2,75],65:[2,75],66:[2,75],68:[2,75],70:[2,75],71:[2,75],75:[2,75],81:[2,75],82:[2,75],83:[2,75],88:[2,75],90:[2,75],99:[2,75],101:[2,75],102:[2,75],103:[2,75],107:[2,75],115:[2,75],123:[2,75],125:[2,75],126:[2,75],129:[2,75],130:[2,75],131:[2,75],132:[2,75],133:[2,75],134:[2,75]},{1:[2,101],6:[2,101],25:[2,101],26:[2,101],47:[2,101],52:[2,101],55:[2,101],64:[2,101],65:[2,101],66:[2,101],68:[2,101],70:[2,101],71:[2,101],75:[2,101],79:102,81:[2,101],82:[1,103],83:[2,101],88:[2,101],90:[2,101],99:[2,101],101:[2,101],102:[2,101],103:[2,101],107:[2,101],115:[2,101],123:[2,101],125:[2,101],126:[2,101],129:[2,101],130:[2,101],131:[2,101],132:[2,101],133:[2,101],134:[2,101]},{27:107,28:[1,71],42:108,46:104,47:[2,53],52:[2,53],53:105,54:106,56:109,57:110,73:[1,68],86:[1,111],87:[1,112]},{5:113,25:[1,5]},{8:114,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:116,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:117,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{13:119,14:120,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:121,42:61,56:47,57:48,59:118,61:25,62:26,63:27,73:[1,68],80:[1,28],85:[1,56],86:[1,57],87:[1,55],98:[1,54]},{13:119,14:120,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:121,42:61,56:47,57:48,59:122,61:25,62:26,63:27,73:[1,68],80:[1,28],85:[1,56],86:[1,57],87:[1,55],98:[1,54]},{1:[2,68],6:[2,68],25:[2,68],26:[2,68],38:[2,68],47:[2,68],52:[2,68],55:[2,68],64:[2,68],65:[2,68],66:[2,68],68:[2,68],70:[2,68],71:[2,68],75:[2,68],77:[1,126],81:[2,68],82:[2,68],83:[2,68],88:[2,68],90:[2,68],99:[2,68],101:[2,68],102:[2,68],103:[2,68],107:[2,68],115:[2,68],123:[2,68],125:[2,68],126:[2,68],127:[1,123],128:[1,124],129:[2,68],130:[2,68],131:[2,68],132:[2,68],133:[2,68],134:[2,68],135:[1,125]},{1:[2,174],6:[2,174],25:[2,174],26:[2,174],47:[2,174],52:[2,174],55:[2,174],70:[2,174],75:[2,174],83:[2,174],88:[2,174],90:[2,174],99:[2,174],101:[2,174],102:[2,174],103:[2,174],107:[2,174],115:[2,174],118:[1,127],123:[2,174],125:[2,174],126:[2,174],129:[2,174],130:[2,174],131:[2,174],132:[2,174],133:[2,174],134:[2,174]},{5:128,25:[1,5]},{5:129,25:[1,5]},{1:[2,142],6:[2,142],25:[2,142],26:[2,142],47:[2,142],52:[2,142],55:[2,142],70:[2,142],75:[2,142],83:[2,142],88:[2,142],90:[2,142],99:[2,142],101:[2,142],102:[2,142],103:[2,142],107:[2,142],115:[2,142],123:[2,142],125:[2,142],126:[2,142],129:[2,142],130:[2,142],131:[2,142],132:[2,142],133:[2,142],134:[2,142]},{5:130,25:[1,5]},{8:131,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,132],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,91],5:133,6:[2,91],13:119,14:120,25:[1,5],26:[2,91],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:121,42:61,47:[2,91],52:[2,91],55:[2,91],56:47,57:48,59:135,61:25,62:26,63:27,70:[2,91],73:[1,68],75:[2,91],77:[1,134],80:[1,28],83:[2,91],85:[1,56],86:[1,57],87:[1,55],88:[2,91],90:[2,91],98:[1,54],99:[2,91],101:[2,91],102:[2,91],103:[2,91],107:[2,91],115:[2,91],123:[2,91],125:[2,91],126:[2,91],129:[2,91],130:[2,91],131:[2,91],132:[2,91],133:[2,91],134:[2,91]},{8:136,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,45],6:[2,45],8:137,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,45],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],99:[2,45],100:39,101:[2,45],103:[2,45],104:40,105:[1,65],106:41,107:[2,45],108:67,116:[1,42],121:37,122:[1,62],123:[2,45],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,46],6:[2,46],25:[2,46],26:[2,46],52:[2,46],75:[2,46],99:[2,46],101:[2,46],103:[2,46],107:[2,46],123:[2,46]},{1:[2,69],6:[2,69],25:[2,69],26:[2,69],38:[2,69],47:[2,69],52:[2,69],55:[2,69],64:[2,69],65:[2,69],66:[2,69],68:[2,69],70:[2,69],71:[2,69],75:[2,69],81:[2,69],82:[2,69],83:[2,69],88:[2,69],90:[2,69],99:[2,69],101:[2,69],102:[2,69],103:[2,69],107:[2,69],115:[2,69],123:[2,69],125:[2,69],126:[2,69],129:[2,69],130:[2,69],131:[2,69],132:[2,69],133:[2,69],134:[2,69]},{1:[2,70],6:[2,70],25:[2,70],26:[2,70],38:[2,70],47:[2,70],52:[2,70],55:[2,70],64:[2,70],65:[2,70],66:[2,70],68:[2,70],70:[2,70],71:[2,70],75:[2,70],81:[2,70],82:[2,70],83:[2,70],88:[2,70],90:[2,70],99:[2,70],101:[2,70],102:[2,70],103:[2,70],107:[2,70],115:[2,70],123:[2,70],125:[2,70],126:[2,70],129:[2,70],130:[2,70],131:[2,70],132:[2,70],133:[2,70],134:[2,70]},{1:[2,29],6:[2,29],25:[2,29],26:[2,29],47:[2,29],52:[2,29],55:[2,29],64:[2,29],65:[2,29],66:[2,29],68:[2,29],70:[2,29],71:[2,29],75:[2,29],81:[2,29],82:[2,29],83:[2,29],88:[2,29],90:[2,29],99:[2,29],101:[2,29],102:[2,29],103:[2,29],107:[2,29],115:[2,29],123:[2,29],125:[2,29],126:[2,29],129:[2,29],130:[2,29],131:[2,29],132:[2,29],133:[2,29],134:[2,29]},{1:[2,30],6:[2,30],25:[2,30],26:[2,30],47:[2,30],52:[2,30],55:[2,30],64:[2,30],65:[2,30],66:[2,30],68:[2,30],70:[2,30],71:[2,30],75:[2,30],81:[2,30],82:[2,30],83:[2,30],88:[2,30],90:[2,30],99:[2,30],101:[2,30],102:[2,30],103:[2,30],107:[2,30],115:[2,30],123:[2,30],125:[2,30],126:[2,30],129:[2,30],130:[2,30],131:[2,30],132:[2,30],133:[2,30],134:[2,30]},{1:[2,31],6:[2,31],25:[2,31],26:[2,31],47:[2,31],52:[2,31],55:[2,31],64:[2,31],65:[2,31],66:[2,31],68:[2,31],70:[2,31],71:[2,31],75:[2,31],81:[2,31],82:[2,31],83:[2,31],88:[2,31],90:[2,31],99:[2,31],101:[2,31],102:[2,31],103:[2,31],107:[2,31],115:[2,31],123:[2,31],125:[2,31],126:[2,31],129:[2,31],130:[2,31],131:[2,31],132:[2,31],133:[2,31],134:[2,31]},{1:[2,32],6:[2,32],25:[2,32],26:[2,32],47:[2,32],52:[2,32],55:[2,32],64:[2,32],65:[2,32],66:[2,32],68:[2,32],70:[2,32],71:[2,32],75:[2,32],81:[2,32],82:[2,32],83:[2,32],88:[2,32],90:[2,32],99:[2,32],101:[2,32],102:[2,32],103:[2,32],107:[2,32],115:[2,32],123:[2,32],125:[2,32],126:[2,32],129:[2,32],130:[2,32],131:[2,32],132:[2,32],133:[2,32],134:[2,32]},{1:[2,33],6:[2,33],25:[2,33],26:[2,33],47:[2,33],52:[2,33],55:[2,33],64:[2,33],65:[2,33],66:[2,33],68:[2,33],70:[2,33],71:[2,33],75:[2,33],81:[2,33],82:[2,33],83:[2,33],88:[2,33],90:[2,33],99:[2,33],101:[2,33],102:[2,33],103:[2,33],107:[2,33],115:[2,33],123:[2,33],125:[2,33],126:[2,33],129:[2,33],130:[2,33],131:[2,33],132:[2,33],133:[2,33],134:[2,33]},{4:138,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,139],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:140,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,144],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,58:145,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],84:142,85:[1,56],86:[1,57],87:[1,55],88:[1,141],91:143,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,107],6:[2,107],25:[2,107],26:[2,107],47:[2,107],52:[2,107],55:[2,107],64:[2,107],65:[2,107],66:[2,107],68:[2,107],70:[2,107],71:[2,107],75:[2,107],81:[2,107],82:[2,107],83:[2,107],88:[2,107],90:[2,107],99:[2,107],101:[2,107],102:[2,107],103:[2,107],107:[2,107],115:[2,107],123:[2,107],125:[2,107],126:[2,107],129:[2,107],130:[2,107],131:[2,107],132:[2,107],133:[2,107],134:[2,107]},{1:[2,108],6:[2,108],25:[2,108],26:[2,108],27:146,28:[1,71],47:[2,108],52:[2,108],55:[2,108],64:[2,108],65:[2,108],66:[2,108],68:[2,108],70:[2,108],71:[2,108],75:[2,108],81:[2,108],82:[2,108],83:[2,108],88:[2,108],90:[2,108],99:[2,108],101:[2,108],102:[2,108],103:[2,108],107:[2,108],115:[2,108],123:[2,108],125:[2,108],126:[2,108],129:[2,108],130:[2,108],131:[2,108],132:[2,108],133:[2,108],134:[2,108]},{25:[2,49]},{25:[2,50]},{1:[2,64],6:[2,64],25:[2,64],26:[2,64],38:[2,64],47:[2,64],52:[2,64],55:[2,64],64:[2,64],65:[2,64],66:[2,64],68:[2,64],70:[2,64],71:[2,64],75:[2,64],77:[2,64],81:[2,64],82:[2,64],83:[2,64],88:[2,64],90:[2,64],99:[2,64],101:[2,64],102:[2,64],103:[2,64],107:[2,64],115:[2,64],123:[2,64],125:[2,64],126:[2,64],127:[2,64],128:[2,64],129:[2,64],130:[2,64],131:[2,64],132:[2,64],133:[2,64],134:[2,64],135:[2,64]},{1:[2,67],6:[2,67],25:[2,67],26:[2,67],38:[2,67],47:[2,67],52:[2,67],55:[2,67],64:[2,67],65:[2,67],66:[2,67],68:[2,67],70:[2,67],71:[2,67],75:[2,67],77:[2,67],81:[2,67],82:[2,67],83:[2,67],88:[2,67],90:[2,67],99:[2,67],101:[2,67],102:[2,67],103:[2,67],107:[2,67],115:[2,67],123:[2,67],125:[2,67],126:[2,67],127:[2,67],128:[2,67],129:[2,67],130:[2,67],131:[2,67],132:[2,67],133:[2,67],134:[2,67],135:[2,67]},{8:147,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:148,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:149,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{5:150,8:151,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{27:156,28:[1,71],56:157,57:158,62:152,73:[1,68],87:[1,55],110:153,111:[1,154],112:155},{109:159,113:[1,160],114:[1,161]},{6:[2,86],11:165,25:[2,86],27:166,28:[1,71],29:167,30:[1,69],31:[1,70],39:163,40:164,42:168,44:[1,46],52:[2,86],74:162,75:[2,86],86:[1,111]},{1:[2,27],6:[2,27],25:[2,27],26:[2,27],41:[2,27],47:[2,27],52:[2,27],55:[2,27],64:[2,27],65:[2,27],66:[2,27],68:[2,27],70:[2,27],71:[2,27],75:[2,27],81:[2,27],82:[2,27],83:[2,27],88:[2,27],90:[2,27],99:[2,27],101:[2,27],102:[2,27],103:[2,27],107:[2,27],115:[2,27],123:[2,27],125:[2,27],126:[2,27],129:[2,27],130:[2,27],131:[2,27],132:[2,27],133:[2,27],134:[2,27]},{1:[2,28],6:[2,28],25:[2,28],26:[2,28],41:[2,28],47:[2,28],52:[2,28],55:[2,28],64:[2,28],65:[2,28],66:[2,28],68:[2,28],70:[2,28],71:[2,28],75:[2,28],81:[2,28],82:[2,28],83:[2,28],88:[2,28],90:[2,28],99:[2,28],101:[2,28],102:[2,28],103:[2,28],107:[2,28],115:[2,28],123:[2,28],125:[2,28],126:[2,28],129:[2,28],130:[2,28],131:[2,28],132:[2,28],133:[2,28],134:[2,28]},{1:[2,26],6:[2,26],25:[2,26],26:[2,26],38:[2,26],41:[2,26],47:[2,26],52:[2,26],55:[2,26],64:[2,26],65:[2,26],66:[2,26],68:[2,26],70:[2,26],71:[2,26],75:[2,26],77:[2,26],81:[2,26],82:[2,26],83:[2,26],88:[2,26],90:[2,26],99:[2,26],101:[2,26],102:[2,26],103:[2,26],107:[2,26],113:[2,26],114:[2,26],115:[2,26],123:[2,26],125:[2,26],126:[2,26],127:[2,26],128:[2,26],129:[2,26],130:[2,26],131:[2,26],132:[2,26],133:[2,26],134:[2,26],135:[2,26]},{1:[2,6],6:[2,6],7:169,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,6],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],99:[2,6],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,3]},{1:[2,24],6:[2,24],25:[2,24],26:[2,24],47:[2,24],52:[2,24],55:[2,24],70:[2,24],75:[2,24],83:[2,24],88:[2,24],90:[2,24],95:[2,24],96:[2,24],99:[2,24],101:[2,24],102:[2,24],103:[2,24],107:[2,24],115:[2,24],118:[2,24],120:[2,24],123:[2,24],125:[2,24],126:[2,24],129:[2,24],130:[2,24],131:[2,24],132:[2,24],133:[2,24],134:[2,24]},{6:[1,72],26:[1,170]},{1:[2,185],6:[2,185],25:[2,185],26:[2,185],47:[2,185],52:[2,185],55:[2,185],70:[2,185],75:[2,185],83:[2,185],88:[2,185],90:[2,185],99:[2,185],101:[2,185],102:[2,185],103:[2,185],107:[2,185],115:[2,185],123:[2,185],125:[2,185],126:[2,185],129:[2,185],130:[2,185],131:[2,185],132:[2,185],133:[2,185],134:[2,185]},{8:171,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:172,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:173,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:174,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:175,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:176,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:177,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:178,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,141],6:[2,141],25:[2,141],26:[2,141],47:[2,141],52:[2,141],55:[2,141],70:[2,141],75:[2,141],83:[2,141],88:[2,141],90:[2,141],99:[2,141],101:[2,141],102:[2,141],103:[2,141],107:[2,141],115:[2,141],123:[2,141],125:[2,141],126:[2,141],129:[2,141],130:[2,141],131:[2,141],132:[2,141],133:[2,141],134:[2,141]},{1:[2,146],6:[2,146],25:[2,146],26:[2,146],47:[2,146],52:[2,146],55:[2,146],70:[2,146],75:[2,146],83:[2,146],88:[2,146],90:[2,146],99:[2,146],101:[2,146],102:[2,146],103:[2,146],107:[2,146],115:[2,146],123:[2,146],125:[2,146],126:[2,146],129:[2,146],130:[2,146],131:[2,146],132:[2,146],133:[2,146],134:[2,146]},{8:179,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,140],6:[2,140],25:[2,140],26:[2,140],47:[2,140],52:[2,140],55:[2,140],70:[2,140],75:[2,140],83:[2,140],88:[2,140],90:[2,140],99:[2,140],101:[2,140],102:[2,140],103:[2,140],107:[2,140],115:[2,140],123:[2,140],125:[2,140],126:[2,140],129:[2,140],130:[2,140],131:[2,140],132:[2,140],133:[2,140],134:[2,140]},{1:[2,145],6:[2,145],25:[2,145],26:[2,145],47:[2,145],52:[2,145],55:[2,145],70:[2,145],75:[2,145],83:[2,145],88:[2,145],90:[2,145],99:[2,145],101:[2,145],102:[2,145],103:[2,145],107:[2,145],115:[2,145],123:[2,145],125:[2,145],126:[2,145],129:[2,145],130:[2,145],131:[2,145],132:[2,145],133:[2,145],134:[2,145]},{79:180,82:[1,103]},{1:[2,65],6:[2,65],25:[2,65],26:[2,65],38:[2,65],47:[2,65],52:[2,65],55:[2,65],64:[2,65],65:[2,65],66:[2,65],68:[2,65],70:[2,65],71:[2,65],75:[2,65],77:[2,65],81:[2,65],82:[2,65],83:[2,65],88:[2,65],90:[2,65],99:[2,65],101:[2,65],102:[2,65],103:[2,65],107:[2,65],115:[2,65],123:[2,65],125:[2,65],126:[2,65],127:[2,65],128:[2,65],129:[2,65],130:[2,65],131:[2,65],132:[2,65],133:[2,65],134:[2,65],135:[2,65]},{82:[2,104]},{27:181,28:[1,71]},{27:182,28:[1,71]},{1:[2,79],6:[2,79],25:[2,79],26:[2,79],27:183,28:[1,71],38:[2,79],47:[2,79],52:[2,79],55:[2,79],64:[2,79],65:[2,79],66:[2,79],68:[2,79],70:[2,79],71:[2,79],75:[2,79],77:[2,79],81:[2,79],82:[2,79],83:[2,79],88:[2,79],90:[2,79],99:[2,79],101:[2,79],102:[2,79],103:[2,79],107:[2,79],115:[2,79],123:[2,79],125:[2,79],126:[2,79],127:[2,79],128:[2,79],129:[2,79],130:[2,79],131:[2,79],132:[2,79],133:[2,79],134:[2,79],135:[2,79]},{1:[2,80],6:[2,80],25:[2,80],26:[2,80],38:[2,80],47:[2,80],52:[2,80],55:[2,80],64:[2,80],65:[2,80],66:[2,80],68:[2,80],70:[2,80],71:[2,80],75:[2,80],77:[2,80],81:[2,80],82:[2,80],83:[2,80],88:[2,80],90:[2,80],99:[2,80],101:[2,80],102:[2,80],103:[2,80],107:[2,80],115:[2,80],123:[2,80],125:[2,80],126:[2,80],127:[2,80],128:[2,80],129:[2,80],130:[2,80],131:[2,80],132:[2,80],133:[2,80],134:[2,80],135:[2,80]},{8:185,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],55:[1,189],56:47,57:48,59:36,61:25,62:26,63:27,69:184,72:186,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],89:187,90:[1,188],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{67:190,68:[1,97],71:[1,98]},{79:191,82:[1,103]},{1:[2,66],6:[2,66],25:[2,66],26:[2,66],38:[2,66],47:[2,66],52:[2,66],55:[2,66],64:[2,66],65:[2,66],66:[2,66],68:[2,66],70:[2,66],71:[2,66],75:[2,66],77:[2,66],81:[2,66],82:[2,66],83:[2,66],88:[2,66],90:[2,66],99:[2,66],101:[2,66],102:[2,66],103:[2,66],107:[2,66],115:[2,66],123:[2,66],125:[2,66],126:[2,66],127:[2,66],128:[2,66],129:[2,66],130:[2,66],131:[2,66],132:[2,66],133:[2,66],134:[2,66],135:[2,66]},{6:[1,193],8:192,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,194],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,102],6:[2,102],25:[2,102],26:[2,102],47:[2,102],52:[2,102],55:[2,102],64:[2,102],65:[2,102],66:[2,102],68:[2,102],70:[2,102],71:[2,102],75:[2,102],81:[2,102],82:[2,102],83:[2,102],88:[2,102],90:[2,102],99:[2,102],101:[2,102],102:[2,102],103:[2,102],107:[2,102],115:[2,102],123:[2,102],125:[2,102],126:[2,102],129:[2,102],130:[2,102],131:[2,102],132:[2,102],133:[2,102],134:[2,102]},{8:197,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,144],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,58:145,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],83:[1,195],84:196,85:[1,56],86:[1,57],87:[1,55],91:143,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{47:[1,198],52:[1,199]},{47:[2,54],52:[2,54]},{38:[1,201],47:[2,56],52:[2,56],55:[1,200]},{38:[2,59],47:[2,59],52:[2,59],55:[2,59]},{38:[2,60],47:[2,60],52:[2,60],55:[2,60]},{38:[2,61],47:[2,61],52:[2,61],55:[2,61]},{38:[2,62],47:[2,62],52:[2,62],55:[2,62]},{27:146,28:[1,71]},{8:197,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,144],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,58:145,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],84:142,85:[1,56],86:[1,57],87:[1,55],88:[1,141],91:143,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,48],6:[2,48],25:[2,48],26:[2,48],47:[2,48],52:[2,48],55:[2,48],70:[2,48],75:[2,48],83:[2,48],88:[2,48],90:[2,48],99:[2,48],101:[2,48],102:[2,48],103:[2,48],107:[2,48],115:[2,48],123:[2,48],125:[2,48],126:[2,48],129:[2,48],130:[2,48],131:[2,48],132:[2,48],133:[2,48],134:[2,48]},{1:[2,178],6:[2,178],25:[2,178],26:[2,178],47:[2,178],52:[2,178],55:[2,178],70:[2,178],75:[2,178],83:[2,178],88:[2,178],90:[2,178],99:[2,178],100:85,101:[2,178],102:[2,178],103:[2,178],106:86,107:[2,178],108:67,115:[2,178],123:[2,178],125:[2,178],126:[2,178],129:[1,76],130:[2,178],131:[2,178],132:[2,178],133:[2,178],134:[2,178]},{100:88,101:[1,63],103:[1,64],106:89,107:[1,66],108:67,123:[1,87]},{1:[2,179],6:[2,179],25:[2,179],26:[2,179],47:[2,179],52:[2,179],55:[2,179],70:[2,179],75:[2,179],83:[2,179],88:[2,179],90:[2,179],99:[2,179],100:85,101:[2,179],102:[2,179],103:[2,179],106:86,107:[2,179],108:67,115:[2,179],123:[2,179],125:[2,179],126:[2,179],129:[1,76],130:[2,179],131:[2,179],132:[2,179],133:[2,179],134:[2,179]},{1:[2,180],6:[2,180],25:[2,180],26:[2,180],47:[2,180],52:[2,180],55:[2,180],70:[2,180],75:[2,180],83:[2,180],88:[2,180],90:[2,180],99:[2,180],100:85,101:[2,180],102:[2,180],103:[2,180],106:86,107:[2,180],108:67,115:[2,180],123:[2,180],125:[2,180],126:[2,180],129:[1,76],130:[2,180],131:[2,180],132:[2,180],133:[2,180],134:[2,180]},{1:[2,181],6:[2,181],25:[2,181],26:[2,181],47:[2,181],52:[2,181],55:[2,181],64:[2,68],65:[2,68],66:[2,68],68:[2,68],70:[2,181],71:[2,68],75:[2,181],81:[2,68],82:[2,68],83:[2,181],88:[2,181],90:[2,181],99:[2,181],101:[2,181],102:[2,181],103:[2,181],107:[2,181],115:[2,181],123:[2,181],125:[2,181],126:[2,181],129:[2,181],130:[2,181],131:[2,181],132:[2,181],133:[2,181],134:[2,181]},{60:91,64:[1,93],65:[1,94],66:[1,95],67:96,68:[1,97],71:[1,98],78:90,81:[1,92],82:[2,103]},{60:100,64:[1,93],65:[1,94],66:[1,95],67:96,68:[1,97],71:[1,98],78:99,81:[1,92],82:[2,103]},{64:[2,71],65:[2,71],66:[2,71],68:[2,71],71:[2,71],81:[2,71],82:[2,71]},{1:[2,182],6:[2,182],25:[2,182],26:[2,182],47:[2,182],52:[2,182],55:[2,182],64:[2,68],65:[2,68],66:[2,68],68:[2,68],70:[2,182],71:[2,68],75:[2,182],81:[2,68],82:[2,68],83:[2,182],88:[2,182],90:[2,182],99:[2,182],101:[2,182],102:[2,182],103:[2,182],107:[2,182],115:[2,182],123:[2,182],125:[2,182],126:[2,182],129:[2,182],130:[2,182],131:[2,182],132:[2,182],133:[2,182],134:[2,182]},{1:[2,183],6:[2,183],25:[2,183],26:[2,183],47:[2,183],52:[2,183],55:[2,183],70:[2,183],75:[2,183],83:[2,183],88:[2,183],90:[2,183],99:[2,183],101:[2,183],102:[2,183],103:[2,183],107:[2,183],115:[2,183],123:[2,183],125:[2,183],126:[2,183],129:[2,183],130:[2,183],131:[2,183],132:[2,183],133:[2,183],134:[2,183]},{1:[2,184],6:[2,184],25:[2,184],26:[2,184],47:[2,184],52:[2,184],55:[2,184],70:[2,184],75:[2,184],83:[2,184],88:[2,184],90:[2,184],99:[2,184],101:[2,184],102:[2,184],103:[2,184],107:[2,184],115:[2,184],123:[2,184],125:[2,184],126:[2,184],129:[2,184],130:[2,184],131:[2,184],132:[2,184],133:[2,184],134:[2,184]},{8:202,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,203],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:204,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{5:205,25:[1,5],122:[1,206]},{1:[2,127],6:[2,127],25:[2,127],26:[2,127],47:[2,127],52:[2,127],55:[2,127],70:[2,127],75:[2,127],83:[2,127],88:[2,127],90:[2,127],94:207,95:[1,208],96:[1,209],99:[2,127],101:[2,127],102:[2,127],103:[2,127],107:[2,127],115:[2,127],123:[2,127],125:[2,127],126:[2,127],129:[2,127],130:[2,127],131:[2,127],132:[2,127],133:[2,127],134:[2,127]},{1:[2,139],6:[2,139],25:[2,139],26:[2,139],47:[2,139],52:[2,139],55:[2,139],70:[2,139],75:[2,139],83:[2,139],88:[2,139],90:[2,139],99:[2,139],101:[2,139],102:[2,139],103:[2,139],107:[2,139],115:[2,139],123:[2,139],125:[2,139],126:[2,139],129:[2,139],130:[2,139],131:[2,139],132:[2,139],133:[2,139],134:[2,139]},{1:[2,147],6:[2,147],25:[2,147],26:[2,147],47:[2,147],52:[2,147],55:[2,147],70:[2,147],75:[2,147],83:[2,147],88:[2,147],90:[2,147],99:[2,147],101:[2,147],102:[2,147],103:[2,147],107:[2,147],115:[2,147],123:[2,147],125:[2,147],126:[2,147],129:[2,147],130:[2,147],131:[2,147],132:[2,147],133:[2,147],134:[2,147]},{25:[1,210],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{117:211,119:212,120:[1,213]},{1:[2,92],6:[2,92],25:[2,92],26:[2,92],47:[2,92],52:[2,92],55:[2,92],70:[2,92],75:[2,92],83:[2,92],88:[2,92],90:[2,92],99:[2,92],101:[2,92],102:[2,92],103:[2,92],107:[2,92],115:[2,92],123:[2,92],125:[2,92],126:[2,92],129:[2,92],130:[2,92],131:[2,92],132:[2,92],133:[2,92],134:[2,92]},{8:214,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,95],5:215,6:[2,95],25:[1,5],26:[2,95],47:[2,95],52:[2,95],55:[2,95],64:[2,68],65:[2,68],66:[2,68],68:[2,68],70:[2,95],71:[2,68],75:[2,95],77:[1,216],81:[2,68],82:[2,68],83:[2,95],88:[2,95],90:[2,95],99:[2,95],101:[2,95],102:[2,95],103:[2,95],107:[2,95],115:[2,95],123:[2,95],125:[2,95],126:[2,95],129:[2,95],130:[2,95],131:[2,95],132:[2,95],133:[2,95],134:[2,95]},{1:[2,132],6:[2,132],25:[2,132],26:[2,132],47:[2,132],52:[2,132],55:[2,132],70:[2,132],75:[2,132],83:[2,132],88:[2,132],90:[2,132],99:[2,132],100:85,101:[2,132],102:[2,132],103:[2,132],106:86,107:[2,132],108:67,115:[2,132],123:[2,132],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,44],6:[2,44],26:[2,44],99:[2,44],100:85,101:[2,44],103:[2,44],106:86,107:[2,44],108:67,123:[2,44],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{6:[1,72],99:[1,217]},{4:218,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{6:[2,123],25:[2,123],52:[2,123],55:[1,220],88:[2,123],89:219,90:[1,188],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,110],6:[2,110],25:[2,110],26:[2,110],38:[2,110],47:[2,110],52:[2,110],55:[2,110],64:[2,110],65:[2,110],66:[2,110],68:[2,110],70:[2,110],71:[2,110],75:[2,110],81:[2,110],82:[2,110],83:[2,110],88:[2,110],90:[2,110],99:[2,110],101:[2,110],102:[2,110],103:[2,110],107:[2,110],113:[2,110],114:[2,110],115:[2,110],123:[2,110],125:[2,110],126:[2,110],129:[2,110],130:[2,110],131:[2,110],132:[2,110],133:[2,110],134:[2,110]},{6:[2,51],25:[2,51],51:221,52:[1,222],88:[2,51]},{6:[2,118],25:[2,118],26:[2,118],52:[2,118],83:[2,118],88:[2,118]},{8:197,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,144],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,58:145,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],84:223,85:[1,56],86:[1,57],87:[1,55],91:143,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{6:[2,124],25:[2,124],26:[2,124],52:[2,124],83:[2,124],88:[2,124]},{1:[2,109],6:[2,109],25:[2,109],26:[2,109],38:[2,109],41:[2,109],47:[2,109],52:[2,109],55:[2,109],64:[2,109],65:[2,109],66:[2,109],68:[2,109],70:[2,109],71:[2,109],75:[2,109],77:[2,109],81:[2,109],82:[2,109],83:[2,109],88:[2,109],90:[2,109],99:[2,109],101:[2,109],102:[2,109],103:[2,109],107:[2,109],115:[2,109],123:[2,109],125:[2,109],126:[2,109],127:[2,109],128:[2,109],129:[2,109],130:[2,109],131:[2,109],132:[2,109],133:[2,109],134:[2,109],135:[2,109]},{5:224,25:[1,5],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,135],6:[2,135],25:[2,135],26:[2,135],47:[2,135],52:[2,135],55:[2,135],70:[2,135],75:[2,135],83:[2,135],88:[2,135],90:[2,135],99:[2,135],100:85,101:[1,63],102:[1,225],103:[1,64],106:86,107:[1,66],108:67,115:[2,135],123:[2,135],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,137],6:[2,137],25:[2,137],26:[2,137],47:[2,137],52:[2,137],55:[2,137],70:[2,137],75:[2,137],83:[2,137],88:[2,137],90:[2,137],99:[2,137],100:85,101:[1,63],102:[1,226],103:[1,64],106:86,107:[1,66],108:67,115:[2,137],123:[2,137],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,143],6:[2,143],25:[2,143],26:[2,143],47:[2,143],52:[2,143],55:[2,143],70:[2,143],75:[2,143],83:[2,143],88:[2,143],90:[2,143],99:[2,143],101:[2,143],102:[2,143],103:[2,143],107:[2,143],115:[2,143],123:[2,143],125:[2,143],126:[2,143],129:[2,143],130:[2,143],131:[2,143],132:[2,143],133:[2,143],134:[2,143]},{1:[2,144],6:[2,144],25:[2,144],26:[2,144],47:[2,144],52:[2,144],55:[2,144],70:[2,144],75:[2,144],83:[2,144],88:[2,144],90:[2,144],99:[2,144],100:85,101:[1,63],102:[2,144],103:[1,64],106:86,107:[1,66],108:67,115:[2,144],123:[2,144],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,148],6:[2,148],25:[2,148],26:[2,148],47:[2,148],52:[2,148],55:[2,148],70:[2,148],75:[2,148],83:[2,148],88:[2,148],90:[2,148],99:[2,148],101:[2,148],102:[2,148],103:[2,148],107:[2,148],115:[2,148],123:[2,148],125:[2,148],126:[2,148],129:[2,148],130:[2,148],131:[2,148],132:[2,148],133:[2,148],134:[2,148]},{113:[2,150],114:[2,150]},{27:156,28:[1,71],56:157,57:158,73:[1,68],87:[1,112],110:227,112:155},{52:[1,228],113:[2,155],114:[2,155]},{52:[2,152],113:[2,152],114:[2,152]},{52:[2,153],113:[2,153],114:[2,153]},{52:[2,154],113:[2,154],114:[2,154]},{1:[2,149],6:[2,149],25:[2,149],26:[2,149],47:[2,149],52:[2,149],55:[2,149],70:[2,149],75:[2,149],83:[2,149],88:[2,149],90:[2,149],99:[2,149],101:[2,149],102:[2,149],103:[2,149],107:[2,149],115:[2,149],123:[2,149],125:[2,149],126:[2,149],129:[2,149],130:[2,149],131:[2,149],132:[2,149],133:[2,149],134:[2,149]},{8:229,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:230,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{6:[2,51],25:[2,51],51:231,52:[1,232],75:[2,51]},{6:[2,87],25:[2,87],26:[2,87],52:[2,87],75:[2,87]},{6:[2,37],25:[2,37],26:[2,37],41:[1,233],52:[2,37],75:[2,37]},{6:[2,40],25:[2,40],26:[2,40],52:[2,40],75:[2,40]},{6:[2,41],25:[2,41],26:[2,41],41:[2,41],52:[2,41],75:[2,41]},{6:[2,42],25:[2,42],26:[2,42],41:[2,42],52:[2,42],75:[2,42]},{6:[2,43],25:[2,43],26:[2,43],41:[2,43],52:[2,43],75:[2,43]},{1:[2,5],6:[2,5],26:[2,5],99:[2,5]},{1:[2,25],6:[2,25],25:[2,25],26:[2,25],47:[2,25],52:[2,25],55:[2,25],70:[2,25],75:[2,25],83:[2,25],88:[2,25],90:[2,25],95:[2,25],96:[2,25],99:[2,25],101:[2,25],102:[2,25],103:[2,25],107:[2,25],115:[2,25],118:[2,25],120:[2,25],123:[2,25],125:[2,25],126:[2,25],129:[2,25],130:[2,25],131:[2,25],132:[2,25],133:[2,25],134:[2,25]},{1:[2,186],6:[2,186],25:[2,186],26:[2,186],47:[2,186],52:[2,186],55:[2,186],70:[2,186],75:[2,186],83:[2,186],88:[2,186],90:[2,186],99:[2,186],100:85,101:[2,186],102:[2,186],103:[2,186],106:86,107:[2,186],108:67,115:[2,186],123:[2,186],125:[2,186],126:[2,186],129:[1,76],130:[1,79],131:[2,186],132:[2,186],133:[2,186],134:[2,186]},{1:[2,187],6:[2,187],25:[2,187],26:[2,187],47:[2,187],52:[2,187],55:[2,187],70:[2,187],75:[2,187],83:[2,187],88:[2,187],90:[2,187],99:[2,187],100:85,101:[2,187],102:[2,187],103:[2,187],106:86,107:[2,187],108:67,115:[2,187],123:[2,187],125:[2,187],126:[2,187],129:[1,76],130:[1,79],131:[2,187],132:[2,187],133:[2,187],134:[2,187]},{1:[2,188],6:[2,188],25:[2,188],26:[2,188],47:[2,188],52:[2,188],55:[2,188],70:[2,188],75:[2,188],83:[2,188],88:[2,188],90:[2,188],99:[2,188],100:85,101:[2,188],102:[2,188],103:[2,188],106:86,107:[2,188],108:67,115:[2,188],123:[2,188],125:[2,188],126:[2,188],129:[1,76],130:[2,188],131:[2,188],132:[2,188],133:[2,188],134:[2,188]},{1:[2,189],6:[2,189],25:[2,189],26:[2,189],47:[2,189],52:[2,189],55:[2,189],70:[2,189],75:[2,189],83:[2,189],88:[2,189],90:[2,189],99:[2,189],100:85,101:[2,189],102:[2,189],103:[2,189],106:86,107:[2,189],108:67,115:[2,189],123:[2,189],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[2,189],132:[2,189],133:[2,189],134:[2,189]},{1:[2,190],6:[2,190],25:[2,190],26:[2,190],47:[2,190],52:[2,190],55:[2,190],70:[2,190],75:[2,190],83:[2,190],88:[2,190],90:[2,190],99:[2,190],100:85,101:[2,190],102:[2,190],103:[2,190],106:86,107:[2,190],108:67,115:[2,190],123:[2,190],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[2,190],133:[2,190],134:[1,83]},{1:[2,191],6:[2,191],25:[2,191],26:[2,191],47:[2,191],52:[2,191],55:[2,191],70:[2,191],75:[2,191],83:[2,191],88:[2,191],90:[2,191],99:[2,191],100:85,101:[2,191],102:[2,191],103:[2,191],106:86,107:[2,191],108:67,115:[2,191],123:[2,191],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[2,191],134:[1,83]},{1:[2,192],6:[2,192],25:[2,192],26:[2,192],47:[2,192],52:[2,192],55:[2,192],70:[2,192],75:[2,192],83:[2,192],88:[2,192],90:[2,192],99:[2,192],100:85,101:[2,192],102:[2,192],103:[2,192],106:86,107:[2,192],108:67,115:[2,192],123:[2,192],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[2,192],133:[2,192],134:[2,192]},{1:[2,177],6:[2,177],25:[2,177],26:[2,177],47:[2,177],52:[2,177],55:[2,177],70:[2,177],75:[2,177],83:[2,177],88:[2,177],90:[2,177],99:[2,177],100:85,101:[1,63],102:[2,177],103:[1,64],106:86,107:[1,66],108:67,115:[2,177],123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,176],6:[2,176],25:[2,176],26:[2,176],47:[2,176],52:[2,176],55:[2,176],70:[2,176],75:[2,176],83:[2,176],88:[2,176],90:[2,176],99:[2,176],100:85,101:[1,63],102:[2,176],103:[1,64],106:86,107:[1,66],108:67,115:[2,176],123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,99],6:[2,99],25:[2,99],26:[2,99],47:[2,99],52:[2,99],55:[2,99],64:[2,99],65:[2,99],66:[2,99],68:[2,99],70:[2,99],71:[2,99],75:[2,99],81:[2,99],82:[2,99],83:[2,99],88:[2,99],90:[2,99],99:[2,99],101:[2,99],102:[2,99],103:[2,99],107:[2,99],115:[2,99],123:[2,99],125:[2,99],126:[2,99],129:[2,99],130:[2,99],131:[2,99],132:[2,99],133:[2,99],134:[2,99]},{1:[2,76],6:[2,76],25:[2,76],26:[2,76],38:[2,76],47:[2,76],52:[2,76],55:[2,76],64:[2,76],65:[2,76],66:[2,76],68:[2,76],70:[2,76],71:[2,76],75:[2,76],77:[2,76],81:[2,76],82:[2,76],83:[2,76],88:[2,76],90:[2,76],99:[2,76],101:[2,76],102:[2,76],103:[2,76],107:[2,76],115:[2,76],123:[2,76],125:[2,76],126:[2,76],127:[2,76],128:[2,76],129:[2,76],130:[2,76],131:[2,76],132:[2,76],133:[2,76],134:[2,76],135:[2,76]},{1:[2,77],6:[2,77],25:[2,77],26:[2,77],38:[2,77],47:[2,77],52:[2,77],55:[2,77],64:[2,77],65:[2,77],66:[2,77],68:[2,77],70:[2,77],71:[2,77],75:[2,77],77:[2,77],81:[2,77],82:[2,77],83:[2,77],88:[2,77],90:[2,77],99:[2,77],101:[2,77],102:[2,77],103:[2,77],107:[2,77],115:[2,77],123:[2,77],125:[2,77],126:[2,77],127:[2,77],128:[2,77],129:[2,77],130:[2,77],131:[2,77],132:[2,77],133:[2,77],134:[2,77],135:[2,77]},{1:[2,78],6:[2,78],25:[2,78],26:[2,78],38:[2,78],47:[2,78],52:[2,78],55:[2,78],64:[2,78],65:[2,78],66:[2,78],68:[2,78],70:[2,78],71:[2,78],75:[2,78],77:[2,78],81:[2,78],82:[2,78],83:[2,78],88:[2,78],90:[2,78],99:[2,78],101:[2,78],102:[2,78],103:[2,78],107:[2,78],115:[2,78],123:[2,78],125:[2,78],126:[2,78],127:[2,78],128:[2,78],129:[2,78],130:[2,78],131:[2,78],132:[2,78],133:[2,78],134:[2,78],135:[2,78]},{70:[1,234]},{55:[1,189],70:[2,83],89:235,90:[1,188],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{70:[2,84]},{8:236,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{12:[2,112],28:[2,112],30:[2,112],31:[2,112],33:[2,112],34:[2,112],35:[2,112],36:[2,112],43:[2,112],44:[2,112],45:[2,112],49:[2,112],50:[2,112],70:[2,112],73:[2,112],76:[2,112],80:[2,112],85:[2,112],86:[2,112],87:[2,112],93:[2,112],97:[2,112],98:[2,112],101:[2,112],103:[2,112],105:[2,112],107:[2,112],116:[2,112],122:[2,112],124:[2,112],125:[2,112],126:[2,112],127:[2,112],128:[2,112]},{12:[2,113],28:[2,113],30:[2,113],31:[2,113],33:[2,113],34:[2,113],35:[2,113],36:[2,113],43:[2,113],44:[2,113],45:[2,113],49:[2,113],50:[2,113],70:[2,113],73:[2,113],76:[2,113],80:[2,113],85:[2,113],86:[2,113],87:[2,113],93:[2,113],97:[2,113],98:[2,113],101:[2,113],103:[2,113],105:[2,113],107:[2,113],116:[2,113],122:[2,113],124:[2,113],125:[2,113],126:[2,113],127:[2,113],128:[2,113]},{1:[2,82],6:[2,82],25:[2,82],26:[2,82],38:[2,82],47:[2,82],52:[2,82],55:[2,82],64:[2,82],65:[2,82],66:[2,82],68:[2,82],70:[2,82],71:[2,82],75:[2,82],77:[2,82],81:[2,82],82:[2,82],83:[2,82],88:[2,82],90:[2,82],99:[2,82],101:[2,82],102:[2,82],103:[2,82],107:[2,82],115:[2,82],123:[2,82],125:[2,82],126:[2,82],127:[2,82],128:[2,82],129:[2,82],130:[2,82],131:[2,82],132:[2,82],133:[2,82],134:[2,82],135:[2,82]},{1:[2,100],6:[2,100],25:[2,100],26:[2,100],47:[2,100],52:[2,100],55:[2,100],64:[2,100],65:[2,100],66:[2,100],68:[2,100],70:[2,100],71:[2,100],75:[2,100],81:[2,100],82:[2,100],83:[2,100],88:[2,100],90:[2,100],99:[2,100],101:[2,100],102:[2,100],103:[2,100],107:[2,100],115:[2,100],123:[2,100],125:[2,100],126:[2,100],129:[2,100],130:[2,100],131:[2,100],132:[2,100],133:[2,100],134:[2,100]},{1:[2,34],6:[2,34],25:[2,34],26:[2,34],47:[2,34],52:[2,34],55:[2,34],70:[2,34],75:[2,34],83:[2,34],88:[2,34],90:[2,34],99:[2,34],100:85,101:[2,34],102:[2,34],103:[2,34],106:86,107:[2,34],108:67,115:[2,34],123:[2,34],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{8:237,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:238,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,105],6:[2,105],25:[2,105],26:[2,105],47:[2,105],52:[2,105],55:[2,105],64:[2,105],65:[2,105],66:[2,105],68:[2,105],70:[2,105],71:[2,105],75:[2,105],81:[2,105],82:[2,105],83:[2,105],88:[2,105],90:[2,105],99:[2,105],101:[2,105],102:[2,105],103:[2,105],107:[2,105],115:[2,105],123:[2,105],125:[2,105],126:[2,105],129:[2,105],130:[2,105],131:[2,105],132:[2,105],133:[2,105],134:[2,105]},{6:[2,51],25:[2,51],51:239,52:[1,222],83:[2,51]},{6:[2,123],25:[2,123],26:[2,123],52:[2,123],55:[1,240],83:[2,123],88:[2,123],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{48:241,49:[1,58],50:[1,59]},{27:107,28:[1,71],42:108,53:242,54:106,56:109,57:110,73:[1,68],86:[1,111],87:[1,112]},{47:[2,57],52:[2,57]},{8:243,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,193],6:[2,193],25:[2,193],26:[2,193],47:[2,193],52:[2,193],55:[2,193],70:[2,193],75:[2,193],83:[2,193],88:[2,193],90:[2,193],99:[2,193],100:85,101:[2,193],102:[2,193],103:[2,193],106:86,107:[2,193],108:67,115:[2,193],123:[2,193],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{8:244,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,195],6:[2,195],25:[2,195],26:[2,195],47:[2,195],52:[2,195],55:[2,195],70:[2,195],75:[2,195],83:[2,195],88:[2,195],90:[2,195],99:[2,195],100:85,101:[2,195],102:[2,195],103:[2,195],106:86,107:[2,195],108:67,115:[2,195],123:[2,195],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,175],6:[2,175],25:[2,175],26:[2,175],47:[2,175],52:[2,175],55:[2,175],70:[2,175],75:[2,175],83:[2,175],88:[2,175],90:[2,175],99:[2,175],101:[2,175],102:[2,175],103:[2,175],107:[2,175],115:[2,175],123:[2,175],125:[2,175],126:[2,175],129:[2,175],130:[2,175],131:[2,175],132:[2,175],133:[2,175],134:[2,175]},{8:245,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,128],6:[2,128],25:[2,128],26:[2,128],47:[2,128],52:[2,128],55:[2,128],70:[2,128],75:[2,128],83:[2,128],88:[2,128],90:[2,128],95:[1,246],99:[2,128],101:[2,128],102:[2,128],103:[2,128],107:[2,128],115:[2,128],123:[2,128],125:[2,128],126:[2,128],129:[2,128],130:[2,128],131:[2,128],132:[2,128],133:[2,128],134:[2,128]},{5:247,25:[1,5]},{27:248,28:[1,71]},{117:249,119:212,120:[1,213]},{26:[1,250],118:[1,251],119:252,120:[1,213]},{26:[2,168],118:[2,168],120:[2,168]},{8:254,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],92:253,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,93],5:255,6:[2,93],25:[1,5],26:[2,93],47:[2,93],52:[2,93],55:[2,93],70:[2,93],75:[2,93],83:[2,93],88:[2,93],90:[2,93],99:[2,93],100:85,101:[1,63],102:[2,93],103:[1,64],106:86,107:[1,66],108:67,115:[2,93],123:[2,93],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,96],6:[2,96],25:[2,96],26:[2,96],47:[2,96],52:[2,96],55:[2,96],70:[2,96],75:[2,96],83:[2,96],88:[2,96],90:[2,96],99:[2,96],101:[2,96],102:[2,96],103:[2,96],107:[2,96],115:[2,96],123:[2,96],125:[2,96],126:[2,96],129:[2,96],130:[2,96],131:[2,96],132:[2,96],133:[2,96],134:[2,96]},{8:256,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,133],6:[2,133],25:[2,133],26:[2,133],47:[2,133],52:[2,133],55:[2,133],64:[2,133],65:[2,133],66:[2,133],68:[2,133],70:[2,133],71:[2,133],75:[2,133],81:[2,133],82:[2,133],83:[2,133],88:[2,133],90:[2,133],99:[2,133],101:[2,133],102:[2,133],103:[2,133],107:[2,133],115:[2,133],123:[2,133],125:[2,133],126:[2,133],129:[2,133],130:[2,133],131:[2,133],132:[2,133],133:[2,133],134:[2,133]},{6:[1,72],26:[1,257]},{8:258,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{6:[2,63],12:[2,113],25:[2,63],28:[2,113],30:[2,113],31:[2,113],33:[2,113],34:[2,113],35:[2,113],36:[2,113],43:[2,113],44:[2,113],45:[2,113],49:[2,113],50:[2,113],52:[2,63],73:[2,113],76:[2,113],80:[2,113],85:[2,113],86:[2,113],87:[2,113],88:[2,63],93:[2,113],97:[2,113],98:[2,113],101:[2,113],103:[2,113],105:[2,113],107:[2,113],116:[2,113],122:[2,113],124:[2,113],125:[2,113],126:[2,113],127:[2,113],128:[2,113]},{6:[1,260],25:[1,261],88:[1,259]},{6:[2,52],8:197,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[2,52],26:[2,52],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,58:145,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],83:[2,52],85:[1,56],86:[1,57],87:[1,55],88:[2,52],91:262,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{6:[2,51],25:[2,51],26:[2,51],51:263,52:[1,222]},{1:[2,172],6:[2,172],25:[2,172],26:[2,172],47:[2,172],52:[2,172],55:[2,172],70:[2,172],75:[2,172],83:[2,172],88:[2,172],90:[2,172],99:[2,172],101:[2,172],102:[2,172],103:[2,172],107:[2,172],115:[2,172],118:[2,172],123:[2,172],125:[2,172],126:[2,172],129:[2,172],130:[2,172],131:[2,172],132:[2,172],133:[2,172],134:[2,172]},{8:264,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:265,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{113:[2,151],114:[2,151]},{27:156,28:[1,71],56:157,57:158,73:[1,68],87:[1,112],112:266},{1:[2,157],6:[2,157],25:[2,157],26:[2,157],47:[2,157],52:[2,157],55:[2,157],70:[2,157],75:[2,157],83:[2,157],88:[2,157],90:[2,157],99:[2,157],100:85,101:[2,157],102:[1,267],103:[2,157],106:86,107:[2,157],108:67,115:[1,268],123:[2,157],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,158],6:[2,158],25:[2,158],26:[2,158],47:[2,158],52:[2,158],55:[2,158],70:[2,158],75:[2,158],83:[2,158],88:[2,158],90:[2,158],99:[2,158],100:85,101:[2,158],102:[1,269],103:[2,158],106:86,107:[2,158],108:67,115:[2,158],123:[2,158],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{6:[1,271],25:[1,272],75:[1,270]},{6:[2,52],11:165,25:[2,52],26:[2,52],27:166,28:[1,71],29:167,30:[1,69],31:[1,70],39:273,40:164,42:168,44:[1,46],75:[2,52],86:[1,111]},{8:274,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,275],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,81],6:[2,81],25:[2,81],26:[2,81],38:[2,81],47:[2,81],52:[2,81],55:[2,81],64:[2,81],65:[2,81],66:[2,81],68:[2,81],70:[2,81],71:[2,81],75:[2,81],77:[2,81],81:[2,81],82:[2,81],83:[2,81],88:[2,81],90:[2,81],99:[2,81],101:[2,81],102:[2,81],103:[2,81],107:[2,81],115:[2,81],123:[2,81],125:[2,81],126:[2,81],127:[2,81],128:[2,81],129:[2,81],130:[2,81],131:[2,81],132:[2,81],133:[2,81],134:[2,81],135:[2,81]},{8:276,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,70:[2,116],73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{70:[2,117],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,35],6:[2,35],25:[2,35],26:[2,35],47:[2,35],52:[2,35],55:[2,35],70:[2,35],75:[2,35],83:[2,35],88:[2,35],90:[2,35],99:[2,35],100:85,101:[2,35],102:[2,35],103:[2,35],106:86,107:[2,35],108:67,115:[2,35],123:[2,35],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{26:[1,277],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{6:[1,260],25:[1,261],83:[1,278]},{6:[2,63],25:[2,63],26:[2,63],52:[2,63],83:[2,63],88:[2,63]},{5:279,25:[1,5]},{47:[2,55],52:[2,55]},{47:[2,58],52:[2,58],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{26:[1,280],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{5:281,25:[1,5],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{5:282,25:[1,5]},{1:[2,129],6:[2,129],25:[2,129],26:[2,129],47:[2,129],52:[2,129],55:[2,129],70:[2,129],75:[2,129],83:[2,129],88:[2,129],90:[2,129],99:[2,129],101:[2,129],102:[2,129],103:[2,129],107:[2,129],115:[2,129],123:[2,129],125:[2,129],126:[2,129],129:[2,129],130:[2,129],131:[2,129],132:[2,129],133:[2,129],134:[2,129]},{5:283,25:[1,5]},{26:[1,284],118:[1,285],119:252,120:[1,213]},{1:[2,166],6:[2,166],25:[2,166],26:[2,166],47:[2,166],52:[2,166],55:[2,166],70:[2,166],75:[2,166],83:[2,166],88:[2,166],90:[2,166],99:[2,166],101:[2,166],102:[2,166],103:[2,166],107:[2,166],115:[2,166],123:[2,166],125:[2,166],126:[2,166],129:[2,166],130:[2,166],131:[2,166],132:[2,166],133:[2,166],134:[2,166]},{5:286,25:[1,5]},{26:[2,169],118:[2,169],120:[2,169]},{5:287,25:[1,5],52:[1,288]},{25:[2,125],52:[2,125],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,94],6:[2,94],25:[2,94],26:[2,94],47:[2,94],52:[2,94],55:[2,94],70:[2,94],75:[2,94],83:[2,94],88:[2,94],90:[2,94],99:[2,94],101:[2,94],102:[2,94],103:[2,94],107:[2,94],115:[2,94],123:[2,94],125:[2,94],126:[2,94],129:[2,94],130:[2,94],131:[2,94],132:[2,94],133:[2,94],134:[2,94]},{1:[2,97],5:289,6:[2,97],25:[1,5],26:[2,97],47:[2,97],52:[2,97],55:[2,97],70:[2,97],75:[2,97],83:[2,97],88:[2,97],90:[2,97],99:[2,97],100:85,101:[1,63],102:[2,97],103:[1,64],106:86,107:[1,66],108:67,115:[2,97],123:[2,97],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{99:[1,290]},{88:[1,291],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,111],6:[2,111],25:[2,111],26:[2,111],38:[2,111],47:[2,111],52:[2,111],55:[2,111],64:[2,111],65:[2,111],66:[2,111],68:[2,111],70:[2,111],71:[2,111],75:[2,111],81:[2,111],82:[2,111],83:[2,111],88:[2,111],90:[2,111],99:[2,111],101:[2,111],102:[2,111],103:[2,111],107:[2,111],113:[2,111],114:[2,111],115:[2,111],123:[2,111],125:[2,111],126:[2,111],129:[2,111],130:[2,111],131:[2,111],132:[2,111],133:[2,111],134:[2,111]},{8:197,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,58:145,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],91:292,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:197,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,144],27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,58:145,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],84:293,85:[1,56],86:[1,57],87:[1,55],91:143,93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{6:[2,119],25:[2,119],26:[2,119],52:[2,119],83:[2,119],88:[2,119]},{6:[1,260],25:[1,261],26:[1,294]},{1:[2,136],6:[2,136],25:[2,136],26:[2,136],47:[2,136],52:[2,136],55:[2,136],70:[2,136],75:[2,136],83:[2,136],88:[2,136],90:[2,136],99:[2,136],100:85,101:[1,63],102:[2,136],103:[1,64],106:86,107:[1,66],108:67,115:[2,136],123:[2,136],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,138],6:[2,138],25:[2,138],26:[2,138],47:[2,138],52:[2,138],55:[2,138],70:[2,138],75:[2,138],83:[2,138],88:[2,138],90:[2,138],99:[2,138],100:85,101:[1,63],102:[2,138],103:[1,64],106:86,107:[1,66],108:67,115:[2,138],123:[2,138],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{113:[2,156],114:[2,156]},{8:295,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:296,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:297,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,85],6:[2,85],25:[2,85],26:[2,85],38:[2,85],47:[2,85],52:[2,85],55:[2,85],64:[2,85],65:[2,85],66:[2,85],68:[2,85],70:[2,85],71:[2,85],75:[2,85],81:[2,85],82:[2,85],83:[2,85],88:[2,85],90:[2,85],99:[2,85],101:[2,85],102:[2,85],103:[2,85],107:[2,85],113:[2,85],114:[2,85],115:[2,85],123:[2,85],125:[2,85],126:[2,85],129:[2,85],130:[2,85],131:[2,85],132:[2,85],133:[2,85],134:[2,85]},{11:165,27:166,28:[1,71],29:167,30:[1,69],31:[1,70],39:298,40:164,42:168,44:[1,46],86:[1,111]},{6:[2,86],11:165,25:[2,86],26:[2,86],27:166,28:[1,71],29:167,30:[1,69],31:[1,70],39:163,40:164,42:168,44:[1,46],52:[2,86],74:299,86:[1,111]},{6:[2,88],25:[2,88],26:[2,88],52:[2,88],75:[2,88]},{6:[2,38],25:[2,38],26:[2,38],52:[2,38],75:[2,38],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{8:300,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{70:[2,115],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,36],6:[2,36],25:[2,36],26:[2,36],47:[2,36],52:[2,36],55:[2,36],70:[2,36],75:[2,36],83:[2,36],88:[2,36],90:[2,36],99:[2,36],101:[2,36],102:[2,36],103:[2,36],107:[2,36],115:[2,36],123:[2,36],125:[2,36],126:[2,36],129:[2,36],130:[2,36],131:[2,36],132:[2,36],133:[2,36],134:[2,36]},{1:[2,106],6:[2,106],25:[2,106],26:[2,106],47:[2,106],52:[2,106],55:[2,106],64:[2,106],65:[2,106],66:[2,106],68:[2,106],70:[2,106],71:[2,106],75:[2,106],81:[2,106],82:[2,106],83:[2,106],88:[2,106],90:[2,106],99:[2,106],101:[2,106],102:[2,106],103:[2,106],107:[2,106],115:[2,106],123:[2,106],125:[2,106],126:[2,106],129:[2,106],130:[2,106],131:[2,106],132:[2,106],133:[2,106],134:[2,106]},{1:[2,47],6:[2,47],25:[2,47],26:[2,47],47:[2,47],52:[2,47],55:[2,47],70:[2,47],75:[2,47],83:[2,47],88:[2,47],90:[2,47],99:[2,47],101:[2,47],102:[2,47],103:[2,47],107:[2,47],115:[2,47],123:[2,47],125:[2,47],126:[2,47],129:[2,47],130:[2,47],131:[2,47],132:[2,47],133:[2,47],134:[2,47]},{1:[2,194],6:[2,194],25:[2,194],26:[2,194],47:[2,194],52:[2,194],55:[2,194],70:[2,194],75:[2,194],83:[2,194],88:[2,194],90:[2,194],99:[2,194],101:[2,194],102:[2,194],103:[2,194],107:[2,194],115:[2,194],123:[2,194],125:[2,194],126:[2,194],129:[2,194],130:[2,194],131:[2,194],132:[2,194],133:[2,194],134:[2,194]},{1:[2,173],6:[2,173],25:[2,173],26:[2,173],47:[2,173],52:[2,173],55:[2,173],70:[2,173],75:[2,173],83:[2,173],88:[2,173],90:[2,173],99:[2,173],101:[2,173],102:[2,173],103:[2,173],107:[2,173],115:[2,173],118:[2,173],123:[2,173],125:[2,173],126:[2,173],129:[2,173],130:[2,173],131:[2,173],132:[2,173],133:[2,173],134:[2,173]},{1:[2,130],6:[2,130],25:[2,130],26:[2,130],47:[2,130],52:[2,130],55:[2,130],70:[2,130],75:[2,130],83:[2,130],88:[2,130],90:[2,130],99:[2,130],101:[2,130],102:[2,130],103:[2,130],107:[2,130],115:[2,130],123:[2,130],125:[2,130],126:[2,130],129:[2,130],130:[2,130],131:[2,130],132:[2,130],133:[2,130],134:[2,130]},{1:[2,131],6:[2,131],25:[2,131],26:[2,131],47:[2,131],52:[2,131],55:[2,131],70:[2,131],75:[2,131],83:[2,131],88:[2,131],90:[2,131],95:[2,131],99:[2,131],101:[2,131],102:[2,131],103:[2,131],107:[2,131],115:[2,131],123:[2,131],125:[2,131],126:[2,131],129:[2,131],130:[2,131],131:[2,131],132:[2,131],133:[2,131],134:[2,131]},{1:[2,164],6:[2,164],25:[2,164],26:[2,164],47:[2,164],52:[2,164],55:[2,164],70:[2,164],75:[2,164],83:[2,164],88:[2,164],90:[2,164],99:[2,164],101:[2,164],102:[2,164],103:[2,164],107:[2,164],115:[2,164],123:[2,164],125:[2,164],126:[2,164],129:[2,164],130:[2,164],131:[2,164],132:[2,164],133:[2,164],134:[2,164]},{5:301,25:[1,5]},{26:[1,302]},{6:[1,303],26:[2,170],118:[2,170],120:[2,170]},{8:304,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{1:[2,98],6:[2,98],25:[2,98],26:[2,98],47:[2,98],52:[2,98],55:[2,98],70:[2,98],75:[2,98],83:[2,98],88:[2,98],90:[2,98],99:[2,98],101:[2,98],102:[2,98],103:[2,98],107:[2,98],115:[2,98],123:[2,98],125:[2,98],126:[2,98],129:[2,98],130:[2,98],131:[2,98],132:[2,98],133:[2,98],134:[2,98]},{1:[2,134],6:[2,134],25:[2,134],26:[2,134],47:[2,134],52:[2,134],55:[2,134],64:[2,134],65:[2,134],66:[2,134],68:[2,134],70:[2,134],71:[2,134],75:[2,134],81:[2,134],82:[2,134],83:[2,134],88:[2,134],90:[2,134],99:[2,134],101:[2,134],102:[2,134],103:[2,134],107:[2,134],115:[2,134],123:[2,134],125:[2,134],126:[2,134],129:[2,134],130:[2,134],131:[2,134],132:[2,134],133:[2,134],134:[2,134]},{1:[2,114],6:[2,114],25:[2,114],26:[2,114],47:[2,114],52:[2,114],55:[2,114],64:[2,114],65:[2,114],66:[2,114],68:[2,114],70:[2,114],71:[2,114],75:[2,114],81:[2,114],82:[2,114],83:[2,114],88:[2,114],90:[2,114],99:[2,114],101:[2,114],102:[2,114],103:[2,114],107:[2,114],115:[2,114],123:[2,114],125:[2,114],126:[2,114],129:[2,114],130:[2,114],131:[2,114],132:[2,114],133:[2,114],134:[2,114]},{6:[2,120],25:[2,120],26:[2,120],52:[2,120],83:[2,120],88:[2,120]},{6:[2,51],25:[2,51],26:[2,51],51:305,52:[1,222]},{6:[2,121],25:[2,121],26:[2,121],52:[2,121],83:[2,121],88:[2,121]},{1:[2,159],6:[2,159],25:[2,159],26:[2,159],47:[2,159],52:[2,159],55:[2,159],70:[2,159],75:[2,159],83:[2,159],88:[2,159],90:[2,159],99:[2,159],100:85,101:[2,159],102:[2,159],103:[2,159],106:86,107:[2,159],108:67,115:[1,306],123:[2,159],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,161],6:[2,161],25:[2,161],26:[2,161],47:[2,161],52:[2,161],55:[2,161],70:[2,161],75:[2,161],83:[2,161],88:[2,161],90:[2,161],99:[2,161],100:85,101:[2,161],102:[1,307],103:[2,161],106:86,107:[2,161],108:67,115:[2,161],123:[2,161],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,160],6:[2,160],25:[2,160],26:[2,160],47:[2,160],52:[2,160],55:[2,160],70:[2,160],75:[2,160],83:[2,160],88:[2,160],90:[2,160],99:[2,160],100:85,101:[2,160],102:[2,160],103:[2,160],106:86,107:[2,160],108:67,115:[2,160],123:[2,160],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{6:[2,89],25:[2,89],26:[2,89],52:[2,89],75:[2,89]},{6:[2,51],25:[2,51],26:[2,51],51:308,52:[1,232]},{26:[1,309],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{26:[1,310]},{1:[2,167],6:[2,167],25:[2,167],26:[2,167],47:[2,167],52:[2,167],55:[2,167],70:[2,167],75:[2,167],83:[2,167],88:[2,167],90:[2,167],99:[2,167],101:[2,167],102:[2,167],103:[2,167],107:[2,167],115:[2,167],123:[2,167],125:[2,167],126:[2,167],129:[2,167],130:[2,167],131:[2,167],132:[2,167],133:[2,167],134:[2,167]},{26:[2,171],118:[2,171],120:[2,171]},{25:[2,126],52:[2,126],100:85,101:[1,63],103:[1,64],106:86,107:[1,66],108:67,123:[1,84],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{6:[1,260],25:[1,261],26:[1,311]},{8:312,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{8:313,9:115,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:60,28:[1,71],29:49,30:[1,69],31:[1,70],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:23,42:61,43:[1,45],44:[1,46],45:[1,29],48:30,49:[1,58],50:[1,59],56:47,57:48,59:36,61:25,62:26,63:27,73:[1,68],76:[1,43],80:[1,28],85:[1,56],86:[1,57],87:[1,55],93:[1,38],97:[1,44],98:[1,54],100:39,101:[1,63],103:[1,64],104:40,105:[1,65],106:41,107:[1,66],108:67,116:[1,42],121:37,122:[1,62],124:[1,31],125:[1,32],126:[1,33],127:[1,34],128:[1,35]},{6:[1,271],25:[1,272],26:[1,314]},{6:[2,39],25:[2,39],26:[2,39],52:[2,39],75:[2,39]},{1:[2,165],6:[2,165],25:[2,165],26:[2,165],47:[2,165],52:[2,165],55:[2,165],70:[2,165],75:[2,165],83:[2,165],88:[2,165],90:[2,165],99:[2,165],101:[2,165],102:[2,165],103:[2,165],107:[2,165],115:[2,165],123:[2,165],125:[2,165],126:[2,165],129:[2,165],130:[2,165],131:[2,165],132:[2,165],133:[2,165],134:[2,165]},{6:[2,122],25:[2,122],26:[2,122],52:[2,122],83:[2,122],88:[2,122]},{1:[2,162],6:[2,162],25:[2,162],26:[2,162],47:[2,162],52:[2,162],55:[2,162],70:[2,162],75:[2,162],83:[2,162],88:[2,162],90:[2,162],99:[2,162],100:85,101:[2,162],102:[2,162],103:[2,162],106:86,107:[2,162],108:67,115:[2,162],123:[2,162],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{1:[2,163],6:[2,163],25:[2,163],26:[2,163],47:[2,163],52:[2,163],55:[2,163],70:[2,163],75:[2,163],83:[2,163],88:[2,163],90:[2,163],99:[2,163],100:85,101:[2,163],102:[2,163],103:[2,163],106:86,107:[2,163],108:67,115:[2,163],123:[2,163],125:[1,78],126:[1,77],129:[1,76],130:[1,79],131:[1,80],132:[1,81],133:[1,82],134:[1,83]},{6:[2,90],25:[2,90],26:[2,90],52:[2,90],75:[2,90]}],defaultActions:{58:[2,49],59:[2,50],73:[2,3],92:[2,104],186:[2,84]},parseError:function(a,b){throw new Error(a)},parse:function(a){function o(){var a;a=b.lexer.lex()||1,typeof a!="number"&&(a=b.symbols_[a]||a);return a}function n(a){c.length=c.length-2*a,d.length=d.length-a,e.length=e.length-a}var b=this,c=[0],d=[null],e=[],f=this.table,g="",h=0,i=0,j=0,k=2,l=1;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,typeof this.lexer.yylloc=="undefined"&&(this.lexer.yylloc={});var m=this.lexer.yylloc;e.push(m),typeof this.yy.parseError=="function"&&(this.parseError=this.yy.parseError);var p,q,r,s,t,u,v={},w,x,y,z;for(;;){r=c[c.length-1],this.defaultActions[r]?s=this.defaultActions[r]:(p==null&&(p=o()),s=f[r]&&f[r][p]);if(typeof s=="undefined"||!s.length||!s[0]){if(!j){z=[];for(w in f[r])this.terminals_[w]&&w>2&&z.push("'"+this.terminals_[w]+"'");var A="";this.lexer.showPosition?A="Parse error on line "+(h+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+z.join(", "):A="Parse error on line "+(h+1)+": Unexpected "+(p==1?"end of input":"'"+(this.terminals_[p]||p)+"'"),this.parseError(A,{text:this.lexer.match,token:this.terminals_[p]||p,line:this.lexer.yylineno,loc:m,expected:z})}if(j==3){if(p==l)throw new Error(A||"Parsing halted.");i=this.lexer.yyleng,g=this.lexer.yytext,h=this.lexer.yylineno,m=this.lexer.yylloc,p=o()}for(;;){if(k.toString()in f[r])break;if(r==0)throw new Error(A||"Parsing halted.");n(1),r=c[c.length-1]}q=p,p=k,r=c[c.length-1],s=f[r]&&f[r][k],j=3}if(s[0]instanceof Array&&s.length>1)throw new Error("Parse Error: multiple actions possible at state: "+r+", token: "+p);switch(s[0]){case 1:c.push(p),d.push(this.lexer.yytext),e.push(this.lexer.yylloc),c.push(s[1]),p=null,q?(p=q,q=null):(i=this.lexer.yyleng,g=this.lexer.yytext,h=this.lexer.yylineno,m=this.lexer.yylloc,j>0&&j--);break;case 2:x=this.productions_[s[1]][1],v.$=d[d.length-x],v._$={first_line:e[e.length-(x||1)].first_line,last_line:e[e.length-1].last_line,first_column:e[e.length-(x||1)].first_column,last_column:e[e.length-1].last_column},u=this.performAction.call(v,g,i,h,this.yy,s[1],d,e);if(typeof u!="undefined")return u;x&&(c=c.slice(0,-1*x*2),d=d.slice(0,-1*x),e=e.slice(0,-1*x)),c.push(this.productions_[s[1]][0]),d.push(v.$),e.push(v._$),y=f[c[c.length-2]][c[c.length-1]],c.push(y);break;case 3:return!0}}return!0}};return a}();typeof require!="undefined"&&typeof a!="undefined"&&(a.parser=b,a.parse=function(){return b.parse.apply(b,arguments)},a.main=function(b){if(!b[1])throw new Error("Usage: "+b[0]+" FILE");if(typeof process!="undefined")var c=require("fs").readFileSync(require("path").join(process.cwd(),b[1]),"utf8");else var d=require("file").path(require("file").cwd()),c=d.join(b[1]).read({charset:"utf-8"});return a.parser.parse(c)},typeof module!="undefined"&&require.main===module&&a.main(typeof process!="undefined"?process.argv.slice(1):require("system").args))},require["./scope"]=new function(){var a=this;(function(){var b,c,d,e;e=require("./helpers"),c=e.extend,d=e.last,a.Scope=b=function(){function a(b,c,d){this.parent=b,this.expressions=c,this.method=d,this.variables=[{name:"arguments",type:"arguments"}],this.positions={},this.parent||(a.root=this)}a.root=null,a.prototype.add=function(a,b,c){if(this.shared&&!c)return this.parent.add(a,b,c);return Object.prototype.hasOwnProperty.call(this.positions,a)?this.variables[this.positions[a]].type=b:this.positions[a]=this.variables.push({name:a,type:b})-1},a.prototype.find=function(a,b){if(this.check(a,b))return!0;this.add(a,"var");return!1},a.prototype.parameter=function(a){if(!this.shared||!this.parent.check(a,!0))return this.add(a,"param")},a.prototype.check=function(a,b){var c,d;c=!!this.type(a);if(c||b)return c;return(d=this.parent)!=null?!!d.check(a):!!void 0},a.prototype.temporary=function(a,b){return a.length>1?"_"+a+(b>1?b:""):"_"+(b+parseInt(a,36)).toString(36).replace(/\d/g,"a")},a.prototype.type=function(a){var b,c,d,e;e=this.variables;for(c=0,d=e.length;c1&&a.level>=w?"("+c+")":c},b.prototype.compileRoot=function(a){var b,c,d,e,f,g;a.indent=a.bare?"":Q,a.scope=new M(null,this,null),a.level=z,this.spaced=!0,e="",a.bare||(f=function(){var a,b,e;b=this.expressions,e=[];for(d=0,a=b.length;d=u?"(void 0)":"void 0":this.value==="this"?((c=a.scope.method)!=null?c.bound:void 0)?a.scope.method.context:this.value:this.value.reserved&&(d=""+this.value)!=="eval"&&d!=="arguments"?'"'+this.value+'"':this.value;return this.isStatement()?""+this.tab+b+";":b},b.prototype.toString=function(){return' "'+this.value+'"'};return b}(e),a.Return=K=function(a){function b(a){a&&!a.unwrap().isUndefined&&(this.expression=a)}bj(b,a),b.prototype.children=["expression"],b.prototype.isStatement=X,b.prototype.makeReturn=R,b.prototype.jumps=R,b.prototype.compile=function(a,c){var d,e;d=(e=this.expression)!=null?e.makeReturn():void 0;return!d||d instanceof b?b.__super__.compile.call(this,a,c):d.compile(a,c)},b.prototype.compileNode=function(a){return this.tab+("return"+[this.expression?" "+this.expression.compile(a,y):void 0]+";")};return b}(e),a.Value=V=function(a){function b(a,c,d){if(!c&&a instanceof b)return a;this.base=a,this.properties=c||[],d&&(this[d]=!0);return this}bj(b,a),b.prototype.children=["base","properties"],b.prototype.add=function(a){this.properties=this.properties.concat(a);return this},b.prototype.hasProperties=function(){return!!this.properties.length},b.prototype.isArray=function(){return!this.properties.length&&this.base instanceof c},b.prototype.isComplex=function(){return this.hasProperties()||this.base.isComplex()},b.prototype.isAssignable=function(){return this.hasProperties()||this.base.isAssignable()},b.prototype.isSimpleNumber=function(){return this.base instanceof A&&L.test(this.base.value)},b.prototype.isAtomic=function(){var a,b,c,d;d=this.properties.concat(this.base);for(b=0,c=d.length;b"+this.equals],h=l[0],e=l[1],c=this.stepNum?+this.stepNum>0?""+h+" "+this.toVar:""+e+" "+this.toVar:g?(m=[+this.fromNum,+this.toNum],d=m[0],j=m[1],m,d<=j?""+h+" "+j:""+e+" "+j):(b=""+this.fromVar+" <= "+this.toVar,""+b+" ? "+h+" "+this.toVar+" : "+e+" "+this.toVar),i=this.stepVar?""+f+" += "+this.stepVar:g?d<=j?""+f+"++":""+f+"--":""+b+" ? "+f+"++ : "+f+"--";return""+k+"; "+c+"; "+i},b.prototype.compileArray=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;if(this.fromNum&&this.toNum&&Math.abs(this.fromNum-this.toNum)<=20){j=function(){p=[];for(var a=n=+this.fromNum,b=+this.toNum;n<=b?a<=b:a>=b;n<=b?a++:a--)p.push(a);return p}.apply(this),this.exclusive&&j.pop();return"["+j.join(", ")+"]"}g=this.tab+Q,f=a.scope.freeVariable("i"),k=a.scope.freeVariable("results"),i="\n"+g+k+" = [];",this.fromNum&&this.toNum?(a.index=f,c=this.compileNode(a)):(l=""+f+" = "+this.fromC+(this.toC!==this.toVar?", "+this.toC:""),d=""+this.fromVar+" <= "+this.toVar,c="var "+l+"; "+d+" ? "+f+" <"+this.equals+" "+this.toVar+" : "+f+" >"+this.equals+" "+this.toVar+"; "+d+" ? "+f+"++ : "+f+"--"),h="{ "+k+".push("+f+"); }\n"+g+"return "+k+";\n"+a.indent,e=function(a){return a!=null?a.contains(function(a){return a instanceof A&&a.value==="arguments"&&!a.asKey}):void 0};if(e(this.from)||e(this.to))b=", arguments";return"(function() {"+i+"\n"+g+"for ("+c+")"+h+"}).apply(this"+(b!=null?b:"")+")"};return b}(e),a.Slice=N=function(a){function b(a){this.range=a,b.__super__.constructor.call(this)}bj(b,a),b.prototype.children=["range"],b.prototype.compileNode=function(a){var b,c,d,e,f,g;g=this.range,e=g.to,c=g.from,d=c&&c.compile(a,y)||"0",b=e&&e.compile(a,u),e&&(!!this.range.exclusive||+b!==-1)&&(f=", "+(this.range.exclusive?b:L.test(b)?(+b+1).toString():""+b+" + 1 || 9e9"));return".slice("+d+(f||"")+")"};return b}(e),a.Obj=E=function(a){function b(a,b){this.generated=b!=null?b:!1,this.objects=this.properties=a||[]}bj(b,a),b.prototype.children=["properties"],b.prototype.compileNode=function(a){var b,c,e,f,g,h,i,j,l,m,n;l=this.properties;if(!l.length)return this.front?"({})":"{}";if(this.generated)for(m=0,n=l.length;m=0?"[\n"+a.indent+b+"\n"+this.tab+"]":"["+b+"]"},b.prototype.assigns=function(a){var b,c,d,e;e=this.objects;for(c=0,d=e.length;c=0},c.prototype.assigns=function(a){return this[this.context==="object"?"value":"variable"].assigns(a)},c.prototype.unfoldSoak=function(a){return bf(a,this,"variable")},c.prototype.compileNode=function(a){var b,c,d,e,f,g,h,i,k;if(b=this.variable instanceof V){if(this.variable.isArray()||this.variable.isObject())return this.compilePatternMatch(a);if(this.variable.isSplice())return this.compileSplice(a);if((g=this.context)==="||="||g==="&&="||g==="?=")return this.compileConditional(a)}d=this.variable.compile(a,w);if(!this.context){if(!(f=this.variable.unwrapAll()).isAssignable())throw SyntaxError('"'+this.variable.compile(a)+'" cannot be assigned.');if(typeof f.hasProperties=="function"?!f.hasProperties():!void 0)this.param?a.scope.add(d,"var"):a.scope.find(d)}this.value instanceof j&&(c=B.exec(d))&&(c[1]&&(this.value.klass=c[1]),this.value.name=(h=(i=(k=c[2])!=null?k:c[3])!=null?i:c[4])!=null?h:c[5]),e=this.value.compile(a,w);if(this.context==="object")return""+d+": "+e;e=d+(" "+(this.context||"=")+" ")+e;return a.level<=w?e:"("+e+")"},c.prototype.compilePatternMatch=function(a){var d,e,f,g,h,i,j,k,l,m,n,p,q,r,s,u,v,y,B,C,D,E,F,G,J,K;s=a.level===z,v=this.value,m=this.variable.base.objects;if(!(n=m.length)){f=v.compile(a);return a.level>=x?"("+f+")":f}i=this.variable.isObject();if(s&&n===1&&!((l=m[0])instanceof O)){l instanceof c?(C=l,D=C.variable,h=D.base,l=C.value):l.base instanceof H?(E=(new V(l.unwrapAll())).cacheReference(a),l=E[0],h=E[1]):h=i?l["this"]?l.properties[0].name:l:new A(0),d=o.test(h.unwrap().value||0),v=new V(v),v.properties.push(new(d?b:t)(h));if(F=l.unwrap().value,bk.call(["arguments","eval"].concat(I),F)>=0)throw new SyntaxError("assignment to a reserved word: "+l.compile(a)+" = "+v.compile(a));return(new c(l,v,null,{param:this.param})).compile(a,z)}y=v.compile(a,w),e=[],r=!1;if(!o.test(y)||this.variable.assigns(y))e.push(""+(p=a.scope.freeVariable("ref"))+" = "+y),y=p;for(g=0,B=m.length;g=0)throw new SyntaxError("assignment to a reserved word: "+l.compile(a)+" = "+u.compile(a));e.push((new c(l,u,null,{param:this.param,subpattern:!0})).compile(a,w))}!s&&!this.subpattern&&e.push(y),f=e.join(", ");return a.level=0&&(a.isExistentialEquals=!0);return(new F(this.context.slice(0,-1),b,new c(d,this.value,"="))).compile(a)},c.prototype.compileSplice=function(a){var b,c,d,e,f,g,h,i,j,k,l,m;k=this.variable.properties.pop().range,d=k.from,h=k.to,c=k.exclusive,g=this.variable.compile(a),l=(d!=null?d.cache(a,x):void 0)||["0","0"],e=l[0],f=l[1],h?(d!=null?d.isSimpleNumber():void 0)&&h.isSimpleNumber()?(h=+h.compile(a)- +f,c||(h+=1)):(h=h.compile(a,u)+" - "+f,c||(h+=" + 1")):h="9e9",m=this.value.cache(a,w),i=m[0],j=m[1],b="[].splice.apply("+g+", ["+e+", "+h+"].concat("+i+")), "+j;return a.level>z?"("+b+")":b};return c}(e),a.Code=j=function(a){function b(a,b,c){this.params=a||[],this.body=b||new f,this.bound=c==="boundfunc",this.bound&&(this.context="_this")}bj(b,a),b.prototype.children=["params","body"],b.prototype.isStatement=function(){return!!this.ctor},b.prototype.jumps=D,b.prototype.compileNode=function(a){var b,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,v,w,x,y,z,B,C,D,E;a.scope=new M(a.scope,this.body,this),a.scope.shared=Z(a,"sharedScope"),a.indent+=Q,delete a.bare,o=[],e=[],z=this.params;for(q=0,v=z.length;q=u?"("+b+")":b},b.prototype.traverseChildren=function(a,c){if(a)return b.__super__.traverseChildren.call(this,a,c)};return b}(e),a.Param=G=function(a){function b(a,b,c){this.name=a,this.value=b,this.splat=c}bj(b,a),b.prototype.children=["name","value"],b.prototype.compile=function(a){return this.name.compile(a,w)},b.prototype.asReference=function(a){var b;if(this.reference)return this.reference;b=this.name,b["this"]?(b=b.properties[0].name,b.value.reserved&&(b=new A("_"+b.value))):b.isComplex()&&(b=new A(a.scope.freeVariable("arg"))),b=new V(b),this.splat&&(b=new O(b));return this.reference=b},b.prototype.isComplex=function(){return this.name.isComplex()};return b}(e),a.Splat=O=function(a){function b(a){this.name=a.compile?a:new A(a)}bj(b,a),b.prototype.children=["name"],b.prototype.isAssignable=X,b.prototype.assigns=function(a){return this.name.assigns(a)},b.prototype.compile=function(a){return this.index!=null?this.compileParam(a):this.name.compile(a)},b.prototype.unwrap=function(){return this.name},b.compileSplattedArray=function(a,c,d){var e,f,g,h,i,j,k;i=-1;while((j=c[++i])&&!(j instanceof b))continue;if(i>=c.length)return"";if(c.length===1){g=c[0].compile(a,w);if(d)return g;return""+bg("slice")+".call("+g+")"}e=c.slice(i);for(h=0,k=e.length;h1?b.expressions.unshift(new r((new H(this.guard)).invert(),new A("continue"))):this.guard&&(b=f.wrap([new r(this.guard,b)]))),b="\n"+b.compile(a,z)+"\n"+this.tab),c=e+this.tab+("while ("+this.condition.compile(a,y)+") {"+b+"}"),this.returns&&(c+="\n"+this.tab+"return "+d+";");return c};return b}(e),a.Op=F=function(a){function e(a,c,d,e){var f;if(a==="in")return new s(c,d);if(a==="do"){f=new g(c,c.params||[]),f["do"]=!0;return f}if(a==="new"){if(c instanceof g&&!c["do"]&&!c.isNew)return c.newInstance();if(c instanceof j&&c.bound||c["do"])c=new H(c)}this.operator=b[a]||a,this.first=c,this.second=d,this.flip=!!e;return this}var b,c;bj(e,a),b={"==":"===","!=":"!==",of:"in"},c={"!==":"===","===":"!=="},e.prototype.children=["first","second"],e.prototype.isSimpleNumber=D,e.prototype.isUnary=function(){return!this.second},e.prototype.isComplex=function(){var a;return!this.isUnary()||(a=this.operator)!=="+"&&a!=="-"||this.first.isComplex()},e.prototype.isChainable=function(){var a;return(a=this.operator)==="<"||a===">"||a===">="||a==="<="||a==="==="||a==="!=="},e.prototype.invert=function(){var a,b,d,f,g;if(this.isChainable()&&this.first.isChainable()){a=!0,b=this;while(b&&b.operator)a&&(a=b.operator in c),b=b.first;if(!a)return(new H(this)).invert();b=this;while(b&&b.operator)b.invert=!b.invert,b.operator=c[b.operator],b=b.first;return this}if(f=c[this.operator]){this.operator=f,this.first.unwrap()instanceof e&&this.first.invert();return this}return this.second?(new H(this)).invert():this.operator==="!"&&(d=this.first.unwrap())instanceof e&&((g=d.operator)==="!"||g==="in"||g==="instanceof")?d:new e("!",this)},e.prototype.unfoldSoak=function(a){var b;return((b=this.operator)==="++"||b==="--"||b==="delete")&&bf(a,this,"first")},e.prototype.compileNode=function(a){var b,c;c=this.isChainable()&&this.first.isChainable(),c||(this.first.front=this.front);if(this.isUnary())return this.compileUnary(a);if(c)return this.compileChain(a);if(this.operator==="?")return this.compileExistence(a);b=this.first.compile(a,x)+" "+this.operator+" "+this.second.compile(a,x);return a.level<=x?b:"("+b+")"},e.prototype.compileChain=function(a){var b,c,d,e;e=this.first.second.cache(a),this.first.second=e[0],d=e[1],c=this.first.compile(a,x),b=""+c+" "+(this.invert?"&&":"||")+" "+d.compile(a)+" "+this.operator+" "+this.second.compile(a,x);return"("+b+")"},e.prototype.compileExistence=function(a){var b,c;this.first.isComplex()&&a.level>z?(c=new A(a.scope.freeVariable("ref")),b=new H(new d(c,this.first))):(b=this.first,c=b);return(new r(new l(b),c,{type:"if"})).addElse(this.second).compile(a)},e.prototype.compileUnary=function(a){var b,c,d;c=[b=this.operator],d=b==="+"||b==="-",(b==="new"||b==="typeof"||b==="delete"||d&&this.first instanceof e&&this.first.operator===b)&&c.push(" ");if(d&&this.first instanceof e||b==="new"&&this.first.isStatement(a))this.first=new H(this.first);c.push(this.first.compile(a,x)),this.flip&&c.reverse();return c.join("")},e.prototype.toString=function(a){return e.__super__.toString.call(this,a,this.constructor.name+" "+this.operator)};return e}(e),a.In=s=function(a){function b(a,b){this.object=a,this.array=b}bj(b,a),b.prototype.children=["object","array"],b.prototype.invert=C,b.prototype.compileNode=function(a){var b,c,d,e,f;if(this.array instanceof V&&this.array.isArray()){f=this.array.base.objects;for(d=0,e=f.length;d= 0");if(d===c)return b;b=d+", "+b;return a.level1?b.expressions.unshift(new r((new H(this.guard)).invert(),new A("continue"))):this.guard&&(b=f.wrap([new r(this.guard,b)]))),this.pattern&&b.expressions.unshift(new d(this.name,new A(""+D+"["+k+"]"))),c+=this.pluckDirectCall(a,b),p&&(E="\n"+i+p+";"),this.object&&(e=""+k+" in "+D,this.own&&(h="\n"+i+"if (!"+bg("hasProp")+".call("+D+", "+k+")) continue;")),b=b.compile(bc(a,{indent:i}),z),b&&(b="\n"+b+"\n");return""+c+(s||"")+this.tab+"for ("+e+") {"+h+E+b+this.tab+"}"+(t||"")},b.prototype.pluckDirectCall=function(a,b){var c,e,f,h,i,k,l,m,n,o,p,q,r,s;e="",n=b.expressions;for(i=0,m=n.length;if.length+d.length)return""+this.tab+"if ("+f+") "+d.replace(/^\s+/,"");d&&(d="\n"+d+"\n"+this.tab),h="if ("+f+") {"+d+"}",e||(h=this.tab+h);if(!this.elseBody)return h;return h+" else "+(this.isChain?(a.indent=this.tab,a.chainChild=!0,this.elseBody.unwrap().compile(a,z)):"{\n"+this.elseBody.compile(a,z)+"\n"+this.tab+"}")},b.prototype.compileExpression=function(a){var b,c,d,e;e=this.condition.compile(a,v),c=this.bodyNode().compile(a,w),b=this.elseBodyNode()?this.elseBodyNode().compile(a,w):"void 0",d=""+e+" ? "+c+" : "+b;return a.level>=v?"("+d+")":d},b.prototype.unfoldSoak=function(){return this.soak&&this};return b}(e),i={wrap:function(a,c,d){var e,h,i,k,l;if(a.jumps())return a;i=new j([],f.wrap([a])),e=[];if((k=a.contains(this.literalArgs))||a.contains(this.literalThis))l=new A(k?"apply":"call"),e=[new A("this")],k&&e.push(new A("arguments")),i=new V(i,[new b(l)]);i.noReturn=d,h=new g(i,e);return c?f.wrap([h]):h},literalArgs:function(a){return a instanceof A&&a.value==="arguments"&&!a.asKey},literalThis:function(a){return a instanceof A&&a.value==="this"&&!a.asKey||a instanceof j&&a.bound}},bf=function(a,b,c){var d;if(!!(d=b[c].unfoldSoak(a))){b[c]=d.body,d.body=new V(b);return d}},U={"extends":function(){return"function(child, parent) { for (var key in parent) { if ("+bg("hasProp")+".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }"},bind:function(){return"function(fn, me){ return function(){ return fn.apply(me, arguments); }; }"},indexOf:function(){return"Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }"},hasProp:function(){return"Object.prototype.hasOwnProperty"},slice:function(){return"Array.prototype.slice"}},z=1,y=2,w=3,v=4,x=5,u=6,Q=" ",p="[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*",o=RegExp("^"+p+"$"),L=/^[+-]?\d+$/,B=RegExp("^(?:("+p+")\\.prototype(?:\\.("+p+")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\]))|("+p+")$"),q=/^['"]/,bg=function(a){var b;b="__"+a,M.root.assign(b,U[a]());return b},bd=function(a,b){a=a.replace(/\n/g,"$&"+b);return a.replace(/\s+$/,"")}}).call(this)},require["./coffee-script"]=new function(){var a=this;(function(){var b,c,d,e,f,g,h,i,j,k=Object.prototype.hasOwnProperty;e=require("fs"),h=require("path"),j=require("./lexer"),b=j.Lexer,c=j.RESERVED,g=require("./parser").parser,i=require("vm"),require.extensions?require.extensions[".coffee"]=function(a,b){var c;c=d(e.readFileSync(b,"utf8"),{filename:b});return a._compile(c,b)}:require.registerExtension&&require.registerExtension(".coffee",function(a){return d(a)}),a.VERSION="1.2.0",a.RESERVED=c,a.helpers=require("./helpers"),a.compile=d=function(b,c){var d;c==null&&(c={}),d=a.helpers.merge;try{return g.parse(f.tokenize(b)).compile(d({},c))}catch(e){c.filename&&(e.message="In "+c.filename+", "+e.message);throw e}},a.tokens=function(a,b){return f.tokenize(a,b)},a.nodes=function(a,b){return typeof a=="string"?g.parse(f.tokenize(a,b)):g.parse(a)},a.run=function(a,b){var c;c=require.main,c.filename=process.argv[1]=b.filename?e.realpathSync(b.filename):".",c.moduleCache&&(c.moduleCache={}),c.paths=require("module")._nodeModulePaths(h.dirname(b.filename));return h.extname(c.filename)!==".coffee"||require.extensions?c._compile(d(a,b),c.filename):c._compile(a,c.filename)},a.eval=function(a,b){var c,e,f,g,j,l,m,n,o,p,q,r,s,t;b==null&&(b={});if(!!(a=a.trim())){e=i.Script;if(e){if(b.sandbox!=null){if(b.sandbox instanceof e.createContext().constructor)m=b.sandbox;else{m=e.createContext(),r=b.sandbox;for(g in r){if(!k.call(r,g))continue;n=r[g],m[g]=n}}m.global=m.root=m.GLOBAL=m}else m=global;m.__filename=b.filename||"eval",m.__dirname=h.dirname(m.__filename);if(m===global&&!m.module&&!m.require){c=require("module"),m.module=q=new c(b.modulename||"eval"),m.require=t=function(a){return c._load(a,q,!0)},q.filename=m.__filename,s=Object.getOwnPropertyNames(require);for(o=0,p=s.length;o polygons + // around the sides. We will make sure though that the cylinder will have an edge at every + // face that touches this side. This ensures that we will get a smooth fill even + // if two edges are at, say, 10 degrees and the resolution is low. + // Note: the result is not retesselated yet but it really should be! + for(vertextagpair in vertexpairs) + { + var vertexpair = vertexpairs[vertextagpair]; + var startpoint = vertexpair.v1.pos; + var endpoint = vertexpair.v2.pos; + // our x,y and z vectors: + var zbase = endpoint.minus(startpoint).unit(); + var xbase = vertexpair.planenormals[0].unit(); + var ybase = xbase.cross(zbase); + + // make a list of angles that the cylinder should traverse: + var angles = []; + + // first of all equally spaced around the cylinder: + for(var i = 0; i < resolution; i++) + { + var angle = i * Math.PI * 2 / resolution; + angles.push(angle); + } + + // and also at every normal of all touching planes: + vertexpair.planenormals.map(function(planenormal){ + var si = ybase.dot(planenormal); + var co = xbase.dot(planenormal); + var angle = Math.atan2(si,co); + if(angle < 0) angle += Math.PI*2; + angles.push(angle); + angle = Math.atan2(-si,-co); + if(angle < 0) angle += Math.PI*2; + angles.push(angle); + }); + + // this will result in some duplicate angles but we will get rid of those later. + // Sort: + angles = angles.sort(function(a,b){return a-b;}); + + // Now construct the cylinder by traversing all angles: + var numangles = angles.length; + var prevp1, prevp2; + var startfacevertices = [], endfacevertices = []; + var polygons = []; + var prevangle; + for(var i = -1; i < numangles; i++) + { + var angle = angles[(i < 0)?(i+numangles):i]; + var si = Math.sin(angle); + var co = Math.cos(angle); + var p = xbase.times(co * radius).plus(ybase.times(si * radius)); + var p1 = startpoint.plus(p); + var p2 = endpoint.plus(p); + var skip = false; + if(i >= 0) + { + if(p1.distanceTo(prevp1) < 1e-5) + { + skip = true; + } + } + if(!skip) + { + if(i >= 0) + { + startfacevertices.push(new CSG.Vertex(p1)); + endfacevertices.push(new CSG.Vertex(p2)); + var polygonvertices = [ + new CSG.Vertex(prevp2), + new CSG.Vertex(p2), + new CSG.Vertex(p1), + new CSG.Vertex(prevp1), + ]; + var polygon = new CSG.Polygon(polygonvertices); + polygons.push(polygon); + } + prevp1 = p1; + prevp2 = p2; + } + } + endfacevertices.reverse(); + polygons.push(new CSG.Polygon(startfacevertices)); + polygons.push(new CSG.Polygon(endfacevertices)); + var cylinder = CSG.fromPolygons(polygons); + result = result.unionSub(cylinder, false, false); + } + + // make a list of all unique vertices + // For each vertex we also collect the list of normals of the planes touching the vertices + var vertexmap = {}; + csg.polygons.map(function(polygon){ + polygon.vertices.map(function(vertex){ + var vertextag = vertex.getTag(); + var obj; + if(vertextag in vertexmap) + { + obj = vertexmap[vertextag]; + } + else + { + obj = { + pos: vertex.pos, + normals: [], + }; + vertexmap[vertextag] = obj; + } + obj.normals.push(polygon.plane.normal); + }); + }); + + // and build spheres at each vertex + // We will try to set the x and z axis to the normals of 2 planes + // This will ensure that our sphere tesselation somewhat matches 2 planes + for(vertextag in vertexmap) + { + var vertexobj = vertexmap[vertextag]; + // use the first normal to be the x axis of our sphere: + var xaxis = vertexobj.normals[0].unit(); + // and find a suitable z axis. We will use the normal which is most perpendicular to the x axis: + var bestzaxis = null; + var bestzaxisorthogonality = 0; + for(var i = 1; i < vertexobj.normals.length; i++) + { + var normal = vertexobj.normals[i].unit(); + var cross = xaxis.cross(normal); + var crosslength = cross.length(); + if(crosslength > 0.05) + { + if(crosslength > bestzaxisorthogonality) + { + bestzaxisorthogonality = crosslength; + bestzaxis = normal; + } + } + } + if(! bestzaxis) + { + bestzaxis = xaxis.randomNonParallelVector(); + } + var yaxis = xaxis.cross(bestzaxis).unit(); + var zaxis = yaxis.cross(xaxis); + var sphere = CSG.sphere({ + center: vertexobj.pos, + radius: radius, + resolution: resolution, + axes: [xaxis, yaxis, zaxis]}); + result = result.unionSub(sphere, false, false); + } + + return result; + }, + + canonicalized: function () { + if(this.isCanonicalized) + { + return this; + } + else + { + var factory = new CSG.fuzzyCSGFactory(); + var result = factory.getCSG(this); + result.isCanonicalized = true; + result.isRetesselated = this.isRetesselated; + result.properties = this.properties; // keep original properties + return result; + } + }, + + reTesselated: function () { + if(this.isRetesselated) + { + return this; + } + else + { + var csg=this.canonicalized(); + var polygonsPerPlane = {}; + csg.polygons.map(function(polygon) { + var planetag = polygon.plane.getTag(); + var sharedtag = polygon.shared.getTag(); + planetag += "/"+sharedtag; + if(! (planetag in polygonsPerPlane) ) + { + polygonsPerPlane[planetag] = []; + } + polygonsPerPlane[planetag].push(polygon); + }); + var destpolygons = []; + for(planetag in polygonsPerPlane) + { + var sourcepolygons = polygonsPerPlane[planetag]; + if(sourcepolygons.length < 2) + { + destpolygons = destpolygons.concat(sourcepolygons); + } + else + { + var retesselayedpolygons = []; + CSG.reTesselateCoplanarPolygons(sourcepolygons, retesselayedpolygons); + destpolygons = destpolygons.concat(retesselayedpolygons); + } + } + var result = CSG.fromPolygons(destpolygons); + result.isRetesselated = true; + result=result.canonicalized(); +// result.isCanonicalized = true; + result.properties = this.properties; // keep original properties + return result; + } + }, + + // returns an array of two CSG.Vector3Ds (minimum coordinates and maximum coordinates) + getBounds: function() { + if(!this.cachedBoundingBox) + { + var minpoint = new CSG.Vector3D(0,0,0); + var maxpoint = new CSG.Vector3D(0,0,0); + var polygons = this.polygons; + var numpolygons = polygons.length; + for(var i=0; i < numpolygons; i++) + { + var polygon = polygons[i]; + var bounds = polygon.boundingBox(); + if(i == 0) + { + minpoint = bounds[0]; + maxpoint = bounds[1]; + } + else + { + minpoint = minpoint.min(bounds[0]); + maxpoint = maxpoint.max(bounds[1]); + } + } + this.cachedBoundingBox = [minpoint, maxpoint]; + } + return this.cachedBoundingBox; + }, + + // returns true if there is a possibility that the two solids overlap + // returns false if we can be sure that they do not overlap + mayOverlap: function(csg) { + if( (this.polygons.length == 0) || (csg.polygons.length == 0) ) + { + return false; + } + else + { + var mybounds = this.getBounds(); + var otherbounds = csg.getBounds(); + if(mybounds[1].x < otherbounds[0].x) return false; + if(mybounds[0].x > otherbounds[1].x) return false; + if(mybounds[1].y < otherbounds[0].y) return false; + if(mybounds[0].y > otherbounds[1].y) return false; + if(mybounds[1].z < otherbounds[0].z) return false; + if(mybounds[0].z > otherbounds[1].z) return false; + return true; + } + }, + + // Cut the solid by a plane. Returns the solid on the back side of the plane + cutByPlane: function(plane) { + // Ideally we would like to do an intersection with a polygon of inifinite size + // but this is not supported by our implementation. As a workaround, we will create + // a cube, with one face on the plane, and a size larger enough so that the entire + // solid fits in the cube. + + // find the max distance of any vertex to the center of the plane: + var planecenter = plane.normal.times(plane.w); + var maxdistance = 0; + this.polygons.map(function(polygon){ + polygon.vertices.map(function(vertex){ + var distance = vertex.pos.distanceToSquared(planecenter); + if(distance > maxdistance) maxdistance = distance; + }); + }); + maxdistance = Math.sqrt(maxdistance); + maxdistance *= 1.01; // make sure it's really larger + + // Now build a polygon on the plane, at any point farther than maxdistance from the plane center: + var vertices = []; + var orthobasis = new CSG.OrthoNormalBasis(plane); + vertices.push(new CSG.Vertex(orthobasis.to3D(new CSG.Vector2D(maxdistance,maxdistance)))); + vertices.push(new CSG.Vertex(orthobasis.to3D(new CSG.Vector2D(-maxdistance,maxdistance)))); + vertices.push(new CSG.Vertex(orthobasis.to3D(new CSG.Vector2D(-maxdistance,-maxdistance)))); + vertices.push(new CSG.Vertex(orthobasis.to3D(new CSG.Vector2D(maxdistance,-maxdistance)))); + var polygon = new CSG.Polygon(vertices, null, plane.flipped()); + + // and extrude the polygon into a cube, backwards of the plane: + var cube = polygon.extrude(plane.normal.times(-maxdistance)); + + // Now we can do the intersection: + var result = this.intersect(cube); + result.properties = this.properties; // keep original properties + return result; + }, + + // Connect a solid to another solid, such that two CSG.Connectors become connected + // myConnector: a CSG.Connector of this solid + // otherConnector: a CSG.Connector to which myConnector should be connected + // mirror: false: the 'axis' vectors of the connectors should point in the same direction + // true: the 'axis' vectors of the connectors should point in opposite direction + // normalrotation: degrees of rotation between the 'normal' vectors of the two + // connectors + connectTo: function(myConnector, otherConnector, mirror, normalrotation) { + var matrix = myConnector.getTransformationTo(otherConnector, mirror, normalrotation); + return this.transform(matrix); + }, + + // set the .shared property of all polygons + // Returns a new CSG solid, the original is unmodified! + setShared: function(shared) { + var polygons = this.polygons.map( function(p) { + return new CSG.Polygon(p.vertices, shared, p.plane); + }); + var result = CSG.fromPolygons(polygons); + result.properties = this.properties; // keep original properties + result.isRetesselated = this.isRetesselated; + result.isCanonicalized = this.isCanonicalized; + return result; + }, + + setColor: function(red,green,blue) { + var newshared = new CSG.Polygon.Shared([red, green, blue]); + return this.setShared(newshared); + }, + + toCompactBinary: function() { + var csg = this.canonicalized(); + var numpolygons = csg.polygons.length; + var numpolygonvertices = 0; + var numvertices = 0; + var vertexmap = {}; + var vertices = []; + var numplanes = 0; + var planemap = {}; + var polygonindex = 0; + var planes = []; + var shareds = []; + var sharedmap = {}; + var numshared = 0; + csg.polygons.map(function(p){ + p.vertices.map(function(v){ + ++numpolygonvertices; + var vertextag = v.getTag(); + if(! (vertextag in vertexmap)) + { + vertexmap[vertextag] = numvertices++; + vertices.push(v); + } + }); + var planetag = p.plane.getTag(); + if(! (planetag in planemap)) + { + planemap[planetag] = numplanes++; + planes.push(p.plane); + } + var sharedtag = p.shared.getTag(); + if(! (sharedtag in sharedmap)) + { + sharedmap[sharedtag] = numshared++; + shareds.push(p.shared); + } + }); + var numVerticesPerPolygon = new Uint32Array(numpolygons); + var polygonSharedIndexes = new Uint32Array(numpolygons); + var polygonVertices = new Uint32Array(numpolygonvertices); + var polygonPlaneIndexes = new Uint32Array(numpolygons); + var vertexData = new Float64Array(numvertices * 3); + var planeData = new Float64Array(numplanes * 4); + var polygonVerticesIndex = 0; + for(var polygonindex = 0; polygonindex < numpolygons; ++polygonindex) + { + var p = csg.polygons[polygonindex]; + numVerticesPerPolygon[polygonindex] = p.vertices.length; + p.vertices.map(function(v){ + var vertextag = v.getTag(); + var vertexindex = vertexmap[vertextag]; + polygonVertices[polygonVerticesIndex++] = vertexindex; + }); + var planetag = p.plane.getTag(); + var planeindex = planemap[planetag]; + polygonPlaneIndexes[polygonindex] = planeindex; + var sharedtag = p.shared.getTag(); + var sharedindex = sharedmap[sharedtag]; + polygonSharedIndexes[polygonindex] = sharedindex; + } + var verticesArrayIndex = 0; + vertices.map(function(v){ + var pos = v.pos; + vertexData[verticesArrayIndex++] = pos._x; + vertexData[verticesArrayIndex++] = pos._y; + vertexData[verticesArrayIndex++] = pos._z; + }); + var planesArrayIndex = 0; + planes.map(function(p){ + var normal = p.normal; + planeData[planesArrayIndex++] = normal._x; + planeData[planesArrayIndex++] = normal._y; + planeData[planesArrayIndex++] = normal._z; + planeData[planesArrayIndex++] = p.w; + }); + var result = { + numPolygons: numpolygons, + numVerticesPerPolygon: numVerticesPerPolygon, + polygonPlaneIndexes: polygonPlaneIndexes, + polygonSharedIndexes: polygonSharedIndexes, + polygonVertices: polygonVertices, + vertexData: vertexData, + planeData: planeData, + shared: shareds, + }; + return result; + }, + + // For debugging + // Creates a new solid with a tiny cube at every vertex of the source solid + toPointCloud: function(cuberadius) { + var csg = this.reTesselated(); + + var result = new CSG(); + + // make a list of all unique vertices + // For each vertex we also collect the list of normals of the planes touching the vertices + var vertexmap = {}; + csg.polygons.map(function(polygon){ + polygon.vertices.map(function(vertex){ + vertexmap[vertex.getTag()] = vertex.pos; + }); + }); + + for(vertextag in vertexmap) + { + var pos = vertexmap[vertextag]; + var cube = CSG.cube({center: pos, radius: cuberadius}); + result = result.unionSub(cube, false, false); + } + result = result.reTesselated(); + return result; + }, + +}; + +// Parse an option from the options object +// If the option is not present, return the default value +CSG.parseOption = function(options, optionname, defaultvalue) { + var result = defaultvalue; + if(options) + { + if(optionname in options) + { + result = options[optionname]; + } + } + return result; +}; + +// Parse an option and force into a CSG.Vector3D. If a scalar is passed it is converted +// into a vector with equal x,y,z +CSG.parseOptionAs3DVector = function(options, optionname, defaultvalue) { + var result = CSG.parseOption(options, optionname, defaultvalue); + result = new CSG.Vector3D(result); + return result; +}; + +// Parse an option and force into a CSG.Vector2D. If a scalar is passed it is converted +// into a vector with equal x,y +CSG.parseOptionAs2DVector = function(options, optionname, defaultvalue) { + var result = CSG.parseOption(options, optionname, defaultvalue); + result = new CSG.Vector2D(result); + return result; +}; + +CSG.parseOptionAsFloat = function(options, optionname, defaultvalue) { + var result = CSG.parseOption(options, optionname, defaultvalue); + if(typeof(result) == "string") + { + result = Number(result); + } + else if(typeof(result) != "number") + { + throw new Error("Parameter "+optionname+" should be a number"); + } + return result; +}; + +CSG.parseOptionAsInt = function(options, optionname, defaultvalue) { + var result = CSG.parseOption(options, optionname, defaultvalue); + return Number(Math.floor(result)); +}; + +CSG.parseOptionAsBool = function(options, optionname, defaultvalue) { + var result = CSG.parseOption(options, optionname, defaultvalue); + if(typeof(result) == "string") + { + if(result == "true") result = true; + if(result == "false") result = false; + if(result == 0) result = false; + } + result = !!result; + return result; +}; + +// Construct an axis-aligned solid cuboid. +// Parameters: +// center: center of cube (default [0,0,0]) +// radius: radius of cube (default [1,1,1]), can be specified as scalar or as 3D vector +// +// Example code: +// +// var cube = CSG.cube({ +// center: [0, 0, 0], +// radius: 1 +// }); +CSG.cube = function(options) { + var c = CSG.parseOptionAs3DVector(options, "center", [0,0,0]); + var s = CSG.parseOptionAs3DVector(options, "size", [2,2,2]); + var r = CSG.parseOptionAs3DVector(options, "radius", [s.x/2,s.y/2,s.z/2]); + var result = CSG.fromPolygons([ + [[0, 4, 6, 2], [-1, 0, 0]], + [[1, 3, 7, 5], [+1, 0, 0]], + [[0, 1, 5, 4], [0, -1, 0]], + [[2, 6, 7, 3], [0, +1, 0]], + [[0, 2, 3, 1], [0, 0, -1]], + [[4, 5, 7, 6], [0, 0, +1]] + ].map(function(info) { + var normal = new CSG.Vector3D(info[1]); + //var plane = new CSG.Plane(normal, 1); + var vertices = info[0].map(function(i) { + var pos = new CSG.Vector3D( + c.x + r.x * (2 * !!(i & 1) - 1), + c.y + r.y * (2 * !!(i & 2) - 1), + c.z + r.z * (2 * !!(i & 4) - 1) + ); + return new CSG.Vertex(pos); + }); + return new CSG.Polygon(vertices, null /* , plane */); + })); + result.properties.cube = new CSG.Properties(); + result.properties.cube.center = new CSG.Vector3D(c); + // add 6 connectors, at the centers of each face: + result.properties.cube.facecenters = [ + new CSG.Connector(new CSG.Vector3D([r.x, 0, 0]).plus(c), [1, 0, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([-r.x, 0, 0]).plus(c), [-1, 0, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([0, r.y, 0]).plus(c), [0, 1, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([0, -r.y, 0]).plus(c), [0, -1, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([0, 0, r.z]).plus(c), [0, 0, 1], [1, 0, 0]), + new CSG.Connector(new CSG.Vector3D([0, 0, -r.z]).plus(c), [0, 0, -1], [1, 0, 0]), + ]; + return result; +}; + +// Construct a solid sphere +// +// Parameters: +// center: center of sphere (default [0,0,0]) +// radius: radius of sphere (default 1), must be a scalar +// resolution: determines the number of polygons per 360 degree revolution (default 12) +// axes: (optional) an array with 3 vectors for the x, y and z base vectors +// +// Example usage: +// +// var sphere = CSG.sphere({ +// center: [0, 0, 0], +// radius: 2, +// resolution: 32, +// }); +CSG.sphere = function(options) { + options = options || {}; + var center = CSG.parseOptionAs3DVector(options, "center", [0,0,0]); + var radius = CSG.parseOptionAsFloat(options, "radius", 1); + var resolution = CSG.parseOptionAsInt(options, "resolution", 12); + var xvector, yvector, zvector; + if('axes' in options) + { + xvector = options.axes[0].unit().times(radius); + yvector = options.axes[1].unit().times(radius); + zvector = options.axes[2].unit().times(radius); + } + else + { + xvector = new CSG.Vector3D([1,0,0]).times(radius); + yvector = new CSG.Vector3D([0,-1,0]).times(radius); + zvector = new CSG.Vector3D([0,0,1]).times(radius); + } + if(resolution < 4) resolution = 4; + var qresolution = Math.round(resolution / 4); + var prevcylinderpoint; + var polygons = []; + for(var slice1 = 0; slice1 <= resolution; slice1++) + { + var angle = Math.PI * 2.0 * slice1 / resolution; + var cylinderpoint = xvector.times(Math.cos(angle)).plus(yvector.times(Math.sin(angle))); + if(slice1 > 0) + { + // cylinder vertices: + var vertices = []; + var prevcospitch, prevsinpitch; + for(var slice2 = 0; slice2 <= qresolution; slice2++) + { + var pitch = 0.5 * Math.PI * slice2 / qresolution; + var cospitch = Math.cos(pitch); + var sinpitch = Math.sin(pitch); + if(slice2 > 0) + { + vertices = []; + vertices.push(new CSG.Vertex(center.plus(prevcylinderpoint.times(prevcospitch).minus(zvector.times(prevsinpitch))))); + vertices.push(new CSG.Vertex(center.plus(cylinderpoint.times(prevcospitch).minus(zvector.times(prevsinpitch))))); + if(slice2 < qresolution) + { + vertices.push(new CSG.Vertex(center.plus(cylinderpoint.times(cospitch).minus(zvector.times(sinpitch))))); + } + vertices.push(new CSG.Vertex(center.plus(prevcylinderpoint.times(cospitch).minus(zvector.times(sinpitch))))); + polygons.push(new CSG.Polygon(vertices)); + vertices = []; + vertices.push(new CSG.Vertex(center.plus(prevcylinderpoint.times(prevcospitch).plus(zvector.times(prevsinpitch))))); + vertices.push(new CSG.Vertex(center.plus(cylinderpoint.times(prevcospitch).plus(zvector.times(prevsinpitch))))); + if(slice2 < qresolution) + { + vertices.push(new CSG.Vertex(center.plus(cylinderpoint.times(cospitch).plus(zvector.times(sinpitch))))); + } + vertices.push(new CSG.Vertex(center.plus(prevcylinderpoint.times(cospitch).plus(zvector.times(sinpitch))))); + vertices.reverse(); + polygons.push(new CSG.Polygon(vertices)); + } + prevcospitch = cospitch; + prevsinpitch = sinpitch; + } + } + prevcylinderpoint = cylinderpoint; + } + var result = CSG.fromPolygons(polygons); + result.properties.sphere = new CSG.Properties(); + result.properties.sphere.center = new CSG.Vector3D(center); + result.properties.sphere.facepoint = center.plus(xvector); + return result; +}; + +// Construct a solid cylinder. +// +// Parameters: +// start: start point of cylinder (default [0, -1, 0]) +// end: end point of cylinder (default [0, 1, 0]) +// radius: radius of cylinder (default 1), must be a scalar +// resolution: determines the number of polygons per 360 degree revolution (default 12) +// +// Example usage: +// +// var cylinder = CSG.cylinder({ +// start: [0, -1, 0], +// end: [0, 1, 0], +// radius: 1, +// resolution: 16 +// }); +CSG.cylinder = function(options) { + var s = CSG.parseOptionAs3DVector(options, "start", [0, -1, 0]); + var e = CSG.parseOptionAs3DVector(options, "end", [0, 1, 0]); + var r = CSG.parseOptionAsFloat(options, "radius", 1); + var slices = CSG.parseOptionAsFloat(options, "resolution", 12); + var ray = e.minus(s); + var axisZ = ray.unit(), isY = (Math.abs(axisZ.y) > 0.5); + var axisX = new CSG.Vector3D(isY, !isY, 0).cross(axisZ).unit(); + var axisY = axisX.cross(axisZ).unit(); + var start = new CSG.Vertex(s); + var end = new CSG.Vertex(e); + var polygons = []; + function point(stack, slice, normalBlend) { + var angle = slice * Math.PI * 2; + var out = axisX.times(Math.cos(angle)).plus(axisY.times(Math.sin(angle))); + var pos = s.plus(ray.times(stack)).plus(out.times(r)); + var normal = out.times(1 - Math.abs(normalBlend)).plus(axisZ.times(normalBlend)); + return new CSG.Vertex(pos); + } + for (var i = 0; i < slices; i++) { + var t0 = i / slices, t1 = (i + 1) / slices; + polygons.push(new CSG.Polygon([start, point(0, t0, -1), point(0, t1, -1)])); + polygons.push(new CSG.Polygon([point(0, t1, 0), point(0, t0, 0), point(1, t0, 0), point(1, t1, 0)])); + polygons.push(new CSG.Polygon([end, point(1, t1, 1), point(1, t0, 1)])); + } + var result = CSG.fromPolygons(polygons); + result.properties.cylinder = new CSG.Properties(); + result.properties.cylinder.start = new CSG.Connector(s, axisZ.negated(), axisX); + result.properties.cylinder.end = new CSG.Connector(e, axisZ, axisX); + result.properties.cylinder.facepoint = s.plus(axisX.times(r)); + return result; +}; + +// Like a cylinder, but with rounded ends instead of flat +// +// Parameters: +// start: start point of cylinder (default [0, -1, 0]) +// end: end point of cylinder (default [0, 1, 0]) +// radius: radius of cylinder (default 1), must be a scalar +// resolution: determines the number of polygons per 360 degree revolution (default 12) +// normal: a vector determining the starting angle for tesselation. Should be non-parallel to start.minus(end) +// +// Example usage: +// +// var cylinder = CSG.roundedCylinder({ +// start: [0, -1, 0], +// end: [0, 1, 0], +// radius: 1, +// resolution: 16 +// }); +CSG.roundedCylinder = function(options) { + var p1 = CSG.parseOptionAs3DVector(options, "start", [0, -1, 0]); + var p2 = CSG.parseOptionAs3DVector(options, "end", [0, 1, 0]); + var radius = CSG.parseOptionAsFloat(options, "radius", 1); + var direction = p2.minus(p1); + var defaultnormal; + if(Math.abs(direction.x) > Math.abs(direction.y)) + { + defaultnormal = new CSG.Vector3D(0,1,0); + } + else + { + defaultnormal = new CSG.Vector3D(1,0,0); + } + var normal = CSG.parseOptionAs3DVector(options, "normal", defaultnormal); + var resolution = CSG.parseOptionAsFloat(options, "resolution", 12); + if(resolution < 4) resolution = 4; + var polygons = []; + var qresolution = Math.floor(0.25*resolution); + var length = direction.length(); + if(length < 1e-10) + { + return CSG.sphere({center: p1, radius: radius, resolution: resolution}); + } + var zvector = direction.unit().times(radius); + var xvector = zvector.cross(normal).unit().times(radius); + var yvector = xvector.cross(zvector).unit().times(radius); + var prevcylinderpoint; + for(var slice1 = 0; slice1 <= resolution; slice1++) + { + var angle = Math.PI * 2.0 * slice1 / resolution; + var cylinderpoint = xvector.times(Math.cos(angle)).plus(yvector.times(Math.sin(angle))); + if(slice1 > 0) + { + // cylinder vertices: + var vertices = []; + vertices.push(new CSG.Vertex(p1.plus(cylinderpoint))); + vertices.push(new CSG.Vertex(p1.plus(prevcylinderpoint))); + vertices.push(new CSG.Vertex(p2.plus(prevcylinderpoint))); + vertices.push(new CSG.Vertex(p2.plus(cylinderpoint))); + polygons.push(new CSG.Polygon(vertices)); + var prevcospitch, prevsinpitch; + for(var slice2 = 0; slice2 <= qresolution; slice2++) + { + var pitch = 0.5 * Math.PI * slice2 / qresolution; + //var pitch = Math.asin(slice2/qresolution); + var cospitch = Math.cos(pitch); + var sinpitch = Math.sin(pitch); + if(slice2 > 0) + { + vertices = []; + vertices.push(new CSG.Vertex(p1.plus(prevcylinderpoint.times(prevcospitch).minus(zvector.times(prevsinpitch))))); + vertices.push(new CSG.Vertex(p1.plus(cylinderpoint.times(prevcospitch).minus(zvector.times(prevsinpitch))))); + if(slice2 < qresolution) + { + vertices.push(new CSG.Vertex(p1.plus(cylinderpoint.times(cospitch).minus(zvector.times(sinpitch))))); + } + vertices.push(new CSG.Vertex(p1.plus(prevcylinderpoint.times(cospitch).minus(zvector.times(sinpitch))))); + polygons.push(new CSG.Polygon(vertices)); + vertices = []; + vertices.push(new CSG.Vertex(p2.plus(prevcylinderpoint.times(prevcospitch).plus(zvector.times(prevsinpitch))))); + vertices.push(new CSG.Vertex(p2.plus(cylinderpoint.times(prevcospitch).plus(zvector.times(prevsinpitch))))); + if(slice2 < qresolution) + { + vertices.push(new CSG.Vertex(p2.plus(cylinderpoint.times(cospitch).plus(zvector.times(sinpitch))))); + } + vertices.push(new CSG.Vertex(p2.plus(prevcylinderpoint.times(cospitch).plus(zvector.times(sinpitch))))); + vertices.reverse(); + polygons.push(new CSG.Polygon(vertices)); + } + prevcospitch = cospitch; + prevsinpitch = sinpitch; + } + } + prevcylinderpoint = cylinderpoint; + } + var result = CSG.fromPolygons(polygons); + var ray = zvector.unit(); + var axisX = xvector.unit(); + result.properties.roundedCylinder = new CSG.Properties(); + result.properties.roundedCylinder.start = new CSG.Connector(p1, ray.negated(), axisX); + result.properties.roundedCylinder.end = new CSG.Connector(p2, ray, axisX); + result.properties.roundedCylinder.facepoint = p1.plus(xvector); + return result; +}; + +// Construct an axis-aligned solid rounded cuboid. +// Parameters: +// center: center of cube (default [0,0,0]) +// radius: radius of cube (default [1,1,1]), can be specified as scalar or as 3D vector +// roundradius: radius of rounded corners (default 0.2), must be a scalar +// resolution: determines the number of polygons per 360 degree revolution (default 8) +// +// Example code: +// +// var cube = CSG.roundedCube({ +// center: [0, 0, 0], +// radius: 1, +// roundradius: 0.2, +// resolution: 8, +// }); +CSG.roundedCube = function(options) { + var center = CSG.parseOptionAs3DVector(options, "center", [0,0,0]); + var cubesize = CSG.parseOptionAs3DVector(options, "size", [2,2,2]); + var cuberadius = CSG.parseOptionAs3DVector(options, "radius", [cubesize.x/2,cubesize.y/2,cubesize.z/2]); + var resolution = CSG.parseOptionAsFloat(options, "resolution", 8); + if(resolution < 4) resolution = 4; + var roundradius = CSG.parseOptionAsFloat(options, "roundradius", 0.2); + var innercuberadius=cuberadius; + innercuberadius = innercuberadius.minus(new CSG.Vector3D(roundradius)); + var result = CSG.cube({center: center, radius: [cuberadius.x, innercuberadius.y, innercuberadius.z]}); + result = result.unionSub( CSG.cube({center: center, radius: [innercuberadius.x, cuberadius.y, innercuberadius.z]}),false,false); + result = result.unionSub( CSG.cube({center: center, radius: [innercuberadius.x, innercuberadius.y, cuberadius.z]}),false,false); + for(var level=0; level < 2; level++) + { + var z = innercuberadius.z; + if(level == 1) z = -z; + var p1 = new CSG.Vector3D(innercuberadius.x, innercuberadius.y, z).plus(center); + var p2 = new CSG.Vector3D(innercuberadius.x, -innercuberadius.y, z).plus(center); + var p3 = new CSG.Vector3D(-innercuberadius.x, -innercuberadius.y, z).plus(center); + var p4 = new CSG.Vector3D(-innercuberadius.x, innercuberadius.y, z).plus(center); + var sphere = CSG.sphere({center: p1, radius: roundradius, resolution: resolution}); + result = result.unionSub(sphere,false,false); + sphere = CSG.sphere({center: p2, radius: roundradius, resolution: resolution}); + result = result.unionSub(sphere,false,false); + sphere = CSG.sphere({center: p3, radius: roundradius, resolution: resolution}); + result = result.unionSub(sphere,false,false); + sphere = CSG.sphere({center: p4, radius: roundradius, resolution: resolution}); + result = result.unionSub(sphere,false,true); + var cylinder = CSG.cylinder({start:p1, end: p2, radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder,false,false); + cylinder = CSG.cylinder({start:p2, end: p3, radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder,false,false); + cylinder = CSG.cylinder({start:p3, end: p4, radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder,false,false); + cylinder = CSG.cylinder({start:p4, end: p1, radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder,false,false); + if(level == 0) { + var d = new CSG.Vector3D(0, 0, -2*z); + cylinder = CSG.cylinder({start:p1, end: p1.plus(d), radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder); + cylinder = CSG.cylinder({start:p2, end: p2.plus(d), radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder); + cylinder = CSG.cylinder({start:p3, end: p3.plus(d), radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder); + cylinder = CSG.cylinder({start:p4, end: p4.plus(d), radius: roundradius, resolution: resolution}); + result = result.unionSub(cylinder,false,true); + } + } + result = result.reTesselated(); + result.properties.roundedCube = new CSG.Properties(); + result.properties.roundedCube.center = new CSG.Vertex(center); + result.properties.roundedCube.facecenters = [ + new CSG.Connector(new CSG.Vector3D([cuberadius.x, 0, 0]).plus(center), [1, 0, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([-cuberadius.x, 0, 0]).plus(center), [-1, 0, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([0, cuberadius.y, 0]).plus(center), [0, 1, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([0, -cuberadius.y, 0]).plus(center), [0, -1, 0], [0, 0, 1]), + new CSG.Connector(new CSG.Vector3D([0, 0, cuberadius.z]).plus(center), [0, 0, 1], [1, 0, 0]), + new CSG.Connector(new CSG.Vector3D([0, 0, -cuberadius.z]).plus(center), [0, 0, -1], [1, 0, 0]), + ]; + return result; +}; + + + +// # class Vector3D + +// Represents a 3D vector. +// +// Example usage: +// +// new CSG.Vector3D(1, 2, 3); +// new CSG.Vector3D([1, 2, 3]); +// new CSG.Vector3D({ x: 1, y: 2, z: 3 }); + +CSG.Vector3D = function(x, y, z) { + if (arguments.length == 3) + { + this._x = x; + this._y = y; + this._z = z; + } + else + { + var ok = true; + if (arguments.length == 1) + { + if(typeof(x) == "object") + { + if(x instanceof CSG.Vector3D) + { + this._x = x._x; + this._y = x._y; + this._z = x._z; + } + else if(x instanceof Array) + { + this._x = x[0]; + this._y = x[1]; + this._z = x[2]; + } + else if( ('x' in x) && ('y' in x) && ('z' in x) ) + { + this._x = x.x; + this._y = x.y; + this._z = x.z; + } + else ok = false; + } + else + { + var v = Number(x); + this._x = v; + this._y = v; + this._z = v; + } + } + else ok = false; + if(!ok) + { + throw new Error("wrong arguments"); + } + } +}; + +CSG.Vector3D.prototype = { + get x() { + return this._x; + }, + get y() { + return this._y; + }, + get z() { + return this._z; + }, + + set x(v) { + throw new Error("Vector3D is immutable"); + }, + set y(v) { + throw new Error("Vector3D is immutable"); + }, + set z(v) { + throw new Error("Vector3D is immutable"); + }, + + clone: function() { + return new CSG.Vector3D(this); + }, + + negated: function() { + return new CSG.Vector3D(-this._x, -this._y, -this._z); + }, + + abs: function() { + return new CSG.Vector3D(Math.abs(this._x), Math.abs(this._y), Math.abs(this._z)); + }, + + plus: function(a) { + return new CSG.Vector3D(this._x + a._x, this._y + a._y, this._z + a._z); + }, + + minus: function(a) { + return new CSG.Vector3D(this._x - a._x, this._y - a._y, this._z - a._z); + }, + + times: function(a) { + return new CSG.Vector3D(this._x * a, this._y * a, this._z * a); + }, + + dividedBy: function(a) { + return new CSG.Vector3D(this._x / a, this._y / a, this._z / a); + }, + + dot: function(a) { + return this._x * a._x + this._y * a._y + this._z * a._z; + }, + + lerp: function(a, t) { + return this.plus(a.minus(this).times(t)); + }, + + lengthSquared: function() { + return this.dot(this); + }, + + length: function() { + return Math.sqrt(this.lengthSquared()); + }, + + unit: function() { + return this.dividedBy(this.length()); + }, + + cross: function(a) { + return new CSG.Vector3D( + this._y * a._z - this._z * a._y, + this._z * a._x - this._x * a._z, + this._x * a._y - this._y * a._x + ); + }, + + distanceTo: function(a) { + return this.minus(a).length(); + }, + + distanceToSquared: function(a) { + return this.minus(a).lengthSquared(); + }, + + equals: function(a) { + return (this._x == a._x) && (this._y == a._y) && (this._z == a._z); + }, + + // Right multiply by a 4x4 matrix (the vector is interpreted as a row vector) + // Returns a new CSG.Vector3D + multiply4x4: function(matrix4x4) { + return matrix4x4.leftMultiply1x3Vector(this); + }, + + transform: function(matrix4x4) { + return matrix4x4.leftMultiply1x3Vector(this); + }, + + toStlString: function() { + return this._x+" "+this._y+" "+this._z; + }, + + toString: function() { + return "("+this._x+", "+this._y+", "+this._z+")"; + }, + + // find a vector that is somewhat perpendicular to this one + randomNonParallelVector: function() { + var abs = this.abs(); + if( (abs._x <= abs._y) && (abs._x <= abs._z) ) + { + return new CSG.Vector3D(1,0,0); + } + else if( (abs._y <= abs._x) && (abs._y <= abs._z) ) + { + return new CSG.Vector3D(0,1,0); + } + else + { + return new CSG.Vector3D(0,0,1); + } + }, + + min: function(p) { + return new CSG.Vector3D( + Math.min(this._x, p._x), + Math.min(this._y, p._y), + Math.min(this._z, p._z) + ); + }, + + max: function(p) { + return new CSG.Vector3D( + Math.max(this._x, p._x), + Math.max(this._y, p._y), + Math.max(this._z, p._z) + ); + }, +}; + +// # class Vertex + +// Represents a vertex of a polygon. Use your own vertex class instead of this +// one to provide additional features like texture coordinates and vertex +// colors. Custom vertex classes need to provide a `pos` property +// `flipped()`, and `interpolate()` methods that behave analogous to the ones +// defined by `CSG.Vertex`. + +CSG.Vertex = function(pos) { + this.pos = pos; +}; + +// create from an untyped object with identical property names: +CSG.Vertex.fromObject = function(obj) { + var pos = new CSG.Vector3D(obj.pos); + return new CSG.Vertex(pos); +}; + +CSG.Vertex.prototype = { + // Return a vertex with all orientation-specific data (e.g. vertex normal) flipped. Called when the + // orientation of a polygon is flipped. + flipped: function() { + return this; + }, + + getTag: function() { + var result = this.tag; + if(!result) + { + result = CSG.getTag(); + this.tag = result; + } + return result; + }, + + // Create a new vertex between this vertex and `other` by linearly + // interpolating all properties using a parameter of `t`. Subclasses should + // override this to interpolate additional properties. + interpolate: function(other, t) { + var newpos = this.pos.lerp(other.pos, t); + return new CSG.Vertex(newpos); + }, + + // Affine transformation of vertex. Returns a new CSG.Vertex + transform: function(matrix4x4) { + var newpos = this.pos.multiply4x4(matrix4x4); + return new CSG.Vertex(newpos); + }, + + toStlString: function() { + return "vertex "+this.pos.toStlString()+"\n"; + }, + + toString: function() { + return this.pos.toString(); + }, +}; + +// # class Plane + +// Represents a plane in 3D space. + +CSG.Plane = function(normal, w) { + this.normal = normal; + this.w = w; +}; + +// create from an untyped object with identical property names: +CSG.Plane.fromObject = function(obj) { + var normal = new CSG.Vector3D(obj.normal); + var w = parseFloat(obj.w); + return new CSG.Plane(normal, w); +}; + +// `CSG.Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a +// point is on the plane. +CSG.Plane.EPSILON = 1e-5; + +CSG.Plane.fromVector3Ds = function(a, b, c) { + var n = b.minus(a).cross(c.minus(a)).unit(); + return new CSG.Plane(n, n.dot(a)); +}; + +// like fromVector3Ds, but allow the vectors to be on one point or one line +// in such a case a random plane through the given points is constructed +CSG.Plane.anyPlaneFromVector3Ds = function(a, b, c) { + var v1 = b.minus(a); + var v2 = c.minus(a); + if(v1.length() < 1e-5) + { + v1 = v2.randomNonParallelVector(); + } + if(v2.length() < 1e-5) + { + v2 = v1.randomNonParallelVector(); + } + var normal = v1.cross(v2); + if(normal.length() < 1e-5) + { + // this would mean that v1 == v2.negated() + v2 = v1.randomNonParallelVector(); + normal = v1.cross(v2); + } + normal = normal.unit(); + return new CSG.Plane(normal, normal.dot(a)); +}; + +CSG.Plane.fromPoints = function(a, b, c) { + a = new CSG.Vector3D(a); + b = new CSG.Vector3D(b); + c = new CSG.Vector3D(c); + return CSG.Plane.fromVector3Ds(a, b, c); +}; + +CSG.Plane.fromNormalAndPoint = function(normal, point) { + normal = new CSG.Vector3D(normal); + point = new CSG.Vector3D(point); + normal = normal.unit(); + var w = point.dot(normal); + return new CSG.Plane(normal, w); +}; + +CSG.Plane.prototype = { + flipped: function() { + return new CSG.Plane(this.normal.negated(), -this.w); + }, + + getTag: function() { + var result = this.tag; + if(!result) + { + result = CSG.getTag(); + this.tag = result; + } + return result; + }, + + equals: function(n) { + return this.normal.equals(n.normal) && this.w == n.w; + }, + + transform: function(matrix4x4) { + var origin = new CSG.Vector3D(0,0,0); + var pointOnPlane = this.normal.times(this.w); + var neworigin = origin.multiply4x4(matrix4x4); + var neworiginPlusNormal = this.normal.multiply4x4(matrix4x4); + var newnormal = neworiginPlusNormal.minus(neworigin); + var newpointOnPlane = pointOnPlane.multiply4x4(matrix4x4); + var neww = newnormal.dot(newpointOnPlane); + return new CSG.Plane(newnormal, neww); + }, + + // Returns object: + // .type: + // 0: coplanar-front + // 1: coplanar-back + // 2: front + // 3: back + // 4: spanning + // In case the polygon is spanning, returns: + // .front: a CSG.Polygon of the front part + // .back: a CSG.Polygon of the back part + splitPolygon: function(polygon) { + var result = { + type: null, + front: null, + back: null, + }; + // cache in local vars (speedup): + var planenormal = this.normal; + var vertices = polygon.vertices; + var numvertices = vertices.length; + if(polygon.plane.equals(this)) + { + result.type = 0; + } + else + { + var EPS = CSG.Plane.EPSILON; + var thisw = this.w; + var hasfront = false; + var hasback = false; + var vertexIsBack = []; + var MINEPS = -EPS; + for (var i = 0; i < numvertices; i++) { + var t = planenormal.dot(vertices[i].pos) - thisw; + var isback = (t < 0); + vertexIsBack.push(isback); + if(t > EPS) hasfront = true; + if(t < MINEPS) hasback = true; + } + if( (!hasfront) && (!hasback) ) + { + // all points coplanar + var t = planenormal.dot(polygon.plane.normal); + result.type = (t >= 0)? 0:1; + } + else if(!hasback) + { + result.type = 2; + } + else if(!hasfront) + { + result.type = 3; + } + else + { + // spanning + result.type = 4; + var frontvertices = [], backvertices = []; + var isback = vertexIsBack[0]; + for(var vertexindex = 0; vertexindex < numvertices; vertexindex++) + { + var vertex = vertices[vertexindex]; + var nextvertexindex = vertexindex + 1; + if(nextvertexindex >= numvertices) nextvertexindex = 0; + var nextisback = vertexIsBack[nextvertexindex]; + if(isback == nextisback) + { + // line segment is on one side of the plane: + if(isback) + { + backvertices.push(vertex); + } + else + { + frontvertices.push(vertex); + } + } + else + { + // line segment intersects plane: + var point = vertex.pos; + var nextpoint = vertices[nextvertexindex].pos; + var line = CSG.Line3D.fromPoints(point, nextpoint); + var intersectionpoint = this.intersectWithLine(line); + var intersectionvertex = new CSG.Vertex(intersectionpoint); + if(isback) + { + backvertices.push(vertex); + backvertices.push(intersectionvertex); + frontvertices.push(intersectionvertex); + } + else + { + frontvertices.push(vertex); + frontvertices.push(intersectionvertex); + backvertices.push(intersectionvertex); + } + } + isback = nextisback; + } // for vertexindex + + // remove duplicate vertices: + var EPS_SQUARED = CSG.Plane.EPSILON * CSG.Plane.EPSILON; + if(backvertices.length >= 3) + { + var prevvertex = backvertices[backvertices.length - 1]; + for(var vertexindex = 0; vertexindex < backvertices.length; vertexindex++) + { + var vertex = backvertices[vertexindex]; + if(vertex.pos.distanceToSquared(prevvertex.pos) < EPS_SQUARED) + { + backvertices.splice(vertexindex,1); + vertexindex--; + } + prevvertex = vertex; + } + } + if(frontvertices.length >= 3) + { + var prevvertex = frontvertices[frontvertices.length - 1]; + for(var vertexindex = 0; vertexindex < frontvertices.length; vertexindex++) + { + var vertex = frontvertices[vertexindex]; + if(vertex.pos.distanceToSquared(prevvertex.pos) < EPS_SQUARED) + { + frontvertices.splice(vertexindex,1); + vertexindex--; + } + prevvertex = vertex; + } + } + if (frontvertices.length >= 3) + { + result.front = new CSG.Polygon(frontvertices, polygon.shared, polygon.plane); + } + if (backvertices.length >= 3) + { + result.back = new CSG.Polygon(backvertices, polygon.shared, polygon.plane); + } + } + } + return result; + }, + + // returns CSG.Vector3D + intersectWithLine: function(line3d) { + return line3d.intersectWithPlane(this); + }, + + // intersection of two planes + intersectWithPlane: function(plane) { + return CSG.Line3D.fromPlanes(this, plane); + }, + + signedDistanceToPoint: function(point) { + var t = this.normal.dot(point) - this.w; + return t; + }, + + toString: function() { + return "[normal: "+this.normal.toString()+", w: "+this.w+"]"; + }, + + mirrorPoint: function(point3d) { + var distance = this.signedDistanceToPoint(point3d); + var mirrored = point3d.minus(this.normal.times(distance * 2.0)); + return mirrored; + }, +}; + + +// # class Polygon + +// Represents a convex polygon. The vertices used to initialize a polygon must +// be coplanar and form a convex loop. They do not have to be `CSG.Vertex` +// instances but they must behave similarly (duck typing can be used for +// customization). +// +// Each convex polygon has a `shared` property, which is shared between all +// polygons that are clones of each other or were split from the same polygon. +// This can be used to define per-polygon properties (such as surface color). +// +// The plane of the polygon is calculated from the vertex coordinates +// To avoid unnecessary recalculation, the plane can alternatively be +// passed as the third argument +CSG.Polygon = function(vertices, shared, plane) { + this.vertices = vertices; + if(!shared) shared = CSG.Polygon.defaultShared; + this.shared = shared; + var numvertices = vertices.length; + + if(arguments.length >= 3) + { + this.plane = plane; + } + else + { + this.plane = CSG.Plane.fromVector3Ds(vertices[0].pos, vertices[1].pos, vertices[2].pos); + } + + if(_CSGDEBUG) + { + this.checkIfConvex(); + } +}; + +// create from an untyped object with identical property names: +CSG.Polygon.fromObject = function(obj) { + var vertices = obj.vertices.map(function(v) { + return CSG.Vertex.fromObject(v); + }); + var shared = CSG.Polygon.Shared.fromObject(obj.shared); + var plane = CSG.Plane.fromObject(obj.plane); + return new CSG.Polygon(vertices, shared, plane); +}; + +CSG.Polygon.prototype = { + // check whether the polygon is convex (it should be, otherwise we will get unexpected results) + checkIfConvex: function() { + if(! CSG.Polygon.verticesConvex(this.vertices, this.plane.normal)) + { + throw new Error("Not convex!"); + } + }, + + // Extrude a polygon into the direction offsetvector + // Returns a CSG object + extrude: function(offsetvector) { + var newpolygons = []; + + var polygon1=this; + var direction = polygon1.plane.normal.dot(offsetvector); + if(direction > 0) + { + polygon1 = polygon1.flipped(); + } + newpolygons.push(polygon1); + var polygon2=polygon1.translate(offsetvector); + var numvertices=this.vertices.length; + for(var i=0; i < numvertices; i++) + { + var sidefacepoints = []; + var nexti = (i < (numvertices-1))? i+1:0; + sidefacepoints.push(polygon1.vertices[i].pos); + sidefacepoints.push(polygon2.vertices[i].pos); + sidefacepoints.push(polygon2.vertices[nexti].pos); + sidefacepoints.push(polygon1.vertices[nexti].pos); + var sidefacepolygon=CSG.Polygon.createFromPoints(sidefacepoints, this.shared); + newpolygons.push(sidefacepolygon); + } + polygon2 = polygon2.flipped(); + newpolygons.push(polygon2); + return CSG.fromPolygons(newpolygons); + }, + + translate: function(offset) { + return this.transform(CSG.Matrix4x4.translation(offset)); + }, + + // returns an array with a CSG.Vector3D (center point) and a radius + boundingSphere: function() { + if(!this.cachedBoundingSphere) + { + var box = this.boundingBox(); + var middle = box[0].plus(box[1]).times(0.5); + var radius3 = box[1].minus(middle); + var radius = radius3.length(); + this.cachedBoundingSphere = [middle, radius]; + } + return this.cachedBoundingSphere; + }, + + // returns an array of two CSG.Vector3Ds (minimum coordinates and maximum coordinates) + boundingBox: function() { + if(!this.cachedBoundingBox) + { + var minpoint, maxpoint; + var vertices = this.vertices; + var numvertices = vertices.length; + if(numvertices == 0) + { + minpoint=new CSG.Vector3D(0,0,0); + } + else + { + minpoint=vertices[0].pos; + } + maxpoint=minpoint; + for(var i=1; i < numvertices; i++) + { + var point = vertices[i].pos; + minpoint = minpoint.min(point); + maxpoint = maxpoint.max(point); + } + this.cachedBoundingBox = [minpoint, maxpoint]; + } + return this.cachedBoundingBox; + }, + + flipped: function() { + var newvertices = this.vertices.map(function(v) { return v.flipped(); }); + newvertices.reverse(); + var newplane = this.plane.flipped(); + return new CSG.Polygon(newvertices, this.shared, newplane); + }, + + // Affine transformation of polygon. Returns a new CSG.Polygon + transform: function(matrix4x4) { + var newvertices = this.vertices.map(function(v) { return v.transform(matrix4x4); } ); + var newplane = this.plane.transform(matrix4x4); + var scalefactor = matrix4x4.elements[0] * matrix4x4.elements[5] * matrix4x4.elements[10]; + if(scalefactor < 0) + { + // the transformation includes mirroring. We need to reverse the vertex order + // in order to preserve the inside/outside orientation: + newvertices.reverse(); + } + return new CSG.Polygon(newvertices, this.shared, newplane); + }, + + toStlString: function() { + var result=""; + if(this.vertices.length >= 3) // should be! + { + // STL requires triangular polygons. If our polygon has more vertices, create + // multiple triangles: + var firstVertexStl = this.vertices[0].toStlString(); + for(var i=0; i < this.vertices.length-2; i++) + { + result += "facet normal "+this.plane.normal.toStlString()+"\nouter loop\n"; + result += firstVertexStl; + result += this.vertices[i+1].toStlString(); + result += this.vertices[i+2].toStlString(); + result += "endloop\nendfacet\n"; + } + } + return result; + }, + + toString: function() { + var result = "Polygon plane: "+this.plane.toString()+"\n"; + this.vertices.map(function(vertex) { + result += " "+vertex.toString()+"\n"; + }); + return result; + }, +}; + +CSG.Polygon.verticesConvex = function(vertices, planenormal) { + var numvertices = vertices.length; + if(numvertices > 2) + { + var prevprevpos=vertices[numvertices-2].pos; + var prevpos=vertices[numvertices-1].pos; + for(var i=0; i < numvertices; i++) + { + var pos=vertices[i].pos; + if(!CSG.Polygon.isConvexPoint(prevprevpos, prevpos, pos, planenormal)) + { + return false; + } + prevprevpos=prevpos; + prevpos=pos; + } + } + return true; +}; + +// Create a polygon from the given points +CSG.Polygon.createFromPoints = function(points, shared, plane) { + var normal; + if(arguments.length < 3) + { + // initially set a dummy vertex normal: + normal = new CSG.Vector3D(0, 0, 0); + } + else + { + normal = plane.normal; + } + var vertices = []; + points.map( function(p) { + var vec = new CSG.Vector3D(p); + var vertex = new CSG.Vertex(vec); + vertices.push(vertex); + }); + var polygon; + if(arguments.length < 3) + { + polygon = new CSG.Polygon(vertices, shared); + } + else + { + polygon = new CSG.Polygon(vertices, shared, plane); + } + return polygon; +}; + +// calculate whether three points form a convex corner +// prevpoint, point, nextpoint: the 3 coordinates (CSG.Vector3D instances) +// normal: the normal vector of the plane +CSG.Polygon.isConvexPoint = function(prevpoint, point, nextpoint, normal) { + var crossproduct=point.minus(prevpoint).cross(nextpoint.minus(point)); + var crossdotnormal=crossproduct.dot(normal); + return (crossdotnormal >= 0); +}; + +CSG.Polygon.isStrictlyConvexPoint = function(prevpoint, point, nextpoint, normal) { + var crossproduct=point.minus(prevpoint).cross(nextpoint.minus(point)); + var crossdotnormal=crossproduct.dot(normal); + return (crossdotnormal >= 1e-5); +}; + +// # class CSG.Polygon.Shared + +// Holds the shared properties for each polygon (currently only color) + +CSG.Polygon.Shared = function(color) { + this.color = color; +}; + +CSG.Polygon.Shared.fromObject = function(obj) { + return new CSG.Polygon.Shared(obj.color); +}; + +CSG.Polygon.Shared.prototype = { + getTag: function() { + var result = this.tag; + if(!result) + { + result = CSG.getTag(); + this.tag = result; + } + return result; + }, + // get a string uniquely identifying this object + getHash: function() { + if(!this.color) return "null"; + return ""+this.color[0]+"/"+this.color[1]+"/"+this.color[2]; + }, +}; + +CSG.Polygon.defaultShared = new CSG.Polygon.Shared(null); + +// # class PolygonTreeNode + +// This class manages hierarchical splits of polygons +// At the top is a root node which doesn hold a polygon, only child PolygonTreeNodes +// Below that are zero or more 'top' nodes; each holds a polygon. The polygons can be in different planes +// splitByPlane() splits a node by a plane. If the plane intersects the polygon, two new child nodes +// are created holding the splitted polygon. +// getPolygons() retrieves the polygon from the tree. If for PolygonTreeNode the polygon is split but +// the two split parts (child nodes) are still intact, then the unsplit polygon is returned. +// This ensures that we can safely split a polygon into many fragments. If the fragments are untouched, +// getPolygons() will return the original unsplit polygon instead of the fragments. +// remove() removes a polygon from the tree. Once a polygon is removed, the parent polygons are invalidated +// since they are no longer intact. + +// constructor creates the root node: +CSG.PolygonTreeNode = function() { + this.parent = null; + this.children = []; + this.polygon = null; + this.removed = false; +}; + +CSG.PolygonTreeNode.prototype = { + // fill the tree with polygons. Should be called on the root node only; child nodes must + // always be a derivate (split) of the parent node. + addPolygons: function(polygons) { + if(!this.isRootNode()) throw new Error("Assertion failed"); // new polygons can only be added to root node; children can only be splitted polygons + var _this = this; + polygons.map(function(polygon) { + _this.addChild(polygon); + }); + }, + + // remove a node + // - the siblings become toplevel nodes + // - the parent is removed recursively + remove: function() { + if(!this.removed) + { + this.removed=true; + + if(_CSGDEBUG) + { + if(this.isRootNode()) throw new Error("Assertion failed"); // can't remove root node + if(this.children.length) throw new Error("Assertion failed"); // we shouldn't remove nodes with children + } + + // remove ourselves from the parent's children list: + var parentschildren = this.parent.children; + var i = parentschildren.indexOf(this); + if(i < 0) throw new Error("Assertion failed"); + parentschildren.splice(i,1); + + // invalidate the parent's polygon, and of all parents above it: + this.parent.recursivelyInvalidatePolygon(); + } + }, + + isRemoved: function() { + return this.removed; + }, + + isRootNode: function() { + return !this.parent; + }, + + // invert all polygons in the tree. Call on the root node + invert: function() { + if(!this.isRootNode()) throw new Error("Assertion failed"); // can only call this on the root node + this.invertSub(); + }, + + getPolygon: function () { + if(!this.polygon) throw new Error("Assertion failed"); // doesn't have a polygon, which means that it has been broken down + return this.polygon; + }, + + getPolygons: function (result) { + if(this.polygon) + { + // the polygon hasn't been broken yet. We can ignore the children and return our polygon: + result.push(this.polygon); + } + else + { + // our polygon has been split up and broken, so gather all subpolygons from the children: + var childpolygons = []; + this.children.map(function(child) { + child.getPolygons(childpolygons); + }); + childpolygons.map(function(p) { + result.push(p); + }); + } + }, + + // split the node by a plane; add the resulting nodes to the frontnodes and backnodes array + // If the plane doesn't intersect the polygon, the 'this' object is added to one of the arrays + // If the plane does intersect the polygon, two new child nodes are created for the front and back fragments, + // and added to both arrays. + splitByPlane: function(plane, coplanarfrontnodes, coplanarbacknodes, frontnodes, backnodes) { + var children = this.children; + var numchildren = children.length; + if(numchildren > 0) + { + // if we have children, split the children + for(var i = 0; i < numchildren; i++) + { + children[i].splitByPlane(plane, coplanarfrontnodes, coplanarbacknodes, frontnodes, backnodes); + } + } + else + { + // no children. Split the polygon: + var polygon = this.polygon; + if(polygon) + { + var bound = polygon.boundingSphere(); + var sphereradius = bound[1] + 1e-4; + var planenormal = plane.normal; + var spherecenter = bound[0]; + var d = planenormal.dot(spherecenter) - plane.w; + if(d > sphereradius) + { + frontnodes.push(this); + } + else if(d < -sphereradius) + { + backnodes.push(this); + } + else + { + var splitresult = plane.splitPolygon(polygon); + switch(splitresult.type) + { + case 0: // coplanar front: + coplanarfrontnodes.push(this); + break; + + case 1: // coplanar back: + coplanarbacknodes.push(this); + break; + + case 2: // front: + frontnodes.push(this); + break; + + case 3: // back: + backnodes.push(this); + break; + + case 4: // spanning: + if(splitresult.front) + { + var frontnode = this.addChild(splitresult.front); + frontnodes.push(frontnode); + } + if(splitresult.back) + { + var backnode = this.addChild(splitresult.back); + backnodes.push(backnode); + } + break; + } + } + } + } + }, + + + // PRIVATE methods from here: + + // add child to a node + // this should be called whenever the polygon is split + // a child should be created for every fragment of the split polygon + // returns the newly created child + addChild: function(polygon) { + var newchild = new CSG.PolygonTreeNode(); + newchild.parent = this; + newchild.polygon = polygon; + this.children.push(newchild); + return newchild; + }, + + invertSub: function() { + if(this.polygon) + { + this.polygon = this.polygon.flipped(); + } + this.children.map(function(child) { + child.invertSub(); + }); + }, + + recursivelyInvalidatePolygon: function() { + if(this.polygon) + { + this.polygon = null; + if(this.parent) + { + this.parent.recursivelyInvalidatePolygon(); + } + } + }, + +}; + + + +// # class Tree +// This is the root of a BSP tree +// We are using this separate class for the root of the tree, to hold the PolygonTreeNode root +// The actual tree is kept in this.rootnode +CSG.Tree = function(polygons) { + this.polygonTree = new CSG.PolygonTreeNode(); + this.rootnode = new CSG.Node(null); + if (polygons) this.addPolygons(polygons); +}; + +CSG.Tree.prototype = { + invert: function() { + this.polygonTree.invert(); + this.rootnode.invert(); + }, + + // Remove all polygons in this BSP tree that are inside the other BSP tree + // `tree`. + clipTo: function(tree, alsoRemovecoplanarFront) { + alsoRemovecoplanarFront = alsoRemovecoplanarFront? true:false; + this.rootnode.clipTo(tree, alsoRemovecoplanarFront); + }, + + allPolygons: function() { + var result = []; + this.polygonTree.getPolygons(result); + return result; + }, + + addPolygons: function(polygons) { + var _this = this; + var polygontreenodes = polygons.map(function(p) { + return _this.polygonTree.addChild(p); + }); + this.rootnode.addPolygonTreeNodes(polygontreenodes); + }, +}; + +// # class Node + +// Holds a node in a BSP tree. A BSP tree is built from a collection of polygons +// by picking a polygon to split along. +// Polygons are not stored directly in the tree, but in PolygonTreeNodes, stored in +// this.polygontreenodes. Those PolygonTreeNodes are children of the owning +// CSG.Tree.polygonTree +// This is not a leafy BSP tree since there is +// no distinction between internal and leaf nodes. + +CSG.Node = function(parent) { + this.plane = null; + this.front = null; + this.back = null; + this.polygontreenodes = []; + this.parent = parent; +}; + +CSG.Node.prototype = { + // Convert solid space to empty space and empty space to solid space. + invert: function() { + if (this.plane) this.plane = this.plane.flipped(); + if (this.front) this.front.invert(); + if (this.back) this.back.invert(); + var temp = this.front; + this.front = this.back; + this.back = temp; + }, + + // clip polygontreenodes to our plane + // calls remove() for all clipped PolygonTreeNodes + clipPolygons: function(polygontreenodes, alsoRemovecoplanarFront) { + if(this.plane) + { + var backnodes = []; + var frontnodes = []; + var coplanarfrontnodes = alsoRemovecoplanarFront? backnodes:frontnodes; + var plane = this.plane; + var numpolygontreenodes = polygontreenodes.length; + for(i=0; i < numpolygontreenodes; i++) + { + var node = polygontreenodes[i]; + if(!node.isRemoved() ) + { + node.splitByPlane(plane, coplanarfrontnodes, backnodes, frontnodes, backnodes); + } + } + if(this.front && (frontnodes.length > 0) ) + { + this.front.clipPolygons(frontnodes, alsoRemovecoplanarFront); + } + var numbacknodes = backnodes.length; + if(this.back && (numbacknodes > 0) ) + { + this.back.clipPolygons(backnodes, alsoRemovecoplanarFront); + } + else + { + // there's nothing behind this plane. Delete the nodes behind this plane: + for(i=0; i < numbacknodes; i++) + { + backnodes[i].remove(); + } + } + } + }, + + // Remove all polygons in this BSP tree that are inside the other BSP tree + // `tree`. + clipTo: function(tree, alsoRemovecoplanarFront) { + if(this.polygontreenodes.length > 0) + { + tree.rootnode.clipPolygons(this.polygontreenodes, alsoRemovecoplanarFront); + } + if (this.front) this.front.clipTo(tree, alsoRemovecoplanarFront); + if (this.back) this.back.clipTo(tree, alsoRemovecoplanarFront); + }, + + addPolygonTreeNodes: function(polygontreenodes) { + if(polygontreenodes.length == 0) return; + var _this = this; + if(!this.plane) + { + var bestplane = polygontreenodes[0].getPolygon().plane; +/* + var parentnormals = []; + this.getParentPlaneNormals(parentnormals, 6); +//parentnormals = []; + var numparentnormals = parentnormals.length; + var minmaxnormal = 1.0; + polygontreenodes.map(function(polygontreenode){ + var plane = polygontreenodes[0].getPolygon().plane; + var planenormal = plane.normal; + var maxnormaldot = -1.0; + parentnormals.map(function(parentnormal){ + var dot = parentnormal.dot(planenormal); + if(dot > maxnormaldot) maxnormaldot = dot; + }); + if(maxnormaldot < minmaxnormal) + { + minmaxnormal = maxnormaldot; + bestplane = plane; + } + }); +*/ + this.plane = bestplane; + } + var frontnodes = []; + var backnodes = []; + polygontreenodes.map(function(polygontreenode){ + polygontreenode.splitByPlane(_this.plane, _this.polygontreenodes, _this.polygontreenodes, frontnodes, backnodes); + }); + if(frontnodes.length > 0) + { + if (!this.front) this.front = new CSG.Node(this); + this.front.addPolygonTreeNodes(frontnodes); + } + if(backnodes.length > 0) + { + if (!this.back) this.back = new CSG.Node(this); + this.back.addPolygonTreeNodes(backnodes); + } + }, + + getParentPlaneNormals: function(normals, maxdepth) { + if(maxdepth > 0) + { + if(this.parent) + { + normals.push(this.parent.plane.normal); + this.parent.getParentPlaneNormals(normals,maxdepth-1); + } + } + }, +}; + +////////// + +// # class Matrix4x4: +// Represents a 4x4 matrix. Elements are specified in row order +CSG.Matrix4x4 = function(elements) { + if (arguments.length >= 1) { + this.elements=elements; + } + else + { + // if no arguments passed: create unity matrix + this.elements=[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + } +} + +CSG.Matrix4x4.prototype = { + plus: function(m) { + var r=[]; + for(var i=0; i < 16; i++) + { + r[i]=this.elements[i]+m.elements[i]; + } + return new CSG.Matrix4x4(r); + }, + + minus: function(m) { + var r=[]; + for(var i=0; i < 16; i++) + { + r[i]=this.elements[i]-m.elements[i]; + } + return new CSG.Matrix4x4(r); + }, + + // right multiply by another 4x4 matrix: + multiply: function(m) { + // cache elements in local variables, for speedup: + var this0=this.elements[0]; + var this1=this.elements[1]; + var this2=this.elements[2]; + var this3=this.elements[3]; + var this4=this.elements[4]; + var this5=this.elements[5]; + var this6=this.elements[6]; + var this7=this.elements[7]; + var this8=this.elements[8]; + var this9=this.elements[9]; + var this10=this.elements[10]; + var this11=this.elements[11]; + var this12=this.elements[12]; + var this13=this.elements[13]; + var this14=this.elements[14]; + var this15=this.elements[15]; + var m0=m.elements[0]; + var m1=m.elements[1]; + var m2=m.elements[2]; + var m3=m.elements[3]; + var m4=m.elements[4]; + var m5=m.elements[5]; + var m6=m.elements[6]; + var m7=m.elements[7]; + var m8=m.elements[8]; + var m9=m.elements[9]; + var m10=m.elements[10]; + var m11=m.elements[11]; + var m12=m.elements[12]; + var m13=m.elements[13]; + var m14=m.elements[14]; + var m15=m.elements[15]; + + var result=[]; + result[0] = this0*m0 + this1*m4 + this2*m8 + this3*m12; + result[1] = this0*m1 + this1*m5 + this2*m9 + this3*m13; + result[2] = this0*m2 + this1*m6 + this2*m10 + this3*m14; + result[3] = this0*m3 + this1*m7 + this2*m11 + this3*m15; + result[4] = this4*m0 + this5*m4 + this6*m8 + this7*m12; + result[5] = this4*m1 + this5*m5 + this6*m9 + this7*m13; + result[6] = this4*m2 + this5*m6 + this6*m10 + this7*m14; + result[7] = this4*m3 + this5*m7 + this6*m11 + this7*m15; + result[8] = this8*m0 + this9*m4 + this10*m8 + this11*m12; + result[9] = this8*m1 + this9*m5 + this10*m9 + this11*m13; + result[10] = this8*m2 + this9*m6 + this10*m10 + this11*m14; + result[11] = this8*m3 + this9*m7 + this10*m11 + this11*m15; + result[12] = this12*m0 + this13*m4 + this14*m8 + this15*m12; + result[13] = this12*m1 + this13*m5 + this14*m9 + this15*m13; + result[14] = this12*m2 + this13*m6 + this14*m10 + this15*m14; + result[15] = this12*m3 + this13*m7 + this14*m11 + this15*m15; + return new CSG.Matrix4x4(result); + }, + + clone: function() { + var elements = this.elements.map(function(p) { return p; }); + return new CSG.Matrix4x4(elements); + }, + + // Right multiply the matrix by a CSG.Vector3D (interpreted as 3 row, 1 column) + // (result = M*v) + // Fourth element is taken as 1 + rightMultiply1x3Vector: function(v) { + var v0 = v._x; + var v1 = v._y; + var v2 = v._z; + var v3 = 1; + var x = v0*this.elements[0] + v1*this.elements[1] + v2*this.elements[2] + v3*this.elements[3]; + var y = v0*this.elements[4] + v1*this.elements[5] + v2*this.elements[6] + v3*this.elements[7]; + var z = v0*this.elements[8] + v1*this.elements[9] + v2*this.elements[10] + v3*this.elements[11]; + var w = v0*this.elements[12] + v1*this.elements[13] + v2*this.elements[14] + v3*this.elements[15]; + // scale such that fourth element becomes 1: + if(w != 1) + { + var invw=1.0/w; + x *= invw; + y *= invw; + z *= invw; + } + return new CSG.Vector3D(x,y,z); + }, + + // Multiply a CSG.Vector3D (interpreted as 3 column, 1 row) by this matrix + // (result = v*M) + // Fourth element is taken as 1 + leftMultiply1x3Vector: function(v) { + var v0 = v._x; + var v1 = v._y; + var v2 = v._z; + var v3 = 1; + var x = v0*this.elements[0] + v1*this.elements[4] + v2*this.elements[8] + v3*this.elements[12]; + var y = v0*this.elements[1] + v1*this.elements[5] + v2*this.elements[9] + v3*this.elements[13]; + var z = v0*this.elements[2] + v1*this.elements[6] + v2*this.elements[10] + v3*this.elements[14]; + var w = v0*this.elements[3] + v1*this.elements[7] + v2*this.elements[11] + v3*this.elements[15]; + // scale such that fourth element becomes 1: + if(w != 1) + { + var invw=1.0/w; + x *= invw; + y *= invw; + z *= invw; + } + return new CSG.Vector3D(x,y,z); + }, + + // Right multiply the matrix by a CSG.Vector2D (interpreted as 2 row, 1 column) + // (result = M*v) + // Fourth element is taken as 1 + rightMultiply1x2Vector: function(v) { + var v0 = v.x; + var v1 = v.y; + var v2 = 0; + var v3 = 1; + var x = v0*this.elements[0] + v1*this.elements[1] + v2*this.elements[2] + v3*this.elements[3]; + var y = v0*this.elements[4] + v1*this.elements[5] + v2*this.elements[6] + v3*this.elements[7]; + var z = v0*this.elements[8] + v1*this.elements[9] + v2*this.elements[10] + v3*this.elements[11]; + var w = v0*this.elements[12] + v1*this.elements[13] + v2*this.elements[14] + v3*this.elements[15]; + // scale such that fourth element becomes 1: + if(w != 1) + { + var invw=1.0/w; + x *= invw; + y *= invw; + z *= invw; + } + return new CSG.Vector2D(x,y); + }, + + // Multiply a CSG.Vector2D (interpreted as 2 column, 1 row) by this matrix + // (result = v*M) + // Fourth element is taken as 1 + leftMultiply1x2Vector: function(v) { + var v0 = v.x; + var v1 = v.y; + var v2 = 0; + var v3 = 1; + var x = v0*this.elements[0] + v1*this.elements[4] + v2*this.elements[8] + v3*this.elements[12]; + var y = v0*this.elements[1] + v1*this.elements[5] + v2*this.elements[9] + v3*this.elements[13]; + var z = v0*this.elements[2] + v1*this.elements[6] + v2*this.elements[10] + v3*this.elements[14]; + var w = v0*this.elements[3] + v1*this.elements[7] + v2*this.elements[11] + v3*this.elements[15]; + // scale such that fourth element becomes 1: + if(w != 1) + { + var invw=1.0/w; + x *= invw; + y *= invw; + z *= invw; + } + return new CSG.Vector2D(x,y); + }, +}; + +// return the unity matrix +CSG.Matrix4x4.unity = function() { + return new CSG.Matrix4x4(); +}; + +// Create a rotation matrix for rotating around the x axis +CSG.Matrix4x4.rotationX = function(degrees) { + var radians = degrees * Math.PI * (1.0/180.0); + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var els = [ + 1, 0, 0, 0, + 0, cos, sin, 0, + 0, -sin, cos, 0, + 0, 0, 0, 1 + ]; + return new CSG.Matrix4x4(els); +}; + +// Create a rotation matrix for rotating around the y axis +CSG.Matrix4x4.rotationY = function(degrees) { + var radians = degrees * Math.PI * (1.0/180.0); + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var els = [ + cos, 0, -sin, 0, + 0, 1, 0, 0, + sin, 0, cos, 0, + 0, 0, 0, 1 + ]; + return new CSG.Matrix4x4(els); +}; + +// Create a rotation matrix for rotating around the z axis +CSG.Matrix4x4.rotationZ = function(degrees) { + var radians = degrees * Math.PI * (1.0/180.0); + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var els = [ + cos, sin, 0, 0, + -sin, cos, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ]; + return new CSG.Matrix4x4(els); +}; + +// Matrix for rotation about arbitrary point and axis +CSG.Matrix4x4.rotation = function(rotationCenter, rotationAxis, degrees) { + var rotationPlane = CSG.Plane.fromNormalAndPoint(rotationAxis, rotationCenter); + var orthobasis = new CSG.OrthoNormalBasis(rotationPlane); + var transformation = CSG.Matrix4x4.translation(rotationCenter.negated()); + transformation = transformation.multiply(orthobasis.getProjectionMatrix()); + transformation = transformation.multiply(CSG.Matrix4x4.rotationZ(degrees)); + transformation = transformation.multiply(orthobasis.getInverseProjectionMatrix()); + transformation = transformation.multiply(CSG.Matrix4x4.translation(rotationCenter)); + return transformation; +}; + +// Create an affine matrix for translation: +CSG.Matrix4x4.translation = function(v) { + // parse as CSG.Vector3D, so we can pass an array or a CSG.Vector3D + var vec = new CSG.Vector3D(v); + var els = [ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + vec.x, vec.y, vec.z, 1 + ]; + return new CSG.Matrix4x4(els); +}; + +// Create an affine matrix for mirroring into an arbitrary plane: +CSG.Matrix4x4.mirroring = function(plane) { + var nx = plane.normal.x; + var ny = plane.normal.y; + var nz = plane.normal.z; + var w = plane.w; + var els = [ + (1.0-2.0*nx*nx), (-2.0*ny*nx), (-2.0*nz*nx), 0, + (-2.0*nx*ny), (1.0-2.0*ny*ny), (-2.0*nz*ny), 0, + (-2.0*nx*nz), (-2.0*ny*nz), (1.0-2.0*nz*nz), 0, + (-2.0*nx*w), (-2.0*ny*w), (-2.0*nz*w), 1 + ]; + return new CSG.Matrix4x4(els); +}; + +// Create an affine matrix for scaling: +CSG.Matrix4x4.scaling = function(v) { + // parse as CSG.Vector3D, so we can pass an array or a CSG.Vector3D + var vec = new CSG.Vector3D(v); + var els = [ + vec.x, 0, 0, 0, + 0, vec.y, 0, 0, + 0, 0, vec.z, 0, + 0, 0, 0, 1 + ]; + return new CSG.Matrix4x4(els); +}; + +/////////////////////////////////////////////////// + +// # class Vector2D: +// Represents a 2 element vector +CSG.Vector2D = function(x, y) { + var ok = true; + if (arguments.length == 1) + { + if(typeof(x) == "object") + { + if(x instanceof Array) + { + this.x = x[0]; + this.y = x[1]; + } + else if( ('x' in x) && ('y' in x) ) + { + this.x = x.x; + this.y = x.y; + } + else ok = false; + } + else + { + var v = Number(x); + this.x = v; + this.y = v; + } + } + else if (arguments.length == 2) + { + this.x = Number(x); + this.y = Number(y); + } + else ok = false; + if(!ok) + { + throw new Error("wrong arguments"); + } +}; + +CSG.Vector2D.fromAngle = function(radians) { + return CSG.Vector2D.fromAngleRadians(radians); +}; + +CSG.Vector2D.fromAngleDegrees = function(degrees) { + var radians = Math.PI * degrees / 180; + return CSG.Vector2D.fromAngleRadians(radians); +}; + +CSG.Vector2D.fromAngleRadians = function(radians) { + return new CSG.Vector2D(Math.cos(radians), Math.sin(radians)); +}; + +CSG.Vector2D.prototype = { + // extend to a 3D vector by adding a z coordinate: + toVector3D: function(z) { + return new CSG.Vector3D(this.x, this.y, z); + }, + + equals: function(a) { + return (this.x == a.x) && (this.y == a.y); + }, + + clone: function() { + return new CSG.Vector2D(this.x, this.y); + }, + + negated: function() { + return new CSG.Vector2D(-this.x, -this.y); + }, + + plus: function(a) { + return new CSG.Vector2D(this.x + a.x, this.y + a.y); + }, + + minus: function(a) { + return new CSG.Vector2D(this.x - a.x, this.y - a.y); + }, + + times: function(a) { + return new CSG.Vector2D(this.x * a, this.y * a); + }, + + dividedBy: function(a) { + return new CSG.Vector2D(this.x / a, this.y / a); + }, + + dot: function(a) { + return this.x * a.x + this.y * a.y; + }, + + lerp: function(a, t) { + return this.plus(a.minus(this).times(t)); + }, + + length: function() { + return Math.sqrt(this.dot(this)); + }, + + distanceTo: function(a) { + return this.minus(a).length(); + }, + + unit: function() { + return this.dividedBy(this.length()); + }, + + // returns the vector rotated by 90 degrees clockwise + normal: function() { + return new CSG.Vector2D(this.y, -this.x); + }, + + // Right multiply by a 4x4 matrix (the vector is interpreted as a row vector) + // Returns a new CSG.Vector2D + multiply4x4: function(matrix4x4) { + return matrix4x4.leftMultiply1x2Vector(this); + }, + + angle: function() { + return this.angleRadians(); + }, + + angleDegrees: function() { + var radians = this.angleRadians(); + return 180 * radians / Math.PI; + }, + + angleRadians: function() { + // y=sin, x=cos + return Math.atan2(this.y, this.x); + }, +}; + +// A polygon in 2D space: +CSG.Polygon2D = function(points, shared) { + var vectors = []; + if(arguments.length >= 1) { + points.map( function(p) { + vectors.push(new CSG.Vector2D(p) ); + }); + } + this.points = vectors; + this.shared = shared; +}; + +CSG.Polygon2D.prototype = { + // Matrix transformation of polygon. Returns a new CSG.Polygon2D + transform: function(matrix4x4) { + var newpoints = this.points.map(function(p) { return p.multiply4x4(matrix4x4); } ); + return new CSG.Polygon2D(newpoints, this.shared); + }, + + translate: function(v) { + v=new CSG.Vector2D(v); + return this.transform(CSG.Matrix4x4.translation(v.toVector3D(0))); + }, + + scale: function(f) { + f=new CSG.Vector2D(f); + return this.transform(CSG.Matrix4x4.scaling(f.toVector3D(1))); + }, + + rotate: function(deg) { + return this.transform(CSG.Matrix4x4.rotationZ(deg)); + }, + + // convert into a CSG.Polygon; set z coordinate to the given value + toPolygon3D: function(z) { + var points3d=[]; + this.points.map( function(p) { + var vec3d = p.toVector3D(z); + points3d.push(vec3d); + }); + var polygon = CSG.Polygon.createFromPoints(points3d, this.shared); + polygon.checkIfConvex(); + return polygon; + }, + + // extruded=shape2d.extrude({offset: [0,0,10], twistangle: 360, twiststeps: 100}); + // linear extrusion of 2D polygon, with optional twist + // The 2d polygon is placed in in z=0 plane and extruded into direction (a CSG.Vector3D) + // The final face is rotated degrees. Rotation is done around the origin of the 2d shape (i.e. x=0, y=0) + // twiststeps determines the resolution of the twist (should be >= 1) + // returns a CSG object + extrude: function(options) { + var offsetvector = CSG.parseOptionAs3DVector(options, "offset", [0,0,1]); + var twistangle = CSG.parseOptionAsFloat(options, "twistangle", 0); + var twiststeps = CSG.parseOptionAsInt(options, "twiststeps", 10); + + if(twistangle == 0) twiststeps = 1; + if(twiststeps < 1) twiststeps = 1; + + // create the polygons: + var newpolygons = []; + + // bottom face polygon: + var bottomfacepolygon = this.toPolygon3D(0); + var direction = bottomfacepolygon.plane.normal.dot(offsetvector); + if(direction > 0) + { + bottomfacepolygon = bottomfacepolygon.flipped(); + } + newpolygons.push(bottomfacepolygon); + + var getTwistedPolygon = function(twiststep) { + var fraction = (twiststep + 1) / twiststeps; + var rotation = twistangle * fraction; + var offset = offsetvector.times(fraction); + var transformmatrix = CSG.Matrix4x4.rotationZ(rotation).multiply( CSG.Matrix4x4.translation(offset) ); + var polygon = bottomfacepolygon.transform(transformmatrix); + return polygon; + }; + + // create the side face polygons: + var numvertices = bottomfacepolygon.vertices.length; + var prevlevelpolygon = bottomfacepolygon; + for(var twiststep=0; twiststep < twiststeps; ++twiststep) + { + var levelpolygon = getTwistedPolygon(twiststep); + for(var i=0; i < numvertices; i++) + { + var sidefacepoints = []; + var nexti = (i < (numvertices-1))? i+1:0; + sidefacepoints.push(prevlevelpolygon.vertices[i].pos); + sidefacepoints.push(levelpolygon.vertices[i].pos); + sidefacepoints.push(levelpolygon.vertices[nexti].pos); + sidefacepoints.push(prevlevelpolygon.vertices[nexti].pos); + var sidefacepolygon=CSG.Polygon.createFromPoints(sidefacepoints, this.shared); + newpolygons.push(sidefacepolygon); + } + if(twiststep == (twiststeps -1) ) + { + // last level; add the top face polygon: + levelpolygon = levelpolygon.flipped(); // flip so that the normal points outwards + newpolygons.push(levelpolygon); + } + prevlevelpolygon = levelpolygon; + } + + return CSG.fromPolygons(newpolygons); + } +}; + + + +// # class Line2D + +// Represents a directional line in 2D space +// A line is parametrized by its normal vector (perpendicular to the line, rotated 90 degrees counter clockwise) +// and w. The line passes through the point .times(w). +// normal must be a unit vector! +// Equation: p is on line if normal.dot(p)==w +CSG.Line2D = function(normal, w) { + this.normal = normal; + this.w = w; +}; + +CSG.Line2D.fromPoints = function(p1, p2) { + var direction = p2.minus(p1); + var normal = direction.normal().negated().unit(); + var w = p1.dot(normal); + return new CSG.Line2D(normal, w); +}; + +CSG.Line2D.prototype = { + // same line but opposite direction: + inverse: function() { + return new CSG.Line2D(this.normal.negated(), -this.w); + }, + + equals: function(l) { + return (l.normal.equals(this.normal) && (l.w == this.w)); + }, + + origin: function() { + return this.normal.times(this.w); + }, + + direction: function() { + return this.normal.normal(); + }, + + xAtY: function(y) { + // (py == y) && (normal * p == w) + // -> px = (w - normal.y * y) / normal.x + var x = (this.w - this.normal.y * y) / this.normal.x; + return x; + }, + + absDistanceToPoint: function(point) { + var point_projected = point.dot(this.normal); + var distance = Math.abs(point_projected - this.w); + return distance; + }, + + closestPoint: function(point) { + var vector = point.dot(this.direction()); + return origin.plus(vector); + }, +}; + +// # class Line3D + +// Represents a line in 3D space +// direction must be a unit vector +// point is a random point on the line + +CSG.Line3D = function(point, direction) { + this.point = point; + this.direction = direction; +}; + +CSG.Line3D.fromPoints = function(p1, p2) { + var direction = p2.minus(p1).unit(); + return new CSG.Line3D(p1, direction); +}; + +CSG.Line3D.fromPlanes = function(p1, p2) { + var direction = p1.normal.cross(p2.normal); + var l=direction.length(); + if(l < 1e-10) + { + throw new Error("Parallel planes"); + } + direction = direction.times(1.0/l); + + var mabsx = Math.abs(direction.x); + var mabsy = Math.abs(direction.y); + var mabsz = Math.abs(direction.z); + var origin; + if( (mabsx >= mabsy) && (mabsx >= mabsz) ) + { + // direction vector is mostly pointing towards x + // find a point p for which x is zero: + var r = CSG.Line3D.Solve2Linear(p1.normal.y, p1.normal.z, p2.normal.y, p2.normal.z, p1.w, p2.w); + origin = new CSG.Vector3D(0, r[0], r[1]); + } + else if( (mabsy >= mabsx) && (mabsy >= mabsz) ) + { + // find a point p for which y is zero: + var r = CSG.Line3D.Solve2Linear(p1.normal.x, p1.normal.z, p2.normal.x, p2.normal.z, p1.w, p2.w); + origin = new CSG.Vector3D(r[0], 0, r[1]); + } + else + { + // find a point p for which z is zero: + var r = CSG.Line3D.Solve2Linear(p1.normal.x, p1.normal.y, p2.normal.x, p2.normal.y, p1.w, p2.w); + origin = new CSG.Vector3D(r[0], r[1], 0); + } + return new CSG.Line3D(origin, direction); +}; + +// solve +// [ab][x] = [u] +// [cd][y] [v] +CSG.Line3D.Solve2Linear = function(a,b,c,d,u,v) { + var det = a*d - b*c; + var invdet = 1.0/det; + var x = u*d - b*v; + var y = -u*c + a*v; + x *= invdet; + y *= invdet; + return [x,y]; +}; + +CSG.Line3D.prototype = { + intersectWithPlane: function(plane) { + // plane: plane.normal * p = plane.w + // line: p=line.point + labda * line.direction + var labda = (plane.w - plane.normal.dot(this.point)) / plane.normal.dot(this.direction); + var point = this.point.plus(this.direction.times(labda)); + return point; + }, + + clone: function(line) { + return new CSG.Line3D(this.point.clone(), this.direction.clone()); + }, + + reverse: function() { + return new CSG.Line3D(this.point.clone(), this.direction.negated()); + }, + + transform: function(matrix4x4) { + var newpoint = this.point.multiply4x4(matrix4x4); + var pointPlusDirection = this.point.plus(this.direction); + var newPointPlusDirection = pointPlusDirection.multiply4x4(matrix4x4); + var newdirection = newPointPlusDirection.minus(newpoint); + return new CSG.Line3D(newpoint, newdirection); + }, + + closestPointOnLine: function(point) { + var t = point.minus(this.point).dot(this.direction) / this.direction.dot(this.direction); + var closestpoint = this.point.plus(this.direction.times(t)); + return closestpoint; + }, + + distanceToPoint: function(point) { + var closestpoint = this.closestPointOnLine(point); + var distancevector = point.minus(closestpoint); + var distance = distancevector.length(); + return distance; + }, + + equals: function(line3d) { + if(!this.direction.equals(line3d.direction)) return false; + var distance = this.distanceToPoint(line3d.point); + if(distance > 1e-8) return false; + return true; + }, +}; + + +// # class OrthoNormalBasis + +// Reprojects points on a 3D plane onto a 2D plane +// or from a 2D plane back onto the 3D plane + +CSG.OrthoNormalBasis = function (plane) { + // choose an arbitrary right hand vector, making sure it is somewhat orthogonal to the plane normal: + var rightvector; + if(Math.abs(plane.normal.x) > Math.abs(plane.normal.y)) + { + rightvector = new CSG.Vector3D(0, 1, 0); + } + else + { + rightvector = new CSG.Vector3D(1, 0, 0); + } + this.v = rightvector.cross(plane.normal).unit(); + this.u = plane.normal.cross(this.v); + this.plane = plane; + this.planeorigin = plane.normal.times(plane.w); +}; + +CSG.OrthoNormalBasis.prototype = { + getProjectionMatrix: function() { + return new CSG.Matrix4x4([ + this.u.x, this.v.x, this.plane.normal.x, 0, + this.u.y, this.v.y, this.plane.normal.y, 0, + this.u.z, this.v.z, this.plane.normal.z, 0, + 0, 0, -this.plane.w, 1 + ]); + }, + + getInverseProjectionMatrix: function() { + var wtimesnormal = this.plane.normal.times(this.plane.w); + return new CSG.Matrix4x4([ + this.u.x, this.u.y, this.u.z, 0, + this.v.x, this.v.y, this.v.z, 0, + this.plane.normal.x, this.plane.normal.y, this.plane.normal.z, 0, + wtimesnormal.x, wtimesnormal.y, wtimesnormal.z, 1 + ]); + }, + + to2D: function(vec3) { + return new CSG.Vector2D(vec3.dot(this.u), vec3.dot(this.v)); + }, + + to3D: function(vec2) { + return this.planeorigin.plus(this.u.times(vec2.x)).plus(this.v.times(vec2.y)); + }, + + line3Dto2D: function(line3d) { + var a = line3d.point; + var b = line3d.direction.plus(a); + var a2d = this.to2D(a); + var b2d = this.to2D(b); + return CSG.Line2D.fromPoints(a2d, b2d); + }, + + line2Dto3D: function(line2d) { + var a = line2d.origin(); + var b = line2d.direction().plus(a); + var a3d = this.to3D(a); + var b3d = this.to3D(b); + return CSG.Line3D.fromPoints(a3d, b3d); + }, +}; + +function insertSorted(array, element, comparefunc) { + var leftbound = 0; + var rightbound = array.length; + while(rightbound > leftbound) + { + var testindex = Math.floor( (leftbound + rightbound) / 2); + var testelement = array[testindex]; + var compareresult = comparefunc(element, testelement); + if(compareresult > 0) // element > testelement + { + leftbound = testindex + 1; + } + else + { + rightbound = testindex; + } + } + array.splice(leftbound,0,element); +} + +// Get the x coordinate of a point with a certain y coordinate, interpolated between two +// points (CSG.Vector2D). +// Interpolation is robust even if the points have the same y coordinate +CSG.interpolateBetween2DPointsForY = function(point1, point2, y) { + var f1 = y - point1.y; + var f2 = point2.y - point1.y; + if(f2 < 0) + { + f1 = -f1; + f2 = -f2; + } + var t; + if(f1 <= 0) + { + t = 0.0; + } + else if(f1 >= f2) + { + t = 1.0; + } + else if(f2 < 1e-10) + { + t = 0.5; + } + else + { + t = f1 / f2; + } + var result = point1.x + t * (point2.x - point1.x); + return result; +}; + +// Retesselation function for a set of coplanar polygons. See the introduction at the top of +// this file. +CSG.reTesselateCoplanarPolygons = function(sourcepolygons, destpolygons) +{ + var EPS = 1e-5; + + var numpolygons = sourcepolygons.length; + if(numpolygons > 0) + { + var plane = sourcepolygons[0].plane; + var shared = sourcepolygons[0].shared; + var orthobasis = new CSG.OrthoNormalBasis(plane); + var polygonvertices2d = []; // array of array of CSG.Vector2D + var polygontopvertexindexes = []; // array of indexes of topmost vertex per polygon + var topy2polygonindexes = {}; + var ycoordinatetopolygonindexes = {}; + + var xcoordinatebins = {}; + var ycoordinatebins = {}; + + // convert all polygon vertices to 2D + // Make a list of all encountered y coordinates + // And build a map of all polygons that have a vertex at a certain y coordinate: + var ycoordinateBinningFactor = 1.0/EPS * 10; + for(var polygonindex=0; polygonindex < numpolygons; polygonindex++) + { + var poly3d = sourcepolygons[polygonindex]; + var vertices2d = []; + var numvertices = poly3d.vertices.length; + var minindex = -1; + if(numvertices > 0) + { + var miny, maxy, maxindex; + for(var i=0; i < numvertices; i++) + { + var pos2d = orthobasis.to2D(poly3d.vertices[i].pos); + // perform binning of y coordinates: If we have multiple vertices very + // close to each other, give them the same y coordinate: + var ycoordinatebin = Math.floor(pos2d.y * ycoordinateBinningFactor); + if(ycoordinatebin in ycoordinatebins) + { + pos2d.y = ycoordinatebins[ycoordinatebin]; + } + else if(ycoordinatebin+1 in ycoordinatebins) + { + pos2d.y = ycoordinatebins[ycoordinatebin+1]; + } + else if(ycoordinatebin-1 in ycoordinatebins) + { + pos2d.y = ycoordinatebins[ycoordinatebin-1]; + } + else + { + ycoordinatebins[ycoordinatebin] = pos2d.y; + } + vertices2d.push(pos2d); + var y = pos2d.y; + if( (i == 0) || (y < miny) ) + { + miny = y; + minindex = i; + } + if( (i == 0) || (y > maxy) ) + { + maxy = y; + maxindex = i; + } + if(! (y in ycoordinatetopolygonindexes)) + { + ycoordinatetopolygonindexes[y] = {}; + } + ycoordinatetopolygonindexes[y][polygonindex]=true; + } + if(miny >= maxy) + { + // degenerate polygon, all vertices have same y coordinate. Just ignore it from now: + vertices2d = []; + } + else + { + if(! (miny in topy2polygonindexes)) + { + topy2polygonindexes[miny] = []; + } + topy2polygonindexes[miny].push(polygonindex); + } + } // if(numvertices > 0) + polygonvertices2d.push(vertices2d); + polygontopvertexindexes.push(minindex); + } + var ycoordinates = []; + for(var ycoordinate in ycoordinatetopolygonindexes) ycoordinates.push(ycoordinate); + ycoordinates.sort(function(a,b) {return a-b}); + + // Now we will iterate over all y coordinates, from lowest to highest y coordinate + // activepolygons: source polygons that are 'active', i.e. intersect with our y coordinate + // Is sorted so the polygons are in left to right order + // Each element in activepolygons has these properties: + // polygonindex: the index of the source polygon (i.e. an index into the sourcepolygons and polygonvertices2d arrays) + // leftvertexindex: the index of the vertex at the left side of the polygon (lowest x) that is at or just above the current y coordinate + // rightvertexindex: dito at right hand side of polygon + // topleft, bottomleft: coordinates of the left side of the polygon crossing the current y coordinate + // topright, bottomright: coordinates of the right hand side of the polygon crossing the current y coordinate + var activepolygons = []; + var prevoutpolygonrow = []; + for(var yindex = 0; yindex < ycoordinates.length; yindex++) + { + var newoutpolygonrow = []; + var ycoordinate_as_string = ycoordinates[yindex]; + var ycoordinate = Number(ycoordinate_as_string); + + // update activepolygons for this y coordinate: + // - Remove any polygons that end at this y coordinate + // - update leftvertexindex and rightvertexindex (which point to the current vertex index + // at the the left and right side of the polygon + // Iterate over all polygons that have a corner at this y coordinate: + var polygonindexeswithcorner = ycoordinatetopolygonindexes[ycoordinate_as_string]; + for(var activepolygonindex = 0; activepolygonindex < activepolygons.length; ++activepolygonindex) + { + var activepolygon = activepolygons[activepolygonindex]; + var polygonindex = activepolygon.polygonindex; + if(polygonindexeswithcorner[polygonindex]) + { + // this active polygon has a corner at this y coordinate: + var vertices2d = polygonvertices2d[polygonindex]; + var numvertices = vertices2d.length; + var newleftvertexindex = activepolygon.leftvertexindex; + var newrightvertexindex = activepolygon.rightvertexindex; + // See if we need to increase leftvertexindex or decrease rightvertexindex: + while(true) + { + var nextleftvertexindex = newleftvertexindex+1; + if(nextleftvertexindex >= numvertices) nextleftvertexindex = 0; + if(vertices2d[nextleftvertexindex].y != ycoordinate) break; + newleftvertexindex = nextleftvertexindex; + } + var nextrightvertexindex = newrightvertexindex-1; + if(nextrightvertexindex < 0) nextrightvertexindex = numvertices-1; + if(vertices2d[nextrightvertexindex].y == ycoordinate) + { + newrightvertexindex = nextrightvertexindex; + } + if( (newleftvertexindex != activepolygon.leftvertexindex) && (newleftvertexindex == newrightvertexindex) ) + { + // We have increased leftvertexindex or decreased rightvertexindex, and now they point to the same vertex + // This means that this is the bottom point of the polygon. We'll remove it: + activepolygons.splice(activepolygonindex, 1); + --activepolygonindex; + } + else + { + activepolygon.leftvertexindex = newleftvertexindex; + activepolygon.rightvertexindex = newrightvertexindex; + activepolygon.topleft = vertices2d[newleftvertexindex]; + activepolygon.topright = vertices2d[newrightvertexindex]; + var nextleftvertexindex = newleftvertexindex+1; + if(nextleftvertexindex >= numvertices) nextleftvertexindex = 0; + activepolygon.bottomleft = vertices2d[nextleftvertexindex]; + var nextrightvertexindex = newrightvertexindex-1; + if(nextrightvertexindex < 0) nextrightvertexindex = numvertices-1; + activepolygon.bottomright = vertices2d[nextrightvertexindex]; + } + } // if polygon has corner here + } // for activepolygonindex + + var nextycoordinate; + if(yindex >= ycoordinates.length-1) + { + // last row, all polygons must be finished here: + activepolygons = []; + nextycoordinate = null; + } + else // yindex < ycoordinates.length-1 + { + nextycoordinate = Number(ycoordinates[yindex+1]); + var middleycoordinate = 0.5 * (ycoordinate + nextycoordinate); + // update activepolygons by adding any polygons that start here: + var startingpolygonindexes = topy2polygonindexes[ycoordinate_as_string]; + for(var polygonindex_key in startingpolygonindexes) + { + var polygonindex = startingpolygonindexes[polygonindex_key]; + var vertices2d = polygonvertices2d[polygonindex]; + var numvertices = vertices2d.length; + var topvertexindex = polygontopvertexindexes[polygonindex]; + // the top of the polygon may be a horizontal line. In that case topvertexindex can point to any point on this line. + // Find the left and right topmost vertices which have the current y coordinate: + var topleftvertexindex = topvertexindex; + while(true) + { + var i = topleftvertexindex + 1; + if(i >= numvertices) i = 0; + if(vertices2d[i].y != ycoordinate) break; + if(i == topvertexindex) break; // should not happen, but just to prevent endless loops + topleftvertexindex = i; + } + var toprightvertexindex = topvertexindex; + while(true) + { + var i = toprightvertexindex - 1; + if(i < 0) i = numvertices - 1; + if(vertices2d[i].y != ycoordinate) break; + if(i == topleftvertexindex) break; // should not happen, but just to prevent endless loops + toprightvertexindex = i; + } + var nextleftvertexindex = topleftvertexindex+1; + if(nextleftvertexindex >= numvertices) nextleftvertexindex = 0; + var nextrightvertexindex = toprightvertexindex-1; + if(nextrightvertexindex < 0) nextrightvertexindex = numvertices-1; + var newactivepolygon = { + polygonindex: polygonindex, + leftvertexindex: topleftvertexindex, + rightvertexindex: toprightvertexindex, + topleft: vertices2d[topleftvertexindex], + topright: vertices2d[toprightvertexindex], + bottomleft: vertices2d[nextleftvertexindex], + bottomright: vertices2d[nextrightvertexindex], + }; + insertSorted(activepolygons, newactivepolygon, function(el1, el2) { + var x1 = CSG.interpolateBetween2DPointsForY(el1.topleft, el1.bottomleft, middleycoordinate); + var x2 = CSG.interpolateBetween2DPointsForY(el2.topleft, el2.bottomleft, middleycoordinate); + if(x1 > x2) return 1; + if(x1 < x2) return -1; + return 0; + }); + } // for(var polygonindex in startingpolygonindexes) + } // yindex < ycoordinates.length-1 + //if( (yindex == ycoordinates.length-1) || (nextycoordinate - ycoordinate > EPS) ) + if(true) + { + // Now activepolygons is up to date + // Build the output polygons for the next row in newoutpolygonrow: + for(var activepolygon_key in activepolygons) + { + var activepolygon = activepolygons[activepolygon_key]; + var polygonindex = activepolygon.polygonindex; + var vertices2d = polygonvertices2d[polygonindex]; + var numvertices = vertices2d.length; + + var x = CSG.interpolateBetween2DPointsForY(activepolygon.topleft, activepolygon.bottomleft, ycoordinate); + var topleft=new CSG.Vector2D(x, ycoordinate); + x = CSG.interpolateBetween2DPointsForY(activepolygon.topright, activepolygon.bottomright, ycoordinate); + var topright=new CSG.Vector2D(x, ycoordinate); + x = CSG.interpolateBetween2DPointsForY(activepolygon.topleft, activepolygon.bottomleft, nextycoordinate); + var bottomleft=new CSG.Vector2D(x, nextycoordinate); + x = CSG.interpolateBetween2DPointsForY(activepolygon.topright, activepolygon.bottomright, nextycoordinate); + var bottomright=new CSG.Vector2D(x, nextycoordinate); + var outpolygon = { + topleft: topleft, + topright: topright, + bottomleft: bottomleft, + bottomright: bottomright, + leftline: CSG.Line2D.fromPoints(topleft, bottomleft), + rightline: CSG.Line2D.fromPoints(bottomright, topright), + }; + if(newoutpolygonrow.length > 0) + { + var prevoutpolygon = newoutpolygonrow[newoutpolygonrow.length - 1]; + var d1 = outpolygon.topleft.distanceTo(prevoutpolygon.topright); + var d2 = outpolygon.bottomleft.distanceTo(prevoutpolygon.bottomright); + if( (d1 < EPS) && (d2 < EPS) ) + { + // we can join this polygon with the one to the left: + outpolygon.topleft = prevoutpolygon.topleft; + outpolygon.leftline = prevoutpolygon.leftline; + outpolygon.bottomleft = prevoutpolygon.bottomleft; + newoutpolygonrow.splice(newoutpolygonrow.length - 1, 1); + } + } + newoutpolygonrow.push(outpolygon); + } // for(activepolygon in activepolygons) + if(yindex > 0) + { + // try to match the new polygons against the previous row: + var prevcontinuedindexes = {}; + var matchedindexes = {}; + for(var i = 0; i < newoutpolygonrow.length; i++) + { + var thispolygon = newoutpolygonrow[i]; + for(var ii = 0; ii < prevoutpolygonrow.length; ii++) + { + if(!matchedindexes[ii]) // not already processed? + { + // We have a match if the sidelines are equal or if the top coordinates + // are on the sidelines of the previous polygon + var prevpolygon = prevoutpolygonrow[ii]; + if(prevpolygon.bottomleft.distanceTo(thispolygon.topleft) < EPS) + { + if(prevpolygon.bottomright.distanceTo(thispolygon.topright) < EPS) + { + // Yes, the top of this polygon matches the bottom of the previous: + matchedindexes[ii] = true; + // Now check if the joined polygon would remain convex: + var d1 = thispolygon.leftline.direction().x - prevpolygon.leftline.direction().x; + var d2 = thispolygon.rightline.direction().x - prevpolygon.rightline.direction().x; + var leftlinecontinues = Math.abs(d1) < EPS; + var rightlinecontinues = Math.abs(d2) < EPS; + var leftlineisconvex = leftlinecontinues || (d1 >= 0); + var rightlineisconvex = rightlinecontinues || (d2 >= 0); + if(leftlineisconvex && rightlineisconvex) + { + // yes, both sides have convex corners: + // This polygon will continue the previous polygon + thispolygon.outpolygon = prevpolygon.outpolygon; + thispolygon.leftlinecontinues = leftlinecontinues; + thispolygon.rightlinecontinues = rightlinecontinues; + prevcontinuedindexes[ii] = true; + } + break; + } + } + } // if(!prevcontinuedindexes[ii]) + } // for ii + } // for i + for(var ii = 0; ii < prevoutpolygonrow.length; ii++) + { + if(!prevcontinuedindexes[ii]) + { + // polygon ends here + // Finish the polygon with the last point(s): + var prevpolygon = prevoutpolygonrow[ii]; + prevpolygon.outpolygon.rightpoints.push(prevpolygon.bottomright); + if(prevpolygon.bottomright.distanceTo(prevpolygon.bottomleft) > EPS) + { + // polygon ends with a horizontal line: + prevpolygon.outpolygon.leftpoints.push(prevpolygon.bottomleft); + } + // reverse the right half so we get a counterclockwise circle: + prevpolygon.outpolygon.rightpoints.reverse(); + var points2d = prevpolygon.outpolygon.leftpoints.concat(prevpolygon.outpolygon.rightpoints); + var vertices3d = []; + points2d.map(function(point2d) { + var point3d = orthobasis.to3D(point2d); + var vertex3d = new CSG.Vertex(point3d); + vertices3d.push(vertex3d); + }); + var polygon = new CSG.Polygon(vertices3d, shared, plane); + destpolygons.push(polygon); + } + } + } // if(yindex > 0) + for(var i = 0; i < newoutpolygonrow.length; i++) + { + var thispolygon = newoutpolygonrow[i]; + if(!thispolygon.outpolygon) + { + // polygon starts here: + thispolygon.outpolygon = { + leftpoints: [], + rightpoints: [], + }; + thispolygon.outpolygon.leftpoints.push(thispolygon.topleft); + if(thispolygon.topleft.distanceTo(thispolygon.topright) > EPS) + { + // we have a horizontal line at the top: + thispolygon.outpolygon.rightpoints.push(thispolygon.topright); + } + } + else + { + // continuation of a previous row + if(! thispolygon.leftlinecontinues ) + { + thispolygon.outpolygon.leftpoints.push(thispolygon.topleft); + } + if(! thispolygon.rightlinecontinues ) + { + thispolygon.outpolygon.rightpoints.push(thispolygon.topright); + } + } + } + prevoutpolygonrow = newoutpolygonrow; + } + } // for yindex + } // if(numpolygons > 0) +} + +//////////////////////////////// + +// ## class fuzzyFactory + +// This class acts as a factory for objects. We can search for an object with approximately +// the desired properties (say a rectangle with width 2 and height 1) +// The lookupOrCreate() method looks for an existing object (for example it may find an existing rectangle +// with width 2.0001 and height 0.999. If no object is found, the user supplied callback is +// called, which should generate a new object. The new object is inserted into the database +// so it can be found by future lookupOrCreate() calls. + +// Constructor: +// numdimensions: the number of parameters for each object +// for example for a 2D rectangle this would be 2 +// tolerance: The maximum difference for each parameter allowed to be considered a match + +CSG.fuzzyFactory = function(numdimensions, tolerance) { + var lookuptable = []; + for(var i=0; i < numdimensions; i++) + { + lookuptable.push({}); + } + this.lookuptable = lookuptable; + this.nextElementId = 1; + this.multiplier = 1.0 / tolerance; + this.objectTable = {}; +}; + +CSG.fuzzyFactory.prototype = { + // var obj = f.lookupOrCreate([el1, el2, el3], function(elements) {/* create the new object */}); + // Performs a fuzzy lookup of the object with the specified elements. + // If found, returns the existing object + // If not found, calls the supplied callback function which should create a new object with + // the specified properties. This object is inserted in the lookup database. + lookupOrCreate: function(els, creatorCallback) { + var object; + var key = this.lookupKey(els); + if(key === null) + { + object = creatorCallback(els); + key = this.nextElementId++; + this.objectTable[key] = object; + for(var dimension = 0; dimension < els.length; dimension++) + { + var elementLookupTable = this.lookuptable[dimension]; + var value = els[dimension]; + var valueMultiplied = value * this.multiplier; + var valueQuantized1 = Math.floor(valueMultiplied); + var valueQuantized2 = Math.ceil(valueMultiplied); + CSG.fuzzyFactory.insertKey(key, elementLookupTable, valueQuantized1); + CSG.fuzzyFactory.insertKey(key, elementLookupTable, valueQuantized2); + } + } + else + { + object = this.objectTable[key]; + } + return object; + }, + + // ----------- PRIVATE METHODS: + lookupKey: function(els) { + var keyset = {}; + for(var dimension=0; dimension < els.length; dimension++) + { + var elementLookupTable = this.lookuptable[dimension]; + var value = els[dimension]; + var valueQuantized = Math.round(value * this.multiplier); + valueQuantized += ""; + if(valueQuantized in elementLookupTable) + { + if(dimension == 0) + { + keyset = elementLookupTable[valueQuantized]; + } + else + { + keyset = CSG.fuzzyFactory.intersectSets(keyset, elementLookupTable[valueQuantized]); + } + } + else + { + return null; + } + if(CSG.fuzzyFactory.isEmptySet(keyset)) return null; + } + // return first matching key: + for(var key in keyset) return key; + return null; + }, + + lookupKeySetForDimension: function(dimension, value) { + var result; + var elementLookupTable = this.lookuptable[dimension]; + var valueMultiplied = value * this.multiplier; + var valueQuantized = Math.floor(value * this.multiplier); + if(valueQuantized in elementLookupTable) + { + result = elementLookupTable[valueQuantized]; + } + else + { + result = {}; + } + return result; + }, +}; + +CSG.fuzzyFactory.insertKey = function(key, lookuptable, quantizedvalue) { + if(quantizedvalue in lookuptable) + { + lookuptable[quantizedvalue][key] = true; + } + else + { + var newset = {}; + newset[key] = true; + lookuptable[quantizedvalue] = newset; + } +}; + +CSG.fuzzyFactory.isEmptySet = function(obj) { + for(var key in obj) return false; + return true; +}; + +CSG.fuzzyFactory.intersectSets = function(set1, set2) { + var result = {}; + for(var key in set1) + { + if(key in set2) + { + result[key] = true; + } + } + return result; +}; + +CSG.fuzzyFactory.joinSets = function(set1, set2) { + var result = {}; + for(var key in set1) + { + result[key] = true; + } + for(var key in set2) + { + result[key] = true; + } + return result; +}; + +////////////////////////////////////// + +CSG.fuzzyCSGFactory = function() { + this.vertexfactory = new CSG.fuzzyFactory(3, 1e-5); + this.planefactory = new CSG.fuzzyFactory(4, 1e-5); + this.polygonsharedfactory = {}; +}; + +CSG.fuzzyCSGFactory.prototype = { + getPolygonShared: function(sourceshared) { + var hash = sourceshared.getHash(); + if(hash in this.polygonsharedfactory) + { + return this.polygonsharedfactory[hash]; + } + else + { + this.polygonsharedfactory[hash] = sourceshared; + return sourceshared; + } + }, + + getVertex: function(sourcevertex) { + var elements = [sourcevertex.pos._x, sourcevertex.pos._y, sourcevertex.pos._z]; + var result = this.vertexfactory.lookupOrCreate(elements, function(els) { + return sourcevertex; + }); + return result; + }, + + getPlane: function(sourceplane) { + var elements = [sourceplane.normal._x, sourceplane.normal._y, sourceplane.normal._z, sourceplane.w]; + var result = this.planefactory.lookupOrCreate(elements, function(els) { + return sourceplane; + }); + return result; + }, + + getPolygon: function(sourcepolygon) { + var newplane = this.getPlane(sourcepolygon.plane); + var newshared = this.getPolygonShared(sourcepolygon.shared); + var _this = this; + var newvertices = sourcepolygon.vertices.map(function(vertex) { + return _this.getVertex(vertex); + }); + return new CSG.Polygon(newvertices, newshared, newplane); + }, + + getCSG: function(sourcecsg) { + var _this = this; + var newpolygons = sourcecsg.polygons.map(function(polygon) { + return _this.getPolygon(polygon); + }); + return CSG.fromPolygons(newpolygons); + }, +}; + +////////////////////////////////////// + +// Tag factory: we can request a unique tag through CSG.getTag() +CSG.staticTag = 1; + +CSG.getTag = function () { + return CSG.staticTag++; +}; + +////////////////////////////////////// + +// # Class Properties +// This class is used to store properties of a solid +// A property can for example be a CSG.Vertex, a CSG.Plane or a CSG.Line3D +// Whenever an affine transform is applied to the CSG solid, all its properties are +// transformed as well. +// The properties can be stored in a complex nested structure (using arrays and objects) +CSG.Properties = function() { +}; + +CSG.Properties.prototype = { + _transform: function(matrix4x4) { + var result = new CSG.Properties(); + CSG.Properties.transformObj(this, result, matrix4x4); + return result; + }, + _merge: function(otherproperties) { + var result = new CSG.Properties(); + CSG.Properties.cloneObj(this, result); + CSG.Properties.addFrom(result, otherproperties); + return result; + }, +}; + +CSG.Properties.transformObj = function(source, result, matrix4x4) +{ + for(var propertyname in source) + { + if(propertyname == "_transform") continue; + if(propertyname == "_merge") continue; + var propertyvalue = source[propertyname]; + var transformed = propertyvalue; + if(typeof(propertyvalue) == "object") + { + if( ('transform' in propertyvalue) && (typeof(propertyvalue.transform) == "function") ) + { + transformed = propertyvalue.transform(matrix4x4); + } + else if(propertyvalue instanceof Array) + { + transformed = []; + CSG.Properties.transformObj(propertyvalue, transformed, matrix4x4); + } + else if(propertyvalue instanceof CSG.Properties) + { + transformed = new CSG.Properties(); + CSG.Properties.transformObj(propertyvalue, transformed, matrix4x4); + } + } + result[propertyname] = transformed; + } +}; + +CSG.Properties.cloneObj = function(source, result) +{ + for(var propertyname in source) + { + if(propertyname == "_transform") continue; + if(propertyname == "_merge") continue; + var propertyvalue = source[propertyname]; + var cloned = propertyvalue; + if(typeof(propertyvalue) == "object") + { + if(propertyvalue instanceof Array) + { + cloned = []; + for(var i=0; i < propertyvalue.length; i++) + { + cloned.push(propertyvalue[i]); + } + } + else if(propertyvalue instanceof CSG.Properties) + { + cloned = new CSG.Properties(); + CSG.Properties.cloneObj(propertyvalue, cloned); + } + } + result[propertyname] = cloned; + } +}; + +CSG.Properties.addFrom = function(result, otherproperties) +{ + for(var propertyname in otherproperties) + { + if(propertyname == "_transform") continue; + if(propertyname == "_merge") continue; + if( (propertyname in result) + && (typeof(result[propertyname]) == "object") + && (result[propertyname] instanceof CSG.Properties) + && (typeof(otherproperties[propertyname]) == "object") + && (otherproperties[propertyname] instanceof CSG.Properties) ) + { + CSG.Properties.addFrom(result[propertyname], otherproperties[propertyname]); + } + else if(!(propertyname in result)) + { + result[propertyname] = otherproperties[propertyname]; + } + } +}; + +////////////////////////////////////// + +// # class Connector +// A connector allows to attach two objects at predefined positions +// For example a servo motor and a servo horn: +// Both can have a Connector called 'shaft' +// The horn can be moved and rotated such that the two connectors match +// and the horn is attached to the servo motor at the proper position. +// Connectors are stored in the properties of a CSG solid so they are +// ge the same transformations applied as the solid + +CSG.Connector = function(point, axisvector, normalvector) { + this.point = new CSG.Vector3D(point); + this.axisvector = new CSG.Vector3D(axisvector); + this.normalvector = new CSG.Vector3D(normalvector); +}; + +CSG.Connector.prototype = { + normalized: function() { + var axisvector = this.axisvector.unit(); + // make the normal vector truly normal: + var n = this.normalvector.cross(axisvector).unit(); + var normalvector = axisvector.cross(n); + return new CSG.Connector(this.point, axisvector, normalvector); + }, + + transform: function(matrix4x4) { + var point = this.point.multiply4x4(matrix4x4); + var axisvector = this.point.plus(this.axisvector).multiply4x4(matrix4x4).minus(point); + var normalvector = this.point.plus(this.normalvector).multiply4x4(matrix4x4).minus(point); + return new CSG.Connector(point, axisvector, normalvector); + }, + + // Get the transformation matrix to connect this Connector to another connector + // other: a CSG.Connector to which this connector should be connected + // mirror: false: the 'axis' vectors of the connectors should point in the same direction + // true: the 'axis' vectors of the connectors should point in opposite direction + // normalrotation: degrees of rotation between the 'normal' vectors of the two + // connectors + getTransformationTo: function(other, mirror, normalrotation) { + mirror = mirror? true:false; + normalrotation = normalrotation? Number(normalrotation):0; + var us = this.normalized(); + other = other.normalized(); + // shift to the origin: + var transformation = CSG.Matrix4x4.translation(this.point.negated()); + // construct the plane crossing through the origin and the two axes: + var axesplane = CSG.Plane.anyPlaneFromVector3Ds( + new CSG.Vector3D(0,0,0), + us.axisvector, + other.axisvector + ); + var axesbasis = new CSG.OrthoNormalBasis(axesplane); + var angle1 = axesbasis.to2D(us.axisvector).angle(); + var angle2 = axesbasis.to2D(other.axisvector).angle(); + var rotation = 180.0 * (angle2 - angle1) / Math.PI; + if(mirror) rotation += 180.0; + transformation = transformation.multiply(axesbasis.getProjectionMatrix()); + transformation = transformation.multiply(CSG.Matrix4x4.rotationZ(rotation)); + transformation = transformation.multiply(axesbasis.getInverseProjectionMatrix()); + var usAxesAligned = us.transform(transformation); + // Now we have done the transformation for aligning the axes. + // We still need to align the normals: + var normalsplane = CSG.Plane.fromNormalAndPoint(other.axisvector, new CSG.Vector3D(0,0,0)); + var normalsbasis = new CSG.OrthoNormalBasis(normalsplane); + angle1 = normalsbasis.to2D(usAxesAligned.normalvector).angle(); + angle2 = normalsbasis.to2D(other.normalvector).angle(); + rotation = 180.0 * (angle2 - angle1) / Math.PI; + rotation += normalrotation; + transformation = transformation.multiply(normalsbasis.getProjectionMatrix()); + transformation = transformation.multiply(CSG.Matrix4x4.rotationZ(rotation)); + transformation = transformation.multiply(normalsbasis.getInverseProjectionMatrix()); + // and translate to the destination point: + transformation = transformation.multiply(CSG.Matrix4x4.translation(other.point)); + var usAligned = us.transform(transformation); + return transformation; + }, + + axisLine: function() { + return new CSG.Line3D(this.point, this.axisvector); + }, +}; + + +////////////////////////////////////// + +// # Class Path2D + +CSG.Path2D = function(points, closed) { + closed = !!closed; + points = points || []; + // re-parse the points into CSG.Vector2D + // and remove any duplicate points + var prevpoint = null; + if(closed && (points.length > 0)) + { + prevpoint = new CSG.Vector2D(points[points.length-1]); + } + var newpoints = []; + points.map(function(point) { + point = new CSG.Vector2D(point); + var skip = false; + if(prevpoint !== null) + { + var distance = point.distanceTo(prevpoint); + skip = distance < 1e-5; + } + if(!skip) newpoints.push(point); + prevpoint = point; + }); + this.points = newpoints; + this.closed = closed; +}; + +/* +Construct a (part of a) circle. Parameters: + options.center: the center point of the arc (CSG.Vector2D or array [x,y]) + options.radius: the circle radius (float) + options.startangle: the starting angle of the arc, in degrees + 0 degrees corresponds to [1,0] + 90 degrees to [0,1] + and so on + options.endangle: the ending angle of the arc, in degrees + options.resolution: number of points per 360 degree of rotation + options.maketangent: adds two extra tiny line segments at both ends of the circle + this ensures that the gradients at the edges are tangent to the circle +Returns a CSG.Path2D. The path is not closed (even if it is a 360 degree arc). +close() the resultin path if you want to create a true circle. +*/ +CSG.Path2D.arc = function(options) { + var center = CSG.parseOptionAs2DVector(options, "center", 0); + var radius = CSG.parseOptionAsFloat(options, "radius", 1); + var startangle = CSG.parseOptionAsFloat(options, "startangle", 0); + var endangle = CSG.parseOptionAsFloat(options, "endangle", 360); + var resolution = CSG.parseOptionAsFloat(options, "resolution", 16); + var maketangent =CSG.parseOptionAsBool(options, "maketangent", false); + // no need to make multiple turns: + while(endangle - startangle >= 720) + { + endangle -= 360; + } + while(endangle - startangle <= -720) + { + endangle += 360; + } + var points = []; + var absangledif = Math.abs(endangle-startangle); + if(absangledif < 1e-5) + { + var point = CSG.Vector2D.fromAngle(startangle / 180.0 * Math.PI).times(radius); + points.push(point.plus(center)); + } + else + { + var numsteps = Math.floor(resolution * absangledif / 360) + 1; + var edgestepsize = numsteps * 0.5 / absangledif; // step size for half a degree + if(edgestepsize > 0.25) edgestepsize = 0.25; + var numsteps_mod = maketangent? (numsteps+2):numsteps; + for(var i = 0; i <= numsteps_mod; i++) + { + var step = i; + if(maketangent) + { + step = (i-1)*(numsteps-2*edgestepsize)/numsteps+edgestepsize; + if(step < 0) step = 0; + if(step > numsteps) step = numsteps; + } + var angle = startangle + step * (endangle - startangle) / numsteps; + var point = CSG.Vector2D.fromAngle(angle / 180.0 * Math.PI).times(radius); + points.push(point.plus(center)); + } + } + return new CSG.Path2D(points, false); +}; + +CSG.Path2D.prototype = { + concat: function(otherpath) { + if(this.closed || otherpath.closed) + { + throw new Error("Paths must not be closed"); + } + var newpoints = this.points.concat(otherpath.points); + return new CSG.Path2D(newpoints); + }, + + appendPoint: function(point) { + if(this.closed) + { + throw new Error("Paths must not be closed"); + } + var newpoints = this.points.concat([point]); + return new CSG.Path2D(newpoints); + }, + + close: function() { + return new CSG.Path2D(this.points, true); + }, + + // Extrude the path by following it with a rectangle (upright, perpendicular to the path direction) + // Returns a CSG solid + // width: width of the extrusion, in the z=0 plane + // height: height of the extrusion in the z direction + // resolution: number of segments per 360 degrees for the curve in a corner + // roundEnds: if true, the ends of the polygon will be rounded, otherwise they will be flat + rectangularExtrude: function(width, height, resolution, roundEnds) { + var polygon2ds = this.toPolygon2Ds(width/2, resolution, roundEnds); + var result = new CSG(); + var offsetvector = [0, 0, height]; + polygon2ds.map(function(polygon) { + var csg = polygon.extrude({offset: offsetvector}); + result = result.unionSub(csg, false, false); + }); + result = result.reTesselated().canonicalized(); + return result; + }, + + // expand the path (which is just a line with no width) to a 2D shape with a certain path width + // Returns an array of CSG.Polygon2D. Note that those polygons may overlap. + // pathradius: radius of the path, i.e. half of the diameter of the path + // resolution: number of segments per 360 degrees for the curve in a corner + // roundEnds: if true, the ends of the polygon will be rounded, otherwise they will be flat + toPolygon2Ds: function(pathradius, resolution, roundEnds) { + resolution = resolution || 16; + roundEnds = !!roundEnds; + if(this.closed) roundEnds = false; // a closed curve has no ends + if(resolution < 4) resolution = 4; + var polygons = []; + if(this.points.length >= 1) + { + for(var i = 0; i < this.points.length; i++) + { + var previ = i-1; + if(previ < 0) + { + if(this.closed) + { + previ += this.points.length; + } + else + { + if(this.points.length >= 2) + { + previ = i+1; + } + else + { + previ = i; + } + } + } + var prevpoint = this.points[previ]; + var point = this.points[i]; + var direction; + if(this.points.length >= 2) + { + direction = point.minus(prevpoint).unit(); + } + else + { + direction = new CSG.Vector2D(1,0); // arbitrary + } + var normal = direction.normal().times(pathradius); + if(this.points.length >= 2) + { + if( (this.closed) || (i > 0) ) + { + var segpoints = [ + prevpoint.minus(normal), + prevpoint.plus(normal), + point.plus(normal), + point.minus(normal) + ]; + var polygon = new CSG.Polygon2D(segpoints, null); + polygons.push(polygon); + } + } + + // make the curved parts between segments and optionally the rounded end: + if(roundEnds || this.closed || ((i > 0)&&(i+1 < this.points.length))) + { + var nexti = i+1; + if(nexti >= this.points.length) + { + if(this.closed) + { + nexti = 0; + } + else + { + // at the end: go backwards, this will create a rounded end + if(this.points.length >= 2) + { + nexti = i-1; + } + else + { + nexti = i; + } + } + } + var nextpoint = this.points[nexti]; + var nextdirection; + if(this.points.length >= 2) + { + nextdirection = nextpoint.minus(point).unit(); + } + else + { + nextdirection = new CSG.Vector2D(1,0); // arbitrary + } + var nextnormal = nextdirection.normal().times(pathradius); + var directionangle = direction.angleDegrees(); + var nextangle = nextdirection.angleDegrees(); + if(nextangle > directionangle+180) + { + nextangle -= 360; + } + else if(nextangle <= directionangle-180) + { + nextangle += 360; + } + if(this.points.length == 1) + { + nextangle += 360; + } + + + var diffangle = nextangle - directionangle; + var absdiffangle = Math.abs(diffangle); + if(absdiffangle > 1e-5) + { + var numsteps = Math.floor(resolution * absdiffangle / 360) + 1; + var prevcornerpoint = null; + for(var step = 0; step <= numsteps; step++) + { + var angle = directionangle + step*diffangle/numsteps; + if(diffangle > 0) + { + angle -= 90; + } + else + { + angle += 90; + } + var cornerpoint; + if(step == 0) + { + // first point of curve. To prevent rounding errors, use the exact point + if(diffangle > 0) + { + cornerpoint = normal; + } + else + { + cornerpoint = normal.negated(); + } + } + else if(step == numsteps) + { + // last point of curve. To prevent rounding errors, use the exact point + if(diffangle > 0) + { + cornerpoint = nextnormal; + } + else + { + cornerpoint = nextnormal.negated(); + } + } + else + { + cornerpoint = CSG.Vector2D.fromAngleDegrees(angle).times(pathradius); + } + cornerpoint = cornerpoint.plus(point); + if(step > 0) + { + var polygon = new CSG.Polygon2D([point, prevcornerpoint, cornerpoint], null); + polygons.push(polygon); + } + prevcornerpoint = cornerpoint; + } // for step + } // if(absdiffangle > 1e-5) + } // if( (i+1 < this.points.length) || roundEnds || this.closed) + } // for i + } + return polygons; + }, + + transform: function(matrix4x4) { + var newpoints = this.points.map(function(point) { + return point.multiply4x4(matrix4x4); + }); + return new CSG.Path2D(newpoints, this.closed); + }, +}; + diff --git a/gearsdemo.html b/gearsdemo.html new file mode 100644 index 0000000..ee08e28 --- /dev/null +++ b/gearsdemo.html @@ -0,0 +1,187 @@ + + + + + + + + + + +OpenJsCad demo: involute gears + + +

OpenJsCad demo: involute gears

+
+

Source code

+Below is the OpenJsCad script for this demo. To build your own models, create a .jscad script +and use the OpenJsCad parser. For more information see the +OpenJsCad documentation. +

+
+ +

+ + \ No newline at end of file diff --git a/grilledemo.html b/grilledemo.html new file mode 100644 index 0000000..22a5c79 --- /dev/null +++ b/grilledemo.html @@ -0,0 +1,338 @@ + + + + + + + + + + +OpenJsCad demo: Parametric Grille + + +

OpenJsCad demo: Parametric Grille

+
+

Source code

+Below is the OpenJsCad script for this demo. To build your own models, create a .jscad script +and use the OpenJsCad parser. For more information see the +OpenJsCad documentation. +

+
+ +

+ + \ No newline at end of file diff --git a/hookdemo.html b/hookdemo.html new file mode 100644 index 0000000..7eb90db --- /dev/null +++ b/hookdemo.html @@ -0,0 +1,210 @@ + + + + + + + + + + +OpenJsCad demo: Parametric S hook + + +

OpenJsCad demo: Parametric S hook

+
+

Source code

+Below is the OpenJsCad script for this demo. To build your own models, create a .jscad script +and use the OpenJsCad parser. For more information see the +OpenJsCad documentation. +

+
+ +

+ + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..ee8c989 --- /dev/null +++ b/index.html @@ -0,0 +1,709 @@ + + + + + + + + + + +OpenJsCad + + +

OpenJsCad

+Create an STL file for 3D printing using constructive solid modeling in Javascript. +
+

Playground

+Try it by entering some code below. Anything you enter will be lost as soon as this page is reloaded; +to build your own models you should instead store them in a .jscad file on your computer +and use the OpenJsCad parser. +

+
+ +
+

About

+This is intended to become a Javascript based alternative to OpenSCAD, +for 3D solid modeling. +CSG model is contructed using Javascript. For example:
+
function main() {
+  var cube = CSG.cube(); 
+  return cube;
+}
+creates a cube with a radius of 1 and centered at the origin. +The code should always contain a main() function, returning a CSG solid. +

+To build your own models, create a .jscad file with your javascript code and parse the file using the +OpenJsCad parser. When finished, click on Generate STL and save the result +in an .stl file, ready to be printed on your 3d printer. +

Why use OpenJsCad?

+Some of the benefits: +
    +
  • Runs in your browser, no need to install any software.
  • +
  • You can create parametric models with user editable parameters: parameters can be changed in the browser window, +without the need to edit the source script. See the Gears demo for example!
  • +
  • JavaScript is an extremely flexible language, supporting dynamic arrays, object oriented programming, closures, anonymous functions and more
  • +
  • Solids are stored in variables. This allows for example conditional cloning of objects, something which is nearly impossible in OpenSCAD.
  • +
  • Properties and Connectors (see below) make it very easy to attach objects to each other at predetermined +points, even if you don't know the actual orientation or size.
  • +
  • Extensive built in support for 2D and 3D math (classes for Vector2D, Vector3D, Plane, Line3D, Line2D)
  • +
  • Debugging support: step through your code, set breakpoints, inspect variables, etc. See the + OpenJsCad parser for details.
  • +
+

Viewer navigation

+Click and drag to rotate the model around the origin.
+Shift+Drag moves the model around.
+Alt+drag zooms (by changing the distance between camera and model). +

Demos

+ +

License

+Copyright (c) 2012 Joost Nieuwenhuijse. +Uses CSG.js, original copyright (c) 2011 Evan Wallace, +extensively modified, copyright (c) 2012 Joost Nieuwenhuijse. +Uses lightgl.js by Evan Wallace for WebGL rendering. +All code released under MIT license. +

+Contributions are welcome! It's all written in Javascript, so if you know how to use it you +know how to modify it as well.

+To contribute go to OpenJsCad at GitHub (gh-pages tree), +create your own fork and +send me a pull request. +

Primitive solids

+Currently the following solids are supported. The parameters are passed in an object; most +parameters are optional. 3D vectors can be passed in an array. If a scalar is passed +for a parameter which expects a 3D vector, it is used for the x, y and z value. +In other words: radius: 1 will give radius: [1,1,1]. +

+All rounded solids have a 'resolution' parameter which controls tesselation. If resolution +is set to 8, then 8 polygons per 360 degree of revolution are used. Beware that rendering +time will increase dramatically when increasing the resolution. For a sphere the number of polygons +increases quadratically with the resolution used. +

+
+// a cube:
+var cube = CSG.cube({
+  center: [0, 0, 0],
+  radius: [1, 1, 1]
+});
+
+// a sphere:
+var sphere = CSG.sphere({
+  center: [0, 0, 0],
+  radius: 2,            // must be scalar
+  resolution: 32
+});
+
+// a cylinder:
+var cylinder = CSG.cylinder({
+  start: [0, -1, 0],
+  end: [0, 1, 0],
+  radius: 1,
+  resolution: 16
+});
+
+// like a cylinder, but with spherical endpoints:
+var roundedCylinder = CSG.roundedCylinder({
+  start: [0, -1, 0],
+  end: [0, 1, 0],
+  radius: 1,
+  resolution: 16
+});
+
+// a rounded cube:
+var cube = CSG.roundedCube({
+  center: [0, 0, 0],
+  radius: 1,
+  roundradius: 0.2,
+  resolution: 8,
+});
+
+ +

CSG operations

+The 3 standard CSG operations are supported. All CSG operations return a new solid; the source solids +are not modified: +
+var csg1 = cube.union(sphere);
+var csg2 = cube.intersect(sphere);
+var csg3 = cube.subtract(sphere);
+
+ +

Transformations

+Solids can be translated, scaled and rotated. Multiple transforms can be combined into a single matrix transform. +For matrix and vector math see below. +
+var cube = CSG.cube();
+
+// translation:
+var cube2 = cube.translate([1, 2, 3]);
+
+// scaling:
+var largecube = cube.scale(2.0);
+var stretchedcube = cube.scale([1.5, 1, 0.5]);
+
+// rotation:
+var rotated1 = cube.rotateX(-45); // rotate around the X axis
+var rotated2 = cube.rotateY(90);  // rotate around the Y axis
+var rotated3 = cube.rotateZ(20);  // rotate around the Z axis
+
+// combine multiple transforms into a single matrix transform:
+var m = new CSG.Matrix4x4();
+m = m.multiply(CSG.Matrix4x4.rotationX(40));
+m = m.multiply(CSG.Matrix4x4.rotationZ(40));
+m = m.multiply(CSG.Matrix4x4.translation([-.5, 0, 0]));
+m = m.multiply(CSG.Matrix4x4.scaling([1.1, 1.2, 1.3]));
+
+// and apply the transform:
+var cube3 = cube.transform(m);
+
+ +

Mirroring

+Solids can be mirrored in any plane in 3D space. For plane math see below. +
+var cube = CSG.cube().translate([1,0,0]);
+
+var cube2 = cube.mirroredX(); // mirrored in the x=0 plane
+var cube3 = cube.mirroredY(); // mirrored in the y=0 plane
+var cube4 = cube.mirroredZ(); // mirrored in the z=0 plane
+
+// create a plane by specifying 3 points:
+var plane = CSG.Plane.fromPoints([5,0,0], [5, 1, 0], [3, 1, 7]);
+
+// and mirror in that plane:
+var cube5 = cube.mirrored(plane);
+
+ +

Cutting by a plane

+A solid can be cut by a plane; only the part on the back side is kept: + +
+var cube = CSG.cube({radius: 10});
+
+// create a plane by specifying 3 points:
+var plane1 = CSG.Plane.fromPoints([5,0,0], [7, 1, 0], [3, 1, 7]);
+
+// or by specifying a normal and a point on the plane:
+var plane2 = CSG.Plane.fromNormalAndPoint([3, 1, 2], [5, 0, 0]);
+
+// and cut by the plane:
+var part1 = cube.cutByPlane(plane2);
+
+// or if we need the other half of the cube:
+var part2 = cube.cutByPlane(plane2.flipped());
+
+ + +

Expansion and contraction

+Expansion can be seen +as the 3D convolution of an object with a sphere. Contraction is the reverse: the area outside the solid +is expanded, and this is then subtracted from the solid. +

+Expansion and contraction are very powerful ways to get an object with nice smooth corners. For example +a rounded cube can be created by expanding a normal cube. +

+Note that these are expensive operations: spheroids are created around every corner and edge in the original +object, so the number of polygons quickly increases. Expansion and contraction therefore are only practical for simple +non-curved objects. +

+expand() and contract() take two parameters: the first is the radius of expansion or contraction; the second +parameter is optional and specififies the resolution (number of polygons on spherical surfaces, per 360 degree revolution). +
+var cube1 = CSG.cube({radius: 1.0});
+var cube2 = CSG.cube({radius: 1.0}).translate([-0.3, -0.3, -0.3]);
+var csg = cube1.subtract(cube2);
+var rounded = csg.expand(0.2, 8); 
+
+ +

Using Properties

+The 'property' property of a solid can be used to store metadata for the object, +for example the coordinate of a specific point of interest of the solid. Whenever +the object is transformed (i.e. rotated, scaled or translated), the properties +are transformed with it. So the property will keep pointing to the same point +of interest even after several transformations have been applied to the solid. +

+Properties can have any type, but only the properties of classes supporting +a 'transform' method will actually be transformed. This includes CSG.Vector3D, +CSG.Plane and CSG.Connector. In particular CSG.Connector properties (see below) +can be very useful: these can +be used to attach a solid to another solid at a predetermined location regardless of the +current orientation. +

+It's even possible to include a CSG solid as a property of another solid. This could +be used for example +to define the cutout cylinders to create matching screw holes for an object. Those 'solid properties' +get the same transformations as the owning solid but they will not be visible in the result +of CSG operations such as union(). +

+Other kind of properties (for +example, strings) will still be included in the properties of the transformed +solid, but the properties will not get any transformation when the owning solid is transformed.

+All primitive solids have some predefined properties, such as the center point +of a sphere (TODO: document). +

+The solid resulting from CSG operations (union(), subtract(), intersect()) will get +the merged properties of both source solids. If identically named properties exist, only +one of them will be kept. +
+var cube = CSG.cube({radius: 1.0});
+cube.properties.aCorner = new CSG.Vector3D([1, 1, 1]);
+cube = cube.translate([5, 0, 0]);
+cube = cube.scale(2);
+// cube.properties.aCorner will now point to [12, 2, 2],
+// which is still the same corner point 
+
+// Properties can be stored in arrays; all properties in the array
+// will be transformed if the solid is transformed:
+cube.properties.otherCorners = [
+  new CSG.Vector3D([-1, 1, 1]),
+  new CSG.Vector3D([-1, -1, 1])
+];
+
+// and we can create sub-property objects; these must be of the 
+// CSG.Properties class. All sub properties will be transformed with
+// the solid:
+cube.properties.myProperties = new CSG.Properties();
+cube.properties.myProperties.someProperty = new CSG.Vector3D([-1, -1, -1]);
+
+For an example see the Servo motor demo. + +

Connectors

+The CSG.Connector class is intended to facilitate +attaching two solids to each other at a predetermined +location and orientation. +For example suppose we have a CSG solid depicting a servo motor +and a solid of a servo arm: by defining a Connector property for each of them, we +can easily attach the servo arm to the servo motor at the correct position +(i.e. the motor shaft) and orientation (i.e. arm perpendicular to the shaft) +even if we don't know their current position and orientation +in 3D space.

+In other words Connector give us the freedom to rotate and translate objects at will without the need +to keep track of their positions and boundaries. And if a third party library exposes connectors for +its solids, the user of the library does not have to know the actual dimensions or +shapes, only the names of the connector properties. +

+A CSG.Connector consist of 3 properties:
+point: a CSG.Vector3D defining the connection point in 3D space
+axis: a CSG.Vector3D defining the direction vector of the connection +(in the case of the servo motor example it would point in the direction of the shaft)
+normal: a CSG.Vector3D direction vector somewhat perpendicular to axis; this +defines the "12 o'clock" orientation of the connection. +

+When connecting two connectors, the solid is transformed such that the point +properties will be identical, the axis properties will have the same direction +(or opposite direction if mirror == true), and the normals match as much as possible. +

+Connectors can be connected by means of two methods:
+A CSG solid's connectTo() function transforms a solid such that two connectors +become connected.
+Alternatively we can use a connector's getTransformationTo() method to obtain +a transformation matrix which would connect the connectors. This can be used if we +need to apply the same transform to multiple solids. + +
+var cube1 = CSG.cube({radius: 10});
+var cube2 = CSG.cube({radius: 4});
+
+// define a connector on the center of one face of cube1
+// The connector's axis points outwards and its normal points
+// towards the positive z axis:
+cube1.properties.myConnector = new CSG.Connector([10, 0, 0], [1, 0, 0], [0, 0, 1]);
+
+// define a similar connector for cube 2:
+cube2.properties.myConnector = new CSG.Connector([0, -4, 0], [0, -1, 0], [0, 0, 1]);
+
+// do some random transformations on cube 1:
+cube1 = cube1.rotateX(30);
+cube1 = cube1.translate([3.1, 2, 0]);
+
+// Now attach cube2 to cube 1:
+cube2 = cube2.connectTo(
+  cube2.properties.myConnector, 
+  cube1.properties.myConnector, 
+  true,   // mirror 
+  0       // normalrotation
+);
+
+// Or alternatively:
+var matrix = cube2.properties.myConnector.getTransformationTo(
+  cube1.properties.myConnector, 
+  true,   // mirror 
+  0       // normalrotation
+);
+cube2 = cube2.transform(matrix);
+
+var result = cube2.union(cube1);
+
+
+For a more complete example see the Servo motor demo. + +

Determining the bounds of an object

+The getBounds() function can be used to retrieve the bounding box of an object. +getBounds() returns +an array with two elements specifying the minimum x,y,z coordinate and the maximum x,y,z coordinate: + +
+var cube1 = CSG.cube({radius: 10});
+var cube2 = CSG.cube({radius: 5});
+
+// get the right bound of cube1 and the left bound of cube2:
+var deltax = cube1.getBounds()[1].x - cube2.getBounds()[0].x;
+
+// align cube2 so it touches cube1:
+cube2  = cube2.translate([deltax, 0, 0]);
+
+return cube1.union(cube2);
+
+ +

2D shapes

+Two dimensional shapes can be defined through the Polygon2D class. Currently this requires the polygon to be convex +(i.e. all corners less than 180 degrees). Shapes can be transformed (rotation, translation, scaling). +To actually use the shape it needs to be extruded into a 3D CSG object through the extrude() function. extrude() +places the 2D solid onto the z=0 plane, and extrudes in the specified direction. Extrusion can be done with an optional +twist. This rotates the solid around the z axis (and not necessariy around the extrusion axis) during extrusion. +The total degrees of rotation is specified in the twistangle parameter, and twiststeps determine the number of steps +between the bottom and top surface. +
+// Create a shape; argument is an array of 2D coordinates
+// The shape must be convex, can be specified in clockwise or in counterclockwise direction 
+var shape2d=new CSG.Polygon2D([[0,0], [5,0], [3,5], [0,5]]);
+
+// Do some transformations:
+shape2d=shape2d.translate([-2, -2]);
+shape2d=shape2d.rotate(20);
+shape2d=shape2d.scale([0.2, 0.2]);
+
+// And extrude. This creates a CSG solid:
+var extruded=shape2d.extrude({
+  offset: [0.5, 0, 2],   // direction for extrusion
+  twistangle: 180,       // top surface is rotated 180 degrees 
+  twiststeps: 100        // create 100 slices
+});
+
+For an example of 2D shapes see the Parametric S hook demo. + +

2D Paths

+A path is simply a series of points, connected by lines. A path can be open or closed (an additional line +is drawn between the first and last point). 2D paths are supported through the CSG.Path2D class. +

+Paths can be contructed either by giving a series of 2D coordinates, or through the CSG.Path2D.arc() function, +which creates a circular curved path. Paths can be concatenated, the result is a new path. +

+Creating a 3D solid is currently supported by the rectangularExtrude() function. This creates a 3D shape +by following the path with a 2D rectangle (upright, perpendicular to the path direction). +
+var path = new CSG.Path2D([[10,10], [-10,10]], /* closed = */ false);
+var anotherpath = new CSG.Path2D([[-10,-10]]);
+path = path.concat(anotherpath);
+path = path.appendPoint([10,-10]);
+path = path.close(); // close the path
+
+// of course we could simply have done:
+// var path = new CSG.Path2D([[10,10], [-10,10], [-10,-10], [10,-10]], /* closed = */ true);
+
+// We can make arcs and circles:
+var curvedpath = CSG.Path2D.arc({
+  center: [0,0,0],
+  radius: 10,
+  startangle: 0,
+  endangle: 180,
+  resolution: 16,
+});
+
+// Extrude the path by following it with a rectangle (upright, perpendicular to the path direction)
+// Returns a CSG solid
+//   width: width of the extrusion, in the z=0 plane
+//   height: height of the extrusion in the z direction
+//   resolution: number of segments per 360 degrees for the curve in a corner
+//   roundEnds: if true, the ends of the polygon will be rounded, otherwise they will be flat
+var csg = path.rectangularExtrude(3, 4, 16, true);
+return csg;
+
+ +

Interactive parametric models

+It is possible to make certain parameters +editable in the browser. This allows users not familiar with JavaScript to create customized STL files. +

+To do so, add a function getParameterDefinitions() to your .jscad source. This function should return +an array with parameter definitions. Currently 4 parameters types are supported: float, int, text and choice. +The user edited values of the parameters will be supplied as an object parameter to the main() function of your .jscad file. +

+A float, int or text parameter is created by including the following object in the array returned by getParameterDefinitions(): +
{
+  name: 'width',
+  type: 'float',                      // or 'text' or 'int'
+  default: 1.23,                      // optional, sets the initial value
+  caption: 'Width of the thingy:',    // optional, displayed left of the input field
+                                      // if omitted, the 'name' is displayed (i.e. 'width')
+}
+A 'choice' parameter is created using the following object: +
{
+  name: 'shape',
+  type: 'choice',
+  values: ["TRI", "SQU", "CIR"],               // these are the values that will be supplied to your script
+  captions: ["Triangle", "Square", "Circle"],  // optional, these values are shown in the listbox
+                                               // if omitted, the items in the 'values' array are used
+  caption: 'Shape:',                           // optional, displayed left of the input field
+  default: "SQU",                              // optional, default selected value
+                                               // if omitted, the first item is selected by default
+}
+To use the values add an argument to your main() function. This argument will be supplied an object +with the user edited parameter values: +
+function main(params)
+{
+  // custom error checking:
+  if(params.width <= 0) throw new Error("Width should be positive!");
+  
+  if(params.shape == "TRI")
+  {
+    // do something
+  }
+}
+
+ +A complete example. Copy/paste it into the Playground at the top of this page to see how it works: +
+function getParameterDefinitions() {
+  return [
+    {
+      name: 'width', 
+      type: 'float', 
+      default: 10,
+      caption: "Width of the cube:", 
+    },
+    {
+      name: 'height', 
+      type: 'float', 
+      default: 14,
+      caption: "Height of the cube:", 
+    },
+    {
+      name: 'depth', 
+      type: 'float', 
+      default: 7,
+      caption: "Depth of the cube:", 
+    },
+    {
+      name: 'rounded', 
+      type: 'choice',
+      caption: 'Round the corners?',
+      values: [0, 1],
+      captions: ["No thanks", "Yes please"], 
+      default: 1,
+    },
+  ];
+}
+
+function main(params) {
+  var result;
+  if(params.rounded == 1)
+  {
+    result = CSG.roundedCube({radius: [params.width, params.height, params.depth], roundradius: 2, resolution: 32});
+  }
+  else
+  {
+    result = CSG.cube({radius: [params.width, params.height, params.depth]});
+  }
+  return result;
+}
+
+Or see the Gears demo for another example of interactive parameters. + +

Miscellaneous

+Solids can be given a color using the setColor(r, g, b) function. Beware: this returns a new solid, +the original solid is not modified! Faces of the solid will keep their original color when doing +CSG operations (union() etc). Colors values range between 0.0 and 1.0 (not 255). +
+var cube1 = CSG.cube({radius: 10});
+cube1 = cube1.setColor(0.5, 0, 0);
+
+var cube2 = CSG.cube({radius: 10});
+cube2 = cube2.setColor(0, 0.5, 0);
+cube2 = cube2.translate([5,1,4]);
+
+var result = cube1.subtract(cube2);
+// the resulting solid will have faces with 2 different colors
+
+ +

2D and 3D Math

+There are utility classes for many 2D and 3D operations. Below is a quick summary, for details +view the source of csg.js: +
+// --------- Vector3D ---------------------
+var vec1 = new CSG.Vector3D(1,2,3);       // 3 arguments
+var vec2 = new CSG.Vector3D( [1,2,3] );   // 1 array argument
+var vec3 = new CSG.Vector3D(vec2);        // cloning a vector
+// get the values as: vec1.x, vec.y, vec1.z
+// vector math. All operations return a new vector, the original is unmodified!
+// vectors cannot be modified. Instead you should create a new vector.
+vec.negated()
+vec.abs()
+vec.plus(othervector)
+vec.minus(othervector)
+vec.times(3.0)
+vec.dividedBy(-5)
+vec.dot(othervector)
+vec.lerp(othervector, t)  // linear interpolation (0 <= t <= 1)
+vec.length()
+vec.lengthSquared()       // == vec.length()^2
+vec.unit()
+vec.cross(othervector)    // cross product: returns a vector perpendicular to both
+vec.distanceTo(othervector)
+vec.distanceToSquared(othervector)  // == vec.distanceTo(othervector)^2
+vec.equals(othervector)
+vec.multiply4x4(matrix4x4)   // right multiply by a 4x4 matrix
+vec.min(othervector)        // returns a new vector with the minimum x,y and z values
+vec.max(othervector)        // returns a new vector with the maximum x,y and z values
+
+// --------- Vector2D ---------------------
+var vec1 = new CSG.Vector2D(1,2);       // 2 arguments
+var vec2 = new CSG.Vector2D( [1,2] );   // 1 array argument
+var vec3 = new CSG.Vector2D(vec2);      // cloning a vector
+// vector math. All operations return a new vector, the original is unmodified!
+vec.negated()
+vec.abs()
+vec.plus(othervector)
+vec.minus(othervector)
+vec.times(3.0)
+vec.dividedBy(-5)
+vec.dot(othervector)
+vec.lerp(othervector, t)  // linear interpolation (0 <= t <= 1)
+vec.length()
+vec.unit()
+vec.normal()              // returns a 90 degree clockwise rotated vector
+vec.distanceTo(othervector)
+vec.equals(othervector)
+vec.multiply4x4(matrix4x4)   // right multiply by a 4x4 matrix
+vec.toVector3D(z)         // convert to a vector3D by adding a z coordinate
+vec.angleDegrees()        // returns the angle of the vector: [1,0] = 0 degrees, [0, 1] = 90 degrees, etc
+vec.angleRadians()        // ditto in radians
+var vec = CSG.Vector2D.fromAngleDegrees(degrees);  // returns a vector at the specified angle
+var vec = CSG.Vector2D.fromAngleRadians(radians);  // returns a vector at the specified angle
+
+// --------- Matrix4x4 ---------------------
+var m1 = new CSG.Matrix4x4();          // unity matrix
+var m2 = new CSG.Matrix4x4( [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] );
+  // elements are passed in row order
+var result = m1.plus(m2); 
+var result = m1.minus(m2);
+var result = m1.multiply(m2);
+// matrix vector multiplication (vectors are padded with zeroes to get a 4x1 vector):
+var vec3d = m1.rightMultiply1x3Vector(vec3d);  // matrix * vector 
+var vec3d = m1.leftMultiply1x3Vector(vec3d);   // vector * matrix
+var vec2d = m1.rightMultiply1x2Vector(vec2d);  // matrix * vector 
+var vec2d = m1.leftMultiply1x2Vector(vec2d);   // vector * matrix
+// common transformation matrices:
+var m = CSG.Matrix4x4.rotationX(degrees);      // matrix for rotation about X axis
+var m = CSG.Matrix4x4.rotationY(degrees);      // matrix for rotation about Y axis
+var m = CSG.Matrix4x4.rotationZ(degrees);      // matrix for rotation about Z axis
+var m = CSG.Matrix4x4.rotation(rotationCenter, rotationAxis, degrees); // rotation about arbitrary point and axis
+var m = CSG.Matrix4x4.translation(vec3d);      // translation
+var m = CSG.Matrix4x4.scaling(vec3d);          // scale
+var m = CSG.Matrix4x4.mirroring(plane);        // mirroring in a plane; the argument must be a CSG.Plane
+// matrix transformations can be concatenated:
+var transform = CSG.Matrix4x4.rotationX(20).multiply(CSG.Matrix4x4.rotationY(30));
+// Use a CSG solid's transform() method to apply the transformation to a CSG solid
+
+// ------------ Plane --------------------------
+// a 3D plane is represented by a normal vector (should have unit length) and a distance from the origin w 
+// the plane passes through normal.times(w)
+var plane1 = new CSG.Plane(normal, w);         
+// Or we can construct a plane from 3 points:
+var plane2 = CSG.Plane.fromPoints(p1, p2, p3);
+// Or from a normal vector and 1 point:
+var plane3 = CSG.Plane.fromNormalAndPoint(normal, point);
+// Flip a plane (front side becomes back side):
+var plane4 = plane3.flipped();
+// Apply transformations (rotation, scaling, translation):
+var transformed = plane3.transformed(matrix4x4);  // argument is a CSG.Matrix4x4
+// Intersection of plane and 3d line:
+var point = plane3.intersectWithLine(line);        // argument is CSG.Line3D, returns a CSG.Vector3D
+// Intersection of 2 planes:
+var line = plane3.intersectWithPlane(plane);       // argument is another CSG.Plane, returns a CSG.Line3D
+// Distance to point:
+var w = signedDistanceToPoint(point);             // argument is CSG.Vector3D, returns a float (positive
+                                                  //    if in front of plane, negative if in back)
+
+// ------------ Line3D --------------------------
+// A line in 3d space is represented by a point and a direction vector.
+// Direction should be a unit vector. Point can be any point on the line:
+var line = new CSG.Line3D(point, direction);      // argumenst are CSG.Vector3D
+// or by giving two points:
+var line = CSG.Line3D.fromPoints(p1, p2);         // argumenst are CSG.Vector3D
+var point = intersectWithPlane(plane);            // == plane.intersectWithLine(this)
+var line2 = line.reverse();                       // same line but reverse direction
+var line2 = line.transform(matrix4x4);            // for rotation, scaling, etc
+var p = line.closestPointOnLine(point);           // project point onto the line
+var d = line.distanceToPoint(point);
+
+ + + + diff --git a/jquery-1.7.1.min.js b/jquery-1.7.1.min.js new file mode 100644 index 0000000..198b3ff --- /dev/null +++ b/jquery-1.7.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/jquery.js b/jquery.js new file mode 120000 index 0000000..92cf225 --- /dev/null +++ b/jquery.js @@ -0,0 +1 @@ +jquery-1.7.1.min.js \ No newline at end of file diff --git a/lightgl.js b/lightgl.js new file mode 100644 index 0000000..f02987f --- /dev/null +++ b/lightgl.js @@ -0,0 +1,61 @@ +/* + * lightgl.js + * http://github.com/evanw/lightgl.js/ + * + * Copyright 2011 Evan Wallace + * Released under the MIT license + */ +var GL=function(){function I(){d.MODELVIEW=C|1;d.PROJECTION=C|2;var b=new n,c=new n;d.modelviewMatrix=new n;d.projectionMatrix=new n;var a=[],f=[],g,j;d.matrixMode=function(h){switch(h){case d.MODELVIEW:g="modelviewMatrix";j=a;break;case d.PROJECTION:g="projectionMatrix";j=f;break;default:throw"invalid matrix mode "+h;}};d.loadIdentity=function(){n.identity(d[g])};d.loadMatrix=function(h){h=h.m;for(var i=d[g].m,m=0;m<16;m++)i[m]=h[m]};d.multMatrix=function(h){d.loadMatrix(n.multiply(d[g],h,c))};d.perspective= +function(h,i,m,k){d.multMatrix(n.perspective(h,i,m,k,b))};d.frustum=function(h,i,m,k,o,p){d.multMatrix(n.frustum(h,i,m,k,o,p,b))};d.ortho=function(h,i,m,k,o,p){d.multMatrix(n.ortho(h,i,m,k,o,p,b))};d.scale=function(h,i,m){d.multMatrix(n.scale(h,i,m,b))};d.translate=function(h,i,m){d.multMatrix(n.translate(h,i,m,b))};d.rotate=function(h,i,m,k){d.multMatrix(n.rotate(h,i,m,k,b))};d.lookAt=function(h,i,m,k,o,p,J,K,L){d.multMatrix(n.lookAt(h,i,m,k,o,p,J,K,L,b))};d.pushMatrix=function(){j.push(Array.prototype.slice.call(d[g].m))}; +d.popMatrix=function(){var h=j.pop();d[g].m=D?new Float32Array(h):h};d.project=function(h,i,m,k,o,p){k=k||d.modelviewMatrix;o=o||d.projectionMatrix;p=p||d.getParameter(d.VIEWPORT);h=o.transformPoint(k.transformPoint(new l(h,i,m)));return new l(p[0]+p[2]*(h.x*0.5+0.5),p[1]+p[3]*(h.y*0.5+0.5),h.z*0.5+0.5)};d.unProject=function(h,i,m,k,o,p){k=k||d.modelviewMatrix;o=o||d.projectionMatrix;p=p||d.getParameter(d.VIEWPORT);h=new l((h-p[0])/p[2]*2-1,(i-p[1])/p[3]*2-1,m*2-1);return n.inverse(n.multiply(o,k, +b),c).transformPoint(h)};d.matrixMode(d.MODELVIEW)}function M(){var b={mesh:new q({coords:true,colors:true,triangles:false}),mode:-1,coord:[0,0,0,0],color:[1,1,1,1],pointSize:1,shader:new y("uniform float pointSize;varying vec4 color;varying vec4 coord;varying vec2 pixel;void main(){color=gl_Color;coord=gl_TexCoord;gl_Position=gl_ModelViewProjectionMatrix*gl_Vertex;pixel=gl_Position.xy/gl_Position.w*0.5+0.5;gl_PointSize=pointSize;}", +"uniform sampler2D texture;uniform float pointSize;uniform bool useTexture;uniform vec2 windowSize;varying vec4 color;varying vec4 coord;varying vec2 pixel;void main(){gl_FragColor=color;if(useTexture)gl_FragColor*=texture2D(texture,coord.xy);}")};d.pointSize=function(c){b.shader.uniforms({pointSize:c})};d.begin=function(c){if(b.mode!=-1)throw"mismatched gl.begin() and gl.end() calls";b.mode=c;b.mesh.colors=[];b.mesh.coords= +[];b.mesh.vertices=[]};d.color=function(c,a,f,g){b.color=arguments.length==1?c.toArray().concat(1):[c,a,f,g||1]};d.texCoord=function(c,a){b.coord=arguments.length==1?c.toArray(2):[c,a]};d.vertex=function(c,a,f){b.mesh.colors.push(b.color);b.mesh.coords.push(b.coord);b.mesh.vertices.push(arguments.length==1?c.toArray():[c,a,f])};d.end=function(){if(b.mode==-1)throw"mismatched gl.begin() and gl.end() calls";b.mesh.compile();b.shader.uniforms({windowSize:[d.canvas.width,d.canvas.height],useTexture:!!d.getParameter(d.TEXTURE_BINDING_2D)}).draw(b.mesh, +b.mode);b.mode=-1}}function N(){function b(){for(var k in i)if(i[k])return true;return false}function c(k){e=Object.create(k);e.original=k;e.x=e.pageX;e.y=e.pageY;for(k=d.canvas;k;k=k.offsetParent){e.x-=k.offsetLeft;e.y-=k.offsetTop}if(m){e.deltaX=e.x-j;e.deltaY=e.y-h}else{e.deltaX=0;e.deltaY=0;m=true}j=e.x;h=e.y;e.dragging=b();e.preventDefault=function(){e.original.preventDefault()};e.stopPropagation=function(){e.original.stopPropagation()};return e}function a(k){k=c(k);d.onmousemove&&d.onmousemove(k); +k.preventDefault()}function f(k){i[k.which]=false;if(!b()){document.removeEventListener("mousemove",a);document.removeEventListener("mouseup",f);d.canvas.addEventListener("mousemove",a);d.canvas.addEventListener("mouseup",f)}k=c(k);d.onmouseup&&d.onmouseup(k);k.preventDefault()}function g(){m=false}var j=0,h=0,i={},m=false;z(d.canvas,"mousedown",function(k){if(!b()){document.addEventListener("mousemove",a);document.addEventListener("mouseup",f);d.canvas.removeEventListener("mousemove",a);d.canvas.removeEventListener("mouseup", +f)}i[k.which]=true;k=c(k);d.onmousedown&&d.onmousedown(k);k.preventDefault()});d.canvas.addEventListener("mousemove",a);d.canvas.addEventListener("mouseup",f);d.canvas.addEventListener("mouseover",g);d.canvas.addEventListener("mouseout",g)}function E(b){return{8:"BACKSPACE",9:"TAB",13:"ENTER",16:"SHIFT",27:"ESCAPE",32:"SPACE",37:"LEFT",38:"UP",39:"RIGHT",40:"DOWN"}[b]||(b>=65&&b<=90?String.fromCharCode(b):null)}function z(b,c,a){b.addEventListener(c,a)}function O(){(function(b){d.makeCurrent=function(){d= +b}})(d);d.animate=function(){function b(){d=f;var g=new Date;d.onupdate&&d.onupdate((g-a)/1E3);d.ondraw&&d.ondraw();c(b);a=g}var c=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||function(g){setTimeout(g,1E3/60)},a=new Date,f=d;b()};d.fullscreen=function(b){function c(){d.canvas.width=window.innerWidth-f-g;d.canvas.height=window.innerHeight-a-j;d.viewport(0,0,d.canvas.width,d.canvas.height);if(b.camera||!("camera"in b)){d.matrixMode(d.PROJECTION); +d.loadIdentity();d.perspective(b.fov||45,d.canvas.width/d.canvas.height,b.near||0.1,b.far||1E3);d.matrixMode(d.MODELVIEW)}d.ondraw&&d.ondraw()}b=b||{};var a=b.paddingTop||0,f=b.paddingLeft||0,g=b.paddingRight||0,j=b.paddingBottom||0;if(!document.body)throw"document.body doesn't exist yet (call gl.fullscreen() from window.onload() or from inside the tag)";document.body.appendChild(d.canvas);document.body.style.overflow="hidden";d.canvas.style.position="absolute";d.canvas.style.left=f+"px";d.canvas.style.top= +a+"px";window.addEventListener("resize",c);c()}}function n(){var b=Array.prototype.concat.apply([],arguments);b.length||(b=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);this.m=D?new Float32Array(b):b}function w(){this.unique=[];this.indices=[];this.map={}}function x(b,c){this.buffer=null;this.target=b;this.type=c;this.data=[]}function q(b){b=b||{};this.vertexBuffers={};this.indexBuffers={};this.addVertexBuffer("vertices","gl_Vertex");b.coords&&this.addVertexBuffer("coords","gl_TexCoord");b.normals&&this.addVertexBuffer("normals", +"gl_Normal");b.colors&&this.addVertexBuffer("colors","gl_Color");if(!("triangles"in b)||b.triangles)this.addIndexBuffer("triangles");b.lines&&this.addIndexBuffer("lines")}function F(b){return new l((b&1)*2-1,(b&2)-1,(b&4)/2-1)}function t(b,c,a){this.t=arguments.length?b:Number.MAX_VALUE;this.hit=c;this.normal=a}function u(){var b=d.getParameter(d.VIEWPORT),c=d.modelviewMatrix.m,a=new l(c[0],c[4],c[8]),f=new l(c[1],c[5],c[9]),g=new l(c[2],c[6],c[10]);c=new l(c[3],c[7],c[11]);this.eye=new l(-c.dot(a), +-c.dot(f),-c.dot(g));a=b[0];f=a+b[2];g=b[1];c=g+b[3];this.ray00=d.unProject(a,g,1).subtract(this.eye);this.ray10=d.unProject(f,g,1).subtract(this.eye);this.ray01=d.unProject(a,c,1).subtract(this.eye);this.ray11=d.unProject(f,c,1).subtract(this.eye);this.viewport=b}function y(b,c){function a(i,m,k){for(;(result=i.exec(m))!=null;)k(result)}function f(i,m){var k={},o=/^((\s*\/\/.*\n|\s*#extension.*\n)+)[^]*$/.exec(m);m=o?o[1]+i+m.substr(o[1].length):i+m;a(/\bgl_\w+\b/g,i,function(p){if(!(p in k)){m= +m.replace(RegExp("\\b"+p+"\\b","g"),"_"+p);k[p]=true}});return m}function g(i,m){var k=d.createShader(i);d.shaderSource(k,m);d.compileShader(k);if(!d.getShaderParameter(k,d.COMPILE_STATUS))throw"compile error: "+d.getShaderInfoLog(k);return k}var j=b+c;this.needsMVPM=/(gl_ModelViewProjectionMatrix|ftransform)/.test(j);this.needsNM=/gl_NormalMatrix/.test(j);b=f("uniform mat3 gl_NormalMatrix;uniform mat4 gl_ModelViewMatrix;uniform mat4 gl_ProjectionMatrix;uniform mat4 gl_ModelViewProjectionMatrix;attribute vec4 gl_Vertex;attribute vec4 gl_TexCoord;attribute vec3 gl_Normal;attribute vec4 gl_Color;vec4 ftransform(){return gl_ModelViewProjectionMatrix*gl_Vertex;}", +b);c=f("precision highp float;uniform mat3 gl_NormalMatrix;uniform mat4 gl_ModelViewMatrix;uniform mat4 gl_ProjectionMatrix;uniform mat4 gl_ModelViewProjectionMatrix;",c);this.program=d.createProgram();d.attachShader(this.program,g(d.VERTEX_SHADER,b));d.attachShader(this.program,g(d.FRAGMENT_SHADER,c));d.linkProgram(this.program);if(!d.getProgramParameter(this.program,d.LINK_STATUS))throw"link error: "+d.getProgramInfoLog(this.program);this.attributes={};var h={};a(/uniform\s+sampler(1D|2D|3D|Cube)\s+(\w+)\s*;/g, +b+c,function(i){h[i[2]]=1});this.isSampler=h}function s(b,c,a){a=a||{};this.id=d.createTexture();this.width=b;this.height=c;this.format=a.format||d.RGBA;this.type=a.type||d.UNSIGNED_BYTE;d.bindTexture(d.TEXTURE_2D,this.id);d.pixelStorei(d.UNPACK_FLIP_Y_WEBGL,1);d.texParameteri(d.TEXTURE_2D,d.TEXTURE_MAG_FILTER,a.filter||a.magFilter||d.LINEAR);d.texParameteri(d.TEXTURE_2D,d.TEXTURE_MIN_FILTER,a.filter||a.minFilter||d.LINEAR);d.texParameteri(d.TEXTURE_2D,d.TEXTURE_WRAP_S,a.wrap||a.wrapS||d.CLAMP_TO_EDGE); +d.texParameteri(d.TEXTURE_2D,d.TEXTURE_WRAP_T,a.wrap||a.wrapT||d.CLAMP_TO_EDGE);d.texImage2D(d.TEXTURE_2D,0,this.format,b,c,0,this.format,this.type,null)}function l(b,c,a){this.x=b||0;this.y=c||0;this.z=a||0}var d,v={create:function(b){b=b||{};var c=document.createElement("canvas");c.width=800;c.height=600;if(!("alpha"in b))b.alpha=false;try{d=c.getContext("webgl",b)}catch(a){}try{d=d||c.getContext("experimental-webgl",b)}catch(f){}if(!d)throw"WebGL not supported";I();M();N();O();return d},keys:{}, +Matrix:n,Indexer:w,Buffer:x,Mesh:q,HitTest:t,Raytracer:u,Shader:y,Texture:s,Vector:l};z(document,"keydown",function(b){if(!b.altKey&&!b.ctrlKey&&!b.metaKey){var c=E(b.keyCode);if(c)v.keys[c]=true;v.keys[b.keyCode]=true}});z(document,"keyup",function(b){if(!b.altKey&&!b.ctrlKey&&!b.metaKey){var c=E(b.keyCode);if(c)v.keys[c]=false;v.keys[b.keyCode]=false}});var C=305397760,D=typeof Float32Array!="undefined";n.prototype={inverse:function(){return n.inverse(this,new n)},transpose:function(){return n.transpose(this, +new n)},multiply:function(b){return n.multiply(this,b,new n)},transformPoint:function(b){var c=this.m;return(new l(c[0]*b.x+c[1]*b.y+c[2]*b.z+c[3],c[4]*b.x+c[5]*b.y+c[6]*b.z+c[7],c[8]*b.x+c[9]*b.y+c[10]*b.z+c[11])).divide(c[12]*b.x+c[13]*b.y+c[14]*b.z+c[15])},transformVector:function(b){var c=this.m;return new l(c[0]*b.x+c[1]*b.y+c[2]*b.z,c[4]*b.x+c[5]*b.y+c[6]*b.z,c[8]*b.x+c[9]*b.y+c[10]*b.z)}};n.inverse=function(b,c){c=c||new n;var a=b.m,f=c.m;f[0]=a[5]*a[10]*a[15]-a[5]*a[14]*a[11]-a[6]*a[9]*a[15]+ +a[6]*a[13]*a[11]+a[7]*a[9]*a[14]-a[7]*a[13]*a[10];f[1]=-a[1]*a[10]*a[15]+a[1]*a[14]*a[11]+a[2]*a[9]*a[15]-a[2]*a[13]*a[11]-a[3]*a[9]*a[14]+a[3]*a[13]*a[10];f[2]=a[1]*a[6]*a[15]-a[1]*a[14]*a[7]-a[2]*a[5]*a[15]+a[2]*a[13]*a[7]+a[3]*a[5]*a[14]-a[3]*a[13]*a[6];f[3]=-a[1]*a[6]*a[11]+a[1]*a[10]*a[7]+a[2]*a[5]*a[11]-a[2]*a[9]*a[7]-a[3]*a[5]*a[10]+a[3]*a[9]*a[6];f[4]=-a[4]*a[10]*a[15]+a[4]*a[14]*a[11]+a[6]*a[8]*a[15]-a[6]*a[12]*a[11]-a[7]*a[8]*a[14]+a[7]*a[12]*a[10];f[5]=a[0]*a[10]*a[15]-a[0]*a[14]*a[11]- +a[2]*a[8]*a[15]+a[2]*a[12]*a[11]+a[3]*a[8]*a[14]-a[3]*a[12]*a[10];f[6]=-a[0]*a[6]*a[15]+a[0]*a[14]*a[7]+a[2]*a[4]*a[15]-a[2]*a[12]*a[7]-a[3]*a[4]*a[14]+a[3]*a[12]*a[6];f[7]=a[0]*a[6]*a[11]-a[0]*a[10]*a[7]-a[2]*a[4]*a[11]+a[2]*a[8]*a[7]+a[3]*a[4]*a[10]-a[3]*a[8]*a[6];f[8]=a[4]*a[9]*a[15]-a[4]*a[13]*a[11]-a[5]*a[8]*a[15]+a[5]*a[12]*a[11]+a[7]*a[8]*a[13]-a[7]*a[12]*a[9];f[9]=-a[0]*a[9]*a[15]+a[0]*a[13]*a[11]+a[1]*a[8]*a[15]-a[1]*a[12]*a[11]-a[3]*a[8]*a[13]+a[3]*a[12]*a[9];f[10]=a[0]*a[5]*a[15]-a[0]* +a[13]*a[7]-a[1]*a[4]*a[15]+a[1]*a[12]*a[7]+a[3]*a[4]*a[13]-a[3]*a[12]*a[5];f[11]=-a[0]*a[5]*a[11]+a[0]*a[9]*a[7]+a[1]*a[4]*a[11]-a[1]*a[8]*a[7]-a[3]*a[4]*a[9]+a[3]*a[8]*a[5];f[12]=-a[4]*a[9]*a[14]+a[4]*a[13]*a[10]+a[5]*a[8]*a[14]-a[5]*a[12]*a[10]-a[6]*a[8]*a[13]+a[6]*a[12]*a[9];f[13]=a[0]*a[9]*a[14]-a[0]*a[13]*a[10]-a[1]*a[8]*a[14]+a[1]*a[12]*a[10]+a[2]*a[8]*a[13]-a[2]*a[12]*a[9];f[14]=-a[0]*a[5]*a[14]+a[0]*a[13]*a[6]+a[1]*a[4]*a[14]-a[1]*a[12]*a[6]-a[2]*a[4]*a[13]+a[2]*a[12]*a[5];f[15]=a[0]*a[5]* +a[10]-a[0]*a[9]*a[6]-a[1]*a[4]*a[10]+a[1]*a[8]*a[6]+a[2]*a[4]*a[9]-a[2]*a[8]*a[5];a=a[0]*f[0]+a[1]*f[4]+a[2]*f[8]+a[3]*f[12];for(var g=0;g<16;g++)f[g]/=a;return c};n.transpose=function(b,c){c=c||new n;var a=b.m,f=c.m;f[0]=a[0];f[1]=a[4];f[2]=a[8];f[3]=a[12];f[4]=a[1];f[5]=a[5];f[6]=a[9];f[7]=a[13];f[8]=a[2];f[9]=a[6];f[10]=a[10];f[11]=a[14];f[12]=a[3];f[13]=a[7];f[14]=a[11];f[15]=a[15];return c};n.multiply=function(b,c,a){a=a||new n;b=b.m;c=c.m;var f=a.m;f[0]=b[0]*c[0]+b[1]*c[4]+b[2]*c[8]+b[3]*c[12]; +f[1]=b[0]*c[1]+b[1]*c[5]+b[2]*c[9]+b[3]*c[13];f[2]=b[0]*c[2]+b[1]*c[6]+b[2]*c[10]+b[3]*c[14];f[3]=b[0]*c[3]+b[1]*c[7]+b[2]*c[11]+b[3]*c[15];f[4]=b[4]*c[0]+b[5]*c[4]+b[6]*c[8]+b[7]*c[12];f[5]=b[4]*c[1]+b[5]*c[5]+b[6]*c[9]+b[7]*c[13];f[6]=b[4]*c[2]+b[5]*c[6]+b[6]*c[10]+b[7]*c[14];f[7]=b[4]*c[3]+b[5]*c[7]+b[6]*c[11]+b[7]*c[15];f[8]=b[8]*c[0]+b[9]*c[4]+b[10]*c[8]+b[11]*c[12];f[9]=b[8]*c[1]+b[9]*c[5]+b[10]*c[9]+b[11]*c[13];f[10]=b[8]*c[2]+b[9]*c[6]+b[10]*c[10]+b[11]*c[14];f[11]=b[8]*c[3]+b[9]*c[7]+b[10]* +c[11]+b[11]*c[15];f[12]=b[12]*c[0]+b[13]*c[4]+b[14]*c[8]+b[15]*c[12];f[13]=b[12]*c[1]+b[13]*c[5]+b[14]*c[9]+b[15]*c[13];f[14]=b[12]*c[2]+b[13]*c[6]+b[14]*c[10]+b[15]*c[14];f[15]=b[12]*c[3]+b[13]*c[7]+b[14]*c[11]+b[15]*c[15];return a};n.identity=function(b){b=b||new n;var c=b.m;c[0]=c[5]=c[10]=c[15]=1;c[1]=c[2]=c[3]=c[4]=c[6]=c[7]=c[8]=c[9]=c[11]=c[12]=c[13]=c[14]=0;return b};n.perspective=function(b,c,a,f,g){b=Math.tan(b*Math.PI/360)*a;c=b*c;return n.frustum(-c,c,-b,b,a,f,g)};n.frustum=function(b, +c,a,f,g,j,h){h=h||new n;var i=h.m;i[0]=2*g/(c-b);i[1]=0;i[2]=(c+b)/(c-b);i[3]=0;i[4]=0;i[5]=2*g/(f-a);i[6]=(f+a)/(f-a);i[7]=0;i[8]=0;i[9]=0;i[10]=-(j+g)/(j-g);i[11]=-2*j*g/(j-g);i[12]=0;i[13]=0;i[14]=-1;i[15]=0;return h};n.ortho=function(b,c,a,f,g,j,h){h=h||new n;var i=h.m;i[0]=2/(c-b);i[1]=0;i[2]=0;i[3]=-(c+b)/(c-b);i[4]=0;i[5]=2/(f-a);i[6]=0;i[7]=-(f+a)/(f-a);i[8]=0;i[9]=0;i[10]=-2/(j-g);i[11]=-(j+g)/(j-g);i[12]=0;i[13]=0;i[14]=0;i[15]=1;return h};n.scale=function(b,c,a,f){f=f||new n;var g=f.m; +g[0]=b;g[1]=0;g[2]=0;g[3]=0;g[4]=0;g[5]=c;g[6]=0;g[7]=0;g[8]=0;g[9]=0;g[10]=a;g[11]=0;g[12]=0;g[13]=0;g[14]=0;g[15]=1;return f};n.translate=function(b,c,a,f){f=f||new n;var g=f.m;g[0]=1;g[1]=0;g[2]=0;g[3]=b;g[4]=0;g[5]=1;g[6]=0;g[7]=c;g[8]=0;g[9]=0;g[10]=1;g[11]=a;g[12]=0;g[13]=0;g[14]=0;g[15]=1;return f};n.rotate=function(b,c,a,f,g){if(!b||!c&&!a&&!f)return n.identity(g);g=g||new n;var j=g.m,h=Math.sqrt(c*c+a*a+f*f);b*=Math.PI/180;c/=h;a/=h;f/=h;h=Math.cos(b);b=Math.sin(b);var i=1-h;j[0]=c*c*i+h; +j[1]=c*a*i-f*b;j[2]=c*f*i+a*b;j[3]=0;j[4]=a*c*i+f*b;j[5]=a*a*i+h;j[6]=a*f*i-c*b;j[7]=0;j[8]=f*c*i-a*b;j[9]=f*a*i+c*b;j[10]=f*f*i+h;j[11]=0;j[12]=0;j[13]=0;j[14]=0;j[15]=1;return g};n.lookAt=function(b,c,a,f,g,j,h,i,m,k){k=k||new n;var o=k.m;b=new l(b,c,a);f=new l(f,g,j);i=new l(h,i,m);h=b.subtract(f).unit();i=i.cross(h).unit();m=h.cross(i).unit();o[0]=i.x;o[1]=i.y;o[2]=i.z;o[3]=-i.dot(b);o[4]=m.x;o[5]=m.y;o[6]=m.z;o[7]=-m.dot(b);o[8]=h.x;o[9]=h.y;o[10]=h.z;o[11]=-h.dot(b);o[12]=0;o[13]=0;o[14]=0; +o[15]=1;return k};w.prototype={add:function(b){var c=JSON.stringify(b);if(!(c in this.map)){this.map[c]=this.unique.length;this.unique.push(b)}return this.map[c]}};x.prototype={compile:function(b){for(var c=[],a=0;a0,j=[],h=0;h<=detail;h++){for(var i=0;h+i<=detail;i++){var m=h/detail,k=i/detail,o=(detail-h-i)/detail;k={vertex:(new l(m+(m-m*m)/2,k+(k-k*k)/2,o+(o-o*o)/2)).unit().multiply(f).toArray()};if(c.coords)k.coord=f.y>0?[1-m,o]:[o,1-m];j.push(a.add(k))}if(h>0)for(i=0;h+i<=detail;i++){m=(h-1)*(detail+1)+(h-1-(h-1)*(h-1))/2+i;k=h*(detail+1)+(h-h*h)/2+i;c.triangles.push(g?[j[m],j[k],j[m+1]]:[j[m],j[m+1],j[k]]);h+i0&&b.t0&&hf.x)-(b.xf.y)-(b.yf.z)-(b.z0){j=(-h-Math.sqrt(g))/(2*j);b=b.add(c.multiply(j));return new t(j,b,b.subtract(a).divide(f))}return null};u.hitTestTriangle=function(b,c,a,f,g){var j=f.subtract(a),h=g.subtract(a); +g=j.cross(h).unit();f=g.dot(a.subtract(b)).divide(g.dot(c));if(f>0){b=b.add(c.multiply(f));var i=b.subtract(a);a=h.dot(h);c=h.dot(j);h=h.dot(i);var m=j.dot(j);j=j.dot(i);i=a*m-c*c;m=(m*h-c*j)/i;j=(a*j-c*h)/i;if(m>=0&&j>=0&&m+j<=1)return new t(f,b,g)}return null};var P=new n,H=new n;y.prototype={uniforms:function(b){d.useProgram(this.program);for(var c in b){var a=d.getUniformLocation(this.program,c);if(a){var f=b[c];if(f instanceof l)f=[f.x,f.y,f.z];else if(f instanceof n)f=f.m;var g=Object.prototype.toString.call(f); +if(g=="[object Array]"||g=="[object Float32Array]")switch(f.length){case 1:d.uniform1fv(a,new Float32Array(f));break;case 2:d.uniform2fv(a,new Float32Array(f));break;case 3:d.uniform3fv(a,new Float32Array(f));break;case 4:d.uniform4fv(a,new Float32Array(f));break;case 9:d.uniformMatrix3fv(a,false,new Float32Array([f[0],f[3],f[6],f[1],f[4],f[7],f[2],f[5],f[8]]));break;case 16:d.uniformMatrix4fv(a,false,new Float32Array([f[0],f[4],f[8],f[12],f[1],f[5],f[9],f[13],f[2],f[6],f[10],f[14],f[3],f[7],f[11], +f[15]]));break;default:throw"don't know how to load uniform \""+c+'" of length '+f.length;}else{g=Object.prototype.toString.call(f);if(g=="[object Number]"||g=="[object Boolean]")(this.isSampler[c]?d.uniform1i:d.uniform1f).call(d,a,f);else throw'attempted to set uniform "'+c+'" to invalid value '+f;}}}return this},draw:function(b,c){this.drawBuffers(b.vertexBuffers,b.indexBuffers[c==d.LINES?"lines":"triangles"],arguments.length<2?d.TRIANGLES:c)},drawBuffers:function(b,c,a){this.uniforms({_gl_ModelViewMatrix:d.modelviewMatrix, +_gl_ProjectionMatrix:d.projectionMatrix});this.needsMVPM&&this.uniforms({_gl_ModelViewProjectionMatrix:n.multiply(d.projectionMatrix,d.modelviewMatrix,H)});if(this.needsNM){var f=n.transpose(n.inverse(d.modelviewMatrix,P),H).m;this.uniforms({_gl_NormalMatrix:[f[0],f[1],f[2],f[4],f[5],f[6],f[8],f[9],f[10]]})}f=0;for(var g in b){var j=b[g],h=this.attributes[g]||d.getAttribLocation(this.program,g.replace(/^gl_/,"_gl_"));if(!(h==-1||!j.buffer)){this.attributes[g]=h;d.bindBuffer(d.ARRAY_BUFFER,j.buffer); +d.enableVertexAttribArray(h);d.vertexAttribPointer(h,j.buffer.spacing,d.FLOAT,false,0,0);f=j.buffer.length/j.buffer.spacing}}for(g in this.attributes)g in b||d.disableVertexAttribArray(this.attributes[g]);if(f&&(!c||c.buffer))if(c){d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,c.buffer);d.drawElements(a,c.buffer.length,d.UNSIGNED_SHORT,0)}else d.drawArrays(a,0,f);return this}};var A,r,B;s.prototype={bind:function(b){d.activeTexture(d.TEXTURE0+(b||0));d.bindTexture(d.TEXTURE_2D,this.id)},unbind:function(b){d.activeTexture(d.TEXTURE0+ +(b||0));d.bindTexture(d.TEXTURE_2D,null)},drawTo:function(b){var c=d.getParameter(d.VIEWPORT);A=A||d.createFramebuffer();r=r||d.createRenderbuffer();d.bindFramebuffer(d.FRAMEBUFFER,A);d.bindRenderbuffer(d.RENDERBUFFER,r);if(this.width!=r.width||this.height!=r.height){r.width=this.width;r.height=this.height;d.renderbufferStorage(d.RENDERBUFFER,d.DEPTH_COMPONENT16,this.width,this.height)}d.framebufferTexture2D(d.FRAMEBUFFER,d.COLOR_ATTACHMENT0,d.TEXTURE_2D,this.id,0);d.framebufferRenderbuffer(d.FRAMEBUFFER, +d.DEPTH_ATTACHMENT,d.RENDERBUFFER,r);d.viewport(0,0,this.width,this.height);b();d.bindFramebuffer(d.FRAMEBUFFER,null);d.bindRenderbuffer(d.RENDERBUFFER,null);d.viewport(c[0],c[1],c[2],c[3])},swapWith:function(b){var c;c=b.id;b.id=this.id;this.id=c;c=b.width;b.width=this.width;this.width=c;c=b.height;b.height=this.height;this.height=c}};s.fromImage=function(b,c){c=c||{};var a=new s(b.width,b.height,c);try{d.texImage2D(d.TEXTURE_2D,0,a.format,a.format,a.type,b)}catch(f){if(location.protocol=="file:")throw'image not loaded for security reasons (serve this page over "http://" instead)'; +else throw"image not loaded for security reasons (image must originate from the same domain as this page or use Cross-Origin Resource Sharing)";}c.minFilter&&c.minFilter!=d.NEAREST&&c.minFilter!=d.LINEAR&&d.generateMipmap(d.TEXTURE_2D);return a};s.fromURL=function(b,c){B=B||function(){var g=document.createElement("canvas").getContext("2d");g.canvas.width=g.canvas.height=128;for(var j=0;j 0) + { + basecomps.splice(basecomps.length - 1, 1); + } + var urlcomps = url.split("/"); + var comps = basecomps.concat(urlcomps); + var comps2 = []; + comps.map(function(c) { + if(c == "..") + { + if(comps2.length > 0) + { + comps2.splice(comps2.length - 1, 1); + } + } + else + { + comps2.push(c); + } + }); + url = ""; + for(var i = 0; i < comps2.length; i++) + { + if(i > 0) url += "/"; + url += comps2[i]; + } + } + return url; +}; + +OpenJsCad.isChrome = function() +{ + return (navigator.userAgent.search("Chrome") >= 0); +}; + +// This is called from within the web worker. Execute the main() function of the supplied script +// and post a message to the calling thread when finished +OpenJsCad.runMainInWorker = function(mainParameters) +{ + try + { + if(typeof(main) != 'function') throw new Error('Your jscad file should contain a function main() which returns a CSG solid.'); + OpenJsCad.log.prevLogTime = Date.now(); + var csg = main(mainParameters); + if( (typeof(csg) != "object") || (!(csg instanceof CSG)) ) + { + throw new Error("Your main() function should return a CSG solid."); + } + var csg_bin = csg.toCompactBinary(); + csg = null; // not needed anymore + self.postMessage({cmd: 'rendered', csg: csg_bin}); + } + catch(e) + { + var errtxt = e.stack; + if(!errtxt) + { + errtxt = e.toString(); + } + self.postMessage({cmd: 'error', err: errtxt}); + } +}; + +OpenJsCad.javaScriptToSolidSync = function(script, mainParameters, debugging) { + var workerscript = ""; + workerscript += script; + if(debugging) + { + workerscript += "\n\n\n\n\n\n\n/* -------------------------------------------------------------------------\n"; + workerscript += "OpenJsCad debugging\n\nAssuming you are running Chrome:\nF10 steps over an instruction\nF11 steps into an instruction\n"; + workerscript += "F8 continues running\nPress the (||) button at the bottom to enable pausing whenever an error occurs\n"; + workerscript += "Click on a line number to set or clear a breakpoint\n"; + workerscript += "For more information see: http://code.google.com/chrome/devtools/docs/overview.html\n\n"; + workerscript += "------------------------------------------------------------------------- */\n"; + workerscript += "\n\n// Now press F11 twice to enter your main() function:\n\n"; + workerscript += "debugger;\n"; + } + workerscript += "return main("+JSON.stringify(mainParameters)+");"; + var f = new Function(workerscript); + OpenJsCad.log.prevLogTime = Date.now(); + var csg = f(); + return csg; +}; + +// callback: should be function(error, csg) +OpenJsCad.javaScriptToSolidASync = function(script, mainParameters, callback) { + var baselibraries = [ + "csg.js", + "openjscad.js" + ]; + var baseurl = document.location + ''; + var base = document.getElementsByTagName('base'); + if( base) { + base = base.getAttribute('href'); + if( base) + baseurl = OpenJsCad.makeAbsoluteUrl(baseurl, base); + } + var workerscript = ""; + workerscript += script; + workerscript += "\n\n\n\n//// The following code is added by OpenJsCad:\n"; + workerscript += "var _csg_libraries=" + JSON.stringify(baselibraries)+";\n"; + workerscript += "var _csg_baseurl=" + JSON.stringify(baseurl)+";\n"; + workerscript += "var _csg_makeAbsoluteURL=" + OpenJsCad.makeAbsoluteUrl.toString()+";\n"; +// workerscript += "if(typeof(libs) == 'function') _csg_libraries = _csg_libraries.concat(libs());\n"; + workerscript += "_csg_libraries = _csg_libraries.map(function(l){return _csg_makeAbsoluteURL(l,_csg_baseurl);});\n"; + workerscript += "_csg_libraries.map(function(l){importScripts(l)});\n"; + workerscript += "self.addEventListener('message', function(e) {if(e.data && e.data.cmd == 'render'){"; + workerscript += " OpenJsCad.runMainInWorker("+JSON.stringify(mainParameters)+");"; +// workerscript += " if(typeof(main) != 'function') throw new Error('Your jscad file should contain a function main() which returns a CSG solid.');\n"; +// workerscript += " var csg; try {csg = main("+JSON.stringify(mainParameters)+"); self.postMessage({cmd: 'rendered', csg: csg});}"; +// workerscript += " catch(e) {var errtxt = e.stack; self.postMessage({cmd: 'error', err: errtxt});}"; + workerscript += "}},false);\n"; + + var blobURL = OpenJsCad.textToBlobUrl(workerscript); + + if(!window.Worker) throw new Error("Your browser doesn't support Web Workers. Please try the Chrome browser instead."); + var worker = new Worker(blobURL); + worker.onmessage = function(e) { + if(e.data) + { + if(e.data.cmd == 'rendered') + { + //var csg = CSG.fromObject(e.data.csg); + var csg = CSG.fromCompactBinary(e.data.csg); + callback(null, csg); + } + else if(e.data.cmd == "error") + { +// var errtxt = "Error in line "+e.data.err.lineno+": "+e.data.err.message; + callback(e.data.err, null); + } + else if(e.data.cmd == "log") + { + console.log(e.data.txt); + } + } + }; + worker.onerror = function(e) { + var errtxt = "Error in line "+e.lineno+": "+e.message; + callback(errtxt, null); + }; + worker.postMessage({ + cmd: "render" + }); // Start the worker. + return worker; +}; + +OpenJsCad.textToBlobUrl = function(txt) { + var bb; + if(window.BlobBuilder) bb = new window.BlobBuilder() + else if(window.WebKitBlobBuilder) bb = new window.WebKitBlobBuilder() + else if(window.MozBlobBuilder) bb = new window.MozBlobBuilder() + else throw new Error("Your browser doesn't support BlobBuilder"); + + bb.append(txt); + var blob = bb.getBlob(); + var blobURL; + if(window.URL) blobURL = window.URL.createObjectURL(blob) + else if(window.webkitURL) blobURL = window.webkitURL.createObjectURL(blob) + else throw new Error("Your browser doesn't support window.URL"); + if(!blobURL) throw new Error("createObjectURL() failed"); + return blobURL; +}; + +OpenJsCad.revokeBlobUrl = function(url) { + if(window.URL) window.URL.revokeObjectURL(url) + else if(window.webkitURL) window.webkitURL.revokeObjectURL(url) + else throw new Error("Your browser doesn't support window.URL"); +}; + +OpenJsCad.FileSystemApiErrorHandler = function(fileError, operation) { + var errormap = { + 1: 'NOT_FOUND_ERR', + 2: 'SECURITY_ERR', + 3: 'ABORT_ERR', + 4: 'NOT_READABLE_ERR', + 5: 'ENCODING_ERR', + 6: 'NO_MODIFICATION_ALLOWED_ERR', + 7: 'INVALID_STATE_ERR', + 8: 'SYNTAX_ERR', + 9: 'INVALID_MODIFICATION_ERR', + 10: 'QUOTA_EXCEEDED_ERR', + 11: 'TYPE_MISMATCH_ERR', + 12: 'PATH_EXISTS_ERR', + }; + var errname; + if(fileError.code in errormap) + { + errname = errormap[fileError.code]; + } + else + { + errname = "Error #"+fileError.code; + } + var errtxt = "FileSystem API error: "+operation+" returned error "+errname; + throw new Error(errtxt); +}; + +OpenJsCad.AlertUserOfUncaughtExceptions = function() { + window.onerror = function(message, url, line) { + message = message.replace(/^Uncaught /i, ""); + alert(message+"\n\n("+url+" line "+line+")"); + }; +}; + +// parse the jscad script to get the parameter definitions +OpenJsCad.getParamDefinitions = function(script) { + var scriptisvalid = true; + try + { + // first try to execute the script itself + // this will catch any syntax errors + var f = new Function(script); + f(); + } + catch(e) { + scriptisvalid = false; + } + var params = []; + if(scriptisvalid) + { + var script1 = "if(typeof(getParameterDefinitions) == 'function') {return getParameterDefinitions();} else {return [];} "; + script1 += script; + var f = new Function(script1); + params = f(); + if( (typeof(params) != "object") || (typeof(params.length) != "number") ) + { + throw new Error("The getParameterDefinitions() function should return an array with the parameter definitions"); + } + } + return params; +}; + +OpenJsCad.Processor = function(containerdiv, onchange) { + this.containerdiv = containerdiv; + this.onchange = onchange; + this.viewerdiv = null; + this.viewer = null; + this.viewerwidth = 800; + this.viewerheight = 600; + this.initialViewerDistance = 50; + this.processing = false; + this.solid = null; + this.validcsg = false; + this.hasstl = false; + this.worker = null; + this.paramDefinitions = []; + this.paramControls = []; + this.script = null; + this.hasError = false; + this.debugging = false; + this.createElements(); +}; + +OpenJsCad.Processor.prototype = { + createElements: function() { + while(this.containerdiv.children.length > 0) + { + this.containerdiv.removeChild(0); + } + if(!OpenJsCad.isChrome() ) + { + var div = document.createElement("div"); + div.innerHTML = "Please note: OpenJsCad currently only runs reliably on Google Chrome!"; + this.containerdiv.appendChild(div); + } + var viewerdiv = document.createElement("div"); + viewerdiv.className = "viewer"; + viewerdiv.style.width = this.viewerwidth + "px"; + viewerdiv.style.height = this.viewerheight + "px"; + viewerdiv.style.backgroundColor = "rgb(200,200,200)"; + this.containerdiv.appendChild(viewerdiv); + this.viewerdiv = viewerdiv; + try + { + this.viewer = new OpenJsCad.Viewer(this.viewerdiv, this.viewerwidth, this.viewerheight, this.initialViewerDistance); + } catch (e) { +// this.viewer = null; + this.viewerdiv.innerHTML = "

Error: "+e.toString()+"


OpenJsCad currently requires Google Chrome with WebGL enabled"; +// this.viewerdiv.innerHTML = e.toString(); + } + this.errordiv = document.createElement("div"); + this.errorpre = document.createElement("pre"); + this.errordiv.appendChild(this.errorpre); + this.statusdiv = document.createElement("div"); + this.statusdiv.className = "statusdiv"; + //this.statusdiv.style.width = this.viewerwidth + "px"; + this.statusspan = document.createElement("span"); + this.statusbuttons = document.createElement("div"); + this.statusbuttons.style.float = "right"; + this.statusdiv.appendChild(this.statusspan); + this.statusdiv.appendChild(this.statusbuttons); + this.abortbutton = document.createElement("button"); + this.abortbutton.innerHTML = "Abort"; + var that = this; + this.abortbutton.onclick = function(e) { + that.abort(); + }; + this.statusbuttons.appendChild(this.abortbutton); + this.generateStlButton = document.createElement("button"); + this.generateStlButton.innerHTML = "Generate STL"; + this.generateStlButton.onclick = function(e) { + that.generateStl(); + }; + this.statusbuttons.appendChild(this.generateStlButton); + this.downloadStlLink = document.createElement("a"); + this.downloadStlLink.innerHTML = "Download STL"; + this.statusbuttons.appendChild(this.downloadStlLink); + this.parametersdiv = document.createElement("div"); + this.parametersdiv.className = "parametersdiv"; + var headerdiv = document.createElement("div"); + headerdiv.innerText = "Parameters:"; + headerdiv.className = "header"; + this.parametersdiv.appendChild(headerdiv); + this.parameterstable = document.createElement("table"); + this.parameterstable.className = "parameterstable"; + this.parametersdiv.appendChild(this.parameterstable); + var parseParametersButton = document.createElement("button"); + parseParametersButton.innerHTML = "Update"; + parseParametersButton.onclick = function(e) { + that.rebuildSolid(); + }; + this.parametersdiv.appendChild(parseParametersButton); + this.enableItems(); + this.containerdiv.appendChild(this.statusdiv); + this.containerdiv.appendChild(this.errordiv); + this.containerdiv.appendChild(this.parametersdiv); + this.clearViewer(); + }, + + clearViewer: function() { + this.clearStl(); + this.solid = new CSG(); + if(this.viewer) + { + this.viewer.setCsg(this.solid); + } + this.validcsg = false; + this.enableItems(); + }, + + abort: function() { + if(this.processing) + { + //todo: abort + this.processing=false; + this.statusspan.innerHTML = "Aborted."; + this.worker.terminate(); + this.enableItems(); + if(this.onchange) this.onchange(); + } + }, + + enableItems: function() { + this.abortbutton.style.display = this.processing? "inline":"none"; + this.generateStlButton.style.display = ((!this.hasstl)&&(this.validcsg))? "inline":"none"; + this.downloadStlLink.style.display = this.hasstl? "inline":"none"; + this.parametersdiv.style.display = (this.paramControls.length > 0)? "block":"none"; + this.errordiv.style.display = this.hasError? "block":"none"; + this.statusdiv.style.display = this.hasError? "none":"block"; + }, + + setError: function(txt) { + this.hasError = (txt != ""); + this.errorpre.innerText = txt; + this.enableItems(); + }, + + setDebugging: function(debugging) { + this.debugging = debugging; + }, + + // script: javascript code + // filename: optional, the name of the .jscad file + setJsCad: function(script, filename) { + if(!filename) filename = "openjscad.jscad"; + filename = filename.replace(/\.jscad$/i, ""); + this.abort(); + this.clearViewer(); + this.paramDefinitions = []; + this.paramControls = []; + this.script = null; + this.setError(""); + var scripthaserrors = false; + try + { + this.paramDefinitions = OpenJsCad.getParamDefinitions(script); + this.createParamControls(); + } + catch(e) + { + this.setError(e.toString()); + this.statusspan.innerHTML = "Error."; + scripthaserrors = true; + } + if(!scripthaserrors) + { + this.script = script; + this.filename = filename; + this.rebuildSolid(); + } + else + { + this.enableItems(); + if(this.onchange) this.onchange(); + } + }, + + getParamValues: function() + { + var paramValues = {}; + for(var i = 0; i < this.paramDefinitions.length; i++) + { + var paramdef = this.paramDefinitions[i]; + var type = "text"; + if('type' in paramdef) + { + type = paramdef.type; + } + var control = this.paramControls[i]; + var value; + if( (type == "text") || (type == "float") || (type == "int") ) + { + value = control.value; + if( (type == "float") || (type == "int") ) + { + var isnumber = !isNaN(parseFloat(value)) && isFinite(value); + if(!isnumber) + { + throw new Error("Not a number: "+value); + } + if(type == "int") + { + value = parseInt(value); + } + else + { + value = parseFloat(value); + } + } + } + else if(type == "choice") + { + value = control.options[control.selectedIndex].value; + } + paramValues[paramdef.name] = value; + } + return paramValues; + }, + + rebuildSolid: function() + { + this.abort(); + this.setError(""); + this.clearViewer(); + this.processing = true; + this.statusspan.innerHTML = "Processing, please wait..."; + this.enableItems(); + var that = this; + var paramValues = this.getParamValues(); + var useSync = this.debugging; + if(!useSync) + { + try + { + this.worker = OpenJsCad.javaScriptToSolidASync(this.script, paramValues, function(err, csg) { + that.processing = false; + that.worker = null; + if(err) + { + that.setError(err); + that.statusspan.innerHTML = "Error."; + } + else + { + that.solid = csg; + if(that.viewer) that.viewer.setCsg(csg); + that.validcsg = true; + that.statusspan.innerHTML = "Ready."; + } + that.enableItems(); + if(that.onchange) that.onchange(); + }); + } + catch(e) + { + useSync = true; + } + } + + if(useSync) + { + try + { + var csg = OpenJsCad.javaScriptToSolidSync(this.script, paramValues, this.debugging); + that.processing = false; + that.solid = csg; + if(that.viewer) that.viewer.setCsg(csg); + that.validcsg = true; + that.statusspan.innerHTML = "Ready."; + } + catch(e) + { + that.processing = false; + var errtxt = e.stack; + if(!errtxt) + { + errtxt = e.toString(); + } + that.setError(errtxt); + that.statusspan.innerHTML = "Error."; + } + that.enableItems(); + if(that.onchange) that.onchange(); + } + }, + + hasSolid: function() { + return this.validcsg; + }, + + isProcessing: function() { + return this.processing; + }, + +/* + clearStl1: function() { + if(this.hasstl) + { + this.hasstl = false; + OpenJsCad.revokeBlobUrl(this.stlBlobUrl); + this.stlBlobUrl = null; + this.enableItems(); + if(this.onchange) this.onchange(); + } + }, + +*/ + + clearStl: function() { + if(this.hasstl) + { + this.hasstl = false; + if(this.stlDirEntry) + { + this.stlDirEntry.removeRecursively(function(){}); + this.stlDirEntry=null; + } + if(this.stlBlobUrl) + { + OpenJsCad.revokeBlobUrl(this.stlBlobUrl); + this.stlBlobUrl = null; + } + this.enableItems(); + if(this.onchange) this.onchange(); + } + }, + + generateStl: function() { + this.clearStl(); + if(this.validcsg) + { + try + { + this.generateStlFileSystem(); + } + catch(e) + { + this.generateStlBlobUrl(); + } + } + }, + + generateStlBlobUrl: function() { + var stltxt = this.solid.toStlString(); + this.stlBlobUrl = OpenJsCad.textToBlobUrl(stltxt); + this.hasstl = true; + this.downloadStlLink.href = this.stlBlobUrl; + this.enableItems(); + if(this.onchange) this.onchange(); + }, + + generateStlFileSystem: function() { + var stltxt = this.solid.toStlString(); + window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; + window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder; + if(!window.requestFileSystem) + { + throw new Error("Your browser does not support the HTML5 FileSystem API. Please try the Chrome browser instead."); + } + if(!window.BlobBuilder) + { + throw new Error("Your browser does not support the HTML5 BlobBuilder API. Please try the Chrome browser instead."); + } + // create a random directory name: + var dirname = "OpenJsCadStlOutput1_"+parseInt(Math.random()*1000000000, 10)+".stl"; + var filename = this.filename+".stl"; + var that = this; + window.requestFileSystem(TEMPORARY, 20*1024*1024, function(fs){ + fs.root.getDirectory(dirname, {create: true, exclusive: true}, function(dirEntry) { + that.stlDirEntry = dirEntry; + dirEntry.getFile(filename, {create: true, exclusive: true}, function(fileEntry) { + fileEntry.createWriter(function(fileWriter) { + fileWriter.onwriteend = function(e) { + that.hasstl = true; + that.downloadStlLink.href = fileEntry.toURL(); + that.enableItems(); + if(that.onchange) that.onchange(); + }; + fileWriter.onerror = function(e) { + throw new Error('Write failed: ' + e.toString()); + }; + // Create a new Blob and write it to log.txt. + var bb = new window.BlobBuilder(); // Note: window.WebKitBlobBuilder in Chrome 12. + bb.append(stltxt); + fileWriter.write(bb.getBlob()); + }, + function(fileerror){OpenJsCad.FileSystemApiErrorHandler(fileerror, "createWriter");} + ); + }, + function(fileerror){OpenJsCad.FileSystemApiErrorHandler(fileerror, "getFile('"+filename+"')");} + ); + }, + function(fileerror){OpenJsCad.FileSystemApiErrorHandler(fileerror, "getDirectory('"+dirname+"')");} + ); + }, + function(fileerror){OpenJsCad.FileSystemApiErrorHandler(fileerror, "requestFileSystem");} + ); + }, + + createParamControls: function() { + this.parameterstable.innerHTML = ""; + this.paramControls = []; + var paramControls = []; + var tablerows = []; + for(var i = 0; i < this.paramDefinitions.length; i++) + { + var errorprefix = "Error in parameter definition #"+(i+1)+": "; + var paramdef = this.paramDefinitions[i]; + if(!('name' in paramdef)) + { + throw new Error(errorprefix + "Should include a 'name' parameter"); + } + var type = "text"; + if('type' in paramdef) + { + type = paramdef.type; + } + if( (type !== "text") && (type !== "int") && (type !== "float") && (type !== "choice") ) + { + throw new Error(errorprefix + "Unknown parameter type '"+type+"'"); + } + var control; + if( (type == "text") || (type == "int") || (type == "float") ) + { + control = document.createElement("input"); + control.type = "text"; + if('default' in paramdef) + { + control.value = paramdef.default; + } + else + { + if( (type == "int") || (type == "float") ) + { + control.value = "0"; + } + else + { + control.value = ""; + } + } + } + else if(type == "choice") + { + if(!('values' in paramdef)) + { + throw new Error(errorprefix + "Should include a 'values' parameter"); + } + control = document.createElement("select"); + var values = paramdef.values; + var captions; + if('captions' in paramdef) + { + captions = paramdef.captions; + if(captions.length != values.length) + { + throw new Error(errorprefix + "'captions' and 'values' should have the same number of items"); + } + } + else + { + captions = values; + } + var selectedindex = 0; + for(var valueindex = 0; valueindex < values.length; valueindex++) + { + var option = document.createElement("option"); + option.value = values[valueindex]; + option.text = captions[valueindex]; + control.add(option); + if('default' in paramdef) + { + if(paramdef.default == values[valueindex]) + { + selectedindex = valueindex; + } + } + } + if(values.length > 0) + { + control.selectedIndex = selectedindex; + } + } + paramControls.push(control); + var tr = document.createElement("tr"); + var td = document.createElement("td"); + var label = paramdef.name + ":"; + if('caption' in paramdef) + { + label = paramdef.caption; + } + + td.innerHTML = label; + tr.appendChild(td); + td = document.createElement("td"); + td.appendChild(control); + tr.appendChild(td); + tablerows.push(tr); + } + var that = this; + tablerows.map(function(tr){ + that.parameterstable.appendChild(tr); + }); + this.paramControls = paramControls; + }, +}; diff --git a/processfile.html b/processfile.html new file mode 100644 index 0000000..3809a56 --- /dev/null +++ b/processfile.html @@ -0,0 +1,212 @@ + + + + + + + + + + + +OpenJsCad parser + +

OpenJsCad parser

+
+
+
+
Drop your .jscad file here
+
+ dfghdfgh +
+ + + +
+
+
+
+

Instructions:

+Create a new file in your favorite text editor. To get started enter the following text: +
+
function main() {
+  var cube = CSG.roundedCube({radius: 10, roundradius: 2, resolution: 16});
+  var sphere = CSG.sphere({radius: 10, resolution: 16}).translate([5, 5, 5]);
+  return cube.union(sphere);
+}
+
+Save this to a file on your desktop with .jscad extension. Then drag & drop the file from your desktop +to the box above (marked with 'drop your .jscad file here).

+The 3d model should now appear. You can continue to make changes to your .jscad file. Just press Reload +to parse the changes, you do not need to drag & drop the file again. +

+When finished press Generate STL to generate the STL file. Then click Save STL and save it to +a file with .stl extension. +

+For more information about OpenJsCad see the introduction. + +

Debugging

+By default your .jscad file is parsed in a separate thread (in a Web Worker). This allows long running +scripts to be executed while the web browser stays responsive. The web browser's debugger does not +have access to scripts running in web workers however. To allow debugging you can use the Debug button above to execute +your jscad code in the main thread instead of in a web worker. +

+To debug your code in Google Chrome: open the Developer Tools by typing Ctrl+Shift+I (or Command+Option+I on mac). +Then press the Debug button above. The debugger will stop just before executing your main() function. +

+For more information about debugging in Chrome see +Chrome Developer Tools: Overview +

+You can output log messages from your script using: +
+OpenJsCad.log("Hello");
+
+The log messages will appear in the browser's console (shown using Ctrl+Shift+I in Chrome). They will appear +even while not actually debugging. +

+ + + \ No newline at end of file diff --git a/servodemo.html b/servodemo.html new file mode 100644 index 0000000..876745e --- /dev/null +++ b/servodemo.html @@ -0,0 +1,227 @@ + + + + + + + + + + +OpenJsCad demo: servo motor + + +

OpenJsCad demo: servo motor

+
+

Source code

+Below is the OpenJsCad script for this demo. To build your own models, create a .jscad script +and use the OpenJsCad parser. For more information see the +OpenJsCad documentation. +

+
+ +

+ + \ No newline at end of file diff --git a/simple.html b/simple.html new file mode 100644 index 0000000..c09b2b1 --- /dev/null +++ b/simple.html @@ -0,0 +1,772 @@ + + + + + + + + + + + + + + OpenJsCad + + + +
+ + + + + +
+ +
+ +
+ +
+ +
+ + + +