Merge branch 'master' into course-correction

Some package scripts got in the way of each other
This commit is contained in:
Scott Erickson 2015-11-09 18:18:02 -08:00
commit 0c5b39e029
93 changed files with 1032 additions and 3247 deletions

View file

@ -29,10 +29,12 @@ Whether you're novice or pro, the CodeCombat team is ready to help you implement
![Scott Erickson](http://codecombat.com/images/pages/about/scott_small.png)
![Matt Lott](http://codecombat.com/images/pages/about/matt_small.png)
![Catherine Weresow](http://codecombat.com/images/pages/about/cat_small.png)
![Maka Gradin](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Maka%20Gradin/maka_gradin_100.png)
![Rob Blanckaert](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Rob%20Blanckaert/rob_blanckaert_100.png)
![Michael Schmatz](http://codecombat.com/images/pages/about/michael_small.png)
![Josh Lee](http://codecombat.com/images/pages/about/josh_small.png)
![Jeremy Arns](http://codecombat.com/images/pages/about/jeremy_small.png)
![Alex Cotsarelis](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Alex%20Cotsarelis/alex_100.png)
![Alex Crooks](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Alex%20Crooks/alex_100.png)
![Alexandru Caciulescu](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Alexandru%20Caciulescu/alexandru_100.png)
![Andreas Linn](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Andreas%20Linn/andreas_100.png)
![Andrew Witcher](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Andrew%20Witcher/andrew_100.png)
@ -40,22 +42,32 @@ Whether you're novice or pro, the CodeCombat team is ready to help you implement
![Bang Honam](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Bang%20Honam/bang_100.png)
![Benjamin Stern](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Benjamin%20Stern/benjamin_100.png)
![Brad Dickason](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Brad%20Dickason/brad_100.png)
![Carlos Maia](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Carlos%20Maia/carlos_maia_100.png)
![Chloe Fan](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Chloe%20Fan/chloe_100.png)
![Dan Ristic](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Dan%20Ristic/dan_100.png)
![Danny Whittaker](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Danny%20Whittaker/danny_100.png)
![David Liu](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/David%20Liu/david_liu_100.png)
![David Pendray](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/David%20Pendray/david_100.png)
![Deepak1556](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Deepak1556/deepak_100.png)
![Derek Wong](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Derek%20Wong/derek_100.png)
![Dominik Kundel](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Dominik%20Kundel/dominik_k_100.png)
![Glen De Cauwsemaecker](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Glen%20de%20Cauwsemaecker/glen_100.png)
![Ian Li](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Ian%20Li/ian_100.png)
![Jeremy Arns](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Jeremy%20Arns/jeremy_100.png)
![Joachim Brehmer](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Joachim%20Brehmer/joachim_100.png)
![Jose Antonini](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Jose%20Antonini/jose_antonini_100.png)
![Katharine Chan](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Katharine%20Chan/katharine_100.png)
![Ken Stanley](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Ken%20Stanley/ken_100.png)
![Kevin Holland](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Kevin%20Holland/kevin_100.png)
![Laura Watiker](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Laura%20Watiker/laura_100.png)
![Michael Heasell](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Michael%20Heasell/michael_100.png)
![Michael Polyak](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Michael%20Polyak/michael_100.png)
![Mischa Lewis-Norelle](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Mischa%20Lewis-Norelle/mischa_100.png)
![Nathan Gosset](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Nathan%20Gosset/nathan_100.png)
![Oleg Ulyanicky](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Oleg%20Ulyanickiy/oleg_100.png)
![Paul Buser](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Paul%20Buser/paul_100.png)
![Pavel Konstantynov](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Pavel%20Konstantinov/pavel_100.png)
![Popey Gilbert](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Popey%20Gilbert/popey_100.png)
![Prabhsimran Baweja](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Prabhsimran%20Baweja/prabhsimran_100.png)
![Rachel Xiang](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Rachel%20Xiang/rachel_100.png)
![Rebecca Saines](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Rebecca%20Saines/rebecca_100.png)
@ -69,13 +81,3 @@ Whether you're novice or pro, the CodeCombat team is ready to help you implement
![Tom Steinbrecher](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Tom%20Steinbrecher/tom_100.png)
![Yang Shun Tay](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Yang%20Shun%20Tay/yang_shun_tay_100.png)
![Zach Martin](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Zach%20Martin/zack_100.png)
![Alex Crooks](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Alex%20Crooks/alex_100.png)
![Danny Whittaker](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Danny%20Whittaker/danny_100.png)
![Kevin Holland](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Kevin%20Holland/kevin_100.png)
![Joachim Brehmer](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Joachim%20Brehmer/joachim_100.png)
![Jose Antonini](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Jose%20Antonini/jose_antonini_100.png)
![Oleg Ulyanicky](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Oleg%20Ulyanickiy/oleg_100.png)
![Pavel Konstantynov](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Pavel%20Konstantinov/pavel_100.png)
![Popey Gilbert](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Popey%20Gilbert/popey_100.png)
![Rob Blanckaert](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Rob%20Blanckaert/rob_blanckaert_100.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

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

@ -259,8 +259,6 @@
victory_new_item: "New Item"
victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
victory_become_a_viking: "Become a 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"
guide_title: "Guide"
tome_minion_spells: "Your Minions' Spells" # Only in old-style levels.
tome_read_only_spells: "Read-Only Spells" # Only in old-style levels.
@ -363,7 +361,6 @@
auth_caption: "Save your progress."
leaderboard:
leaderboard: "Leaderboard"
view_other_solutions: "View Leaderboards"
scores: "Scores"
top_players: "Top Players by"
@ -604,6 +601,10 @@
retrostyle_blurb: "RetroStyle Games"
rob_title: "Compiler Engineer"
rob_blurb: "Codes things and stuff"
josh_c_title: "Game Designer"
josh_c_blurb: "Designs games"
carlos_title: "Region Manager"
carlos_blurb: "CodeCombat Brazil"
teachers:
more_info: "More Info for Teachers"
@ -895,9 +896,6 @@
send_invites: "Send Invites"
title: "Title"
description: "Description"
languages_available: "Select programming languages available to the class:"
all_lang: "All Languages"
show_progress: "Show student progress to everyone in the class"
creating_class: "Creating class..."
purchasing_course: "Purchasing course..."
buy_course: "Buy Course"
@ -1212,12 +1210,6 @@
last_earned: "Last Earned"
amount_achieved: "Amount"
achievement: "Achievement"
category_contributor: "Contributor"
category_ladder: "Ladder"
category_level: "Level"
category_miscellaneous: "Miscellaneous"
category_levels: "Levels"
category_undefined: "Uncategorized"
current_xp_prefix: ""
current_xp_postfix: " in total"
new_xp_prefix: ""
@ -1227,8 +1219,6 @@
left_xp_postfix: ""
account:
recently_played: "Recently Played"
no_recent_games: "No games played during the past two weeks."
payments: "Payments"
prepaid_codes: "Prepaid Codes"
purchased: "Purchased"

View file

@ -839,16 +839,16 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
playtime: "Tiempo de juego"
last_played: "Último jugado"
leagues_explanation: "Juega en una liga contra otros miembros del clan en estas instancias de arena multijugador."
# track_concepts1: "Track concepts"
track_concepts1: "Haga un seguimiento de los conceptos"
track_concepts2a: "aprendidos por cada estudiante"
track_concepts2b: "aprendidos por cada miembro"
# track_concepts3a: "Track levels completados por cada estudiante"
# track_concepts3b: "Track levels completados por cada miembro"
track_concepts3a: "Haga un seguimiento de los niveles completados por cada estudiante"
track_concepts3b: "Haga un seguimiento de los niveles completados por cada miembro"
track_concepts4a: "Ve a tus estudiantes'"
track_concepts4b: "Ve a tus miembros'"
track_concepts5: "soluciones"
# track_concepts6a: "Sort students by name or progress"
# track_concepts6b: "Sort members by name or progress"
track_concepts6a: "Ordene a sus estudiantes por nombre o progreso"
track_concepts6b: "Ordene a sus miembros por nombre o progreso"
track_concepts7: "Requiere invitación"
track_concepts8: "para unirse"
private_require_sub: "Los clanes privados requieren una subscripción para crearlos o unírseles."
@ -886,7 +886,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
invite_students: "Invite a sus estudiantes a unirse a este grupo."
invite_link_header: "Enlace para unirse al curso"
invite_link_p_1: "Proporciones este enalce a los estudiantes que desee que se unan al curso."
# invite_link_p_2: "Or have us email them directly:"
invite_link_p_2: "O envíenoslos directamente mediante el correo electrónico:"
capacity_used: "Espacios de curso usados:"
enter_emails: "Introducir los emails de los estudiantes a invitar, uno por línea"
send_invites: "¿Mandar Invitaciones?"
@ -1269,13 +1269,13 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
purchase_button: "Enviar Adquisición"
your_codes: "Tus Códigos:" # {change}
redeem_codes: "Reclamar un Código de Subscripción"
# prepaid_code: "Prepaid Code"
prepaid_code: "Código Prepagado"
# lookup_code: "Lookup prepaid code"
# apply_account: "Apply to your account"
# copy_link: "You can copy the code's link and send it to someone."
# quantity: "Quantity"
# redeemed: "Redeemed"
# no_codes: "No codes yet!"
quantity: "Cantidad"
redeemed: "Reclamado"
no_codes: "¡Aún sin códigos!"
loading_error:
could_not_load: "Error cargando del servidor"

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

@ -1,6 +1,6 @@
module.exports = nativeDescription: "Українська", englishDescription: "Ukrainian", translation:
home:
slogan: "Навчіться програмувати, граючи у гру"
slogan: "Навчіться програмувати граючи"
no_ie: "На жаль, CodeCombat не працює в IE8 та старіших версіях!" # Warning that only shows up in IE8 and older
no_mobile: "CodeCombat не призначений для мобільних пристроїв і може не працювати!" # Warning that shows up on mobile devices
play: "Грати" # The big play button that opens up the campaign view.
@ -31,7 +31,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
contact: "Контакти"
twitter_follow: "Фоловити"
teachers: "Учителям"
# careers: "Careers"
careers: "Робота"
modal:
close: "Закрити"
@ -74,7 +74,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
anonymous: "Гравець-анонім"
level_difficulty: "Складність: "
campaign_beginner: "Кампанія для початківців"
awaiting_levels_adventurer_prefix: "Ми випускаємо 5 рівнів на тиждень." # {change}
awaiting_levels_adventurer_prefix: "Ми щотижня додаємо нові рівні."
awaiting_levels_adventurer: "Увійди як Шукач пригод"
awaiting_levels_adventurer_suffix: "стань одним з перших, хто їх спробує."
adjust_volume: "Підлаштувати гучність"
@ -84,12 +84,12 @@ module.exports = nativeDescription: "Українська", englishDescription:
# campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."
share_progress_modal:
blurb: "Ви робите великі успіхи! Розкажіть кому-небудь, як багато ви вивчили з CodeCombat." # {change}
blurb: "У тебе гарно виходить! Розкажи своїм батькам як багато ти знаєш завдяки CodeCombat."
email_invalid: "Невірна електронна адреса."
form_blurb: "Введіть їхні електронні адреси, і ми покажемо ім!"
form_label: "Електронна адреса"
placeholder: "електронна адреса"
title: "Досконала робота, Учень"
title: "Досконала робота, учню"
login:
sign_up: "створення акаунту"
@ -161,7 +161,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
withdrawn: "Відкликано"
accept: "Прийняти"
reject: "Відхилити"
# withdraw: "Withdraw"
withdraw: "Відкликати"
submitter: "Відправник"
submitted: "Відправлено"
commit_msg: "Доручити повідомлення"
@ -343,7 +343,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
tip_free_your_mind: "Нео, ти повинен усе подолати. Страх... сумніви і невіра. Звільни від них свій розум. - Морфіус"
tip_strong_opponents: "Навіть наймогутніший суперник має свою слабкість. - Ітачі Учіха"
tip_paper_and_pen: "Перш ніж почати програмувати, ви завжди можете спробувати з аркушем паперу і ручкою."
# tip_solve_then_write: "First, solve the problem. Then, write the code. - John Johnson"
tip_solve_then_write: "Спершу вирішуй проблему, а потім - пиши код. - Джон Джонсон"
game_menu:
inventory_tab: "Інвентар"
@ -404,9 +404,9 @@ module.exports = nativeDescription: "Українська", englishDescription:
subscribe:
comparison_blurb: "Відточіть свої навички завдяки підписці на CodeCombat!"
feature1: "Більше 60 основних рівней на просторах 4 світів" # {change}
feature2: "7 могутніх <strong>нових героїв</strong> з унікальними здібностями!" # {change}
feature3: "Більше 30 бонусних рівнів" # {change}
feature1: "Більше 110 основних рівней на просторах 4 світів"
feature2: "10 могутніх <strong>нових героїв</strong> з унікальними здібностями!"
feature3: "Більше 80-ти бонусних рівнів"
feature4: "<strong>3500 бонусних самоцвітів</strong> кожного місяця!"
feature5: "Навчальні відеоролики"
feature6: "Екслюзивна підтримка по електронній пошті"
@ -432,8 +432,8 @@ module.exports = nativeDescription: "Українська", englishDescription:
parent_email_sent: "Лист відправлено!"
parent_email_title: "Яка в твоїх батьків електронна адреса?"
parents: "Батькам"
parents_title: "Ваша дитина вчитиметься програмувати." # {change}
parents_blurb1: "Разом з CodeCombat Ваша дитина писатиме реальний код. Почне з простих команд та поступово буде розвиватись до складніших тем."
parents_title: "Дорога мамо/батьку, ваша дитина вчиться програмувати. Чи допоможите ви їй продовжити цю спрову?" # {change}
parents_blurb1: "Разом з CodeCombat Ваша дитина писатиме реальний код. Почне з простих команд та поступово буде розвиватись до складніших тем." # {change}
parents_blurb1a: "Коп'ютерне програмування є необхідними вмінням, що ваша дитина беззаперечно використовуватиме у дорослому віці. До 2020 року 77% професій потребуватимуть базових навичок у програмному забезпечені, а програмісти надзвичайно потрібні у всьому світі. Чи знали ви, що Комп'ютерні Науки - це найбільш високооплачувана університетьська спеціальність?"
parents_blurb2: "За 9.99$ на місяць, вона отримуватиме нові завдання щотижня та персональні листи підтримки від професійних програмістів." # {change}
parents_blurb3: "Жодного ризику: 100% гарантія повернення грошей, легке скасування абонементу одним кліком."
@ -455,7 +455,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
sale_continue: "Готовий продовжити пригоди?"
sale_limited_time: "Обмежена пропозиція!"
sale_new_heroes: "Нові герої!"
# sale_title: "Back to School Sale"
sale_title: "Дошкільні знижки"
sale_view_button: "Купити 1 рік підписки на"
stripe_description: "Щомісячний абонемент"
stripe_description_year_sale: "1 рік підписки (35% знижка)"
@ -473,7 +473,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
managed_subs_desc_2: "Одержувачі повинні мати обліковий запис CodeCombat, пов'язаний з вказаною Вами адресою електронної пошти."
group_discounts: "Групові знижки"
group_discounts_1: "Ми також пропонуємо знижки для пакетних передплат."
group_discounts_1st: "1-ий абонемент (включає Ваш)" # {change}
group_discounts_1st: "1-ий абонемент"
group_discounts_full: "Повна ціна"
group_discounts_2nd: "2-11 абонементи"
group_discounts_20: "Знижка 20%"
@ -485,7 +485,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
users_subscribed: "Підписані користувачі:"
no_users_subscribed: "Користувачі не підписані, будь ласка, перевірте Ваші ел. адреси."
current_recipients: "Поточні отримувачі"
unsubscribing: "Скасування передплати..." # {change}
unsubscribing: "Триває скасування підписки..."
subscribe_prepaid: "Натисніть Підписатися щоб використовувати передплачені коди"
using_prepaid: "Використати передплачений код для щомісячної підписки"
@ -583,15 +583,15 @@ module.exports = nativeDescription: "Українська", englishDescription:
press_paragraph_1_link: "набору-для-преси"
press_paragraph_1_suffix: ". Всі логотипи та зображення можна використовувати, не зв'язуючись із нами напряму."
team: "Команда"
george_title: "Виконавчий директор" # {change}
george_title: "Співзасновник"
george_blurb: "Бізнесмен"
scott_title: "Програміст" # {change}
scott_title: "Співзасновник"
scott_blurb: "Розумник"
nick_title: "Програміст" # {change}
nick_title: "Співзасновник"
nick_blurb: "Ґуру мотивації"
michael_title: "Програміст"
michael_blurb: "Сисадмін"
matt_title: "Програміст" # {change}
matt_title: "Співзасновник"
matt_blurb: "Велосипедист"
cat_title: "Головний ремісник"
cat_blurb: "Маг повітря"
@ -603,7 +603,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
retrostyle_blurb: "Ігри в стилі ретро"
teachers:
# more_info: "More Info for Teachers"
more_info: "Додаткова інформація для вчителів"
intro_1: "CodeCombat - це онлайн гра, що вчить програмуванню. Студенти пишуть код на реальних мовах програмування."
intro_2: "Досвід не потрібен!"
free_title: "Скільки це коштує?"
@ -617,12 +617,12 @@ module.exports = nativeDescription: "Українська", englishDescription:
teacher_subs_3: "щоб налаштувати підписку."
sub_includes_title: "Що входить у підписку?"
sub_includes_1: "На додаток до 110+ основних рівнів, студенти з щомісячною підпискою отримають доступ до цих додаткових функцій:"
sub_includes_2: "70 + рівнів практики" # {change}
sub_includes_2: "80+ рівнів практики"
sub_includes_3: "Відео уроки"
sub_includes_4: "Преміум підтримка по електронній пошті"
sub_includes_5: "10 нових героїв з унікальними навичками для оволодіння"
sub_includes_6: "3500 бонусних дорогоцінних каменів кожен місяць"
sub_includes_7: "Приватні Клани"
sub_includes_6: "3500 бонусних самоцвітів кожен місяць"
sub_includes_7: "Приватні клани"
monitor_progress_title: "Як мені стежити за прогресом студентів?"
monitor_progress_1: "Прогрес студентів може бути відстежити, створивши"
monitor_progress_2: "для вашого класу."
@ -651,8 +651,8 @@ module.exports = nativeDescription: "Українська", englishDescription:
more_info_2: "вчительський форум"
more_info_3: "є гарним місцем для спілкування із колегами-педагогами, котрі використовують CodeCombat."
sys_requirements_title: "Системні вимоги"
sys_requirements_1: "Оскільки CodeCombat — це гра, для нормальної роботи він вимагає у комп'ютерів більше, ніж відео чи текстові посібники. Ми оптимізували його для швидкої роботи в усіх сучасних браузерах і на старіших машинах, щоб кожен міг грати. І ось наші підказки, як отримати від CodeCombat якнайбільше:" # {change}
sys_requirements_2: "Використовуйте новіші версії Chrome або Firefox." # {change}
sys_requirements_1: "Сучасний веб-переглядач. Остання версія Chrome, Firefox або Safari. Internet Explorer 9 та вище."
sys_requirements_2: "CodeCombat наразі не підтримується на iPad."
teachers_survey:
title: "Анкета вчителя"
@ -727,8 +727,8 @@ module.exports = nativeDescription: "Українська", englishDescription:
admin: "Aдмін"
new_password: "Новий пароль"
new_password_verify: "Підтвердження паролю"
type_in_email: "Введіть свій email, щоб підтвердити вилучення" # {change}
type_in_password: "Так само введіть ваш пароль."
type_in_email: "Введіть свій email, аби підтвердити вилучення екаунту."
type_in_password: "Також, введіть свій пароль."
email_subscriptions: "Email-підписки"
email_subscriptions_none: "Жодних підписок."
email_announcements: "Оголошення"
@ -840,16 +840,16 @@ module.exports = nativeDescription: "Українська", englishDescription:
last_played: "Остання гра"
leagues_explanation: "Грайте в лізі проти інших членів клану на мультіплєєрній арені."
# track_concepts1: "Track concepts"
# track_concepts2a: "learned by each student"
# track_concepts2b: "learned by each member"
track_concepts2a: "вивчено усіма студентами"
track_concepts2b: "вивчено усіма учасниками"
# track_concepts3a: "Track levels completed for each student"
# track_concepts3b: "Track levels completed for each member"
# track_concepts4a: "See your students'"
# track_concepts4b: "See your members'"
# track_concepts5: "solutions"
track_concepts5: "рішення"
# track_concepts6a: "Sort students by name or progress"
# track_concepts6b: "Sort members by name or progress"
# track_concepts7: "Requires invitation"
track_concepts7: "Потребує запрошення"
# track_concepts8: "to join"
# private_require_sub: "Private clans require a subscription to create or join."
@ -1183,11 +1183,11 @@ module.exports = nativeDescription: "Українська", englishDescription:
rules: "Правила"
winners: "Переможці"
league: "Ліга"
# red_ai: "Red AI" # "Red AI Wins", at end of multiplayer match playback
# blue_ai: "Blue AI"
# wins: "Wins" # At end of multiplayer match playback
# humans: "Red" # Ladder page display team name
# ogres: "Blue"
red_ai: "Червоний ШІ" # "Red AI Wins", at end of multiplayer match playback
blue_ai: "Синій ШІ"
wins: "переміг" # At end of multiplayer match playback
humans: "Червоний" # Ladder page display team name
ogres: "Синій"
user:
stats: "Статистика"
@ -1258,22 +1258,22 @@ module.exports = nativeDescription: "Українська", englishDescription:
retrying: "Помилка сервера, повторна спроба."
success: "Успішно оплачено. Дякуємо!"
# account_prepaid:
account_prepaid:
# purchase_code: "Purchase a Subscription Code"
# purchase_code1: "Subscription Codes can be redeemed to add premium subscription time to one or more CodeCombat accounts."
# purchase_code2: "Each CodeCombat account can only redeem a particular Subscription Code once."
# purchase_code3: "Subscription Code months will be added to the end of any existing subscription on the account."
# users: "Users"
# months: "Months"
# purchase_total: "Total"
users: "Користувачі"
months: "Місяці"
purchase_total: "Загалом"
# purchase_button: "Submit Purchase"
# your_codes: "Your Codes"
# redeem_codes: "Redeem a Subscription Code"
# prepaid_code: "Prepaid Code"
# lookup_code: "Lookup prepaid code"
# apply_account: "Apply to your account"
apply_account: "Застосувати до свого екаунту"
# copy_link: "You can copy the code's link and send it to someone."
# quantity: "Quantity"
quantity: "Кількіть"
# redeemed: "Redeemed"
# no_codes: "No codes yet!"
@ -1350,12 +1350,12 @@ module.exports = nativeDescription: "Українська", englishDescription:
arrays: "Масиви"
basic_syntax: "Базовий синтаксис"
boolean_logic: "Булева логіка"
# break_statements: "Break Statements"
break_statements: "Оператори зупинки"
classes: "Класи"
# continue_statements: "Continue Statements"
continue_statements: "Оператори продовження"
for_loops: "Цикл For"
functions: "Функції"
# graphics: "Graphics"
graphics: "Графіка"
if_statements: "Умовні оператори"
input_handling: "Обробка введення"
math_operations: "Математичні операції"
@ -1490,7 +1490,7 @@ module.exports = nativeDescription: "Українська", englishDescription:
next_photo: "додайте необов’язкове професійне фото."
next_active: "відзначте що Ви у пошуках пропозицій, щобвідображатися у пошуку."
example_blog: "Блог"
example_personal_site: "Особиста Сторінка"
example_personal_site: "Персональний сайт"
links_header: "Особисті Посилання"
links_blurb: "Посилання на інші сторінки або профілі, які б ви хотіли вказати. Наприклад: аккаунт на GitHub'і, LinkedIn, або ваш блог. "
links_name: "Назва посилання"

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,16 @@
#admin-analytics-view
#site-content-area
width: 100%
.big-stat
width: auto
.active-classes
color: blue
.recurring-revenue
color: green
.active-users
color: red
.count
font-size: 70pt
.description
font-size: 8pt

View file

@ -183,4 +183,24 @@ block content
p(data-i18n="about.rob_title")
| Compiler Engineer
p(data-i18n="about.rob_blurb")
| Codes things and stuff
| Codes things and stuff.
img(src="/images/pages/about/placeholder.png").img-thumbnail
.team_bio
h4.team_name
| Josh Callebaut
p(data-i18n="about.josh_c_title")
| Game Designer
p(data-i18n="about.josh_c_blurb")
| Designs games.
li.row
img(src="/images/pages/about/carlos_small.png").img-thumbnail
.team_bio
h4.team_name
| Carlos Maia
p(data-i18n="about.carlos_title")
| Region Manager
p(data-i18n="about.carlos_blurb")
| CodeCombat Brazil

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,61 @@
extends /templates/base
block content
if me.isAdmin()
.container-fluid
.row
.col-md-5.big-stat.active-classes
if activeClasses.length > 0
div.description 30-day Active Classes
div.count= activeClasses[0].groups[activeClasses[0].groups.length - 1]
.col-md-5.big-stat.recurring-revenue
if revenue.length > 0
div.description 30-day Monthly Recurring Revenue
div.count $#{Math.round((revenue[0].groups[revenue[0].groups.length - 1]) / 100)}
.col-md-5.big-stat.active-users
if activeUsers.length > 0
div.description 30-day Active Users
div.count= activeUsers[0].monthlyCount
h1 Active Classes
table.table.table-striped.table-condensed
tr
th Day
for group in activeClassGroups
th= group.replace('Active classes', '')
each activeClass in activeClasses
tr
td= activeClass.day
each val in activeClass.groups
td= val
h1 Recurring Revenue
table.table.table-striped.table-condensed
tr
th Day
for group in revenueGroups
th= group.replace('DRR ', '')
each entry in revenue
tr
td= entry.day
each val in entry.groups
td $#{(val / 100).toFixed(2)}
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

@ -40,7 +40,7 @@ block content
a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.get('name')
else
a(href="/clans/#{clan.id}")= clan.get('name')
td= clan.get('members').length
td= clan.get('memberCount')
td
if idNameMap && idNameMap[clan.get('ownerID')]
a(href="/user/#{clan.get('ownerID')}")= idNameMap[clan.get('ownerID')]
@ -70,7 +70,7 @@ block content
a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.get('name')
else
a(href="/clans/#{clan.id}")= clan.get('name')
td= clan.get('members').length
td= clan.get('memberCount')
td
if idNameMap && idNameMap[clan.get('ownerID')]
a(href="/user/#{clan.get('ownerID')}")= idNameMap[clan.get('ownerID')]

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

@ -3,7 +3,7 @@ extends /templates/base
block content
h2 Hour of Code(Combat)
p
p
strong Hi Teachers!
p We're excited to participate in Hour of Code this year!
p We've set up an Introduction to Computer Science course, just for you.
@ -12,12 +12,12 @@ block content
ol
li
span.spr Navigate to the
a.spr(href='/courses/teachers?hoc=true') Courses
span page
a(href='/courses/teachers?hoc=true') Courses
span.spl page
li Click the green 'Get FREE course' button under Introduction to Computer Science
li Follow the enrollment instructions
li Add students via the 'Add Students' tab
p
p
span.spr If you have any problems, please email
a(href='mailto:team@codecombat.com') team@codecombat.com
br
@ -66,15 +66,15 @@ block content
p(data-i18n="teachers.monitor_progress_5")
h4(data-i18n="teachers.sub_includes_7")
ul
li
li
strong(data-i18n="clans.track_concepts1")
span.spl(data-i18n="clans.track_concepts2a")
li(data-i18n="clans.track_concepts3a")
li
li
span(data-i18n="clans.track_concepts4a")
strong.spl(data-i18n="clans.track_concepts5")
li(data-i18n="clans.track_concepts6a")
li
li
strong(data-i18n="clans.track_concepts7")
span.spl(data-i18n="clans.track_concepts8")
p
@ -144,7 +144,7 @@ block content
span.spr.spl
a(href='/account/subscription', data-i18n="teachers.how_much_2")
span.spr.spl(data-i18n="teachers.how_much_3")
p
p
span.spr(data-i18n="teachers.how_much_5")
a(href='mailto:team@codecombat.com') team@codecombat.com
span.spl(data-i18n="teachers.how_much_6")
@ -153,7 +153,7 @@ block content
a(href='/account/subscription', data-i18n="subscribe.group_discounts")
p(data-i18n="subscribe.group_discounts_1")
table.table.table-condensed.discount-table
tr
tr
td(data-i18n="subscribe.group_discounts_1st")
td(data-i18n="subscribe.group_discounts_full")
tr

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,96 @@
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
@supermodel.addRequestResource('active_classes', {
url: '/db/analytics_perday/-/active_classes'
method: 'POST'
success: (data) =>
@activeClassGroups = {}
dayEventsMap = {}
for activeClass in data
dayEventsMap[activeClass.day] ?= {}
dayEventsMap[activeClass.day]['Total'] = 0
for event, val of activeClass.classes
@activeClassGroups[event] = true
dayEventsMap[activeClass.day][event] = val
dayEventsMap[activeClass.day]['Total'] += val
@activeClassGroups = Object.keys(@activeClassGroups)
@activeClassGroups.push 'Total'
for day of dayEventsMap
for event in @activeClassGroups
dayEventsMap[day][event] ?= 0
@activeClasses = []
for day of dayEventsMap
data = day: day, groups: []
for group in @activeClassGroups
data.groups.push(dayEventsMap[day][group] ? 0)
@activeClasses.push data
@activeClasses.sort (a, b) -> b.day.localeCompare(a.day)
@render?()
}, 0).load()
@supermodel.addRequestResource('active_users', {
url: '/db/analytics_perday/-/active_users'
method: 'POST'
success: (data) =>
@activeUsers = data
@activeUsers.sort (a, b) -> b.day.localeCompare(a.day)
@render?()
}, 0).load()
@supermodel.addRequestResource('recurring_revenue', {
url: '/db/analytics_perday/-/recurring_revenue'
method: 'POST'
success: (data) =>
@revenueGroups = {}
dayGroupCountMap = {}
for dailyRevenue in data
dayGroupCountMap[dailyRevenue.day] ?= {}
dayGroupCountMap[dailyRevenue.day]['Daily'] = 0
for group, val of dailyRevenue.groups
@revenueGroups[group] = true
dayGroupCountMap[dailyRevenue.day][group] = val
dayGroupCountMap[dailyRevenue.day]['Daily'] += val
@revenueGroups = Object.keys(@revenueGroups)
@revenueGroups.push 'Daily'
@revenueGroups.push 'Monthly'
for day of dayGroupCountMap
for group in @revenueGroups
dayGroupCountMap[day][group] ?= 0
@revenue = []
for day of dayGroupCountMap
data = day: day, groups: []
for group in @revenueGroups
data.groups.push(dayGroupCountMap[day][group] ? 0)
@revenue.push data
@revenue.sort (a, b) -> b.day.localeCompare(a.day)
monthlyValues = []
return unless @revenue.length > 0
for i in [@revenue.length-1..0]
dailyTotal = @revenue[i].groups[@revenue[i].groups.length - 2]
monthlyValues.push(dailyTotal)
monthlyValues.shift() if monthlyValues.length > 30
if monthlyValues.length is 30
monthlyIndex = @revenue[i].groups.length - 1
@revenue[i].groups[monthlyIndex] = _.reduce(monthlyValues, (s, num) -> s + num)
@render?()
}, 0).load()
getRenderData: ->
context = super()
context.activeClasses = @activeClasses ? []
context.activeClassGroups = @activeClassGroups ? {}
context.activeUsers = @activeUsers ? []
context.revenue = @revenue ? []
context.revenueGroups = @revenueGroups ? {}
context

View file

@ -64,7 +64,6 @@ module.exports = class ClanDetailsView extends RootView
@supermodel.loadModel @clan, 'clan', cache: false
@supermodel.loadCollection(@members, 'members', {cache: false})
@supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false})
@supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false})
getRenderData: ->
context = super()
@ -115,7 +114,7 @@ module.exports = class ClanDetailsView extends RootView
lastLevelIndex++
levelCount++
@sortMembers(highestUserLevelCountMap, userConceptsMap) if @clan.get('dashboardType') is 'premium'
@sortMembers(highestUserLevelCountMap, userConceptsMap)# if @clan.get('dashboardType') is 'premium'
context.members = @members?.models ? []
context.lastUserCampaignLevelMap = lastUserCampaignLevelMap
context.showExpandedProgress = maxLastUserCampaignLevel <= 30 or @showExpandedProgress
@ -207,6 +206,8 @@ module.exports = class ClanDetailsView extends RootView
@owner = new User _id: @clan.get('ownerID')
@listenTo @owner, 'sync', => @render?()
@supermodel.loadModel @owner, 'owner', cache: false
if @clan.get("dashboardType") is "premium"
@supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false})
@render?()
onMembersSync: ->

View file

@ -43,8 +43,8 @@ module.exports = class ClansView extends RootView
@idNameMap = {}
sortClanList = (a, b) ->
if a.get('members').length isnt b.get('members').length
if a.get('members').length < b.get('members').length then 1 else -1
if a.get('memberCount') isnt b.get('memberCount')
if a.get('memberCount') < b.get('memberCount') then 1 else -1
else
b.id.localeCompare(a.id)
@publicClans = new CocoCollection([], { url: '/db/clan/-/public', model: Clan, comparator: sortClanList })

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

@ -448,8 +448,6 @@ module.exports = class HeroVictoryModal extends ModalView
navigationEvent = route: nextLevelLink, viewClass: viewClass, viewArgs: viewArgs
if @level.get('slug') is 'lost-viking' and not (me.get('age') in ['0-13', '14-17'])
@showOffer navigationEvent
else if @level.get('slug') is 'a-mayhem-of-munchkins' and not (me.get('age') in ['0-13']) and not options.showLeaderboard
@showOffer navigationEvent
else
Backbone.Mediator.publish 'router:navigate', navigationEvent
@ -476,7 +474,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
@ -262,8 +263,10 @@ module.exports = class SpellView extends CocoView
@ace.commands.on 'exec', (e) =>
# When pressing enter with an active selection, just make a new line under it.
if e.command.name is 'enter-skip-delimiters'
e.editor.execCommand 'gotolineend'
return true
selection = @ace.selection.getRange()
unless selection.start.column is selection.end.column and selection.start.row is selection.end.row
e.editor.execCommand 'gotolineend'
return true
fillACE: ->
@ace.setValue @spell.source
@ -459,7 +462,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

@ -45,7 +45,17 @@ disable = [
GLOBAL.window = GLOBAL
GLOBAL.document = location: pathname: 'headless_client'
GLOBAL.console.debug = console.log
GLOBAL.Worker = require('webworker-threads').Worker
try
GLOBAL.Worker = require('webworker-threads').Worker
catch
console.log ""
console.log "Headless client needs the webworker-threads package from NPM to function."
console.log "Try installing it with the command:"
console.log ""
console.log " npm install webworker-threads"
console.log ""
process.exit(1)
Worker::removeEventListener = (what) ->
if what is 'message'
@onmessage = -> #This webworker api has only one event listener at a time.

View file

@ -33,12 +33,14 @@
"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",
"nodemon": "nodemon",
"jasmine-node": "jasmine-node"
"jasmine-node": "jasmine-node",
"multicore": "coffee multicore.coffee",
"nodemon": "nodemon"
},
"main": "index.js",
"keywords": [
@ -49,6 +51,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",
@ -78,19 +81,21 @@
"stripe": "~2.9.0",
"tv4": "~1.0.16",
"underscore.string": "2.3.x",
"webworker-threads": "~0.5.5",
"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",
@ -110,7 +115,10 @@
"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"
},
"license": "MIT for the code, and CC-BY for the art and music",
"private": true,

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 = 40;
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,44 @@ 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("Getting active class counts...");
var activeClassCounts = getActiveClassCounts(startDay);
// printjson(activeClassCounts);
log("Inserting active class counts...");
for (var event in activeClassCounts) {
for (var day in activeClassCounts[event]) {
if (today === day) continue; // Never save data for today because it's incomplete
insertEventCount(event, day, activeClassCounts[event][day]);
}
}
log("Getting monthly recurring revenue counts...");
var recurringRevenueCounts = getRecurringRevenueCounts(startDay);
// printjson(recurringRevenueCounts);
log("Inserting monthly recurring revenue counts...");
for (var event in recurringRevenueCounts) {
for (var day in recurringRevenueCounts[event]) {
if (today === day) continue; // Never save data for today because it's incomplete
insertEventCount(event, day, recurringRevenueCounts[event][day]);
}
}
log("Script runtime: " + (new Date() - scriptStartTime));
}
catch(err) {
@ -383,7 +417,306 @@ 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 getActiveClassCounts(startDay) {
// Tally active classes per day
// TODO: does not handle class membership changes
if (!startDay) return {};
var minGroupSize = 12;
var classes = {
'Active classes private clan': [],
'Active classes managed subscription': [],
'Active classes bulk subscription': [],
'Active classes prepaid': [],
'Active classes course': [],
};
var userPlayedMap = {};
// Private clans
// TODO: does not handle clan membership changes over time
var cursor = db.clans.find({$and: [{type: 'private'}, {$where: 'this.members.length >= ' + minGroupSize}]});
while (cursor.hasNext()) {
var doc = cursor.next();
var members = doc.members.map(function(a) {
userPlayedMap[a.valueOf()] = [];
return a.valueOf();
});
classes['Active classes private clan'].push({
owner: doc.ownerID.valueOf(),
members: members,
activeDayMap: {}
});
}
// Managed subscriptions
// TODO: does not handle former recipients playing after sponsorship ends
var bulkSubGroups = {};
cursor = db.payments.find({$and: [{service: 'stripe'}, {$where: '!this.purchaser.equals(this.recipient)'}]});
while (cursor.hasNext()) {
var doc = cursor.next();
var purchaser = doc.purchaser.valueOf();
if (!bulkSubGroups[purchaser]) bulkSubGroups[purchaser] = {};
bulkSubGroups[purchaser][doc.recipient.valueOf()] = true;
}
for (var purchaser in bulkSubGroups) {
if (Object.keys(bulkSubGroups[purchaser]).length >= minGroupSize) {
for (var member in bulkSubGroups[purchaser]) {
userPlayedMap[member] = [];
}
classes['Active classes managed subscription'].push({
owner: purchaser,
members: Object.keys(bulkSubGroups[purchaser]),
activeDayMap: {}
});
}
}
// Bulk subscriptions
bulkSubGroups = {};
cursor = db.payments.find({$and: [{service: 'external'}, {$where: '!this.purchaser.equals(this.recipient)'}]});
while (cursor.hasNext()) {
var doc = cursor.next();
var purchaser = doc.purchaser.valueOf();
if (!bulkSubGroups[purchaser]) bulkSubGroups[purchaser] = {};
bulkSubGroups[purchaser][doc.recipient.valueOf()] = true;
}
for (var purchaser in bulkSubGroups) {
if (Object.keys(bulkSubGroups[purchaser]).length >= minGroupSize) {
for (var member in bulkSubGroups[purchaser]) {
userPlayedMap[member] = [];
}
classes['Active classes bulk subscription'].push({
owner: purchaser,
members: Object.keys(bulkSubGroups[purchaser]),
activeDayMap: {}
});
}
}
// Prepaids terminal_subscription & course
bulkSubGroups = {};
cursor = db.prepaids.find(
{$and: [{type: {$in: ['terminal_subscription', 'course']}}, {$where: 'this.redeemers && this.redeemers.length >= ' + minGroupSize}]},
{creator: 1, type: 1, redeemers: 1}
);
while (cursor.hasNext()) {
var doc = cursor.next();
var owner = doc.creator.valueOf();
var members = [];
for (var i = 0 ; i < doc.redeemers.length; i++) {
userPlayedMap[doc.redeemers[i].userID.valueOf()] = [];
members.push(doc.redeemers[i].userID.valueOf());
}
var event = doc.type == 'terminal_subscription' ? 'Active classes prepaid' : 'Active classes course';
classes[event].push({
owner: owner,
members: members,
activeDayMap: {}
});
}
// printjson(classes);
// TODO: classrooms
// Find all the started level events for our class members, for startDay - daysInMonth
var startDate = ISODate(startDay + "T00:00:00.000Z");
startDate.setUTCDate(startDate.getUTCDate() - daysInMonth);
var endDate = ISODate(startDay + "T00:00:00.000Z");
var todayDate = new Date(new Date().toISOString().substring(0, 10));
var startObj = objectIdWithTimestamp(startDate);
var queryParams = {$and: [
{_id: {$gte: startObj}},
{event: 'Started Level'},
{user: {$in: Object.keys(userPlayedMap)}}
]};
cursor = logDB['log'].find(queryParams, {user: 1});
// cursor = db['level.sessions'].find({$and: [{creator: {$in: Object.keys(userPlayedMap)}}, {changed: {$gte: startDate}}]}, {creator: 1, changed: 1});
while (cursor.hasNext()) {
var doc = cursor.next();
userPlayedMap[doc.user].push(doc._id.getTimestamp());
}
// printjson(userPlayedMap);
// print(startDate, endDate, todayDate);
// Now we have a set of classes, and when users played
// For a given day, walk classes and find out how many members were active during the previous daysInMonth
while (endDate < todayDate) {
var endDay = endDate.toISOString().substring(0, 10);
// For each class
for (var event in classes) {
for (var i = 0; i < classes[event].length; i++) {
// For each member of current class
var activeMemberCount = 0;
for (var j = 0; j < classes[event][i].members.length; j++) {
var member = classes[event][i].members[j];
// Was member active during current timeframe?
if (userPlayedMap[member]) {
for (var k = 0; k < userPlayedMap[member].length; k++) {
if (userPlayedMap[member][k] > startDate && userPlayedMap[member][k] <= endDate) {
activeMemberCount++;
break;
}
}
}
}
// Classes active for a given day if has minGroupSize members, and at least 1/2 played in last daysInMonth days
if (activeMemberCount >= Math.round(classes[event][i].members.length / 2)) {
classes[event][i].activeDayMap[endDay] = true;
}
}
}
startDate.setUTCDate(startDate.getUTCDate() + 1);
endDate.setUTCDate(endDate.getUTCDate() + 1);
}
var activeClassCounts = {};
for (var event in classes) {
if (!activeClassCounts[event]) activeClassCounts[event] = {};
for (var i = 0; i < classes[event].length; i++) {
for (var endDay in classes[event][i].activeDayMap) {
if (!activeClassCounts[event][endDay]) activeClassCounts[event][endDay] = 0;
activeClassCounts[event][endDay]++;
}
}
}
return activeClassCounts;
}
function getRecurringRevenueCounts(startDay) {
if (!startDay) return {};
var dailyRevenueCounts = {};
var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z"));
var cursor = db.payments.find({_id: {$gte: startObj}});
while (cursor.hasNext()) {
var doc = cursor.next();
var day = doc._id.getTimestamp().toISOString().substring(0, 10);
if (doc.service === 'ios' || doc.service === 'bitcoin') continue;
if (doc.productID && doc.productID.indexOf('gems_') === 0) {
if (!dailyRevenueCounts['DRR gems']) dailyRevenueCounts['DRR gems'] = {};
if (!dailyRevenueCounts['DRR gems'][day]) dailyRevenueCounts['DRR gems'][day] = 0;
dailyRevenueCounts['DRR gems'][day] += doc.amount
}
else if (doc.productID === 'custom' || doc.service === 'external' || doc.service === 'invoice') {
if (!dailyRevenueCounts['DRR school sales']) dailyRevenueCounts['DRR school sales'] = {};
if (!dailyRevenueCounts['DRR school sales'][day]) dailyRevenueCounts['DRR school sales'][day] = 0;
dailyRevenueCounts['DRR school sales'][day] += doc.amount
}
else if (doc.service === 'stripe' && doc.gems === 42000) {
if (!dailyRevenueCounts['DRR yearly subs']) dailyRevenueCounts['DRR yearly subs'] = {};
if (!dailyRevenueCounts['DRR yearly subs'][day]) dailyRevenueCounts['DRR yearly subs'][day] = 0;
dailyRevenueCounts['DRR yearly subs'][day] += doc.amount
}
else if (doc.service === 'stripe') {
// Catches prepaids, and assumes all are type terminal_subscription
if (!dailyRevenueCounts['DRR monthly subs']) dailyRevenueCounts['DRR monthly subs'] = {};
if (!dailyRevenueCounts['DRR monthly subs'][day]) dailyRevenueCounts['DRR monthly subs'][day] = 0;
dailyRevenueCounts['DRR monthly subs'][day] += doc.amount
}
else if (doc.service === 'paypal') {
if (!dailyRevenueCounts['DRR paypal']) dailyRevenueCounts['DRR paypal'] = {};
if (!dailyRevenueCounts['DRR paypal'][day]) dailyRevenueCounts['DRR paypal'][day] = 0;
dailyRevenueCounts['DRR paypal'][day] += doc.amount
}
// else {
// // printjson(doc);
// // print(doc.service, doc.amount, doc.description, JSON.stringify(doc.stripe));
// }
}
return dailyRevenueCounts;
}
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,13 +14,67 @@ class AnalyticsPerDayHandler extends Handler
getByRelationship: (req, res, args...) ->
return @sendForbiddenError res unless @hasAccess req
return @getActiveClasses(req, res) if args[1] is 'active_classes'
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'
return @getLevelHelpsBySlugs(req, res) if args[1] is 'level_helps'
return @getLevelSubscriptionsBySlugs(req, res) if args[1] is 'level_subscriptions'
return @getRecurringRevenue(req, res) if args[1] is 'recurring_revenue'
super(arguments...)
getActiveClasses: (req, res) ->
events = [
'Active classes private clan',
'Active classes managed subscription',
'Active classes bulk subscription',
'Active classes prepaid',
'Active classes course']
AnalyticsString.find({v: {$in: events}}).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
eventIDs = []
eventStringMap = {}
for doc in documents
eventStringMap[doc._id.valueOf()] = doc.v
eventIDs.push doc._id
return @sendSuccess res, [] unless eventIDs.length is events.length
AnalyticsPerDay.find({e: {$in: eventIDs}}).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
dayCountsMap = {}
for doc in documents
dayCountsMap[doc.d] ?= {}
dayCountsMap[doc.d][eventStringMap[doc.e.valueOf()]] = doc.c
activeClasses = []
for key, val of dayCountsMap
activeClasses.push day: key, classes: dayCountsMap[key]
@sendSuccess(res, activeClasses)
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:
@ -412,4 +466,33 @@ class AnalyticsPerDayHandler extends Handler
@levelSubscriptionsCache[cacheKey] = subscriptions
@sendSuccess res, subscriptions
getRecurringRevenue: (req, res) ->
events = [
'DRR gems',
'DRR school sales',
'DRR yearly subs',
'DRR monthly subs',
'DRR paypal']
AnalyticsString.find({v: {$in: events}}).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
eventIDs = []
eventStringMap = {}
for doc in documents
eventStringMap[doc._id.valueOf()] = doc.v
eventIDs.push doc._id
return @sendSuccess res, [] unless eventIDs.length is events.length
AnalyticsPerDay.find({e: {$in: eventIDs}}).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
dayCountsMap = {}
for doc in documents
dayCountsMap[doc.d] ?= {}
dayCountsMap[doc.d][eventStringMap[doc.e.valueOf()]] = doc.c
recurringRevenue = []
for key, val of dayCountsMap
recurringRevenue.push day: key, groups: dayCountsMap[key] ? {}
@sendSuccess(res, recurringRevenue)
module.exports = new AnalyticsPerDayHandler()

View file

@ -10,6 +10,8 @@ LevelSessionHandler = require '../levels/sessions/level_session_handler'
User = require '../users/User'
UserHandler = require '../users/user_handler'
memberLimit = 200
ClanHandler = class ClanHandler extends Handler
modelClass: Clan
jsonSchema: require '../../app/schemas/models/clan.schema'
@ -94,17 +96,15 @@ ClanHandler = class ClanHandler extends Handler
getMemberAchievements: (req, res, clanID) ->
# TODO: add tests
memberLimit = 200
Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless clan
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
User.find {_id: {$in: memberIDs}}, 'nameLower', {sort: {nameLower: 1}}, (err, users) =>
User.find {_id: {$in: memberIDs}}, 'nameLower', {limit: memberLimit}, (err, users) =>
return @sendDatabaseError(res, err) if err
memberIDs = []
for user in users
memberIDs.push user.id
break unless memberIDs.length < memberLimit
EarnedAchievement.find {user: {$in: memberIDs}}, 'achievementName user', (err, documents) =>
return @sendDatabaseError(res, err) if err?
cleandocs = (EarnedAchievementHandler.formatEntity(req, doc) for doc in documents)
@ -115,8 +115,8 @@ ClanHandler = class ClanHandler extends Handler
Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless clan
memberIDs = clan.get('members') ? []
User.find {_id: {$in: memberIDs}}, 'name nameLower points heroConfig.thangType', {sort: {nameLower: 1}}, (err, users) =>
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
User.find {_id: {$in: memberIDs}}, 'name nameLower points heroConfig.thangType', {}, (err, users) =>
return @sendDatabaseError(res, err) if err
cleandocs = (UserHandler.formatEntity(req, doc) for doc in users)
@sendSuccess(res, cleandocs)
@ -124,12 +124,12 @@ ClanHandler = class ClanHandler extends Handler
getMemberSessions: (req, res, clanID) ->
# TODO: add tests
# TODO: restrict information returned based on clan type
memberLimit = 200
Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless clan
return @sendForbiddenError(res) unless clan.get('dashboardType') is 'premium'
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
User.find {_id: {$in: memberIDs}}, 'name', {sort: {name: 1}}, (err, users) =>
User.find {_id: {$in: memberIDs}}, 'name', {limit: memberLimit}, (err, users) =>
return @sendDatabaseError(res, err) if err
memberIDs = []
for user in users
@ -143,7 +143,7 @@ ClanHandler = class ClanHandler extends Handler
getPublicClans: (req, res) ->
# Return 100 public clans, sorted by member count, created date
query = [{ $match : {type : 'public'} }]
query.push {$project : {_id: 1, name: 1, slug: 1, type: 1, description: 1, members: 1, memberCount: {$size: "$members"}, ownerID: 1}}
query.push {$project : {_id: 1, name: 1, slug: 1, type: 1, description: 1, memberCount: {$size: "$members"}, ownerID: 1}}
query.push {$sort: { memberCount: -1, _id: -1 }}
query.push {$limit: 100}
Clan.aggregate(query).exec (err, documents) =>

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()