Merge branch 'master' into production

This commit is contained in:
Nick Winter 2015-11-04 14:04:30 -08:00
commit 6cd846a39c
80 changed files with 489 additions and 3135 deletions

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/ext/beautify",["require","exports","module","ace/token_iterator","ace/ext/beautify/php_rules"],function(e,t,n){var r=e("ace/token_iterator").TokenIterator,i=e("./beautify/php_rules").transform;t.beautify=function(e){var t=new r(e,0,0),n=t.getCurrentToken(),s=e.$modeId.split("/").pop(),o=i(t,s);e.doc.setValue(o)},t.commands=[{name:"beautify",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]}),ace.define("ace/ext/beautify/php_rules",["require","exports","module","ace/token_iterator"],function(e,t,n){var r=e("ace/token_iterator").TokenIterator;t.newLines=[{type:"support.php_tag",value:"<?php"},{type:"support.php_tag",value:"<?"},{type:"support.php_tag",value:"?>"},{type:"paren.lparen",value:"{",indent:!0},{type:"paren.rparen",breakBefore:!0,value:"}",indent:!1},{type:"paren.rparen",breakBefore:!0,value:"})",indent:!1,dontBreak:!0},{type:"comment"},{type:"text",value:";"},{type:"text",value:":",context:"php"},{type:"keyword",value:"case",indent:!0,dontBreak:!0},{type:"keyword",value:"default",indent:!0,dontBreak:!0},{type:"keyword",value:"break",indent:!1,dontBreak:!0},{type:"punctuation.doctype.end",value:">"},{type:"meta.tag.punctuation.end",value:">"},{type:"meta.tag.punctuation.begin",value:"<",blockTag:!0,indent:!0,dontBreak:!0},{type:"meta.tag.punctuation.begin",value:"</",indent:!1,breakBefore:!0,dontBreak:!0},{type:"punctuation.operator",value:";"}],t.spaces=[{type:"xml-pe",prepend:!0},{type:"entity.other.attribute-name",prepend:!0},{type:"storage.type",value:"var",append:!0},{type:"storage.type",value:"function",append:!0},{type:"keyword.operator",value:"="},{type:"keyword",value:"as",prepend:!0,append:!0},{type:"keyword",value:"function",append:!0},{type:"support.function",next:/[^\(]/,append:!0},{type:"keyword",value:"or",append:!0,prepend:!0},{type:"keyword",value:"and",append:!0,prepend:!0},{type:"keyword",value:"case",append:!0},{type:"keyword.operator",value:"||",append:!0,prepend:!0},{type:"keyword.operator",value:"&&",append:!0,prepend:!0}],t.singleTags=["!doctype","area","base","br","hr","input","img","link","meta"],t.transform=function(e,n,r){var i=e.getCurrentToken(),s=t.newLines,o=t.spaces,u=t.singleTags,a="",f=0,l=!1,c,h,p={},d,v={},m=!1,g="";while(i!==null){console.log(i);if(!i){i=e.stepForward();continue}i.type=="support.php_tag"&&i.value!="?>"?r="php":i.type=="support.php_tag"&&i.value=="?>"?r="html":i.type=="meta.tag.name.style"&&r!="css"?r="css":i.type=="meta.tag.name.style"&&r=="css"?r="html":i.type=="meta.tag.name.script"&&r!="js"?r="js":i.type=="meta.tag.name.script"&&r=="js"&&(r="html"),v=e.stepForward(),v&&v.type.indexOf("meta.tag.name")==0&&(d=v.value),p.type=="support.php_tag"&&p.value=="<?="&&(l=!0),i.type=="meta.tag.name"&&(i.value=i.value.toLowerCase()),i.type=="text"&&(i.value=i.value.trim());if(!i.value){i=v;continue}g=i.value;for(var y in o)i.type==o[y].type&&(!o[y].value||i.value==o[y].value)&&v&&(!o[y].next||o[y].next.test(v.value))&&(o[y].prepend&&(g=" "+i.value),o[y].append&&(g+=" "));i.type.indexOf("meta.tag.name")==0&&(c=i.value),m=!1;for(y in s)if(i.type==s[y].type&&(!s[y].value||i.value==s[y].value)&&(!s[y].blockTag||u.indexOf(d)===-1)&&(!s[y].context||s[y].context===r)){s[y].indent===!1&&f--;if(s[y].breakBefore&&(!s[y].prev||s[y].prev.test(p.value))){a+="\n",m=!0;for(y=0;y<f;y++)a+=" "}break}if(l===!1)for(y in s)if(p.type==s[y].type&&(!s[y].value||p.value==s[y].value)&&(!s[y].blockTag||u.indexOf(c)===-1)&&(!s[y].context||s[y].context===r)){s[y].indent===!0&&f++;if(!s[y].dontBreak&&!m){a+="\n";for(y=0;y<f;y++)a+=" "}break}a+=g,p.type=="support.php_tag"&&p.value=="?>"&&(l=!1),h=c,p=i,i=v;if(i===null)break}return a}}),function(){ace.require(["ace/ext/beautify"],function(){})}()

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){var r=function(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){var t=e.data.range;r&&(n.indexOf(t.start.row)==-1&&n.push(t.start.row),t.end.row!=t.start.row&&n.push(t.end.row))}};(function(){this.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n<r;n++){var i=e[n];if(t.indexOf(i)>-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a<f;a++){var l=o[a];t.push(u),this.$adjustRow(u,l),u++}}this.$inChange=!1},this.$findCellWidthsForBlock=function(e){var t=[],n,r=e;while(r>=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r<s-1){r++,n=this.$cellWidthsForRow(r);if(n.length==0)break;t.push(n)}return{cellWidths:t,firstRow:i}},this.$cellWidthsForRow=function(e){var t=this.$selectionColumnsForRow(e),n=[-1].concat(this.$tabsForRow(e)),r=n.map(function(e){return 0}).slice(1),i=this.$editor.session.getLine(e);for(var s=0,o=n.length-1;s<o;s++){var u=n[s]+1,a=n[s+1],f=this.$rightmostSelectionInCell(t,a),l=i.substring(u,a);r[s]=Math.max(l.replace(/\s+$/g,"").length,f-u)}return r},this.$selectionColumnsForRow=function(e){var t=[],n=this.$editor.getCursorPosition();return this.$editor.session.getSelection().isEmpty()&&e==n.row&&t.push(n.column),t},this.$setBlockCellWidthsToMax=function(e){var t=!0,n,r,i,s=this.$izip_longest(e);for(var o=0,u=s.length;o<u;o++){var a=s[o];if(!a.push){console.error(a);continue}a.push(NaN);for(var f=0,l=a.length;f<l;f++){var c=a[f];t&&(n=f,i=0,t=!1);if(isNaN(c)){r=f;for(var h=n;h<r;h++)e[h][o]=i;t=!0}i=Math.max(i,c)}}return e},this.$rightmostSelectionInCell=function(e,t){var n=0;if(e.length){var r=[];for(var i=0,s=e.length;i<s;i++)e[i]<=t?r.push(i):r.push(0);n=Math.max.apply(Math,r)}return n},this.$tabsForRow=function(e){var t=[],n=this.$editor.session.getLine(e),r=/\t/g,i;while((i=r.exec(n))!=null)t.push(i.index);return t},this.$adjustRow=function(e,t){var n=this.$tabsForRow(e);if(n.length==0)return;var r=0,i=-1,s=this.$izip(t,n);for(var o=0,u=s.length;o<u;o++){var a=s[o][0],f=s[o][1];i+=1+a,f+=r;var l=i-f;if(l==0)continue;var c=this.$editor.session.getLine(e).substr(0,f),h=c.replace(/\s*$/g,""),p=c.length-h.length;l>0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+" "),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},this.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;r<n;r++){var i=e[r].length;i>t&&(t=i)}var s=[];for(var o=0;o<t;o++){var u=[];for(var r=0;r<n;r++)e[r][o]===""?u.push(NaN):u.push(e[r][o]);s.push(u)}return s},this.$izip=function(e,t){var n=e.length>=t.length?t.length:e.length,r=[];for(var i=0;i<n;i++){var s=[e[i],t[i]];r.push(s)}return r}}).call(r.prototype),t.ElasticTabstopsLite=r;var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{useElasticTabstops:{set:function(e){e?(this.elasticTabstops||(this.elasticTabstops=new r(this)),this.commands.on("afterExec",this.elasticTabstops.onAfterExec),this.commands.on("exec",this.elasticTabstops.onExec),this.on("change",this.elasticTabstops.onChange)):this.elasticTabstops&&(this.commands.removeListener("afterExec",this.elasticTabstops.onAfterExec),this.commands.removeListener("exec",this.elasticTabstops.onExec),this.removeListener("change",this.elasticTabstops.onChange))}}})}),function(){ace.require(["ace/ext/elastic_tabstops_lite"],function(){})}()

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
(function(){ace.require(["ace/ext/error_marker"],function(){})})()

View file

@ -1 +0,0 @@
ace.define("ace/ext/keybinding_menu",["require","exports","module","ace/editor","ace/ext/menu_tools/overlay_page","ace/ext/menu_tools/get_editor_keyboard_shortcuts"],function(e,t,n){function i(t){if(!document.getElementById("kbshortcutmenu")){var n=e("./menu_tools/overlay_page").overlayPage,r=e("./menu_tools/get_editor_keyboard_shortcuts").getEditorKeybordShortcuts,i=r(t),s=document.createElement("div"),o=i.reduce(function(e,t){return e+'<div class="ace_optionsMenuEntry"><span class="ace_optionsMenuCommand">'+t.command+"</span> : "+'<span class="ace_optionsMenuKey">'+t.key+"</span></div>"},"");s.id="kbshortcutmenu",s.innerHTML="<h1>Keyboard Shortcuts</h1>"+o+"</div>",n(t,s,"0","0","0",null)}}var r=e("ace/editor").Editor;n.exports.init=function(e){r.prototype.showKeyboardShortcuts=function(){i(this)},e.commands.addCommands([{name:"showKeyboardShortcuts",bindKey:{win:"Ctrl-Alt-h",mac:"Command-Alt-h"},exec:function(e,t){e.showKeyboardShortcuts()}}])}}),ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/lib/dom"],function(e,t,n){var r=e("../../lib/dom"),i="#ace_settingsmenu, #kbshortcutmenu {background-color: #F7F7F7;color: black;box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);padding: 1em 0.5em 2em 1em;overflow: auto;position: absolute;margin: 0;bottom: 0;right: 0;top: 0;z-index: 9991;cursor: default;}.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);background-color: rgba(255, 255, 255, 0.6);color: black;}.ace_optionsMenuEntry:hover {background-color: rgba(100, 100, 100, 0.1);-webkit-transition: all 0.5s;transition: all 0.3s}.ace_closeButton {background: rgba(245, 146, 146, 0.5);border: 1px solid #F48A8A;border-radius: 50%;padding: 7px;position: absolute;right: -8px;top: -8px;z-index: 1000;}.ace_closeButton{background: rgba(245, 146, 146, 0.9);}.ace_optionsMenuKey {color: darkslateblue;font-weight: bold;}.ace_optionsMenuCommand {color: darkcyan;font-weight: normal;}";r.importCssString(i),n.exports.overlayPage=function(t,n,i,s,o,u){function l(e){e.keyCode===27&&a.click()}i=i?"top: "+i+";":"",o=o?"bottom: "+o+";":"",s=s?"right: "+s+";":"",u=u?"left: "+u+";":"";var a=document.createElement("div"),f=document.createElement("div");a.style.cssText="margin: 0; padding: 0; position: fixed; top:0; bottom:0; left:0; right:0;z-index: 9990; background-color: rgba(0, 0, 0, 0.3);",a.addEventListener("click",function(){document.removeEventListener("keydown",l),a.parentNode.removeChild(a),t.focus(),a=null}),document.addEventListener("keydown",l),f.style.cssText=i+s+o+u,f.addEventListener("click",function(e){e.stopPropagation()});var c=r.createElement("div");c.style.position="relative";var h=r.createElement("div");h.className="ace_closeButton",h.addEventListener("click",function(){a.click()}),c.appendChild(h),f.appendChild(c),f.appendChild(n),a.appendChild(f),document.body.appendChild(a),t.blur()}}),ace.define("ace/ext/menu_tools/get_editor_keyboard_shortcuts",["require","exports","module","ace/lib/keys"],function(e,t,n){var r=e("../../lib/keys");n.exports.getEditorKeybordShortcuts=function(e){var t=r.KEY_MODS,n=[],i={};return e.keyBinding.$handlers.forEach(function(e){var r=e.commandKeyBinding;for(var s in r){var o=parseInt(s);o==-1?o="":isNaN(o)?o=s:o=""+(o&t.command?"Cmd-":"")+(o&t.ctrl?"Ctrl-":"")+(o&t.alt?"Alt-":"")+(o&t.shift?"Shift-":"");for(var u in r[s]){var a=r[s][u];typeof a!="string"&&(a=a.name),i[a]?i[a].key+="|"+o+u:(i[a]={key:o+u,command:a},n.push(i[a]))}}}),n}}),function(){ace.require(["ace/ext/keybinding_menu"],function(){})}()

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function i(e){var t=e.editor,n=e.getAccelKey();if(n){var t=e.editor,r=e.getDocumentPosition(),i=t.session,s=i.getTokenAt(r.row,r.column);t._emit("linkHover",{position:r,token:s})}}function s(e){var t=e.getAccelKey(),n=e.getButton();if(n==0&&t){var r=e.editor,i=e.getDocumentPosition(),s=r.session,o=s.getTokenAt(i.row,i.column);r._emit("linkClick",{position:i,token:o})}}var r=e("ace/editor").Editor;e("../config").defineOptions(r.prototype,"editor",{enableLinking:{set:function(e){e?(this.on("click",s),this.on("mousemove",i)):(this.off("click",s),this.off("mousemove",i))},value:!1}})}),function(){ace.require(["ace/ext/linking"],function(){})}()

View file

@ -1 +0,0 @@
ace.define("ace/ext/modelist",["require","exports","module"],function(e,t,n){function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i<r.length;i++)if(r[i].supportsFile(n)){t=r[i];break}return t}var r=[],s=function(e,t,n){this.name=e,this.caption=t,this.mode="ace/mode/"+e,this.extensions=n;if(/\^/.test(n))var r=n.replace(/\|(\^)?/g,function(e,t){return"$|"+(t?"^":"^.*\\.")})+"$";else var r="^.*\\.("+n+")$";this.extRe=new RegExp(r,"gi")};s.prototype.supportsFile=function(e){return e.match(this.extRe)};var o={ABAP:["abap"],ActionScript:["as"],ADA:["ada|adb"],Apache_Conf:["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],AsciiDoc:["asciidoc"],Assembly_x86:["asm"],AutoHotKey:["ahk"],BatchFile:["bat|cmd"],C9Search:["c9search_results"],C_Cpp:["cpp|c|cc|cxx|h|hh|hpp"],Cirru:["cirru|cr"],Clojure:["clj"],Cobol:["CBL|COB"],coffee:["coffee|cf|cson|^Cakefile"],ColdFusion:["cfm"],CSharp:["cs"],CSS:["css"],Curly:["curly"],D:["d|di"],Dart:["dart"],Diff:["diff|patch"],Dockerfile:["^Dockerfile"],Dot:["dot"],Erlang:["erl|hrl"],EJS:["ejs"],Forth:["frt|fs|ldr"],FTL:["ftl"],Gherkin:["feature"],Glsl:["glsl|frag|vert"],golang:["go"],Groovy:["groovy"],HAML:["haml"],Handlebars:["hbs|handlebars|tpl|mustache"],Haskell:["hs"],haXe:["hx"],HTML:["html|htm|xhtml"],HTML_Ruby:["erb|rhtml|html.erb"],INI:["ini|conf|cfg|prefs"],Jack:["jack"],Jade:["jade"],Java:["java"],JavaScript:["js|jsm"],JSON:["json"],JSONiq:["jq"],JSP:["jsp"],JSX:["jsx"],Julia:["jl"],LaTeX:["tex|latex|ltx|bib"],LESS:["less"],Liquid:["liquid"],Lisp:["lisp"],LiveScript:["ls"],LogiQL:["logic|lql"],LSL:["lsl"],Lua:["lua"],LuaPage:["lp"],Lucene:["lucene"],Makefile:["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],MATLAB:["matlab"],Markdown:["md|markdown"],MEL:["mel"],MySQL:["mysql"],MUSHCode:["mc|mush"],Nix:["nix"],ObjectiveC:["m|mm"],OCaml:["ml|mli"],Pascal:["pas|p"],Perl:["pl|pm"],pgSQL:["pgsql"],PHP:["php|phtml"],Powershell:["ps1"],Prolog:["plg|prolog"],Properties:["properties"],Protobuf:["proto"],Python:["py"],R:["r"],RDoc:["Rd"],RHTML:["Rhtml"],Ruby:["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],Rust:["rs"],SASS:["sass"],SCAD:["scad"],Scala:["scala"],Smarty:["smarty|tpl"],Scheme:["scm|rkt"],SCSS:["scss"],SH:["sh|bash|^.bashrc"],SJS:["sjs"],Space:["space"],snippets:["snippets"],Soy_Template:["soy"],SQL:["sql"],Stylus:["styl|stylus"],SVG:["svg"],Tcl:["tcl"],Tex:["tex"],Text:["txt"],Textile:["textile"],Toml:["toml"],Twig:["twig"],Typescript:["ts|typescript|str"],Vala:["vala"],VBScript:["vbs"],Velocity:["vm"],Verilog:["v|vh|sv|svh"],XML:["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl"],XQuery:["xq"],YAML:["yaml|yml"]},u={ObjectiveC:"Objective-C",CSharp:"C#",golang:"Go",C_Cpp:"C/C++",coffee:"CoffeeScript",HTML_Ruby:"HTML (Ruby)",FTL:"FreeMarker"},a={};for(var f in o){var l=o[f],c=(u[f]||f).replace(/_/g," "),h=f.toLowerCase(),p=new s(h,c,l[0]);a[h]=p,r.push(p)}n.exports={getModeForPath:i,modes:r,modesByName:a}}),function(){ace.require(["ace/ext/modelist"],function(){})}()

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/ext/prompt",["require","exports","module","ace/lib/lang","ace/lib/dom","ace/lib/event","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/editor","ace/multi_select"],function(e,t,n){function c(e,t){var n=this.pixelToScreenCoordinates(e,t);return this.session.screenToDocumentPosition(Math.min(this.session.getScreenLength()-1,Math.max(n.row,0)),Math.max(n.column,0))}var r=e("../lib/lang"),i=e("ace/lib/dom"),s=e("ace/lib/event"),o=e("ace/edit_session").EditSession,u=e("ace/undomanager").UndoManager,a=e("ace/virtual_renderer").VirtualRenderer,f=e("ace/editor").Editor,l=e("ace/multi_select").MultiSelect;t.singleLineEditor=function(e){var t=new a;t.container.style.overflow="hidden",t.screenToTextCoordinates=c,t.setStyle("ace_one-line");var n=new f(t);return n.session.setUndoManager(new u),n.setOptions({showPrintMargin:!1,showGutter:!1,highlightGutterLine:!1,focusWaitTimout:0,maxLines:4}),n}}),function(){ace.require(["ace/ext/prompt"],function(){})}()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"],function(e,t,n){var r=e("../lib/event");t.contextMenuHandler=function(e){var t=e.target,n=t.textInput.getElement();if(!t.selection.isEmpty())return;var i=t.getCursorPosition(),s=t.session.getWordRange(i.row,i.column),o=t.session.getTextRange(s);t.session.tokenRe.lastIndex=0;if(!t.session.tokenRe.test(o))return;var u="\x01\x01",a=o+" "+u;n.value=a,n.setSelectionRange(o.length,o.length+1),n.setSelectionRange(0,0),n.setSelectionRange(0,o.length);var f=!1;r.addListener(n,"keydown",function l(){r.removeListener(n,"keydown",l),f=!0}),t.textInput.setInputHandler(function(e){console.log(e,a,n.selectionStart,n.selectionEnd);if(e==a)return"";if(e.lastIndexOf(a,0)===0)return e.slice(a.length);if(e.substr(n.selectionEnd)==a)return e.slice(0,-a.length);if(e.slice(-2)==u){var r=e.slice(0,-2);if(r.slice(-1)==" ")return f?r.substring(0,n.selectionEnd):(r=r.slice(0,-1),t.session.replace(s,r),"")}return e})};var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{spellcheck:{set:function(e){var n=this.textInput.getElement();n.spellcheck=!!e,e?this.on("nativecontextmenu",t.contextMenuHandler):this.removeListener("nativecontextmenu",t.contextMenuHandler)},value:!0}})}),function(){ace.require(["ace/ext/spellcheck"],function(){})}()

View file

@ -1 +0,0 @@
ace.define("ace/ext/split",["require","exports","module","ace/split"],function(e,t,n){n.exports=e("../split")}),ace.define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"],function(e,t,n){function l(e,t){this.$u=e,this.$doc=t}var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./editor").Editor,u=e("./virtual_renderer").VirtualRenderer,a=e("./edit_session").EditSession,f=function(e,t,n){this.BELOW=1,this.BESIDE=0,this.$container=e,this.$theme=t,this.$splits=0,this.$editorCSS="",this.$editors=[],this.$orientation=this.BESIDE,this.setSplits(n||1),this.$cEditor=this.$editors[0],this.on("focus",function(e){this.$cEditor=e}.bind(this))};(function(){r.implement(this,s),this.$createEditor=function(){var e=document.createElement("div");e.className=this.$editorCSS,e.style.cssText="position: absolute; top:0px; bottom:0px",this.$container.appendChild(e);var t=new o(new u(e,this.$theme));return t.on("focus",function(){this._emit("focus",t)}.bind(this)),this.$editors.push(t),t.setFontSize(this.$fontSize),t},this.setSplits=function(e){var t;if(e<1)throw"The number of splits have to be > 0!";if(e==this.$splits)return;if(e>this.$splits){while(this.$splits<this.$editors.length&&this.$splits<e)t=this.$editors[this.$splits],this.$container.appendChild(t.container),t.setFontSize(this.$fontSize),this.$splits++;while(this.$splits<e)this.$createEditor(),this.$splits++}else while(this.$splits>e)t=this.$editors[this.$splits-1],this.$container.removeChild(t.container),this.$splits--;this.resize()},this.getSplits=function(){return this.$splits},this.getEditor=function(e){return this.$editors[e]},this.getCurrentEditor=function(){return this.$cEditor},this.focus=function(){this.$cEditor.focus()},this.blur=function(){this.$cEditor.blur()},this.setTheme=function(e){this.$editors.forEach(function(t){t.setTheme(e)})},this.setKeyboardHandler=function(e){this.$editors.forEach(function(t){t.setKeyboardHandler(e)})},this.forEach=function(e,t){this.$editors.forEach(e,t)},this.$fontSize="",this.setFontSize=function(e){this.$fontSize=e,this.forEach(function(t){t.setFontSize(e)})},this.$cloneSession=function(e){var t=new a(e.getDocument(),e.getMode()),n=e.getUndoManager();if(n){var r=new l(n,t);t.setUndoManager(r)}return t.$informUndoManager=i.delayedCall(function(){t.$deltas=[]}),t.setTabSize(e.getTabSize()),t.setUseSoftTabs(e.getUseSoftTabs()),t.setOverwrite(e.getOverwrite()),t.setBreakpoints(e.getBreakpoints()),t.setUseWrapMode(e.getUseWrapMode()),t.setUseWorker(e.getUseWorker()),t.setWrapLimitRange(e.$wrapLimitRange.min,e.$wrapLimitRange.max),t.$foldData=e.$cloneFoldData(),t},this.setSession=function(e,t){var n;t==null?n=this.$cEditor:n=this.$editors[t];var r=this.$editors.some(function(t){return t.session===e});return r&&(e=this.$cloneSession(e)),n.setSession(e),e},this.getOrientation=function(){return this.$orientation},this.setOrientation=function(e){if(this.$orientation==e)return;this.$orientation=e,this.resize()},this.resize=function(){var e=this.$container.clientWidth,t=this.$container.clientHeight,n;if(this.$orientation==this.BESIDE){var r=e/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=r+"px",n.container.style.top="0px",n.container.style.left=i*r+"px",n.container.style.height=t+"px",n.resize()}else{var s=t/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=e+"px",n.container.style.top=i*s+"px",n.container.style.left="0px",n.container.style.height=s+"px",n.resize()}}}).call(f.prototype),function(){this.execute=function(e){this.$u.execute(e)},this.undo=function(){var e=this.$u.undo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.redo=function(){var e=this.$u.redo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.reset=function(){this.$u.reset()},this.hasUndo=function(){return this.$u.hasUndo()},this.hasRedo=function(){return this.$u.hasRedo()}}.call(l.prototype),t.Split=f}),function(){ace.require(["ace/ext/split"],function(){})}()

View file

@ -1 +0,0 @@
ace.define("ace/ext/static_highlight",["require","exports","module","ace/edit_session","ace/layer/text","ace/config","ace/lib/dom"],function(e,t,n){var r=e("../edit_session").EditSession,i=e("../layer/text").Text,s=".ace_static_highlight {font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;font-size: 12px;}.ace_static_highlight .ace_gutter {width: 25px !important;display: block;float: left;text-align: right;padding: 0 3px 0 0;margin-right: 3px;position: static !important;}.ace_static_highlight .ace_line { clear: both; }.ace_static_highlight .ace_gutter-cell {-moz-user-select: -moz-none;-khtml-user-select: none;-webkit-user-select: none;user-select: none;}.ace_static_highlight .ace_gutter-cell:before {content: counter(ace_line, decimal);counter-increment: ace_line;}.ace_static_highlight {counter-reset: ace_line;}",o=e("../config"),u=e("../lib/dom"),a=function(e,t,n){var r=e.className.match(/lang-(\w+)/),i=t.mode||r&&"ace/mode/"+r[1];if(!i)return!1;var s=t.theme||"ace/theme/textmate",o="",f=[];if(e.firstElementChild){var l=0;for(var c=0;c<e.childNodes.length;c++){var h=e.childNodes[c];h.nodeType==3?(l+=h.data.length,o+=h.data):f.push(l,h)}}else o=u.getInnerText(e),t.trim&&(o=o.trim());a.render(o,i,s,t.firstLineNumber,!t.showGutter,function(t){u.importCssString(t.css,"ace_highlight"),e.innerHTML=t.html;var r=e.firstChild.firstChild;for(var i=0;i<f.length;i+=2){var s=t.session.doc.indexToPosition(f[i]),o=f[i+1],a=r.children[s.row];a&&a.appendChild(o)}n&&n()})};a.render=function(e,t,n,i,s,u){function c(){var r=a.renderSync(e,t,n,i,s);return u?u(r):r}var f=1,l=r.prototype.$modes;return typeof n=="string"&&(f++,o.loadModule(["theme",n],function(e){n=e,--f||c()})),typeof t=="string"&&(f++,o.loadModule(["mode",t],function(e){l[t]||(l[t]=new e.Mode),t=l[t],--f||c()})),--f||c()},a.renderSync=function(e,t,n,o,u){o=parseInt(o||1,10);var a=new r("");a.setUseWorker(!1),a.setMode(t);var f=new i(document.createElement("div"));f.setSession(a),f.config={characterWidth:10,lineHeight:20},a.setValue(e);var l=[],c=a.getLength();for(var h=0;h<c;h++)l.push("<div class='ace_line'>"),u||l.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'></span>"),f.$renderLine(l,h,!0,!1),l.push("\n</div>");var p="<div class='"+n.cssClass+"'>"+"<div class='ace_static_highlight' style='counter-reset:ace_line "+(o-1)+"'>"+l.join("")+"</div>"+"</div>";return f.destroy(),{css:s+n.cssText,html:p,session:a}},n.exports=a,n.exports.highlight=a}),function(){ace.require(["ace/ext/static_highlight"],function(){})}()

View file

@ -1 +0,0 @@
ace.define("ace/ext/statusbar",["require","exports","module","ace/lib/dom","ace/lib/lang"],function(e,t,n){var r=e("ace/lib/dom"),i=e("ace/lib/lang"),s=function(e,t){this.element=r.createElement("div"),this.element.className="ace_status-indicator",this.element.style.cssText="display: inline-block;",t.appendChild(this.element);var n=i.delayedCall(function(){this.updateStatus(e)}.bind(this));e.on("changeStatus",function(){n.schedule(100)}),e.on("changeSelection",function(){n.schedule(100)})};(function(){this.updateStatus=function(e){function n(e,n){e&&t.push(e,n||"|")}var t=[];e.$vimModeHandler?n(e.$vimModeHandler.getStatusText()):e.commands.recording&&n("REC");var r=e.selection.lead;n(r.row+":"+r.column," ");if(!e.selection.isEmpty()){var i=e.getSelectionRange();n("("+(i.end.row-i.start.row)+":"+(i.end.column-i.start.column)+")")}t.pop(),this.element.textContent=t.join("")}}).call(s.prototype),t.StatusBar=s}),function(){ace.require(["ace/ext/statusbar"],function(){})}()

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/ext/themelist",["require","exports","module","ace/lib/fixoldbrowsers"],function(e,t,n){e("ace/lib/fixoldbrowsers");var r=[["Chrome"],["Clouds"],["Crimson Editor"],["Dawn"],["Dreamweaver"],["Eclipse"],["GitHub"],["Solarized Light"],["TextMate"],["Tomorrow"],["XCode"],["Kuroir"],["KatzenMilch"],["Ambiance","ambiance","dark"],["Chaos","chaos","dark"],["Clouds Midnight","clouds_midnight","dark"],["Cobalt","cobalt","dark"],["idle Fingers","idle_fingers","dark"],["krTheme","kr_theme","dark"],["Merbivore","merbivore","dark"],["Merbivore Soft","merbivore_soft","dark"],["Mono Industrial","mono_industrial","dark"],["Monokai","monokai","dark"],["Pastel on dark","pastel_on_dark","dark"],["Solarized Dark","solarized_dark","dark"],["Terminal","terminal","dark"],["Tomorrow Night","tomorrow_night","dark"],["Tomorrow Night Blue","tomorrow_night_blue","dark"],["Tomorrow Night Bright","tomorrow_night_bright","dark"],["Tomorrow Night 80s","tomorrow_night_eighties","dark"],["Twilight","twilight","dark"],["Vibrant Ink","vibrant_ink","dark"]];t.themesByName={},t.themes=r.map(function(e){var n=e[1]||e[0].replace(/ /g,"_").toLowerCase(),r={caption:e[0],theme:"ace/theme/"+n,isDark:e[2]=="dark",name:n};return t.themesByName[n]=r,r})}),function(){ace.require(["ace/ext/themelist"],function(){})}()

View file

@ -1 +0,0 @@
ace.define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"],function(e,t,n){var r=e("../lib/lang");t.$detectIndentation=function(e,t){function h(e){var t=0;for(var r=e;r<n.length;r+=e)t+=n[r]||0;return t}var n=[],r=[],i=0,s=0,o=Math.min(e.length,1e3);for(var u=0;u<o;u++){var a=e[u];if(!/^\s*[^*+\-\s]/.test(a))continue;var f=a.match(/^\t*/)[0].length;a[0]==" "&&i++;var l=a.match(/^ */)[0].length;if(l&&a[l]!=" "){var c=l-s;c>0&&!(s%c)&&!(l%c)&&(r[c]=(r[c]||0)+1),n[l]=(n[l]||0)+1}s=l;while(u<o&&a[a.length-1]=="\\")a=e[u++]}if(!n.length)return;var p=r.reduce(function(e,t){return e+t},0),d={score:0,length:0},v=0;for(var u=1;u<12;u++){if(u==1){v=h(u);var m=1}else var m=h(u)/v;r[u]&&(m+=r[u]/p),m>d.score&&(d={score:m,length:u})}if(d.score&&d.score>1.4)var g=d.length;if(i>v+1)return{ch:" ",length:g};if(v+1>i)return{ch:" ",length:g}},t.detectIndentation=function(e){var n=e.getLines(0,1e3),r=t.$detectIndentation(n)||{};return r.ch&&e.setUseSoftTabs(r.ch==" "),r.length&&e.setTabSize(r.length),r},t.trimTrailingSpace=function(e,t){var n=e.getDocument(),r=n.getAllLines(),i=t?-1:0;for(var s=0,o=r.length;s<o;s++){var u=r[s],a=u.search(/\s+$/);a>i&&n.removeInLine(s,a,u.length)}},t.convertIndentation=function(e,t,n){var i=e.getTabString()[0],s=e.getTabSize();n||(n=s),t||(t=i);var o=t==" "?t:r.stringRepeat(t,n),u=e.doc,a=u.getAllLines(),f={},l={};for(var c=0,h=a.length;c<h;c++){var p=a[c],d=p.match(/^\s*/)[0];if(d){var v=e.$getStringScreenWidth(d)[0],m=Math.floor(v/s),g=v%s,y=f[m]||(f[m]=r.stringRepeat(o,m));y+=l[g]||(l[g]=r.stringRepeat(" ",g)),y!=d&&(u.removeInLine(c,0,d.length),u.insertInLine({row:c,column:0},y))}}e.setTabSize(n),e.setUseSoftTabs(t==" ")},t.$parseStringArg=function(e){var t={};/t/.test(e)?t.ch=" ":/s/.test(e)&&(t.ch=" ");var n=e.match(/\d+/);return n&&(t.length=parseInt(n[0],10)),t},t.$parseArg=function(e){return e?typeof e=="string"?t.$parseStringArg(e):typeof e.text=="string"?t.$parseStringArg(e.text):e:{}},t.commands=[{name:"detectIndentation",exec:function(e){t.detectIndentation(e.session)}},{name:"trimTrailingSpace",exec:function(e){t.trimTrailingSpace(e.session)}},{name:"convertIndentation",exec:function(e,n){var r=t.$parseArg(n);t.convertIndentation(e.session,r.ch,r.length)}},{name:"setIndentation",exec:function(e,n){var r=t.$parseArg(n);r.length&&e.session.setTabSize(r.length),r.ch&&e.session.setUseSoftTabs(r.ch==" ")}}]}),function(){ace.require(["ace/ext/whitespace"],function(){})}()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
ace.define("ace/mode/plain_text",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/text_highlight_rules","ace/mode/behaviour"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("./text_highlight_rules").TextHighlightRules,o=e("./behaviour").Behaviour,u=function(){this.HighlightRules=s,this.$behaviour=new o};r.inherits(u,i),function(){this.type="text",this.getNextLineIndent=function(e,t,n){return""},this.$id="ace/mode/plain_text"}.call(u.prototype),t.Mode=u})

View file

@ -1 +0,0 @@
ace.define("ace/mode/python",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/python_highlight_rules","ace/mode/folding/pythonic","ace/range"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("./python_highlight_rules").PythonHighlightRules,o=e("./folding/pythonic").FoldMode,u=e("../range").Range,a=function(){this.HighlightRules=s,this.foldingRules=new o("\\:")};r.inherits(a,i),function(){this.lineCommentStart="#",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*[\{\(\[\:]\s*$/);o&&(r+=n)}return r};var e={pass:1,"return":1,raise:1,"break":1,"continue":1};this.checkOutdent=function(t,n,r){if(r!=="\r\n"&&r!=="\r"&&r!=="\n")return!1;var i=this.getTokenizer().getLineTokens(n.trim(),t).tokens;if(!i)return!1;do var s=i.pop();while(s&&(s.type=="comment"||s.type=="text"&&s.value.match(/^\s+$/)));return s?s.type=="keyword"&&e[s.value]:!1},this.autoOutdent=function(e,t,n){n+=1;var r=this.$getIndent(t.getLine(n)),i=t.getTabString();r.slice(-i.length)==i&&t.remove(new u(n,r.length-i.length,n,r.length))},this.$id="ace/mode/python"}.call(a.prototype),t.Mode=a}),ace.define("ace/mode/python_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="and|as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|loop|not|or|pass|print|raise|return|try|while|with|yield",t="True|False|None|NotImplemented|Ellipsis|__debug__",n="abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|float|list|raw_input|unichr|callable|format|locals|reduce|unicode|chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|__import__|complex|hash|min|set|apply|delattr|help|next|setattr|buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern",r=this.createKeywordMapper({"invalid.deprecated":"debugger","support.function":n,"constant.language":t,keyword:e},"identifier"),i="(?:r|u|ur|R|U|UR|Ur|uR)?",s="(?:(?:[1-9]\\d*)|(?:0))",o="(?:0[oO]?[0-7]+)",u="(?:0[xX][\\dA-Fa-f]+)",a="(?:0[bB][01]+)",f="(?:"+s+"|"+o+"|"+u+"|"+a+")",l="(?:[eE][+-]?\\d+)",c="(?:\\.\\d+)",h="(?:\\d+)",p="(?:(?:"+h+"?"+c+")|(?:"+h+"\\.))",d="(?:(?:"+p+"|"+h+")"+l+")",v="(?:"+d+"|"+p+")",m="\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})";this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"string",regex:i+'"{3}',next:"qqstring3"},{token:"string",regex:i+'"(?=.)',next:"qqstring"},{token:"string",regex:i+"'{3}",next:"qstring3"},{token:"string",regex:i+"'(?=.)",next:"qstring"},{token:"constant.numeric",regex:"(?:"+v+"|\\d+)[jJ]\\b"},{token:"constant.numeric",regex:v},{token:"constant.numeric",regex:f+"[lL]\\b"},{token:"constant.numeric",regex:f+"\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\[\\(\\{]"},{token:"paren.rparen",regex:"[\\]\\)\\}]"},{token:"text",regex:"\\s+"}],qqstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:'"{3}',next:"start"},{defaultToken:"string"}],qstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:"'{3}",next:"start"},{defaultToken:"string"}],qqstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qqstring"},{token:"string",regex:'"|$',next:"start"},{defaultToken:"string"}],qstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qstring"},{token:"string",regex:"'|$",next:"start"},{defaultToken:"string"}]}};r.inherits(s,i),t.PythonHighlightRules=s}),ace.define("ace/mode/folding/pythonic",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode"],function(e,t,n){var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=t.FoldMode=function(e){this.foldingStartMarker=new RegExp("([\\[{])(?:\\s*)$|("+e+")(?:\\s*)(?:#.*)?$")};r.inherits(s,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i)return i[1]?this.openingBracketBlock(e,i[1],n,i.index):i[2]?this.indentationBlock(e,n,i.index+i[2].length):this.indentationBlock(e,n)}}.call(s.prototype)})

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/snippets/clojure",["require","exports","module"],function(e,t,n){t.snippetText='snippet comm\n (comment\n ${1}\n )\nsnippet condp\n (condp ${1:pred} ${2:expr}\n ${3})\nsnippet def\n (def ${1})\nsnippet defm\n (defmethod ${1:multifn} "${2:doc-string}" ${3:dispatch-val} [${4:args}]\n ${5})\nsnippet defmm\n (defmulti ${1:name} "${2:doc-string}" ${3:dispatch-fn})\nsnippet defma\n (defmacro ${1:name} "${2:doc-string}" ${3:dispatch-fn})\nsnippet defn\n (defn ${1:name} "${2:doc-string}" [${3:arg-list}]\n ${4})\nsnippet defp\n (defprotocol ${1:name}\n ${2})\nsnippet defr\n (defrecord ${1:name} [${2:fields}]\n ${3:protocol}\n ${4})\nsnippet deft\n (deftest ${1:name}\n (is (= ${2:assertion})))\n ${3})\nsnippet is\n (is (= ${1} ${2}))\nsnippet defty\n (deftype ${1:Name} [${2:fields}]\n ${3:Protocol}\n ${4})\nsnippet doseq\n (doseq [${1:elem} ${2:coll}]\n ${3})\nsnippet fn\n (fn [${1:arg-list}] ${2})\nsnippet if\n (if ${1:test-expr}\n ${2:then-expr}\n ${3:else-expr})\nsnippet if-let \n (if-let [${1:result} ${2:test-expr}]\n (${3:then-expr} $1)\n (${4:else-expr}))\nsnippet imp\n (:import [${1:package}])\n & {:keys [${1:keys}] :or {${2:defaults}}}\nsnippet let\n (let [${1:name} ${2:expr}]\n ${3})\nsnippet letfn\n (letfn [(${1:name) [${2:args}]\n ${3})])\nsnippet map\n (map ${1:func} ${2:coll})\nsnippet mapl\n (map #(${1:lambda}) ${2:coll})\nsnippet met\n (${1:name} [${2:this} ${3:args}]\n ${4})\nsnippet ns\n (ns ${1:name}\n ${2})\nsnippet dotimes\n (dotimes [_ 10]\n (time\n (dotimes [_ ${1:times}]\n ${2})))\nsnippet pmethod\n (${1:name} [${2:this} ${3:args}])\nsnippet refer\n (:refer-clojure :exclude [${1}])\nsnippet require\n (:require [${1:namespace} :as [${2}]])\nsnippet use\n (:use [${1:namespace} :only [${2}]])\nsnippet print\n (println ${1})\nsnippet reduce\n (reduce ${1:(fn [p n] ${3})} ${2})\nsnippet when\n (when ${1:test} ${2:body})\nsnippet when-let\n (when-let [${1:result} ${2:test}]\n ${3:body})\n',t.scope="clojure"})

View file

@ -1 +0,0 @@
ace.define("ace/snippets/coffee",["require","exports","module"],function(e,t,n){t.snippetText="# Closure loop\nsnippet forindo\n for ${1:name} in ${2:array}\n do ($1) ->\n ${3:// body}\n# Array comprehension\nsnippet fora\n for ${1:name} in ${2:array}\n ${3:// body...}\n# Object comprehension\nsnippet foro\n for ${1:key}, ${2:value} of ${3:object}\n ${4:// body...}\n# Range comprehension (inclusive)\nsnippet forr\n for ${1:name} in [${2:start}..${3:finish}]\n ${4:// body...}\nsnippet forrb\n for ${1:name} in [${2:start}..${3:finish}] by ${4:step}\n ${5:// body...}\n# Range comprehension (exclusive)\nsnippet forrex\n for ${1:name} in [${2:start}...${3:finish}]\n ${4:// body...}\nsnippet forrexb\n for ${1:name} in [${2:start}...${3:finish}] by ${4:step}\n ${5:// body...}\n# Function\nsnippet fun\n (${1:args}) ->\n ${2:// body...}\n# Function (bound)\nsnippet bfun\n (${1:args}) =>\n ${2:// body...}\n# Class\nsnippet cla class ..\n class ${1:`substitute(Filename(), '\\(_\\|^\\)\\(.\\)', '\\u\\2', 'g')`}\n ${2}\nsnippet cla class .. constructor: ..\n class ${1:`substitute(Filename(), '\\(_\\|^\\)\\(.\\)', '\\u\\2', 'g')`}\n constructor: (${2:args}) ->\n ${3}\n\n ${4}\nsnippet cla class .. extends ..\n class ${1:`substitute(Filename(), '\\(_\\|^\\)\\(.\\)', '\\u\\2', 'g')`} extends ${2:ParentClass}\n ${3}\nsnippet cla class .. extends .. constructor: ..\n class ${1:`substitute(Filename(), '\\(_\\|^\\)\\(.\\)', '\\u\\2', 'g')`} extends ${2:ParentClass}\n constructor: (${3:args}) ->\n ${4}\n\n ${5}\n# If\nsnippet if\n if ${1:condition}\n ${2:// body...}\n# If __ Else\nsnippet ife\n if ${1:condition}\n ${2:// body...}\n else\n ${3:// body...}\n# Else if\nsnippet elif\n else if ${1:condition}\n ${2:// body...}\n# Ternary If\nsnippet ifte\n if ${1:condition} then ${2:value} else ${3:other}\n# Unless\nsnippet unl\n ${1:action} unless ${2:condition}\n# Switch\nsnippet swi\n switch ${1:object}\n when ${2:value}\n ${3:// body...}\n\n# Log\nsnippet log\n console.log ${1}\n# Try __ Catch\nsnippet try\n try\n ${1}\n catch ${2:error}\n ${3}\n# Require\nsnippet req\n ${2:$1} = require '${1:sys}'${3}\n# Export\nsnippet exp\n ${1:root} = exports ? this\n",t.scope="coffee"})

View file

@ -1 +0,0 @@
ace.define("ace/snippets/javascript",["require","exports","module"],function(e,t,n){t.snippetText='# Prototype\nsnippet proto\n ${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n ${4:// body...}\n };\n# Function\nsnippet fun\n function ${1?:function_name}(${2:argument}) {\n ${3:// body...}\n }\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n function${M1?: ${1:functionName}}($2) {\n ${0:$TM_SELECTED_TEXT}\n }${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n (function(${1}) {\n ${0:${TM_SELECTED_TEXT:/* code */}}\n }(${1}));\n# if\nsnippet if\n if (${1:true}) {\n ${0}\n }\n# if ... else\nsnippet ife\n if (${1:true}) {\n ${2}\n } else {\n ${0}\n }\n# tertiary conditional\nsnippet ter\n ${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n switch (${1:expression}) {\n case \'${3:case}\':\n ${4:// code}\n break;\n ${5}\n default:\n ${2:// code}\n }\n# case\nsnippet case\n case \'${1:case}\':\n ${2:// code}\n break;\n ${3}\n\n# while (...) {...}\nsnippet wh\n while (${1:/* condition */}) {\n ${0:/* code */}\n }\n# try\nsnippet try\n try {\n ${0:/* code */}\n } catch (e) {}\n# do...while\nsnippet do\n do {\n ${2:/* code */}\n } while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n ${1:method_name}: function(${2:attribute}) {\n ${0}\n }${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# Get Elements\nsnippet gett\n getElementsBy${1:TagName}(\'${2}\')${3}\n# Get Element\nsnippet get\n getElementBy${1:Id}(\'${2}\')${3}\n# console.log (Firebug)\nsnippet cl\n console.log(${1});\n# return\nsnippet ret\n return ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n for (var ${1:prop} in ${2:Things}) {\n ${0:$2[$1]}\n }\n# hasOwnProperty\nsnippet has\n hasOwnProperty(${1})\n# docstring\nsnippet /**\n /**\n * ${1:description}\n *\n */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n @param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n @return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n JSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n JSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n var ${1:function_name} = function(${2:argument}) {\n ${3:// initial code ...}\n\n $1 = function($2) {\n ${4:// main code}\n };\n }\n# singleton\nsnippet sing\n function ${1:Singleton} (${2:argument}) {\n // the cached instance\n var instance;\n\n // rewrite the constructor\n $1 = function $1($2) {\n return instance;\n };\n \n // carry over the prototype properties\n $1.prototype = this;\n\n // the instance\n instance = new $1();\n\n // reset the constructor pointer\n instance.constructor = $1;\n\n ${3:// code ...}\n\n return instance;\n }\n# class\nsnippet class\nregex /^\\s*/clas{0,2}/\n var ${1:class} = function(${20}) {\n $40$0\n };\n \n (function() {\n ${60:this.prop = ""}\n }).call(${1:class}.prototype);\n \n exports.${1:class} = ${1:class};\n# \nsnippet for-\n for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n ${0:${2:Things}[${1:i}];}\n }\n# for (...) {...}\nsnippet for\n for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n ${3:$2[$1]}$0\n }\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n ${3:$2[$1]}$0\n }\n\n\n#modules\nsnippet def\n ace.define(function(require, exports, module) {\n "use strict";\n var ${1/.*\\///} = require("${1}");\n \n $TM_SELECTED_TEXT\n });\nsnippet req\nguard ^\\s*\n var ${1/.*\\///} = require("${1}");\n $0\nsnippet requ\nguard ^\\s*\n var ${1/.*\\/(.)/\\u$1/} = require("${1}").${1/.*\\/(.)/\\u$1/};\n $0\n',t.scope="javascript"})

View file

@ -1 +0,0 @@
ace.define("ace/snippets/lua",["require","exports","module"],function(e,t,n){t.snippetText="snippet #!\n #!/usr/bin/env lua\n $1\nsnippet local\n local ${1:x} = ${2:1}\nsnippet fun\n function ${1:fname}(${2:...})\n ${3:-- body}\n end\nsnippet for\n for ${1:i}=${2:1},${3:10} do\n ${4:print(i)}\n end\nsnippet forp\n for ${1:i},${2:v} in pairs(${3:table_name}) do\n ${4:-- body}\n end\nsnippet fori\n for ${1:i},${2:v} in ipairs(${3:table_name}) do\n ${4:-- body}\n end\n",t.scope="lua"})

View file

@ -1 +0,0 @@
ace.define("ace/snippets/luapage",["require","exports","module"],function(e,t,n){t.snippetText="",t.scope="luapage"})

View file

@ -1 +0,0 @@
ace.define("ace/snippets/plain_text",["require","exports","module"],function(e,t,n){t.snippetText="",t.scope="plain_text"})

View file

@ -1 +0,0 @@
ace.define("ace/snippets/python",["require","exports","module"],function(e,t,n){t.snippetText='snippet #!\n #!/usr/bin/env python\nsnippet imp\n import ${1:module}\nsnippet from\n from ${1:package} import ${2:module}\n# Module Docstring\nsnippet docs\n \'\'\'\n File: ${1:FILENAME:file_name}\n Author: ${2:author}\n Description: ${3}\n \'\'\'\nsnippet wh\n while ${1:condition}:\n ${2:# TODO: write code...}\n# dowh - does the same as do...while in other languages\nsnippet dowh\n while True:\n ${1:# TODO: write code...}\n if ${2:condition}:\n break\nsnippet with\n with ${1:expr} as ${2:var}:\n ${3:# TODO: write code...}\n# New Class\nsnippet cl\n class ${1:ClassName}(${2:object}):\n """${3:docstring for $1}"""\n def __init__(self, ${4:arg}):\n ${5:super($1, self).__init__()}\n self.$4 = $4\n ${6}\n# New Function\nsnippet def\n def ${1:fname}(${2:`indent(\'.\') ? \'self\' : \'\'`}):\n """${3:docstring for $1}"""\n ${4:# TODO: write code...}\nsnippet deff\n def ${1:fname}(${2:`indent(\'.\') ? \'self\' : \'\'`}):\n ${3:# TODO: write code...}\n# New Method\nsnippet defs\n def ${1:mname}(self, ${2:arg}):\n ${3:# TODO: write code...}\n# New Property\nsnippet property\n def ${1:foo}():\n doc = "${2:The $1 property.}"\n def fget(self):\n ${3:return self._$1}\n def fset(self, value):\n ${4:self._$1 = value}\n# Ifs\nsnippet if\n if ${1:condition}:\n ${2:# TODO: write code...}\nsnippet el\n else:\n ${1:# TODO: write code...}\nsnippet ei\n elif ${1:condition}:\n ${2:# TODO: write code...}\n# For\nsnippet for\n for ${1:item} in ${2:items}:\n ${3:# TODO: write code...}\n# Encodes\nsnippet cutf8\n # -*- coding: utf-8 -*-\nsnippet clatin1\n # -*- coding: latin-1 -*-\nsnippet cascii\n # -*- coding: ascii -*-\n# Lambda\nsnippet ld\n ${1:var} = lambda ${2:vars} : ${3:action}\nsnippet .\n self.\nsnippet try Try/Except\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\nsnippet try Try/Except/Else\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n else:\n ${5:# TODO: write code...}\nsnippet try Try/Except/Finally\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n finally:\n ${5:# TODO: write code...}\nsnippet try Try/Except/Else/Finally\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n else:\n ${5:# TODO: write code...}\n finally:\n ${6:# TODO: write code...}\n# if __name__ == \'__main__\':\nsnippet ifmain\n if __name__ == \'__main__\':\n ${1:main()}\n# __magic__\nsnippet _\n __${1:init}__${2}\n# python debugger (pdb)\nsnippet pdb\n import pdb; pdb.set_trace()\n# ipython debugger (ipdb)\nsnippet ipdb\n import ipdb; ipdb.set_trace()\n# ipython debugger (pdbbb)\nsnippet pdbbb\n import pdbpp; pdbpp.set_trace()\nsnippet pprint\n import pprint; pprint.pprint(${1})${2}\nsnippet "\n """\n ${1:doc}\n """\n# test function/method\nsnippet test\n def test_${1:description}(${2:self}):\n ${3:# TODO: write code...}\n# test case\nsnippet testcase\n class ${1:ExampleCase}(unittest.TestCase):\n \n def test_${2:description}(self):\n ${3:# TODO: write code...}\nsnippet fut\n from __future__ import ${1}\n#getopt\nsnippet getopt\n try:\n # Short option syntax: "hv:"\n # Long option syntax: "help" or "verbose="\n opts, args = getopt.getopt(sys.argv[1:], "${1:short_options}", [${2:long_options}])\n \n except getopt.GetoptError, err:\n # Print debug info\n print str(err)\n ${3:error_action}\n\n for option, argument in opts:\n if option in ("-h", "--help"):\n ${4}\n elif option in ("-v", "--verbose"):\n verbose = argument\n',t.scope="python"})

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ace.define("ace/snippets/snippets",["require","exports","module"],function(e,t,n){t.snippetText="# snippets for making snippets :)\nsnippet snip\n snippet ${1:trigger}\n ${2}\nsnippet msnip\n snippet ${1:trigger} ${2:description}\n ${3}\nsnippet v\n {VISUAL}\n",t.scope="snippets"})

View file

@ -1 +0,0 @@
ace.define("ace/snippets/text",["require","exports","module"],function(e,t,n){t.snippetText="",t.scope="text"})

View file

@ -1 +0,0 @@
ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;border-radius: 2px;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -33,7 +33,7 @@ module.exports = class CocoRouter extends Backbone.Router
'admin/clas': go('admin/CLAsView')
'admin/employers': go('admin/EmployersListView')
'admin/files': go('admin/FilesView')
'admin/analytics/users': go('admin/AnalyticsUsersView')
'admin/analytics': go('admin/AnalyticsView')
'admin/analytics/subscriptions': go('admin/AnalyticsSubscriptionsView')
'admin/level-sessions': go('admin/LevelSessionsView')
'admin/users': go('admin/UsersView')

View file

@ -31,7 +31,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
contact: "Kontakt"
twitter_follow: "Følg"
teachers: "Lærere"
# careers: "Careers"
careers: "Karrierer"
modal:
close: "Luk"
@ -80,7 +80,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
adjust_volume: "Indstil lydstyrke"
campaign_multiplayer: "Multiplayer Arenaer"
campaign_multiplayer_description: "... hvor du koder ansigt-til-ansigt imod andre spillere."
# campaign_old_multiplayer: "(Deprecated) Old Multiplayer Arenas"
campaign_old_multiplayer: "(Forældet) Gammel version af Multiplayer Arenaer"
# campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."
share_progress_modal:
@ -159,7 +159,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
accepted: "Accepteret"
rejected: "Afvist"
withdrawn: "Trukket tilbage"
# accept: "Accept"
accept: "Accepter"
# reject: "Reject"
# withdraw: "Withdraw"
submitter: "Indsender"
@ -196,7 +196,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
player: "Spiller"
player_level: "Niveau" # Like player level 5, not like level: Dungeons of Kithgard
warrior: "Krigsherre"
# ranger: "Ranger"
ranger: "Bueskytte"
wizard: "Troldmand"
units:
@ -217,8 +217,8 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
play_level:
done: "Færdig"
# next_game: "Next game"
# show_menu: "Show game menu"
next_game: "Næste spil"
show_menu: "Vis spil menu"
home: "Hjem" # Not used any more, will be removed soon.
level: "Bane" # Like "Level: Dungeons of Kithgard"
skip: "Spring over"
@ -251,7 +251,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
victory_saving_progress: "Gemmer fremskridt"
victory_go_home: "Gå hjem"
victory_review: "Fortæl os mere!"
# victory_review_placeholder: "How was the level?"
victory_review_placeholder: "Hvordan var levelet?"
victory_hour_of_code_done: "Er du færdig?"
victory_hour_of_code_done_yes: "Ja, jeg er færdig med min Kodetime!"
victory_experience_gained: "XP tjent"
@ -260,7 +260,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
victory_viking_code_school: "For dælen det var en svær bane du lige slog! Hvis ikke du allerede er softwareudvikler, så burde du blive det. Du er lige kommet foran i køen til at blive accepteret hos Viking Code School, du kan tage dine evner til det næste niveau og blive en professionel webudvikler på 14 uger."
victory_become_a_viking: "Bliv en Viking"
# victory_bloc: "Great work! Your skills are improving, and someone's taking notice. If you've considered becoming a software developer, this may be your lucky day. Bloc is an online bootcamp that pairs you 1-on-1 with an expert mentor who will help train you into a professional developer! By beating A Mayhem of Munchkins, you're now eligible for a $500 price reduction with the code: CCRULES"
# victory_bloc_cta: "Meet your mentor learn about Bloc"
victory_bloc_cta: "Mød din mentor - Hør mere om Bloc"
guide_title: "Instruktioner"
tome_minion_spells: "Dine Minions' besværgelser" # Only in old-style levels.
tome_read_only_spells: "Læsebesværgelser" # Only in old-style levels.
@ -298,7 +298,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
tip_scrub_shortcut: "Brug Ctrl+[ og Ctrl+] til at spole tilbage og frem."
tip_guide_exists: "Klik på guiden i spilmenuen (i toppen af siden) for brugbar info."
tip_open_source: "CodeCombat er 100% open source!"
# tip_tell_friends: "Enjoying CodeCombat? Tell your friends about us!"
tip_tell_friends: "Kan du lide CodeCombat? Fortæl dine venner om os!"
tip_beta_launch: "CodeCombat søsatte sin beta i oktober, 2013."
tip_think_solution: "Tænk på løsningen, ikke problemet."
tip_theory_practice: "I teorien er der ingen forskel på teori og praksis. Men i praksis er der. - Yogi Bjørn"
@ -327,23 +327,23 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
# tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
# tip_superpower: "Coding is the closest thing we have to a superpower."
# tip_control_destiny: "In real open source, you have the right to control your own destiny. - Linus Torvalds"
# tip_no_code: "No code is faster than no code."
# tip_code_never_lies: "Code never lies, comments sometimes do. — Ron Jeffries"
# tip_reusable_software: "Before software can be reusable it first has to be usable."
tip_no_code: "Ingen kode er hurtigerer end ingen kode."
tip_code_never_lies: "Kode lyver aldrig, kommentarer gør nogle gange. - Ron Jeffries"
tip_reusable_software: "Før software kan være genbrugeligt skal det først være brugbart."
# tip_optimization_operator: "Every language has an optimization operator. In most languages that operator is //"
# tip_lines_of_code: "Measuring programming progress by lines of code is like measuring aircraft building progress by weight. — Bill Gates"
# tip_source_code: "I want to change the world but they would not give me the source code."
# tip_javascript_java: "Java is to JavaScript what Car is to Carpet. - Chris Heilmann"
# tip_move_forward: "Whatever you do, keep moving forward. - Martin Luther King Jr."
tip_move_forward: "Hvad end du gør, så bliv ved med at rykke fremad. - Martin Luther King Jr."
tip_google: "Har du et problem du ikke kan løse? Google det!"
tip_adding_evil: "Tilføjer et strejf af ondskab.."
# tip_hate_computers: "That's the thing about people who think they hate computers. What they really hate is lousy programmers. - Larry Niven"
# tip_open_source_contribute: "You can help CodeCombat improve!"
# tip_recurse: "To iterate is human, to recurse divine. - L. Peter Deutsch"
# tip_free_your_mind: "You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind. - Morpheus"
# tip_strong_opponents: "Even the strongest of opponents always has a weakness. - Itachi Uchiha"
tip_strong_opponents: "Selv de stærkeste modstandere har en svaghed. - Itachi Uchiha"
tip_paper_and_pen: "Før du starter med at programmere, kan du altid sætte dig ned med et stykke papir og blyant."
# tip_solve_then_write: "First, solve the problem. Then, write the code. - John Johnson"
tip_solve_then_write: "Først, løs problemet, derefter skriv koden. - John Johnson"
game_menu:
inventory_tab: "Dine ting"
@ -367,14 +367,14 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
# view_other_solutions: "View Leaderboards"
# scores: "Scores"
# top_players: "Top Players by"
# day: "Today"
# week: "This Week"
day: "Idag"
week: "Denne uge"
# all: "All-Time"
# time: "Time"
time: "Tid"
# damage_taken: "Damage Taken"
# damage_dealt: "Damage Dealt"
difficulty: "Sværhedsgrad"
# gold_collected: "Gold Collected"
gold_collected: "Guld samlet"
# inventory:
# choose_inventory: "Equip Items"
@ -489,43 +489,43 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
# subscribe_prepaid: "Click Subscribe to use prepaid code"
# using_prepaid: "Using prepaid code for monthly subscription"
# choose_hero:
# choose_hero: "Choose Your Hero"
# programming_language: "Programming Language"
# programming_language_description: "Which programming language do you want to use?"
# default: "Default"
# experimental: "Experimental"
# python_blurb: "Simple yet powerful, great for beginners and experts."
# javascript_blurb: "The language of the web. (Not the same as Java.)"
# coffeescript_blurb: "Nicer JavaScript syntax."
# clojure_blurb: "A modern Lisp."
# lua_blurb: "Game scripting language."
# io_blurb: "Simple but obscure."
# status: "Status"
# hero_type: "Type"
# weapons: "Weapons"
# weapons_warrior: "Swords - Short Range, No Magic"
# weapons_ranger: "Crossbows, Guns - Long Range, No Magic"
# weapons_wizard: "Wands, Staffs - Long Range, Magic"
choose_hero:
choose_hero: "Vælg din helt"
programming_language: "Programmerings sprog"
programming_language_description: "Hvilket programmerings sprog har du lyst til at bruge?"
default: "Standard"
experimental: "Experimental"
python_blurb: "Simplet, dog stærkt, godt for begyndere og eksperter."
javascript_blurb: "Internettets sprog. (Ikke det samme som Java.)"
coffeescript_blurb: "Pænere JavaScript syntax."
clojure_blurb: "En moderne version af Lisp."
lua_blurb: " Spil scripting sprog."
# io_blurb: "Simple but obscure."
status: "Status"
hero_type: "Type"
weapons: "Våben"
weapons_warrior: "Sværd - Kort afstand, Ingen Magi"
weapons_ranger: "Armbryst, Skydevåben - Lang afstand, Ingen Magi"
weapons_wizard: "Tryllestave, Stave - Lang afstand, Magi"
# attack: "Damage" # Can also translate as "Attack"
# health: "Health"
# speed: "Speed"
# regeneration: "Regeneration"
health: "Liv"
speed: "Fart"
regeneration: "Regeneration"
# range: "Range" # As in "attack or visual range"
# blocks: "Blocks" # As in "this shield blocks this much damage"
# backstab: "Backstab" # As in "this dagger does this much backstab damage"
# skills: "Skills"
skills: "Færdigheder"
# attack_1: "Deals"
# attack_2: "of listed"
# attack_3: "weapon damage."
# health_1: "Gains"
# health_2: "of listed"
# health_3: "armor health."
# speed_1: "Moves at"
# speed_2: "meters per second."
# available_for_purchase: "Available for Purchase" # Shows up when you have unlocked, but not purchased, a hero in the hero store
# level_to_unlock: "Level to unlock:" # Label for which level you have to beat to unlock a particular hero (click a locked hero in the store to see)
# restricted_to_certain_heroes: "Only certain heroes can play this level."
speed_1: "Rykker med"
speed_2: "meter i sekundet."
available_for_purchase: "Kan nu blive købt" # Shows up when you have unlocked, but not purchased, a hero in the hero store
level_to_unlock: "Level for at låse op:" # Label for which level you have to beat to unlock a particular hero (click a locked hero in the store to see)
restricted_to_certain_heroes: "Kun visse helt kan spille dette level."
# skill_docs:
# writable: "writable" # Hover over "attack" in Your Skills while playing a level to see most of this

View file

@ -71,7 +71,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
choose_inventory: "Naudoti daiktus"
buy_gems: "Pirkti Deimantus"
# subscription_required: "Subscription Required"
# anonymous: "Anonymous Player"
anonymous: "Anoniminis Žaidėjas"
level_difficulty: "Sudėtingumas: "
campaign_beginner: "Naujoko kampanija"
awaiting_levels_adventurer_prefix: "Kiekvieną savaitę sukuriame naujus lygius."
@ -225,7 +225,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
game_menu: "Žaidimo meniu"
guide: "Vedlys"
restart: "Paleisti iš naujo"
goals: "Tikslai"
goals: "Pagalba"
goal: "Tikslas"
running: "Leidžiama..."
success: "Sėkmingai!"
@ -233,7 +233,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
timed_out: "Laikas baigėsi"
failing: "Nesėkmingai"
# action_timeline: "Action Timeline"
# click_to_select: "Click on a unit to select it."
click_to_select: "Spregtelkite ant veikėjo ar padaro, kad jį pažymėtumėte."
control_bar_multiplayer: "Žaidimas keliese"
control_bar_join_game: "Prisijungti prie žaidimo"
reload: "Perkrauti"
@ -241,7 +241,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
reload_really: "Ar tikrai norite atsukti visą lygį į pradžią?"
reload_confirm: "Perkrauti viską"
victory: "Pergalė"
# victory_title_prefix: ""
victory_title_prefix: ""
victory_title_suffix: " baigta"
victory_sign_up: "Užsiregistruokite, kad išsaugotumėte pažangą"
victory_sign_up_poke: "Norite išsaugoti savo kodą? Sukurkite paskyrą nemokamai!"
@ -299,12 +299,12 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
tip_guide_exists: "Pasirinkite punktą Vedlys žaidimo meniu (puslapio viršuje), jame rasite naudingos informacijos."
tip_open_source: "CodeCombat - 100% atviro kodo!"
tip_tell_friends: "Jums patinka CodeCombat? Papasakokite savo draugams!"
# tip_beta_launch: "CodeCombat launched its beta in October, 2013."
tip_beta_launch: "CodeCombat Beta versija startavo 2013 m. spalio mėnesį."
tip_think_solution: "Galvok ne apie problemą, o apie sprendimą."
# tip_theory_practice: "In theory, there is no difference between theory and practice. But in practice, there is. - Yogi Berra"
tip_theory_practice: "Teoriškai nėra skirtuma tarp teorijos ir praktikos. Praktiškai - yra. - Yogi Berra"
# tip_error_free: "There are two ways to write error-free programs; only the third one works. - Alan Perlis"
# tip_debugging_program: "If debugging is the process of removing bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra"
# tip_forums: "Head over to the forums and tell us what you think!"
tip_forums: "Aplankykite forumą ir parašykite mums Jūsų nuomonę!"
# tip_baby_coders: "In the future, even babies will be Archmages."
# tip_morale_improves: "Loading will continue until morale improves."
# tip_all_species: "We believe in equal opportunities to learn programming for all species."
@ -314,13 +314,13 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
# tip_munchkin: "If you don't eat your vegetables, a munchkin will come after you while you're asleep."
# tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't."
# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda"
# tip_no_try: "Do. Or do not. There is no try. - Yoda"
# tip_patience: "Patience you must have, young Padawan. - Yoda"
# tip_documented_bug: "A documented bug is not a bug; it is a feature."
# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela"
tip_no_try: "Daryk. Arba ne. Jokių 'pabandysiu'. - Yoda"
tip_patience: "Kantrybės turėti turi, jaunasis Padavane. - Yoda"
tip_documented_bug: "Dokumentuota klaida nėra klaida; tai programos ypatybė."
tip_impossible: "Tai visuomet atrodo neįmanoma tol, kol tai nėra padaryta. - Nelson Mandela"
# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds"
# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay"
# tip_hardware_problem: "Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem."
tip_hardware_problem: "K: Kiek programuotojų reikia tam, kad įsuktų lemputę? A: Nei vieno, tai 'geležies' problema."
# tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
# tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
# tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
@ -335,12 +335,12 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
# tip_source_code: "I want to change the world but they would not give me the source code."
# tip_javascript_java: "Java is to JavaScript what Car is to Carpet. - Chris Heilmann"
# tip_move_forward: "Whatever you do, keep moving forward. - Martin Luther King Jr."
# tip_google: "Have a problem you can't solve? Google it!"
tip_google: "Turi problemą kurios negali išspręsti? Pagooglink!"
# tip_adding_evil: "Adding a pinch of evil."
# tip_hate_computers: "That's the thing about people who think they hate computers. What they really hate is lousy programmers. - Larry Niven"
# tip_open_source_contribute: "You can help CodeCombat improve!"
tip_open_source_contribute: "Gali padėti tobulinti CodeCombat!"
# tip_recurse: "To iterate is human, to recurse divine. - L. Peter Deutsch"
# tip_free_your_mind: "You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind. - Morpheus"
tip_free_your_mind: "Turi paleisti visą tai, Neo. Baimę, abejones ir netikėjimą. Išlaisvink savo mintis. - Morpheus"
# tip_strong_opponents: "Even the strongest of opponents always has a weakness. - Itachi Uchiha"
# tip_paper_and_pen: "Before you start coding, you can always plan with a sheet of paper and a pen."
# tip_solve_then_write: "First, solve the problem. Then, write the code. - John Johnson"
@ -349,7 +349,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
inventory_tab: "Inventorius"
save_load_tab: "Įrašyti / Atkurti"
options_tab: "Pasirinkimai"
guide_tab: "Vedlys"
guide_tab: "Pagalba"
guide_video_tutorial: "Video vadovėlis"
guide_tips: "Patarimai"
multiplayer_tab: "Žaidimas keliese"
@ -362,19 +362,19 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
multiplayer_caption: "Žaisk su draugais!"
auth_caption: "Išsaugok savo pažangą."
# leaderboard:
# leaderboard: "Leaderboard"
# view_other_solutions: "View Leaderboards"
# scores: "Scores"
# top_players: "Top Players by"
# day: "Today"
# week: "This Week"
# all: "All-Time"
# time: "Time"
# damage_taken: "Damage Taken"
# damage_dealt: "Damage Dealt"
# difficulty: "Difficulty"
# gold_collected: "Gold Collected"
leaderboard:
leaderboard: "Rezultatai"
view_other_solutions: "Peržiūrėti rezultatus"
scores: "Taškai"
top_players: "Geriausi žaidėjai pagal"
day: "Šiandien"
week: "Savaitė"
all: "Visi laikotarpiai"
time: "Laikas"
damage_taken: "Gauta žalos"
damage_dealt: "Padaryta žalos"
difficulty: "Sudėtingumas"
gold_collected: "Surinkta Aukso"
inventory:
choose_inventory: "Naudoti daiktus"
@ -389,18 +389,18 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
equip: "Naudoti"
unequip: "Nenaudoti"
# buy_gems:
# few_gems: "A few gems"
# pile_gems: "Pile of gems"
# chest_gems: "Chest of gems"
# purchasing: "Purchasing..."
# declined: "Your card was declined"
# retrying: "Server error, retrying."
# prompt_title: "Not Enough Gems"
# prompt_body: "Do you want to get more?"
# prompt_button: "Enter Shop"
# recovered: "Previous gems purchase recovered. Please refresh the page."
# price: "x3500 / mo"
buy_gems:
few_gems: "Sauja deimantų"
pile_gems: "Krūvelė deimantų"
chest_gems: "Skrynia deimantų"
purchasing: "Perkama..."
declined: "Jūsų kortelė atmesta"
retrying: "Serverio klaida, kartojame."
prompt_title: "Deimantų nepakanka"
prompt_body: "Ar norite gauti daugiau?"
prompt_button: "Į Parduotuvę"
recovered: "Atstatyta deimantų pirkimo operacija. Prašome pakraukite puslapį iš naujo."
price: "x3500 / mėn"
# subscribe:
# comparison_blurb: "Sharpen your skills with a CodeCombat subscription!"
@ -500,8 +500,8 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
coffeescript_blurb: "JavaScript su malonesne sintakse."
clojure_blurb: "Šiolaikinis Lisp."
lua_blurb: "Žaidimų skriptų kalba."
# io_blurb: "Simple but obscure."
# status: "Status"
io_blurb: "Paprasta bet paini."
status: "Būsena"
hero_type: "Klasė"
weapons: "Ginklai"
weapons_warrior: "Kardai - artimas atstumas, be Kerų"
@ -551,23 +551,23 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
# granularity_saved_games: "Saved"
# granularity_change_history: "History"
# options:
# general_options: "General Options" # Check out the Options tab in the Game Menu while playing a level
# volume_label: "Volume"
# music_label: "Music"
# music_description: "Turn background music on/off."
# editor_config_title: "Editor Configuration"
# editor_config_keybindings_label: "Key Bindings"
# editor_config_keybindings_default: "Default (Ace)"
# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors."
# editor_config_livecompletion_label: "Live Autocompletion"
# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing."
# editor_config_invisibles_label: "Show Invisibles"
# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs."
# editor_config_indentguides_label: "Show Indent Guides"
# editor_config_indentguides_description: "Displays vertical lines to see indentation better."
# editor_config_behaviors_label: "Smart Behaviors"
# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes."
options:
general_options: "Bendri nustatymai" # Check out the Options tab in the Game Menu while playing a level
volume_label: "Garsumas"
music_label: "Muzika"
music_description: "Įj./išj. fono muziką."
editor_config_title: "Redaktoriaus konfigūravimas"
editor_config_keybindings_label: "Mygtukų funkcijos"
editor_config_keybindings_default: "Pagal nutylėjimą (Ace)"
editor_config_keybindings_description: "Prideda papildomas mygtukų kombinacijas iš žinomų redagavimo programų."
editor_config_livecompletion_label: "Automatinis žodžių užpildymas "
editor_config_livecompletion_description: "Rodyti automatinio užpildymo siūlymus rašymo metu."
editor_config_invisibles_label: "Rodyti nematomus simbolius"
editor_config_invisibles_description: "Rodyti nematomus simbolius, tokius kaip tarpai ar Tab."
editor_config_indentguides_label: "Rodyti poslinkio rekomendacijas"
editor_config_indentguides_description: "Rodomos vertikalios linijos patogesniam poslinkio matymui."
editor_config_behaviors_label: "Išmanusis redagavimas"
editor_config_behaviors_description: "Automatiškai uždaro skliaustus, figurinius skliaustus ir kabutes."
# about:
# why_codecombat: "Why CodeCombat?"
@ -770,14 +770,14 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
# scrub_playback: "Scrub back and forward through time."
# single_scrub_playback: "Scrub back and forward through time by a single frame."
# scrub_execution: "Scrub through current spell execution."
# toggle_debug: "Toggle debug display."
toggle_debug: "Įj./išj. klaidų aptikimo (debug) displejų."
toggle_grid: "Įjungti tinklelį."
# toggle_pathfinding: "Toggle pathfinding overlay."
beautify: "Tvarkyti Jūsų kodą standartizuojant jo formatą."
# maximize_editor: "Maximize/minimize code editor."
maximize_editor: "Išdidinti/sumažinti kodo redaktorių."
# community:
# main_title: "CodeCombat Community"
community:
main_title: "Bendruomenė CodeCombat"
# introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!"
# level_editor_prefix: "Use the CodeCombat"
# level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!"
@ -941,24 +941,24 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
# hours_content: "Hours of content:"
# get_free: "Get FREE course"
# classes:
# archmage_title: "Archmage"
# archmage_title_description: "(Coder)"
classes:
archmage_title: "Arkimagas"
archmage_title_description: "(Koderis)"
# archmage_summary: "If you are a developer interested in coding educational games, become an archmage to help us build CodeCombat!"
# artisan_title: "Artisan"
# artisan_title_description: "(Level Builder)"
artisan_title: "Menininkas"
artisan_title_description: "(Lygių architektas)"
# artisan_summary: "Build and share levels for you and your friends to play. Become an Artisan to learn the art of teaching others to program."
# adventurer_title: "Adventurer"
# adventurer_title_description: "(Level Playtester)"
adventurer_title: "Nuotykių ieškotojas"
adventurer_title_description: "(Lygių bandytojas)"
# adventurer_summary: "Get our new levels (even our subscriber content) for free one week early and help us work out bugs before our public release."
# scribe_title: "Scribe"
# scribe_title_description: "(Article Editor)"
scribe_title: "Raštininkas"
scribe_title_description: "(Straipsnių redaktorius)"
# scribe_summary: "Good code needs good documentation. Write, edit, and improve the docs read by millions of players across the globe."
# diplomat_title: "Diplomat"
# diplomat_title_description: "(Translator)"
diplomat_title: "Diplomatas"
diplomat_title_description: "(Vertėjas)"
# diplomat_summary: "CodeCombat is localized in 45+ languages by our Diplomats. Help us out and contribute translations."
# ambassador_title: "Ambassador"
# ambassador_title_description: "(Support)"
ambassador_title: "Ambasadorius"
ambassador_title_description: "(Palaikymas)"
# ambassador_summary: "Tame our forum users and provide direction for those with questions. Our ambassadors represent CodeCombat to the world."
# editor:

View file

@ -6,12 +6,12 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa
play: "Mula" # The big play button that opens up the campaign view.
old_browser: "Uh oh, browser anda terlalu lama untuk CodeCombat berfungsi. Maaf!" # Warning that shows up on really old Firefox/Chrome/Safari
old_browser_suffix: "Anda boleh mencuba, tapi mungkin ia tidak akan berfungsi."
# ipad_browser: "Bad news: CodeCombat doesn't run on iPad in the browser. Good news: our native iPad app is awaiting Apple approval."
# campaign: "Campaign"
# for_beginners: "For Beginners"
# multiplayer: "Multiplayer" # Not currently shown on home page
# for_developers: "For Developers" # Not currently shown on home page.
# or_ipad: "Or download for iPad"
ipad_browser: "Berita buruk: CodeCombat tidak boleh berfungsi pada iPad di dalam pelayar web. Berita baik: Aplikasi native iPad kami sedang menunggu pengesahan Apple."
campaign: "Kempen"
for_beginners: "Untuk Pemain Baru"
multiplayer: "Ramai-Pemain" # Not currently shown on home page
for_developers: "Untuk Pengaturcara" # Not currently shown on home page.
or_ipad: "Atau muat turun untuk iPad"
nav:
play: "Mula" # The top nav bar entry where players choose which levels to play

View file

@ -280,6 +280,7 @@ _.extend UserSchema.properties,
pollMiscPatches: c.int()
campaignTranslationPatches: c.int()
campaignMiscPatches: c.int()
concepts: {type: 'object', additionalProperties: c.int(), description: 'Number of levels completed using each programming concept.'}
earned: c.RewardSchema 'earned by achievements'
purchased: c.RewardSchema 'purchased with gems or money'

View file

@ -1,4 +1,11 @@
#subscription-view
.invalid-email-message
color: red
font-size: 12px
.recipient-emails.invalid
border: 1px solid red
.logged-out-blurb
font-size: 18px

View file

@ -0,0 +1,12 @@
#admin-analytics-view
#site-content-area
width: 100%
.big-stat
width: auto
.active-users
color: green
.count
font-size: 50pt
.description
font-size: 8pt

View file

@ -150,7 +150,9 @@ block content
if view.recipientSubs.state === 'subscribing'
.alert.alert-info(data-i18n="subscribe.subscribing")
else
textarea.recipient-emails(rows=3, data-i18n="[placeholder]subscribe.recipient_emails_placeholder")
if emailValidator.state === 'invalid'
div.invalid-email-message(aria-hidden="true") please make sure all entries are valid emails
textarea.recipient-emails(rows=3, data-i18n="[placeholder]subscribe.recipient_emails_placeholder")=emailValidator.lastEmails
div
button.recipients-subscribe-button.btn.btn-lg.btn-success(data-i18n="subscribe.subscribe_users")
if view.recipientSubs.state === 'declined'

View file

@ -48,12 +48,11 @@ block content
li
a(href="/admin/pending-patches", data-i18n="resources.patches") Patches
if me.isAdmin()
li Analytics
li
a(href="/admin/analytics") Analytics
ul
li
a(href="/admin/analytics/subscriptions") Subscriptions
li
a(href="/admin/analytics/users") Users (needs updating)
if me.isAdmin()
hr

View file

@ -1,32 +0,0 @@
extends /templates/base
block content
h1(data-i18n="admin.growth_title") Users
if me.isAdmin()
if crunchingData
h4 Crunching Data..
else
h2 Registered Users
h3 Per-Day
h4 Totals
svg.perDayTotal
h4 Added
svg.perDayAdded
table.table.table-striped.table-bordered.table-condensed
-for (var i = 0; i < usersPerDay.length; i++)
tr
td= usersPerDay[i].date
td= usersPerDay[i].added
td= usersPerDay[i].total
h3 Per-Month
h4 Totals
svg.perMonthTotal
h4 Added
svg.perMonthAdded
table.table.table-striped.table-bordered.table-condensed
-for (var i = 0; i < usersPerMonth.length; i++)
tr
td= usersPerMonth[i].date
td= usersPerMonth[i].added
td= usersPerMonth[i].total

View file

@ -0,0 +1,29 @@
extends /templates/base
block content
if me.isAdmin()
.container-fluid
.row
.col-md-5.big-stat.active-users
if activeUsers.length > 0
div.description 30-day Active Users
div.count= activeUsers[0].monthlyCount
h1 Active Users
table.table.table-striped.table-condensed
tr
th Day
th Daily Actives
th Monthly Actives
th DAUs / MAUs
each activeUser in activeUsers
tr
td= activeUser.day
td= activeUser.dailyCount
if activeUser.monthlyCount
td= activeUser.monthlyCount
td #{(activeUser.dailyCount / activeUser.monthlyCount * 100).toFixed(2)}%
else
td
td

View file

@ -120,10 +120,3 @@ block modal-footer-content
img.pull-right(src="/file/db/level/55144b509f0c4854051769c1/viking_2.png")
span(data-i18n="play_level.victory_viking_code_school")
button.btn.btn-illustrated.btn-primary.btn-lg.world-map-button.continue-from-offer-button(data-i18n="play_level.victory_become_a_viking") Become a Viking
.offer.a-mayhem-of-munchkins
p
img.pull-left(src="/file/db/level/55ca29439bc1892c835b0137/bloc_warrior.png")
img.pull-right(src="/file/db/level/55ca29439bc1892c835b0137/bloc_logo.png")
span(data-i18n="play_level.victory_bloc")
button.btn.btn-illustrated.btn-warning.btn-lg.world-map-button.skip-offer-button(data-i18n="play_level.victory_play_continue") Continue
button.btn.btn-illustrated.btn-primary.btn-lg.world-map-button.continue-from-offer-button(data-i18n="play_level.victory_bloc_cta")

View file

@ -49,9 +49,15 @@ module.exports = class SubscriptionView extends RootView
prepaidCode = utils.getQueryVariable '_ppc'
@personalSub = new PersonalSub(@supermodel, prepaidCode)
@recipientSubs = new RecipientSubs(@supermodel)
@emailValidator = new EmailValidator(@superModel)
@personalSub.update => @render?()
@recipientSubs.update => @render?()
getRenderData: ->
c = super()
c.emailValidator = @emailValidator
c
# Personal Subscriptions
onClickStartSubscription: (e) ->
@ -82,7 +88,8 @@ module.exports = class SubscriptionView extends RootView
onClickRecipientsSubscribe: (e) ->
emails = @$el.find('.recipient-emails').val().split('\n')
@recipientSubs.startSubscribe(emails)
valid = @emailValidator.validateEmails(emails, =>@render?())
@recipientSubs.startSubscribe(emails) if valid
onClickRecipientUnsubscribe: (e) ->
$(e.target).addClass('hide')
@ -97,6 +104,31 @@ module.exports = class SubscriptionView extends RootView
# Helper classes for managing subscription actions and updating UI state
class EmailValidator
validateEmails: (emails, render) ->
@lastEmails = emails.join('\n')
#taken from http://www.regular-expressions.info/email.html
emailRegex = /[A-z0-9._%+-]+@[A-z0-9.-]+\.[A-z]{2,4}/
@validEmails = (email for email in emails when emailRegex.test(email.trim().toLowerCase()))
return @emailsInvalid(render) if @validEmails.length < emails.length
return @emailsValid(render)
emailString: ->
return unless @validEmails
return @validEmails.join('\n')
emailsInvalid: (render) ->
@state = "invalid"
render()
return false
emailsValid: (render) ->
@state = "valid"
render()
return true
class PersonalSub
constructor: (@supermodel, @prepaidCode) ->

View file

@ -1,193 +0,0 @@
RootView = require 'views/core/RootView'
template = require 'templates/admin/analytics-users'
RealTimeCollection = require 'collections/RealTimeCollection'
require 'vendor/d3'
# Growth View ###################
#
# Display interesting growth data.
#
# Currently shows:
# Registered user totals and added, per-day and per-month
# 7-day moving average for registered users added per-day
#
# TODO: @padding isn't applied correctly
# TODO: aggregate recent data if missing?
#
module.exports = class AnalyticsUsersView extends RootView
id: 'admin-analytics-users-view'
template: template
height: 300
width: 1000
xAxisGuideHeight: 80
yAxisGuideWidth: 60
padding: 10
constructor: (options) ->
super options
@usersPerMonth = new RealTimeCollection 'growth/users/registered/per-month'
@usersPerMonth.on 'add', @refreshData
@usersPerDay = new RealTimeCollection 'growth/users/registered/per-day'
@usersPerDay.on 'add', @refreshData
destroy: ->
@usersPerMonth.off 'add', @refreshData
@usersPerDay.off 'add', @refreshData
refreshData: =>
@render()
getRenderData: ->
c = super()
c.crunchingData = @usersPerMonth.length is 0 and @usersPerDay.length is 0
c.usersPerDay = []
# @usersPerDay.each (item) ->
# c.usersPerDay.push date: item.get('id'), added: item.get('added'), total: item.get('total')
c.usersPerMonth = []
# @usersPerMonth.each (item) ->
# c.usersPerMonth.push date: item.get('id'), added: item.get('added'), total: item.get('total')
c
afterRender: ->
super()
if me.isAdmin()
@createPerDayChart()
@createPerMonthChart()
createPerDayChart: ->
addedData = []
totalData = []
@usersPerDay.each (item) ->
addedData.push id: item.get('id'), value: item.get('added')
totalData.push id: item.get('id'), value: item.get('total')
@createLineChart ".perDayTotal", totalData, 1000
@createLineChart ".perDayAdded", addedData, 10, true
createPerMonthChart: ->
addedData = []
totalData = []
@usersPerMonth.each (item) ->
addedData.push id: item.get('id'), value: item.get('added')
totalData.push id: item.get('id'), value: item.get('total')
@createLineChart ".perMonthTotal", totalData, 1000
@createLineChart ".perMonthAdded", addedData, 1000
createLineChart: (selector, data, guidelineSpacing, sevenDayAverage=false) ->
return unless data.length > 1
minVal = d3.min(data, (d) -> d.value)
maxVal = d3.max(data, (d) -> d.value)
widthSpacing = (@width - @yAxisGuideWidth - @padding) / (data.length - 1)
y = d3.scale.linear()
.domain([minVal, maxVal])
.range([@height - @xAxisGuideHeight - 2 * @padding, 0])
points = []
for i in [0...data.length]
points.push id: data[i].id, x: i * widthSpacing + @yAxisGuideWidth, y: y(data[i].value) + @padding
links = []
for i in [0...points.length - 1]
if points[i] and points[i + 1]
links.push start: points[i], end: points[i + 1]
guidelines = []
diff = maxVal - minVal
interval = Math.floor(diff / 5)
for i in [0..4]
yVal = i * interval + minVal
yVal = Math.floor(yVal / guidelineSpacing) * guidelineSpacing
guidelines.push start: {id: yVal, x: 0, y: y(yVal)}, end: {id: yVal, x: @width, y: y(yVal)}
sevenPoints = []
sevenLinks = []
if sevenDayAverage
sevenTotal = 0
for i in [0...data.length]
sevenTotal += data[i].value
if i > 5
sevenAvg = sevenTotal / 7
sevenPoints.push x: i * widthSpacing + @yAxisGuideWidth, y: y(sevenAvg) + @padding
if i > 6
sevenTotal -= data[i - 7].value
for i in [0...sevenPoints.length - 1]
if sevenPoints[i] and sevenPoints[i + 1]
sevenLinks.push start: sevenPoints[i], end: sevenPoints[i + 1]
chart = d3.select(selector)
.attr("width", @width)
.attr("height", @height)
chart.selectAll(".circle")
.data(points)
.enter()
.append("circle")
.attr("cx", (d) -> d.x )
.attr("cy", (d) -> d.y )
.attr("r", "2px")
.attr("fill", "black")
chart.selectAll(".text")
.data(points)
.enter()
.append("text")
.attr("dy", ".35em")
.attr("transform", (d, i) => "translate(" + d.x + "," + @height + ") rotate(270)")
.text((d) ->
if d.id.length is 8
return "#{parseInt(d.id[4..5])}/#{parseInt(d.id[6..7])}/#{d.id[0..3]}"
else
return "#{parseInt(d.id[4..5])}/#{d.id[0..3]}"
)
chart.selectAll('.line')
.data(links)
.enter()
.append("line")
.attr("x1", (d) -> d.start.x )
.attr("y1", (d) -> d.start.y )
.attr("x2", (d) -> d.end.x )
.attr("y2", (d) -> d.end.y )
.style("stroke", "rgb(6,120,155)")
chart.selectAll(".circle")
.data(sevenPoints)
.enter()
.append("circle")
.attr("cx", (d) -> d.x )
.attr("cy", (d) -> d.y )
.attr("r", "2px")
.attr("fill", "purple")
chart.selectAll('.line')
.data(sevenLinks)
.enter()
.append("line")
.attr("x1", (d) -> d.start.x )
.attr("y1", (d) -> d.start.y )
.attr("x2", (d) -> d.end.x )
.attr("y2", (d) -> d.end.y )
.style("stroke", "rgb(200,0,0)")
chart.selectAll('.line')
.data(guidelines)
.enter()
.append("line")
.attr("x1", (d) -> d.start.x )
.attr("y1", (d) -> d.start.y )
.attr("x2", (d) -> d.end.x )
.attr("y2", (d) -> d.end.y )
.style("stroke", "rgb(140,140,140)")
chart.selectAll(".text")
.data(guidelines)
.enter()
.append("text")
.attr("x", (d) -> d.start.x)
.attr("y", (d) -> d.start.y - 6)
.attr("dy", ".35em")
.text((d) -> d.start.id)

View file

@ -0,0 +1,27 @@
RootView = require 'views/core/RootView'
template = require 'templates/admin/analytics'
utils = require 'core/utils'
module.exports = class AnalyticsView extends RootView
id: 'admin-analytics-view'
template: template
constructor: (options) ->
super options
startDay = utils.getUTCDay(-30).replace(/-/g, '')
endDay = utils.getUTCDay(-30).replace(/-/g, '')
request = @supermodel.addRequestResource 'active_users', {
url: '/db/analytics_perday/-/active_users'
data: {startDay: startDay, endDay: endDay}
method: 'POST'
success: (data) =>
@activeUsers = data
@activeUsers.sort (a, b) -> b.day.localeCompare(a.day)
@render?()
}, 0
request.load()
getRenderData: ->
context = super()
context.activeUsers = @activeUsers ? []
context

View file

@ -37,7 +37,7 @@ module.exports = class ThangAvatarView extends CocoView
context = super context
context.thang = @thang
options = @thang?.getLankOptions() or {}
options.async = true
#options.async = true # sync builds fail during async builds, and we build HUD version sync
context.avatarURL = @thangType.getPortraitSource(options) unless @thangType.loading
context.includeName = @includeName
context

View file

@ -476,7 +476,6 @@ module.exports = class HeroVictoryModal extends ModalView
onClickContinueFromOffer: (e) ->
url = {
'lost-viking': 'http://www.vikingcodeschool.com/codecombat?utm_source=codecombat&utm_medium=viking_level&utm_campaign=affiliate&ref=Code+Combat+Elite'
'a-mayhem-of-munchkins': 'https://www.bloc.io/web-developer-career-track?utm_campaign=affiliate&utm_source=codecombat&utm_medium=bloc_level'
}[@level.get('slug')]
Backbone.Mediator.publish 'router:navigate', @navigationEventUponCompletion
window.open url, '_blank' if url

View file

@ -106,6 +106,7 @@ module.exports = class SpellView extends CocoView
@ace.setAnimatedScroll true
@ace.setShowFoldWidgets false
@ace.setKeyboardHandler @keyBindings[aceConfig.keyBindings ? 'default']
@ace.$blockScrolling = Infinity
@toggleControls null, @writable
@aceSession.selection.on 'changeCursor', @onCursorActivity
$(@ace.container).find('.ace_gutter').on 'click mouseenter', '.ace_error, .ace_warning, .ace_info', @onAnnotationClick
@ -459,7 +460,7 @@ module.exports = class SpellView extends CocoView
entry.captureReturn = switch e.language
when 'io' then varName + ' := '
when 'javascript' then 'var ' + varName + ' = '
when 'clojure' then '(let [' + varName + ' '
when 'clojure' then '(let [' + varName + ' '
else varName + ' = '
# TODO: Generalize this snippet replacement

View file

@ -41,7 +41,7 @@ module.exports = class LevelGuideView extends CocoView
@docs = specific.concat(general)
@docs = $.extend(true, [], @docs)
@docs = [@docs[0]] if @firstOnly and @docs[0]
doc.html = marked(utils.i18n doc, 'body') for doc in @docs
doc.html = marked(@filterCodeLanguages(utils.i18n(doc, 'body'))) for doc in @docs
doc.name = (utils.i18n doc, 'name') for doc in @docs
doc.slug = _.string.slugify(doc.name) for doc in @docs
super()
@ -72,6 +72,12 @@ module.exports = class LevelGuideView extends CocoView
@$el.find('.nav-tabs a').click(@clickTab)
@playSound 'guide-open'
filterCodeLanguages: (text) ->
currentLanguage = me.get('aceConfig')?.language or 'python'
excludedLanguages = _.without ['javascript', 'python', 'coffeescript', 'clojure', 'lua', 'io'], currentLanguage
exclusionRegex = new RegExp "```(#{excludedLanguages.join('|')})\n[^`]+```\n?", 'gm'
text.replace exclusionRegex, ''
clickSubscribe: (e) ->
level = @levelSlug # Save ref to level slug
@openModalView new SubscribeModal()

View file

@ -32,13 +32,17 @@ exports.config =
overrides:
production:
sourceMaps: 'absoluteUrl'
onCompile: (files) ->
# For some reason, production brunch produces two entries, the first of which is wrong:
# //# sourceMappingURL=public/javascripts/app.js.map
# //# sourceMappingURL=/javascripts/app.js.map
# So we remove the ones that have public in them.
exec = require('child_process').exec
exec "perl -pi -e 's/\\/\\/# sourceMappingURL=public.*//g' public/javascripts/*.js"
plugins:
coffeelint:
pattern: /\A\Z/
afterBrunch: [
"coffee scripts/minify.coffee",
]
fast:
onCompile: (files) -> console.log "I feel the need, the need... for speed."
plugins:
coffeelint:
pattern: /\A\Z/
vagrant:
watcher:
usePolling: true
@ -181,7 +185,6 @@ exports.config =
plugins:
coffeelint:
pattern: /^app\/.*\.coffee$/
# pattern: /^dne/ # use this pattern instead if you want to speed compilation
options:
line_endings:
value: 'unix'
@ -192,16 +195,14 @@ exports.config =
level: 'ignore' # PyCharm can't just autostrip for .coffee, needed for .jade
no_unnecessary_fat_arrows:
level: 'ignore'
uglify:
mangle:
except: ['require']
output:
semicolons: false
sass:
mode: 'native'
allowCache: true
bless:
cacheBuster: false
assetsmanager:
copyTo:
'lib/ace': ['node_modules/ace-builds/src-min-noconflict/*']
modules:
definition: (path, data) ->

View file

@ -33,10 +33,11 @@
"test": "./node_modules/.bin/karma start",
"predeploy": "echo Starting deployment--hold onto your butts.; echo Skipping brunch build --production",
"postdeploy": "echo Deployed. Unclench.",
"postinstall": "bower install && brunch build",
"postinstall": "bower install && brunch build --env fast",
"brunch": "brunch",
"bower": "bower",
"dev": "brunch watch --server",
"multicore": "coffee multicore.coffee",
"nodemon": "nodemon"
},
"main": "index.js",
@ -48,6 +49,7 @@
],
"dependencies": {
"JQDeferred": "~2.1.0",
"ace-builds": "https://github.com/ajaxorg/ace-builds/archive/3fb55e8e374ab02ce47c1ae55ffb60a1835f3055.tar.gz",
"aether": "~0.3.0",
"async": "0.2.x",
"aws-sdk": "~2.0.0",
@ -80,15 +82,18 @@
"winston": "0.6.x"
},
"devDependencies": {
"after-brunch": "0.0.5",
"assetsmanager-brunch": "^1.8.1",
"auto-reload-brunch": "> 1.0 < 1.8",
"bless-brunch": "https://github.com/ThomasConner/bless-brunch/tarball/master",
"bower": "~1.6.4",
"brunch": "^1.8.5",
"coffee-script-brunch": "^1.8.3",
"coffeelint-brunch": "^1.7.1",
"compressible": "~1.0.1",
"commonjs-require-definition": "0.2.0",
"compressible": "~1.0.1",
"css-brunch": "^1.7.0",
"fs-extra": "^0.26.2",
"jade-brunch": "1.7.5",
"jasmine-node": "1.13.x",
"jasmine-spec-reporter": "~0.3.0",
@ -108,7 +113,7 @@
"requirejs": "~2.1.10",
"sass-brunch": "https://github.com/basicer/sass-brunch-bleeding/archive/1.9.1-bleeding.tar.gz",
"telepath-brunch": "https://github.com/nwinter/telepath-brunch/tarball/master",
"uglify-js-brunch": "^1.7.8"
"uglify-js": "^2.5.0"
},
"optionalDependencies": {
"webworker-threads": "~0.5.5"

View file

@ -17,8 +17,8 @@ try {
var scriptStartTime = new Date();
var analyticsStringCache = {};
// Look at last 30 days, same as Mixpanel
var numDays = 30;
var numDays = 32;
var daysInMonth = 30;
var startDay = new Date();
today = startDay.toISOString().substr(0, 10);
@ -27,6 +27,7 @@ try {
var levelCompletionFunnel = ['Started Level', 'Saw Victory'];
var levelHelpEvents = ['Problem alert help clicked', 'Spell palette help clicked', 'Start help video'];
var activeUserEvents = ['Finished Signup', 'Started Level'];
log("Today is " + today);
log("Start day is " + startDay);
@ -39,7 +40,7 @@ try {
for (day in levelCompletionData[level]) {
if (today === day) continue; // Never save data for today because it's incomplete
for (event in levelCompletionData[level][day]) {
insertEventCount(event, level, day, levelCompletionData[level][day][event]);
insertLevelEventCount(event, level, day, levelCompletionData[level][day][event]);
}
}
}
@ -50,7 +51,7 @@ try {
for (level in levelDropCounts) {
for (day in levelDropCounts[level]) {
if (today === day) continue; // Never save data for today because it's incomplete
insertEventCount('User Dropped', level, day, levelDropCounts[level][day]);
insertLevelEventCount('User Dropped', level, day, levelDropCounts[level][day]);
}
}
@ -61,7 +62,7 @@ try {
for (day in levelHelpCounts[level]) {
if (today === day) continue; // Never save data for today because it's incomplete
for (event in levelHelpCounts[level][day]) {
insertEventCount(event, level, day, levelHelpCounts[level][day][event]);
insertLevelEventCount(event, level, day, levelHelpCounts[level][day][event]);
}
}
}
@ -73,11 +74,22 @@ try {
for (day in levelSubscriptionCounts[level]) {
if (today === day) continue; // Never save data for today because it's incomplete
for (event in levelSubscriptionCounts[level][day]) {
insertEventCount(event, level, day, levelSubscriptionCounts[level][day][event]);
insertLevelEventCount(event, level, day, levelSubscriptionCounts[level][day][event]);
}
}
}
log("Getting active user counts...");
var activeUserCounts = getActiveUserCounts(startDay, activeUserEvents);
// printjson(activeUserCounts);
log("Inserting active user counts...");
for (day in activeUserCounts) {
if (today === day) continue; // Never save data for today because it's incomplete
for (event in activeUserCounts[day]) {
insertEventCount(event, day, activeUserCounts[day][event]);
}
}
log("Script runtime: " + (new Date() - scriptStartTime));
}
catch(err) {
@ -383,7 +395,87 @@ function getLevelSubscriptionCounts(startDay) {
return levelFunnelData;
}
function insertEventCount(event, level, day, count) {
function getActiveUserCounts(startDay, activeUserEvents) {
// Counts active users per day
if (!startDay) return {};
var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z"));
var queryParams = {$and: [
{_id: {$gte: startObj}},
{'event': {$in: activeUserEvents}}
]};
var cursor = logDB['log'].find(queryParams);
var dayUserMap = {};
while (cursor.hasNext()) {
var doc = cursor.next();
var created = doc._id.getTimestamp().toISOString();
var day = created.substring(0, 10);
var user = doc.user;
if (!dayUserMap[day]) dayUserMap[day] = {};
dayUserMap[day][user] = true;
}
// printjson(dayUserMap['2015-11-01']);
var activeUsersCounts = {};
var monthlyActives = [];
for (day in dayUserMap) {
activeUsersCounts[day] = {'Daily Active Users': Object.keys(dayUserMap[day]).length};
monthlyActives.push({day: day, users: dayUserMap[day]});
}
monthlyActives.sort(function (a, b) {return a.day.localeCompare(b.day);});
// Calculate monthly actives for each day, starting when we have enough data
for (var i = daysInMonth - 1; i < monthlyActives.length; i++) {
var monthUserMap = {};
for (var j = i - daysInMonth + 1; j <= i; j++) {
for (var user in monthlyActives[j].users) {
monthUserMap[user] = true;
}
}
activeUsersCounts[monthlyActives[i].day]['Monthly Active Users'] = Object.keys(monthUserMap).length;
}
return activeUsersCounts;
}
function insertEventCount(event, day, count) {
// analytics.perdays schema in server/analytics/AnalyticsPeryDay.coffee
day = day.replace(/-/g, '');
var eventID = getAnalyticsString(event);
var filterID = getAnalyticsString('all');
var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z"));
var queryParams = {$and: [{d: day}, {e: eventID}, {f: filterID}]};
var doc = db['analytics.perdays'].findOne(queryParams);
if (doc && doc.c === count) return;
if (doc && doc.c !== count) {
// Update existing count, assume new one is more accurate
// log("Updating count in db for " + day + " " + event + " " + doc.c + " => " + count);
var results = db['analytics.perdays'].update(queryParams, {$set: {c: count}});
if (results.nMatched !== 1 && results.nModified !== 1) {
log("ERROR: update event count failed");
printjson(results);
}
}
else {
var insertDoc = {d: day, e: eventID, f: filterID, c: count};
var results = db['analytics.perdays'].insert(insertDoc);
if (results.nInserted !== 1) {
log("ERROR: insert event failed");
printjson(results);
printjson(insertDoc);
}
// else {
// log("Added " + day + " " + event + " " + count);
// }
}
}
function insertLevelEventCount(event, level, day, count) {
// analytics.perdays schema in server/analytics/AnalyticsPeryDay.coffee
day = day.replace(/-/g, '');

61
scripts/minify.coffee Normal file
View file

@ -0,0 +1,61 @@
path = require 'path'
fs = require 'fs-extra'
_ = require 'lodash'
async = require 'async'
cores = require('os').cpus().length
child_process = require 'child_process'
root = path.join(__dirname, '..', 'public','javascripts');
dest = path.join(__dirname, '..', 'public','javascripts-min');
console.log root
dirStack = [path.join(root)]
files = []
while dirStack.length
dir = dirStack.pop()
contents = fs.readdirSync(dir)
for file in contents
fullPath = "#{dir}/#{file}"
stat = fs.statSync(fullPath)
if stat.isDirectory()
dirStack.push(fullPath)
else if /\.js$/.test(file)
files.push fullPath.replace root + '/', ''
jobs = _.map files, (file) ->
(cb2) ->
fpath = path.join(root, file)
dpath = path.join(dest, file)
smArgs = []
if fs.existsSync fpath + '.map'
smArgs = [
'--in-source-map', fpath + '.map',
'--source-map', dpath + '.map',
'--source-map-include-sources',
'--source-map-url', '/javascripts/' + file.replace('/\\/g', '/') + '.map'
]
args = [fpath, '-m', '-r', 'require' , '-b', 'beautify=false,semicolons=false'].concat smArgs, ['-o', dpath]
async.waterfall [
_.bind(fs.mkdirs, fs, path.dirname dpath),
(last, cb) ->
child = child_process.spawn 'uglifyjs', args, stdio:'inherit'
child.on 'close', (code) ->
if code == 0 then cb null
else cb code
child.on 'error', (err) ->
cb err
], cb2
async.parallelLimit jobs, cores, (err, res)->
if err
console.log "ERROR:", err
else
console.log "Done, minified " + jobs.length + " files."
fs.renameSync(root, root + "-old")
fs.renameSync(dest, root)
fs.removeSync(root + "-old")

View file

@ -14,6 +14,7 @@ class AnalyticsPerDayHandler extends Handler
getByRelationship: (req, res, args...) ->
return @sendForbiddenError res unless @hasAccess req
return @getActiveUsers(req, res) if args[1] is 'active_users'
return @getCampaignCompletionsBySlug(req, res) if args[1] is 'campaign_completions'
return @getLevelCompletionsBySlug(req, res) if args[1] is 'level_completions'
return @getLevelDropsBySlugs(req, res) if args[1] is 'level_drops'
@ -21,6 +22,29 @@ class AnalyticsPerDayHandler extends Handler
return @getLevelSubscriptionsBySlugs(req, res) if args[1] is 'level_subscriptions'
super(arguments...)
getActiveUsers: (req, res) ->
AnalyticsString.find({v: {$in: ['Daily Active Users', 'Monthly Active Users']}}).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
for doc in documents
dailyID = doc._id if doc.v is 'Daily Active Users'
monthlyID = doc._id if doc.v is 'Monthly Active Users'
return @sendSuccess res, [] unless dailyID? and monthlyID?
AnalyticsPerDay.find({e: {$in: [dailyID, monthlyID]}}).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
dayCountsMap = {}
for doc in documents
dayCountsMap[doc.d] ?= {}
dayCountsMap[doc.d]['dailyCount'] = doc.c if doc.e is dailyID
dayCountsMap[doc.d]['monthlyCount'] = doc.c if doc.e is monthlyID
activeUsers = []
for key, val of dayCountsMap
data = day: key
data.dailyCount = val.dailyCount if val.dailyCount
data.monthlyCount = val.monthlyCount if val.monthlyCount
activeUsers.push data
@sendSuccess(res, activeUsers)
getCampaignCompletionsBySlug: (req, res) ->
# Send back an ordered array of level per-day starts and finishes
# Parameters:

View file

@ -166,6 +166,9 @@ module.exports = class Handler
res.end()
if term
filter.filter.$text = $search: term
else if filters.length is 1 and filters[0].filter?.index is true
# All we are doing is an empty text search, but that doesn't hit the index, so we'll just look for the slug.
filter.filter = slug: {$exists: true}
args = [filter.filter]
args.push projection if projection
q = @modelClass.find(args...)

View file

@ -21,6 +21,7 @@ LevelSchema.index(
'language_override': 'searchLanguage'
'textIndexVersion': 2
})
LevelSchema.index(
{
original: 1
@ -32,6 +33,7 @@ LevelSchema.index(
unique: true
})
LevelSchema.index({slug: 1}, {name: 'slug index', sparse: true, unique: true})
LevelSchema.index({index: 1}, {name: 'index index', sparse: true}) # because we can't use the text search index with no term
LevelSchema.plugin(plugins.NamedPlugin)
LevelSchema.plugin(plugins.PermissionsPlugin)

View file

@ -44,6 +44,7 @@ LevelSessionSchema.post 'init', (doc) ->
LevelSessionSchema.pre 'save', (next) ->
User = require '../../users/User' # Avoid mutual inclusion cycles
Level = require '../Level'
@set('changed', new Date())
id = @get('id')
@ -54,12 +55,20 @@ LevelSessionSchema.pre 'save', (next) ->
# Newly completed level
if not (initd and @previousStateInfo['state.complete']) and @get('state.complete')
User.findByIdAndUpdate userID, {$inc: 'stats.gamesCompleted': 1}, {}, (err, doc) ->
Level.findOne({slug: levelID}).select('concepts -_id').lean().exec (err, level) ->
log.error err if err?
oldCopy = doc.toObject()
oldCopy.stats = _.clone oldCopy.stats
oldCopy.stats.gamesCompleted = oldCopy.stats.gamesCompleted - 1
User.schema.statics.createNewEarnedAchievements doc, oldCopy
update = $inc: {'stats.gamesCompleted': 1}
for concept in level?.concepts ? []
update.$inc["stats.concepts.#{concept}"] = 1
User.findByIdAndUpdate userID, update, {}, (err, user) ->
log.error err if err?
oldCopy = user.toObject()
oldCopy.stats = _.clone oldCopy.stats
--oldCopy.stats.gamesCompleted
oldCopy.stats.concepts ?= {}
for concept in level?.concepts ? []
--oldCopy.stats.concepts[concept]
User.schema.statics.createNewEarnedAchievements user, oldCopy
activeUserEvent = "level-completed/#{levelID}"
# Spent at least 30s playing this level

View file

@ -192,7 +192,14 @@ UserSchema.statics.incrementStat = (id, statName, done, inc=1) ->
user.incrementStat statName, done, inc
UserSchema.methods.incrementStat = (statName, done, inc=1) ->
@set statName, (@get(statName) or 0) + inc
if /^concepts\./.test statName
# Concept stats are nested a level deeper.
concepts = @get('concepts') or {}
concept = statName.split('.')[1]
concepts[concept] = (concepts[concept] or 0) + inc
@set 'concepts', concepts
else
@set statName, (@get(statName) or 0) + inc
@save (err) -> done?(err)
UserSchema.statics.unconflictName = unconflictName = (name, done) ->

View file

@ -80,14 +80,13 @@ setupPassportMiddleware = (app) ->
setupCountryRedirectMiddleware = (app, country="china", countryCode="CN", languageCode="zh", serverID="tokyo") ->
shouldRedirectToCountryServer = (req) ->
firstLanguage = req.acceptedLanguages[0]
speaksLanguage = firstLanguage and firstLanguage.indexOf(languageCode) isnt -1
speaksLanguage = _.any req.acceptedLanguages, (language) -> language.indexOf languageCode isnt -1
unless config[serverID]
ip = req.headers['x-forwarded-for'] or req.connection.remoteAddress
ip = ip?.split(/,? /)[0] # If there are two IP addresses, say because of CloudFlare, we just take the first.
geo = geoip.lookup(ip)
#if speaksLanguage or geo?.country is countryCode
# log.info("Should we redirect to #{serverID} server? speaksLanguage: #{speaksLanguage}, firstLanguage: #{firstLanguage}, ip: #{ip}, geo: #{geo} -- so redirecting? #{geo?.country is 'CN' and speaksLanguage}")
# log.info("Should we redirect to #{serverID} server? speaksLanguage: #{speaksLanguage}, acceptedLanguages: #{req.acceptedLanguages}, ip: #{ip}, geo: #{geo} -- so redirecting? #{geo?.country is 'CN' and speaksLanguage}")
return geo?.country is countryCode and speaksLanguage
else
#log.info("We are on #{serverID} server. speaksLanguage: #{speaksLanguage}, acceptedLanguages: #{req.acceptedLanguages[0]}")

View file

@ -1,4 +0,0 @@
require('coffee-script')
require('coffee-script/register')
server = require('./server')
server.startServer()