diff --git a/Jakefile b/Jakefile index 31736a30..77bd1c8c 100644 --- a/Jakefile +++ b/Jakefile @@ -124,7 +124,7 @@ function runAndComplete(cmds, task) { }); } -mkSimpleTask('build/genmeta.js', [ 'tools', ], "tools/genmeta.ts"); +mkSimpleTask('build/genmeta.js', [ 'tools', 'generated/help.cache' ], "tools/genmeta.ts"); file('build/api.js', expand([ "build/genmeta.js", "lib" ]), { async: true }, function () { console.log("[P] generating build/api.js, localization.json and topiclist.json"); runAndComplete([ diff --git a/ast/api.ts b/ast/api.ts index a16ac2a9..298762e0 100644 --- a/ast/api.ts +++ b/ast/api.ts @@ -530,6 +530,7 @@ module TDev { public generalFlags = PropertyFlags.None; public _isImmutable = false; + public minSkill = 0; public _stemName:string; public isData:boolean; public isBuiltin:boolean; @@ -574,6 +575,8 @@ module TDev { public isExtensionEnabled() { return false } public isImmutable() { return this._isImmutable } + // 1 block, 2 coder, 3 pro + public md_skill(sk: number) { this.minSkill = sk; } public md_stem(n: string) { this._stemName = n; } public md_obsolete() { this.isObsolete = true; } public md_isData() { this.isData = true; } diff --git a/ast/ast.ts b/ast/ast.ts index 4d407be4..e7e40d88 100644 --- a/ast/ast.ts +++ b/ast/ast.ts @@ -2134,7 +2134,8 @@ module TDev.AST { this.version = App.currentVersion; } - static metaMapping = [ "showAd", "isLibrary", "allowExport", "isCloud", "hasIds" ]; + // split screen is used as a hit when loaded in the editor, serialized when publishing + static metaMapping = [ "showAd", "isLibrary", "allowExport", "isCloud", "hasIds", "splitScreen" ]; public nodeType() { return "app"; } public things:Decl[] = []; @@ -2189,7 +2190,8 @@ module TDev.AST { public isDocsTopic() { return this.comment && /#docs/i.test(this.comment); } public isTutorial() { return this.isDocsTopic() && this.allActions().some(a => /^#\d/.test(a.getName())) } public allowExport:boolean; - public hasIds:boolean; + public hasIds: boolean; + public splitScreen: boolean; private stillParsing:boolean = true; public accept(v:NodeVisitor) { return v.visitApp(this); } public children() { return this.things; } @@ -4214,6 +4216,10 @@ module TDev.AST { }); } + secondaryRun(app: App) + { + } + run(app: App) { DeepVisitor.clearVisitorState(app); @@ -4237,6 +4243,7 @@ module TDev.AST { this.useAction(a); }) + this.secondaryRun(app); this.traverseActions(); diff --git a/ast/compiler.ts b/ast/compiler.ts index db9c983f..aa8fafde 100644 --- a/ast/compiler.ts +++ b/ast/compiler.ts @@ -1380,7 +1380,9 @@ module TDev.AST var code = "" function localName(l:LocalDef) { - return Api.runtimeName(l.getName().replace(/[?]/g, "")) + var r = Api.runtimeName(l.getName().replace(/[?]/g, "")) + if (r == "s" || r == "lib") return "_" + r + return r } function unterm(t:JsExpr) @@ -3106,5 +3108,14 @@ module TDev.AST { this.options.usedProperties[p.usageKey().toLowerCase()] = true } + + secondaryRun(app: App) + { + app.libraries().forEach(l => { + if (l.isTutorial()) { + l.getPublicActions().forEach(a => this.runOnDecl(a)) + } + }) + } } } diff --git a/editor/apps.ts b/editor/apps.ts index c13f9681..14f46244 100644 --- a/editor/apps.ts +++ b/editor/apps.ts @@ -739,8 +739,7 @@ module TDev.AppExport return wa } - function chooseWebsiteCoreAsync(azureResults:any[]):Promise - { + function chooseWebsiteCoreAsync(azureResults: any[]): Promise { var r = new PromiseInv() var m = new ModalDialog() @@ -756,13 +755,25 @@ module TDev.AppExport var keys = Object.keys(auths).map(k => auths[k]) keys.sort((a, b) => Util.stringCompare(a.website, b.website)) + // populate data from local editor if any + if (LocalShell.mgmtUrl("")) { + var wa = { + deploymentKey: LocalShell.deploymentKey(), + key: 'custom:local', + website: 'local', + webspace: 'custom', + destinationAppUrl: LocalShell.url() + }; + keys.splice(0, 0, wa); + } + var boxes = keys.map(wa => websiteBox(wa) .withClick(() => { - m.dismiss() - r.success(setDeploymentWebsiteAsync(wa)) - }) - ) + m.dismiss() + r.success(setDeploymentWebsiteAsync(wa)) + }) + ) if (getManagementCerificate()) { if (!azureResults) @@ -1238,16 +1249,6 @@ module TDev.AppExport wa.destinationAppUrl = wa.destinationAppUrl.replace(/\/*$/, "/") m.add(div("wall-dialog-header", lf("hooray! your web site is deployed"))); m.add(div('share-url', HTML.mkA('', wa.destinationAppUrl, 'tdwebapp', wa.destinationAppUrl))); - - var lnk = RT.Link.mk(wa.destinationAppUrl, RT.LinkKind.hyperlink) - lnk.set_title(wa.website + " #touchdevelop") - var options = { - header: "share this web site", - noDismiss: true, - justButtons: true - }; - RT.ShareManager.addShareButtons(m, lnk, options) - m.addOk("close", () => { m.dismiss(); }); diff --git a/editor/calculator.ts b/editor/calculator.ts index adaa3265..a33ce788 100644 --- a/editor/calculator.ts +++ b/editor/calculator.ts @@ -2412,18 +2412,18 @@ module TDev }); } else { var maxScore = 1; - var singl:AST.SingletonDef[] = Calculator.sortDecls(api.getSingletons()); + var singl: AST.SingletonDef[] = Calculator.sortDecls(api.getSingletons().filter(sg => sg.isBrowsable())); + var skill = AST.blockMode ? 1 : AST.legacyMode ? 2 : 3; var libSingl:IntelliItem = null; singl.forEach((s:AST.SingletonDef) => { - if (s.isBrowsable()) { - var sc = s.usage.count() + 1e-20; - sc *= s.usageMult(); - var e = this.mkIntelliItem(sc, Ticks.calcIntelliSingleton); - if (sc > maxScore) maxScore = sc; - e.decl = s; - if (s.getName() == AST.libSymbol) - libSingl = e; - } + var sc = s.usage.count() + 1e-20; + sc *= s.usageMult(); + var e = this.mkIntelliItem(sc, Ticks.calcIntelliSingleton); + if (sc > maxScore) maxScore = sc; + if (skill < s.getKind().minSkill) e.score -= 1e10; + e.decl = s; + if (s.getName() == AST.libSymbol) + libSingl = e; }); var libs = Script.libraries().filter(l => l.isBrowsable()).map(l => { @@ -3873,9 +3873,9 @@ module TDev TheEditor.adjustCodeViewSize(this.stmt); } - private sortedIntelliItems() + private sortedIntelliItems() : IntelliItem[] { - var items0 = this.currentIntelliItems; + var items0 = this.currentIntelliItems.filter(ii => ii.score > 0); var usedProfile = false; if (TheEditor.intelliProfile) { var prof = TheEditor.intelliProfile; diff --git a/editor/editor.ts b/editor/editor.ts index ba19204f..4c976aef 100644 --- a/editor/editor.ts +++ b/editor/editor.ts @@ -605,10 +605,6 @@ module TDev return TheEditor.debugSupported(); } - public publishRunHelpLink(title: string) { - return Editor.mkHelpLink("publishing run", title); - } - public fixErrorIn(stableName:string, error:string) { this.hideWallAsync().then(() => { @@ -3046,6 +3042,11 @@ module TDev else return Promise.as(); }).then(() => { if (!Script) return; + // if the script is not edited and it requires split screen, load split screen mode from meta + if (header.status === "published" && !!Script.splitScreen) { + Util.log('published script used split mode, splitting...'); + this.setSplitScreen(true); + } this.currentRt = new Runtime(); this.setupPlayButton(); @@ -4401,6 +4402,8 @@ module TDev { Ticker.dbg("Editor.saveStateAsync"); if (!!Script) { + if (opts.forPublishing) + Script.splitScreen = !!Script.editorState.splitScreen if (!opts.isRevert && !!this.currentCodeView) this.currentCodeView.commit(); Script.setStableNames(); @@ -5427,6 +5430,7 @@ module TDev isRevert?: boolean; clearScript?: boolean; wasUpgraded?: boolean; + forPublishing?: boolean; } export class SearchForNode diff --git a/editor/hub.ts b/editor/hub.ts index 5ad0ddfd..66f127b8 100644 --- a/editor/hub.ts +++ b/editor/hub.ts @@ -20,13 +20,22 @@ module TDev.Browser { } export var hubThemes: StringMap = { + 'minecraft': { + description: 'Learn to code with Mineacraft', + logoArtId: 'eopyzwpm', + wallpaperArtId: 'abqqsurv', + tutorialsTopic: 'ysxp', + requiresShell: true, + scriptSearch: '#minecraft', + }, 'arduino': { - description: 'Environment to program Arduino boards', + description: 'Program Arduino boards', logoArtId: 'kzajxznr', wallpaperArtId: 'kzajxznr', tutorialsTopic: 'arduinotutorials', - requiresShell: true - } + requiresShell: true, + scriptSearch: '#arduino', + }, }; export enum EditorMode { @@ -475,23 +484,35 @@ module TDev.Browser { if ((h[1] == "follow" || h[1] == "follow-tile") && /^\w+$/.test(h[2])) { // temporary fix if (h[2] == 'jumpingbird') h[2] = 'jumpingbirdtutorial'; + Util.log('follow: {0}', h[2]); this.browser().clearAsync(true) - .done(() => { + .done(() => { // try finding built-in topic first var bt = HelpTopic.findById(h[2]); - if (bt) + if (bt) { + Util.log('found built-in topic'); TopicInfo.mk(bt).follow(); - else + } + else { TheApiCacheMgr.getAsync(h[2], true) + .then((res: JsonIdObject) => { + if (res && res.kind == "script" && res.id != (res).updateid) { + Util.log('follow topic updated to ' + (res).updateid); + return TheApiCacheMgr.getAsync((res).updateid, true); + } + else return Promise.as(res); + }) .done(j => { - if (j && j.kind == "script") { - var ti = TopicInfo.mk(HelpTopic.fromJsonScript(j)) + if (j && j.kind == "script") { + var ti = TopicInfo.mk(HelpTopic.fromJsonScript(j)) ti.follow(); - } else Util.setHash("hub"); - }, e => { + } else Util.setHash("hub"); + }, e => { + Util.log('follow route error: {0}, {1}' + h[2], e.message); Util.setHash("hub"); }); - }); + } + }); return; } @@ -753,7 +774,7 @@ module TDev.Browser { }) } - public tutorialsByUpdateIdAsync() + public tutorialsByUpdateIdAsync(): Promise // StringMap { return this.browser().getTutorialsStateAsync().then((headers:AST.HeaderWithState[]) => { var res = {} @@ -807,7 +828,7 @@ module TDev.Browser { // - once this is done, we call [finish] // - because we may have found the tutorial we wanted in the process, we // return a new value for [top] - private findTutorial(templateId: string, finish) { + private findTutorial(templateId: string, finish: (res: { app: AST.App; headers: StringMap }, top: HelpTopic) => void) { var top = HelpTopic.findById("t:" + templateId) if (!this.headerByTutorialId || Date.now() - this.headerByTutorialIdUpdated > 3000) { @@ -816,7 +837,7 @@ module TDev.Browser { } if (top) { - Promise.join([Promise.as(null), this.headerByTutorialId]).done(res => finish(res, top)); + Promise.join([Promise.as(null), this.headerByTutorialId]).done(res => finish({ app: res[0], headers: res[1] }, top)); } else { var fetchingId = null var fetchId = id => { @@ -830,7 +851,7 @@ module TDev.Browser { fetchId(j.updateid); else { top = HelpTopic.fromJsonScript(j); - Promise.join([top.initAsync(), this.headerByTutorialId]).done(res => finish(res, top)); + Promise.join([top.initAsync(), this.headerByTutorialId]).done(res => finish({ app: res[0], headers: res[1] }, top)); } }) } @@ -869,20 +890,20 @@ module TDev.Browser { { var tileOuter = div("tutTileOuter") - var startTutorial = (top, header: Cloud.Header) => { + var startTutorial = (top : HelpTopic, header: Cloud.Header) => { Util.log("tutorialTile.start: " + templateId) if (f) f(header); this.startTutorial(top, header); }; - var finish = (res, top: HelpTopic) => { + var finish = (res: { app: AST.App; headers: StringMap }, top: HelpTopic) => { var isHelpTopic = !!top; var tile = div("tutTile") tileOuter.setChildren([tile]) - var app:AST.App = res[0] - var progs = res[1] + var app:AST.App = res.app + var progs = res.headers var titleText = top.json.name.replace(/ (tutorial|walkthrough)$/i, ""); var descText = top.json.description.replace(/ #(docs|tutorials|stepbystep)\b/ig, " ") @@ -1037,7 +1058,8 @@ module TDev.Browser { bySection[k].forEach((template: ScriptTemplate) => { var icon = div("sdIcon"); icon.style.backgroundColor = ScriptIcons.stableColorFromName(template.title); - icon.setChildren([HTML.mkImg("svg:" + template.icon + ",white")]); + // missing icons + // icon.setChildren([HTML.mkImg("svg:" + template.icon + ",white")]); var nameBlock = div("sdName", lf_static(template.title, true)); var hd = div("sdNameBlock", nameBlock); @@ -1826,12 +1848,12 @@ module TDev.Browser { // Copied from [tutorialTitle], and (hopefully) simplified. this.findTutorial(id, (res, topic: HelpTopic) => { var key = topic.updateKey(); - var header = res[1][key]; // may be null or undefined + var header = res.headers[key]; // may be null or undefined k({ title: topic.json.name.replace(/ (tutorial|walkthrough)$/i, ""), header: header, topic: topic, - app: res[0], + app: res.app, }); }); } @@ -1858,6 +1880,7 @@ module TDev.Browser { : HTML.cssImage(HTML.proxyResource(tutorial.topic.json.screenshot)); btn.style.backgroundSize = "cover"; } + ScriptInfo.addTutorialProgress(btn, tutorial.header); buttons.push(btn); if (buttons.length == 6) { diff --git a/editor/scriptList.ts b/editor/scriptList.ts index b058d306..663f205a 100644 --- a/editor/scriptList.ts +++ b/editor/scriptList.ts @@ -5440,11 +5440,32 @@ module TDev { export module Browser { div("hubTileTitleBar", div("hubTileTitle", spanDirAuto(this.app.getName())), div("hubTileSubtitle", - div("hubTileAuthor", spanDirAuto(this.jsonScript.username), nums)))]) + div("hubTileAuthor", spanDirAuto(this.jsonScript.username), nums)))]) + ScriptInfo.addTutorialProgress(d, this.cloudHeader); }); return d; } + static addTutorialProgress(d: HTMLElement, header : Cloud.Header) { + if (!header || !header.guid) return; + World.getInstalledEditorStateAsync(header.guid).done(text => { + if (!text) return; + var prog = JSON.parse(text); + var num = prog.tutorialNumSteps - (prog.tutorialStep || 0); + if (prog.tutorialId && num > 0) { + var starSpan = span("bold",((prog.tutorialStep || 0) + 1) + "★"); + var ofSteps = prog.tutorialNumSteps ? " of " + (prog.tutorialNumSteps + 1) : ""; + d.appendChild(div("tutProgress", + ((prog.tutorialStep && (prog.tutorialStep == prog.tutorialNumSteps)) ? + div(lf("steps done"), lf("done!"), div("label", starSpan)) + : + div("steps", starSpan, ofSteps, + div("label", lf("tutorial progress")))) + )) + } + }); + } + public willWork() { return !this.app || this.app.supportsAllPlatforms(api.core.currentPlatform); } diff --git a/editor/sideScriptNav.ts b/editor/sideScriptNav.ts index 33337319..854e5fd0 100644 --- a/editor/sideScriptNav.ts +++ b/editor/sideScriptNav.ts @@ -72,7 +72,7 @@ module TDev { if (!app) app = Script - TheEditor.saveStateAsync({ forReal: true }).then(() => { + TheEditor.saveStateAsync({ forReal: true, forPublishing: true }).then(() => { TheEditor.queueNavRefresh(); World.getInstalledHeaderAsync(app.localGuid).then((h: Cloud.Header) => { if (h.status == "published") { @@ -195,13 +195,13 @@ module TDev this.editor.showAppLog(app); })); if (!isParent && TheEditor.widgetEnabled("errorsButton")) - addBtn(HTML.mkRoundButton("svg:SmilieSad,black", lf("errors"), Ticks.sideErrors, () => { + addBtn(HTML.mkRoundButton("svg:SmilieSad,black", lf("errors"), Ticks.sideErrors,() => { + this.editor.typeCheckNow(); this.editor.searchFor(":m"); })); - if (onlyParent && isBeta && TheEditor.widgetEnabled("deployButton") && - (Azure.getWebsiteAuthForApp(app) || app.usesCloudLibs() || Script.usesCloudLibs())) { - addBtn(HTML.mkRoundButton("svg:cloudupload,black", lf("deploy"), Ticks.sideDeployWebSite,() => { + if (onlyParent && TheEditor.widgetEnabled("deployButton")) { + addBtn(HTML.mkRoundButton("svg:cloudupload,black", lf("export"), Ticks.sideDeployWebSite,() => { TDev.RT.App.clearLogs(); var wa = Azure.getWebsiteAuthForApp(app) var recompile = Promise.as() @@ -217,18 +217,21 @@ module TDev Script = res.prevScript }) - recompile - .then(() => AppExport.deployLocalWebappAsync(app, wa)) - .then( - () => AppExport.showStatus(wa), - err => { - if (app == Script) - AppExport.setupAzure() - else - ModalDialog.info(lf("deployment not configured"), + if (app.isCloud) { + recompile + .then(() => AppExport.deployLocalWebappAsync(app, wa)) + .done( + () => AppExport.showStatus(wa), + err => { + if (app == Script) + AppExport.setupAzure() + else + ModalDialog.info(lf("deployment not configured"), lf("Go to the main script and try to deploy from there.")) - }) - .done() + }); + } else { + recompile.done(() => AppExport.deployCordova(app, this.editor.getBaseScriptId())); + } })); } diff --git a/editor/tutorial.ts b/editor/tutorial.ts index 55cc2bf3..b8853331 100644 --- a/editor/tutorial.ts +++ b/editor/tutorial.ts @@ -765,40 +765,56 @@ module TDev // create a new tracking pixel and add it to the tree var trackUrl = this.topic.pixelTrackingUrl(); if (trackUrl) { - // generate new id on demand - var anon = Script.editorState.tutorialAnonymousId; - if (!anon) anon = Script.editorState.tutorialAnonymousId = Util.guidGen(); - trackUrl += "?scriptid=" + this.progressId + "&index=" + prog.index + "&total=" + prog.numSteps + "&completed=" + !!prog.completed + "&time=" + prog.lastUsed + "&anonid=" + anon; - var pixel = document.createElement("img"); - pixel.className = "tracking-pixel"; - pixel.src = trackUrl; - pixel.onload = (el) => pixel.removeSelf(); - pixel.onerror = (el) => pixel.removeSelf(); - elt("root").appendChild(pixel); + var anon = this.loadAnonymousId(); + if (anon) { + trackUrl += "?scriptid=" + this.progressId + "&index=" + prog.index + "&total=" + prog.numSteps + "&completed=" + !!prog.completed + "&time=" + prog.lastUsed + "&anonid=" + anon; + var pixel = document.createElement("img"); + pixel.className = "tracking-pixel"; + pixel.src = trackUrl; + pixel.onload = (el) => pixel.removeSelf(); + pixel.onerror = (el) => pixel.removeSelf(); + elt("root").appendChild(pixel); + } } // pushing directly into event hubs var eventHubsInfo = this.topic.eventHubsTracking(); if (eventHubsInfo) { - var anon = Script.editorState.tutorialAnonymousId; - if (!anon) anon = Script.editorState.tutorialAnonymousId = Util.guidGen(); - var client = new XMLHttpRequest(); - var url = 'https://' + eventHubsInfo.namespace + '.servicebus.windows.net/' + eventHubsInfo.hub + '/publishers/' + anon + '/messages?timeout=60&api-version=2014-01'; - Util.log('event hubs: ' + url); - client.open('POST', url); - client.setRequestHeader('Authorization', eventHubsInfo.token); - client.setRequestHeader("Content-Type", 'application/atom+xml;type=entry;charset=utf-8'); - client.send(JSON.stringify({ - anonid: anon, - scriptid: this.progressId, - index: prog.index, - total: prog.numSteps, - completed: !!prog.completed, - time: prog.lastUsed - })); + var anon = this.loadAnonymousId(); + if (anon) { + var client = new XMLHttpRequest(); + var url = 'https://' + eventHubsInfo.namespace + '.servicebus.windows.net/' + eventHubsInfo.hub + '/publishers/' + anon + '/messages?timeout=60&api-version=2014-01'; + Util.log('event hubs: ' + url); + client.open('POST', url); + client.setRequestHeader('Authorization', eventHubsInfo.token); + client.setRequestHeader("Content-Type", 'application/atom+xml;type=entry;charset=utf-8'); + client.send(JSON.stringify({ + anonid: anon, + scriptid: this.progressId, + index: prog.index, + total: prog.numSteps, + completed: !!prog.completed, + time: prog.lastUsed + })); + } } } + private loadAnonymousId(): string { + if (!Script || !this.topic.json) return ""; + + var anon = Script.editorState.tutorialAnonymousId; + if (!anon) { + var ids = JSON.parse(localStorage["tutorialAnonymousIds"] || "{}"); + anon = ids[this.topic.json.userid]; + if (!anon) { + anon = Script.editorState.tutorialAnonymousId = ids[this.topic.json.userid] = Util.guidGen(); + localStorage["tutorialAnonymousIds"] = JSON.stringify(ids); + } + } + return anon; + } + public showDiff() { var s = this.steps[this.currentStep] @@ -847,10 +863,15 @@ module TDev private nowPublish() { - if (!Cloud.getUserId() || !Cloud.isOnline() || !Cloud.canPublish() || !Script) + TheEditor.leaveTutorial(); // always leave tutorial + + // not generally signed in + if (!Cloud.getUserId() || !Cloud.isOnline() || !Cloud.canPublish() || !Script) return; + + // author explicitely wanted to skip step + if (!this.topic || /none/i.test(this.topic.nextTutorials()[0])) return; - TheEditor.leaveTutorial(); World.getInstalledHeaderAsync(Script.localGuid).done((h: Cloud.Header) => { if (h.status == "published") return Promise.as(); diff --git a/generated/help.cache b/generated/help.cache index e99f1196..0684166f 100644 --- a/generated/help.cache +++ b/generated/help.cache @@ -6,6 +6,7 @@ "bhjyb": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"blank engduino\";\nmeta icon \"CreditCard\";\nmeta color \"#ff00008b\";\nmeta rootId \"SEYbC35yczei4aI3wm7icdMs\";\nmeta iconArtId \"qmjzqlkc\";\nmeta allowExport \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n// A blank Engduino v3 sketch. #arduino #arduinoSketch #Engduink\n#LnSjoBj2DrSx4mcw\naction setup() {\n #mQv6HDl3bdDDAJI0 skip;\n meta private;\n}\n#xq99yDlZpVBNRgrY\naction loop() {\n #xBK6GndqJnRSJkTx @\\u267b→engduino→set_all_LEDs(colors→random);\n #xtbigB2VPSstxCXs @\\u267b→engduino→delay(200);\n #OSTD49T6WAb9oYz6 @\\u267b→engduino→set_all_LEDs(colors→black);\n #jTiWi7fMT5Y0BSEk @\\u267b→engduino→delay(200);\n meta private;\n}\n#xdB9Cm8GWFKxZGcr\naction variables() {\n #khP9iYCJxRB2iUZw skip;\n meta private;\n}\n#Z2bgYR2Rs9Bvcb74\nvar screenshot : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/qmjzqlkc\";\n transient = true;\n}\n#XAWEAriEDqFjwWmS meta import engduino {\n pub \"ogmwd\"\n usage {\n\n action `async` set_LED(led_number: Number, color: Color)\n action `async` millis() returns(ms: Number)\n action `async` micros() returns(us: Number)\n action `async` button_pressed() returns(b: Boolean)\n action `async` button_was_pressed() returns(b: Boolean)\n action `async` delay(millis: Number)\n action `async` acceleration() returns(p: Vector3)\n action `async` temperature() returns(p: Number)\n action `async` set_all_LEDs(color: Color)\n }\n #YPEF5gW7PSmp9b4U resolve arduino = ♻ arduino with {\n }\n}\n#uvXS88LcuackBUtZ\naction main() {\n #EuO57UhnSOMDRRlU // This action emulates the code loop in the bug and will not be compiled.\n #Lo714zCo2ze5KJxO code→setup;\n #rTWfhzlllMzajBW8 while true do {\n #xASbcNy6sOwDn24U code→loop;\n }\n}\n#xEqnQPX6C7o8xLVl meta import arduino {\n pub \"cqfda\"\n usage {\n\n action `sync` digital_read(pin: Number) returns(bit: Number)\n action `sync` digital_write(pin: Number, value: Number)\n action `sync` analog_read(pin: Number) returns(bit: Number)\n action `sync` analog_write(pin: Number, value: Number)\n action `async` pin_mode(pin: Number, mode: Number)\n action `sync` HIGH() returns(v: Number)\n action `sync` LOW() returns(v: Number)\n action `sync` OUTPUT() returns(v: Number)\n action `sync` INPUT() returns(v: Number)\n action `async` delay(millis: Number)\n action `sync` sketch(source: String)\n action `sync` static_buffer(bytes: String) returns(buf: Buffer)\n action `sync` INPUT\\_PULLUP() returns(v: Number)\n action `sync` LED\\_BUILTIN() returns(r: Number)\n action `sync` mac(address: String)\n action `sync` analog_reference(type: Number)\n action `sync` DEFAULT() returns(r: Number)\n action `sync` EXTERNAL() returns(r: Number)\n action `sync` tone(pin: Number, frequency: Number, duration: Number)\n action `sync` no_tone(pin: Number)\n action `sync` millis() returns(millis: Number)\n action `sync` micros() returns(micros: Number)\n action `sync` pulse_in(pin: Number, value: Number, timeout: Number) returns(micros: Number)\n action `sync` board(name: String)\n action `sync` print_value(name: String, value: Number)\n action `sync` print(text: String)\n action `sync` println(text: String)\n action `sync` map(value: Number, from_low: Number, from_high: Number, to_low: Number, to_high: Number) returns(r: Number)\n action `sync` constrain(value: Number, a: Number, b: Number) returns(r: Number)\n action `async` delay_microseconds(micros: Number)\n }\n}\n", "ckbk": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"teach\";\nmeta rootId \"rfFWOBXKYWbKL3882OCwIeVx\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n// Teaching with TouchDevelop. #docs #teach #education\n#sJti4PgyaJBMZl5Xa5UMimxW\naction main() {\n #K1y28DAXzlzjVqnx // {parentTopic:contents}\n #sYkQiq3Kz6SzmixV // {priority:100}\n #VE3zvfX2r4Slzd0O // TouchDevelop makes it fun to learn (and teach) programming skills. This section has lots of ideas for using TouchDevelop in the classroom.\n #A6eQBe2sSnp2lUqk // * **Are you a teacher? Join the [TouchDevelop Teachers group](#pub:sxlktprb)!**\n #xQ6nypfXFlgBD7VZ // ### resources for educators\n #iTqjubSk3ck5JnQE // * [Hour Of Code](https://www.touchdevelop.com/hoc) - all the information to run an **Hour Of Code** with TouchDevelop\n #bBTHXKtvHh3YgmNL // * [](/courses) — choose from different curriculum to teach about mobile app and game creation\n #xbbpj2AABJzoZacv // * [](/tutorials) — step by step tutorials to build games and apps\n #Hd33r1xwwgD7qsD7 // * [docs](/contents) — the built-in documentation\n #qQqt5pFCKhlqbNUX // * [](/book) — currently available for free online; systematic introduction to all basic concepts\n #OPjd1hyHfJ39XbW8 // ### environments\n #lLBw4hzsB8IpuVx9 // * The **TouchDevelop Web App** runs in [most modern browsers](https://www.touchdevelop.com/app/current.browsers).\n #Z4En3ihiQz4Dcdfi // * The [TouchDevelop Windows Phone app](http://www.windowsphone.com/s?appId=fe08ccec-a360-e011-81d2-78e7d1fa76f8) gives access to most sensors and data providers available on modern smartphones. [More resources for educators interested in using Windows Phone...](https://www.touchdevelop.com/teachwindowsphone)\n #uc4AzvPR1oVPRmCN // * The [TouchDevelop Android app](https://play.google.com/store/apps/details?id=com.microsoft.touchdevelop) gives access to notifications on Android\n #bAFkE6FP49vQmk4Q // Learn more about [platforms and supported features](https://www.touchdevelop.com/platforms).\n #T4CItQIBnMyWsjzq // ### create your own tutorials and docs\n #RLolkQMEUD0pU4i5 // In addition to creating fun and useful apps, you can use TouchDevelop to create custom interactive tutorials to augment your curriculum. You can also create your own documentation topics adding to the TouchDevelop documentation. This benefits not only your class, but the entire TouchDevelop community!\n #qc2MeCvS62HoY74P // * [creating interactive tutorials](/creatinginteractivetutorials)\n #Esv88v05v32k6UzH // * [add your own docs](/addyourowndocs)\n #cKhwOfsnzrr9c6Ri // ### manage your classroom\n #ZZ80VlTdiwMCWzcy // * You can create [](/groups) and manage your classrooms through them. Groups have a message board and allow to easily collect homework from your students.\n #xo43SANX5LZxfqRT // * Use a [label printer](/labelprinter) to easily get printed labels from student scripts\n #ow6CAnIoZDQOKOLP // ### follow your students\n #t6fGFzG0xF05rZyE // As a teacher, consider [subscribing](/subscriptions) to your students to see what they are publishing and if they are asking questions.\n #ueEDtziGGzDu30Yi // ### experience\n #x2P2jb0Ng0DiKokb // Visit the [TouchDevelop teaching page](http://research.microsoft.com/touchdevelop/teaching.aspx) at Microsoft Research for a list of how TouchDevelop has been used and is being used in classrooms.\n}\n", "cljk": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"getting started\";\nmeta icon \"CoffeeCup\";\nmeta color \"#ff007fff\";\nmeta rootId \"jgxw4hrQ2FJpvMX5ioKe2B98\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n// A few tips on getting started with TouchDevelop. #docs #gettingStarted\n#xIo02XpbLanjKZPs4Os6Y4LA\naction main() {\n #Oqq61gE3scTEvYZY // {parentTopic:contents}\n #zLfUy9LLj4LtaQx1 // {priority:15}\n #BtM6DR2J5yHB6sPI // TouchDevelop lets you **create apps** on all your devices. Let's get started!\n #xTc92pAlcVjk7NIM // ## interactive tutorials\n #UR4kehofIixy8ZqD // Interactive tutorials let you learn at your own pace. We recommend starting out with one or more of these:\n #BMpEHAl89GLjB6Tj // * {follow:first steps with turtle}\n #RyRvlr3i8Xt2QwpU // * {follow:jumping bird tutorial}\n #ZQgFR1AVUm6THyGs // * {follow:coding jetpack jumper}\n #zObCeEa9dPLp8ooa // * {follow:pixel art tutorial}\n #zxrf3iOVA2LWSucN // Try also\n #q9JFJmh12AXcgatn // * [build your first app](http://aka.ms/buildyourfirstapp)\n #Fi2zIopLiFb4rNH4 // * Run an [Hour Of Code](https://www.touchdevelop.com/hoc) with TouchDevelop!\n #yx3F7H4uaTmcHwkO // Browse many other [interactive tutorials](/tutorials) and [courses](/courses). Learn how to build your own games, social apps, and more! Also, check out the book [TouchDevelop - Programming on the Go](/book). It's available as a free download!\n #xJmv15REfU94PGim // ## if you have programming experience...\n #fl1IdthF70YHQxDf // ### Traditional Languages\n #ss44jvTWrjOMlUod // {pic:eclipse:12x5}\n #h4UEzbiXxngho4qF // If you have experience with a traditional programming language such as Java, JavaScript, Python, C#, or C++:\n #P2cb12dV12LdnGN4 // * Start with [hello world](/helloworld) and create a TouchDevelop version of the classic 'hello world' app.\n #Tk1HQSMDs4fk4SuF // * Go to the [dev boot camp](/devbootcamp) and get a quick overview of the TouchDevelop language and environment.\n #xqE7TP69LpivSkjp // * Try a [social app tutorial](/socialapptutorials).\n #xM8eoCxsFuNcZ6Lc // ### Block Programming Environments\n #A6h4niF5i1xLuOXm // {pic:scratch:11x4}\n #k1oezDF4jvXHgk3V // If you have experience with block programming environments such as **Scratch**, **AppInventor**, **Snap!** (BYOB), **code.org**, **Blockly**, or other tools, let us show you how to [transition from blocks to text](/fromblockstotext).\n #KY8dTaEdqs4sjpRG // ## inform and instruct\n #Retn7qEvVW1pvEQZ // In addition to creating fun and useful apps, you can use TouchDevelop to create custom interactive tutorials to show users how to perform specific tasks. You can also create your own documentation topics to expand the TouchDevelop documentation!\n #xCY1IPuWs8bC15Fj // * [creating interactive tutorials](/creatinginteractivetutorials)\n #HIy9PSdtPgJXRY8Z // * [add your own docs](/addyourowndocs)\n}\n#kZWqFwNpvbKrHfETZ2TSQKCA\nvar scratch : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/fpxfkwlk\";\n transient = true;\n}\n#b97YU9g2RQFdWzG22RPqgK2Y\nvar eclipse : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/srtrixfh\";\n transient = true;\n}\n#SxNnQzF2puTSD7MMUORJP2UN\nvar turtle : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/pskgnelo\";\n transient = true;\n}\n", +"cptje": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync,upperplex\";\nmeta name \"blank minecraft pi\";\nmeta color \"#ffffffff\";\nmeta rootId \"UqtPMmqsRpLtBLICK3xNRKmo\";\nmeta iconArtId \"eopyzwpm\";\nmeta allowExport \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n#ALKdKR1Vv5Af8ary\naction main() {\n #sP3br35YdRFiPoQN $steve := @\\u267b→minecraft_pi→player_;\n #x8bszXo68hv0QbQi $x, $y, $z := $steve→position;\n #m6yuFeDYdeeeljiq $steve→set_position($x, $y + 50, $z);\n}\n#aRCXIAMUsrFd3tkf meta import minecraft_pi {\n pub \"ogxna\"\n usage {\n #BVGhpbmca\n table Block_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n // Gets the block state\n #xNQF2IfWS5kUTCuC state : Number\n // Picks a wool color if applicable.\n // {hints:white,orange,magenta,light blue,yellow,lime,pink,grey,light grey,cyan,purple,blue,brown,green,red,black}\n #xUNtn4WzFNh0J275 wool_color : String\n }\n }\n #xIIDIryL3GdLzzFH\n table Connect_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n // Minecraft Server internet host\n #IhKVKMjdA949jNr3 host : String\n // Minecraft PI port (default 4711)\n #PQgsvjixlAlu49Bw port : Number\n // Address of the web socket proxy\n #nlMXsJlluWZB1fNN proxy : String\n }\n }\n #umgRs0Idq3y9jRyc\n table Block_Event {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #SCV1txxxrjigP8XC kind : String\n #UIy6UFvY6WJWDDoA x : Number\n #wWASeEjKJDoiqrL2 y : Number\n #MkoIqcTcP3QiIoot z : Number\n #kYCW4sVB0Q5jQy0Q face : Number\n #EayHvTpmMjNF3Sfh entity : ♻ minecraft_pi → Entity\n }\n }\n type Entity\n action `async` connect(options\\u003f: ♻ minecraft_pi → Connect_Options)\n action `async` set_block(x: Number, y: Number, z: Number, name: String, options\\u003f: ♻ minecraft_pi → Block_Options)\n action `async` set_blocks(x: Number, y: Number, z: Number, x2: Number, y2: Number, z2: Number, name: String, options\\u003f: ♻ minecraft_pi → Block_Options)\n action `async` block(x: Number, y: Number, z: Number) returns(name: String, state: Number)\n action `async` height(x: Number, z: Number) returns(y: Number)\n action `async` chat(msg: String)\n action `async` position(entity: ♻ minecraft_pi → Entity) returns(x: Number, y: Number, z: Number)\n action `async` set_position(entity: ♻ minecraft_pi → Entity, x: Number, y: Number, z: Number)\n action `async` events_clear()\n action `async` event_block_hits() returns(hits: Collection[ ♻ minecraft_pi → Block_Event])\n action `sync` is_connected() returns(r: Boolean)\n action `async` player_() returns(steve: ♻ minecraft_pi → Entity)\n action `async` players() returns(players: Collection[ ♻ minecraft_pi → Entity])\n action `async` direction(entity: ♻ minecraft_pi → Entity) returns(d: Number)\n action `async` rotation(entity: ♻ minecraft_pi → Entity) returns(d: Number)\n action `async` pitch(entity: ♻ minecraft_pi → Entity) returns(d: Number)\n action `async` player_by_name(name: String) returns(steve: ♻ minecraft_pi → Entity)\n }\n #hP2Xa8sKUY0vfcUl resolve shell = ♻ shell with {\n }\n}\n#x0kfnNJUbyhoMANO meta import shell {\n pub \"ohymc\"\n usage {\n #BdGhpbmca\n table Exec_Output {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #YaaLgMz45N5ZuAeU success : Boolean\n #qrwQiGIhHhUhb8AF error : String\n #ijyQCE4KPQL2ziZD code : Number\n #wf4AkGfhLyWkyKhQ stdout : String\n #ZyLfqXXM99R1znCa stderr : String\n }\n }\n type Command_Result\n type Shell_Socket\n action `async` write_file(path: String, content: String) returns(res: ♻ shell → Command_Result)\n action `sync` mkpath(folder: String, name: String) returns(path: String)\n action `async` mkdir(path: String) returns(res: ♻ shell → Command_Result)\n action `async` exec(cmd: String, cwd: String) returns(res: ♻ shell → Exec_Output)\n action `sync` logger() returns(logger: App_Logger)\n action `async` exec_file(cmd: String, args: Collection[String], cwd: String) returns(res: ♻ shell → Exec_Output)\n action `async` python_env() returns(res: ♻ shell → Command_Result)\n action `async` tcp_connect(host: String, port: Number) returns(sock: ♻ shell → Shell_Socket)\n action `async` receive(sock: ♻ shell → Shell_Socket) returns(netdata: String)\n action `async` send(sock: ♻ shell → Shell_Socket, netdata: String)\n action `async` close(sock: ♻ shell → Shell_Socket)\n }\n}\n", "cqnha": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"blank arduino\";\nmeta icon \"ArrowStandardCircle\";\nmeta color \"#ff00cc99\";\nmeta rootId \"xkbt9ErH776FGA72sWuqxeOz\";\nmeta iconArtId \"kzajxznr\";\nmeta allowExport \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n// An Arduino sketch. #arduino #arduinoSketch\n#KUJMn0ag6zrqQys9\naction setup() {\n #qWODTg5ZnR95PTeF @\\u267b→arduino→pin_mode(13, @\\u267b→arduino→OUTPUT);\n meta private;\n}\n#UzRPACG9RBTCLU2MkuwLAhpD\naction loop() {\n #x5bamvNg9UVXaFY7 @\\u267b→arduino→digital_write(13, @\\u267b→arduino→HIGH);\n #UybvnpQJqqrqtrnH @\\u267b→arduino→delay(200);\n #xqXPRRCVUKc8rCTO @\\u267b→arduino→digital_write(13, @\\u267b→arduino→LOW);\n #um2lxP36WxO2OgOk @\\u267b→arduino→delay(200);\n meta private;\n}\n#iHY2wlj4qcvFdTHc meta import arduino {\n pub \"cqfda\"\n usage {\n action `sync` digital_read(pin: Number) returns(bit: Number)\n action `sync` digital_write(pin: Number, value: Number)\n action `sync` analog_read(pin: Number) returns(bit: Number)\n action `sync` analog_write(pin: Number, value: Number)\n action `async` pin_mode(pin: Number, mode: Number)\n action `sync` HIGH() returns(v: Number)\n action `sync` LOW() returns(v: Number)\n action `sync` OUTPUT() returns(v: Number)\n action `sync` INPUT() returns(v: Number)\n action `async` delay(millis: Number)\n action `sync` sketch(source: String)\n action `sync` static_buffer(bytes: String) returns(buf: Buffer)\n action `sync` INPUT\\_PULLUP() returns(v: Number)\n action `sync` LED\\_BUILTIN() returns(r: Number)\n action `sync` mac(address: String)\n action `sync` analog_reference(type: Number)\n action `sync` DEFAULT() returns(r: Number)\n action `sync` EXTERNAL() returns(r: Number)\n action `sync` tone(pin: Number, frequency: Number, duration: Number)\n action `sync` no_tone(pin: Number)\n action `sync` millis() returns(millis: Number)\n action `sync` micros() returns(micros: Number)\n action `sync` pulse_in(pin: Number, value: Number, timeout: Number) returns(micros: Number)\n action `sync` board(name: String)\n action `sync` print_value(name: String, value: Number)\n action `sync` print(text: String)\n action `sync` println(text: String)\n action `sync` map(value: Number, from_low: Number, from_high: Number, to_low: Number, to_high: Number) returns(r: Number)\n action `sync` constrain(value: Number, a: Number, b: Number) returns(r: Number)\n action `async` delay_microseconds(micros: Number)\n }\n}\n#xJTsvVkdQIFOcF0fRDHFLPLk\naction variables() {\n #xaFPmIVW8ylv5b9P // Initializes your global variables here.\n meta private;\n}\n", "cwgn": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"layout\";\nmeta icon \"NineColumn\";\nmeta color \"#ff9955bb\";\nmeta rootId \"J2g52kon8pb1Qs9cRhmPGKZu\";\nmeta isLibrary \"yes\";\nmeta allowExport \"yes\";\nmeta platform \"current\";\n// A library to help with laying out boxes.\n#main\naction example() {\n // This library provides various helpers to simplify the layout of boxes.\n // * layout vertically or horizontally based on the page orientation\n do box {\n code→use_flexible_layout;\n // ...\n }\n // * stretch and center a box\n do box {\n code→stretch_and_center;\n // ...\n }\n meta private;\n meta test;\n}\n#fADj2RlGhi2LmT1rCUpyRpxM\naction stretch_and_center() {\n // Stretches horizontally and vertically the current box and aligns the content with the center.\n box→set_horizontal_stretch(1);\n box→set_horizontal_align(\"center\");\n box→set_vertical_stretch(1);\n box→set_vertical_align(\"center\");\n meta sync;\n}\n#QpiD4W44RMmIzOZmyI6706Ps\naction use_flexible_layout() {\n // Uses **horizontal layout** if the page is landscape; **vertical layout** if the page is portrait.\n if box→page_width > box→page_height then {\n box→use_horizontal_layout;\n }\n else {\n box→use_vertical_layout;\n }\n meta private;\n meta sync;\n}\n#gridofsquares\naction grid_of_squares(cell_content: Number_Action, count: Number, grid_width: Number, grid_height: Number) {\n // Draw a grid of at least (count) squares, of the specified total width and height.\n $numboxes := $count;\n $Area := $grid_width * $grid_height;\n $bsize := math→sqrt($Area / $numboxes);\n $cols := math→floor($grid_width / $bsize);\n $rows := math→ceiling($numboxes / $cols);\n while $rows * $bsize > $grid_height do {\n $alt1 := $grid_width / ($cols + 1) - .001;\n $alt2 := $grid_height / $rows - 0.001;\n $bsize := math→max($alt1, $alt2);\n $cols := math→floor($grid_width / $bsize);\n $rows := math→ceiling($numboxes / $cols);\n }\n $mgn := .03 * $bsize;\n if $mgn * box→pixels_per_em < 2 then {\n $mgn := 2 / box→pixels_per_em;\n }\n $bsize := $bsize - $mgn;\n do box {\n code→draw_grid($rows, $cols, $mgn, $bsize, $cell_content, 0);\n }\n}\n#drawgrid\naction draw_grid(rows: Number, cols: Number, margin: Number, bsize: Number, cell_content: Number_Action, offset: Number) {\n box→set_height($rows * $bsize + ($rows - 1) * $margin);\n box→use_vertical_layout;\n box→set_vertical_align(\"justify\");\n for 0 ≤ i < $rows do {\n do box {\n box→set_width($cols * $bsize + ($cols - 1) * $margin);\n box→use_horizontal_layout;\n box→set_horizontal_align(\"justify\");\n for 0 ≤ j < $cols do {\n do box {\n do box {\n box→set_width($bsize);\n box→set_height($bsize);\n $cell_content→run($offset + $i * $cols + $j);\n }\n }\n }\n }\n }\n meta private;\n}\n#horizontallyscrollin\naction horizontal_hub_of_squares(cell_content: Number_Action, count: Number, cell_size: Number, group_width: Number, total_height: Number) {\n // Draw a horizontally scrolling grid of at least (count) squares of the specified size, with the specified total height.\n $numboxes := $count;\n $mgn := .03 * $cell_size;\n if $mgn * box→pixels_per_em < 2 then {\n $mgn := 2 / box→pixels_per_em;\n }\n $bsize := $cell_size + $mgn;\n $cols := math→floor($group_width / $bsize);\n $rows := math→floor($total_height / $bsize);\n if $cols ≤ 0 then {\n $cols := $rows;\n }\n $groups := math→ceiling($numboxes / ($rows * $cols));\n box→use_horizontal_layout;\n for 0 ≤ i < $groups do {\n do box {\n if $i ≠ 0 then {\n box→set_margins(0, 0, 0, .2 * $bsize);\n }\n code→draw_grid($rows, $cols, $mgn, $cell_size, $cell_content, $i * ($rows * $cols));\n }\n }\n box→set_scrolling(true, false);\n}\n#verticallyscrollings\naction vertical_hub_of_squares(cell_content: Number_Action, count: Number, cell_size: Number, total_width: Number, group_height: Number) {\n // Draw a vertically scrolling grid of at least (count) squares of the specified size, with the specified total width.\n $numboxes := $count;\n $mgn := .03 * $cell_size;\n if $mgn * box→pixels_per_em < 2 then {\n $mgn := 2 / box→pixels_per_em;\n }\n $bsize := $cell_size + $mgn;\n $cols := math→floor($total_width / $bsize);\n $rows := math→floor($group_height / $bsize);\n if $rows ≤ 0 then {\n $rows := $cols;\n }\n $groups := math→ceiling($numboxes / ($rows * $cols));\n box→use_vertical_layout;\n for 0 ≤ i < $groups do {\n do box {\n if $i ≠ 0 then {\n box→set_margins(.2 * $bsize, 0, 0, 0);\n }\n code→draw_grid($rows, $cols, $mgn, $cell_size, $cell_content, $i * ($rows * $cols));\n }\n }\n box→set_scrolling(false, true);\n}\n", "dbjyb": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"touchdevelop local\";\nmeta icon \"GlobeEUA\";\nmeta color \"#ff007fff\";\nmeta rootId \"O6Rs2BjFB4g0ArT2oat8Gpfc\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n// Explains how to export a script to the App Store. #docs\n#main\naction main() {\n #YKeb2CW4sOdvQyW9 // {parentTopic:contents}\n #OdP2Jka5zS5NMgJG // ## Beta feature!\n #xSh4e5kqwQHcBmkx // It is possible to run TouchDevelop from a local web server on your machine. This allow TouchDevelop to work completely offline or access services required for [app generation](/exporttocordova).\n #x35eEyKbLVKI0YGH // ## installation steps\n #juuuaj9Ro2J2Clco // * install [node.js] (http://nodejs.org/)\n #c72W0S2LKE5DVZEb // * create an empty folder for your projects\n #xFRR2AdHdpXNY6Tp // * open a command prompt in your fresh folder and install the **touchdevelop** npm package.\n #hxp4ucOoAsva9ecH // > ``npm install -g http://aka.ms/touchdevelop.tgz``\n #FDTBrovQEeBZm4YP // * launch TouchDevelop locally (make sure you're in your fresh folder)\n #VdVeyI6zCWRyKLoA // > ``touchdevelop``\n #jB3SWBY83Ya2hQve // This will start the TouchDevelop editor in your default browser.\n #GG0Wwd79o4DWGali // ### using non-default browser\n #c9GeLb0N1ocQTHV0 // If you want to use a different browser run ``touchdevelop --cli`` and then point your browser to the URL printed out, it will look **something like** this:\n #Zt9aw3IdHQhkjOAj // > ``Editor URL: http://localhost:4242/editor/beta#td_deployment_key=``\n #A85X0jwZQ7nxKmA7 // It is very important to copy&paste the deployment key at the end precisely.\n #oZCkpuvERU4pSBgP // ### caching of resources\n #HZg9zZ33hRQewElr // All [art resources](/art) or scripts that are loaded while using TouchDevelop local are automatically cached on disk, which allows for a better experience.\n #dOWKEqjA2EopKrAa // If you are planning to package TouchDevelop, make sure that you use at least once each required script or tutorial so that they get cached.\n #xJW2i0dpR9ECZHbH // ### packaging\n #xk9FWWSoKznWnmdy // If you plan to package and share your local touchdevelop, you need to perform the following step.\n #OWX4ZYDjngkiBEtL // * go to the **hub**,\n #gHhslghRyoF9m2FR // * tap on `[Settings]`\n #xpnUIIdzjeb32vYB // * tap on `[save offline caches]`\n #HBWc0AdjvaE1PBPq // Copy or zip the folder containing the TouchDevelop files.\n}\n#lRC7ZP4I3ytfLfcRhscBaKF6\nvar monster : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/ymggwtmn\";\n transient = true;\n}\n#xZA3MGCJ6sAJtfqSibDFTyzZ\nvar @1_Click_on_Title : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/syhbuwmb\";\n transient = true;\n}\n#x4oXuBrRP7peqBxOraPy0Ppu\nvar @2_Publish_Script : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/uegejzev\";\n transient = true;\n}\n#Pb7ZRhh1Le4Kwz16DOm6h95t\nvar @3_Click_Export_iOS : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/snnlubem\";\n transient = true;\n}\n#JiJThBxgjuQyZZagv84V67Cc\nvar @4_Export_to_App_Store : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/jhmzbank\";\n transient = true;\n}\n#u2byTeHW2wX14mnA374fzvSh\nvar @5_App_is_Ready : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/pnqogdug\";\n transient = true;\n}\n#XhCWNpaqagoeYlvuBl6OZOHa\nvar @6_Search_for_Xcode : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/ukwoekck\";\n transient = true;\n}\n#ZeXqju7M5bfqlm0Gx6CYvtRK\nvar @7_Open_Xcode : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/akluqtvy\";\n transient = true;\n}\n#xzO7Z4FWRmvE3GvB3nUQGdja\nvar @8_Open_Project_Folder : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/duqdaaut\";\n transient = true;\n}\n#JOEveTZ34fcQQBSty0Y64Edz\nvar @9_Run_on_Simulator : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/vxmsyaas\";\n transient = true;\n}\n#xiLx3rI7m5QO2Xo18r4e8IkZ\nvar @10_New_App : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/mpgptjat\";\n transient = true;\n}\n#xvxHs2DcS5TxtO3WUNGJU8SX\nvar @11_App_Info_1 : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/ogcsqjwj\";\n transient = true;\n}\n#ZrjNZAJFXA9xGxb5V6oiQ2fr\nvar @12_App_Info_2 : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/sqvolvpy\";\n transient = true;\n}\n#Y3AswkOZPm0qiy2UVZvlZkez\nvar @13_App_Info_3 : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/aisvqsqf\";\n transient = true;\n}\n#bBNxhIal86lYKIvamSdSIjaY\nvar @14_App_Info_4 : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/afpjiooj\";\n transient = true;\n}\n#NzF4EhVGG7woPhmPnliAixIE\nvar @15_Upload_Images : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/fxzfihkw\";\n transient = true;\n}\n#ncULKNvBE2KztzZPCeZpAkDY\nvar @16_Create_Certificate : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/uzxlvvev\";\n transient = true;\n}\n#HvyrGPpdCBgkgany57HRlfeD\nvar @17_iOS_Device : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/luyofzkt\";\n transient = true;\n}\n#jlzt0AP4sDglw23BWlpFGzmL\nvar @18_Product_Archive : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/mnuosfrx\";\n transient = true;\n}\n#ed23hfCPWk4e4wTEwn4QGZzq\nvar Provisioning_Profile : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/jdzxutxx\";\n transient = true;\n}\n#eXePACFUcwQUUlcmdK8BzBgP\nvar P_Validate : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/waeqjhwx\";\n transient = true;\n}\n#lPh2YgYpDFec75cVhrBPJBW7\nvar Distribute : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/evpvthnw\";\n transient = true;\n}\n#n7TK0c4AGeFXhyBY7vYRqXAx\nvar @3_Click_Export_iOS_2 : Picture {\n is\\_resource = true;\n url = \"https://az31353.vo.msecnd.net/pub/przbvosv\";\n transient = true;\n}\n", @@ -32,6 +33,7 @@ "parp": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"blank turtle\";\nmeta icon \"Snowflake\";\nmeta color \"#ff007fff\";\nmeta rootId \"JfhbuKHwe3K29WLENfXE17iC\";\nmeta allowExport \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n// #turtle\n#k3GG7tZEQiPXLEm5bnyfOkDF\naction main() {\n #iTGtxXhIwXwHLfFT @\\u267b→turtle→forward(100);\n}\n#xEv66n448mkvLMp4 meta import turtle {\n pub \"smzqa\"\n usage {\n type Maze\n action `async` pen_down()\n action `async` pen_up()\n action `async` move_to(x: Number, y: Number)\n action `async` forward(steps: Number)\n action `async` left_turn(angle: Number)\n action `async` set_pen_color(c: Color)\n action `async` xcor() returns(x: Number)\n action `async` ycor() returns(y: Number)\n action `async` heading() returns(a: Number)\n action `async` world_width() returns(w: Number)\n action `async` world_height() returns(h: Number)\n action `async` set_heading(angle: Number)\n action `async` set_pen_size(thickness: Number)\n action `async` right_turn(angle: Number)\n action `async` circle(radius: Number)\n action `async` world_board() returns(board: Board)\n action `async` turn_to(dx: Number, dy: Number)\n action `async` world_picture() returns(pic: Picture)\n action `async` set_speed(steps_per_second: Number)\n action `async` go_home()\n action `async` back(steps: Number)\n action `async` pen_size() returns(size: Number)\n action `async` clean()\n action `async` clear_screen()\n action `async` speed() returns(v: Number)\n action `async` set_xy(xcor: Number, ycor: Number)\n action `async` set_x(xcor: Number)\n action `async` set_y(ycor: Number)\n action `async` pen_color() returns(c: Color)\n action `async` color_under() returns(c: Color)\n action `async` save_picture()\n action `async` xy() returns(x: Number, y: Number)\n action `async` touch_xy() returns(tx: Number, ty: Number)\n action `async` grid()\n action `async` fast()\n action `async` stamp()\n action `async` set_turtle_picture(pic: Picture)\n action `async` set_turtle_opacity(opacity: Number)\n action `async` trail()\n action `async` add_obstacle(maze: ♻ turtle → Maze, x: Number, y: Number, width: Number, height: Number, c: Color)\n action `async` set_goal(maze: ♻ turtle → Maze, x: Number, y: Number, radius: Number, c: Color)\n action `async` maze() returns(maze: ♻ turtle → Maze)\n action `async` lock(maze: ♻ turtle → Maze)\n action `async` history() returns(commands: String)\n action `async` clear_history()\n action `sync` on_command(command: Text_Action)\n action `async` add_way_point(maze: ♻ turtle → Maze)\n action `async` on_collision(maze: ♻ turtle → Maze, collision: Action)\n }\n}\n", "qetpa": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"blank app\";\nmeta icon \"AddressBook\";\nmeta rootId \"xPVLZKRfDmGiasdkBt2RaNR4\";\nmeta allowExport \"yes\";\nmeta platform \"current\";\n#theme meta import theme {\n pub \"gnvi\"\n usage {\n action `async` title_1()\n action `async` title_2()\n action `async` title_3()\n action `async` subtle()\n action `async` normal()\n action `sync` example()\n action `async` accent()\n action `async` set_right_aligned(value: Boolean)\n action `async` huge()\n }\n}\n#main\naction main(\\u2756: * main_page_data) {\n if box→is_init then {\n skip;\n }\n if true then {\n skip;\n }\n meta page;\n meta sync;\n}\n#BbWFpbiBwYWdlIGRhdGEa\ntable main_page_data {\n type = \"Object\";\n persistent = false;\n}\n#YZGaVg1jhqq9sfncCGsIoHbh meta import forms {\n pub \"owroa\"\n usage {\n action `sync` `type` display_code()\n action `sync` `type` validator(s: String) returns(error: String)\n action `sync` button(text: String, on_tapped: Action)\n action `sync` checkbox(text: String, checked: Ref[Boolean])\n action `sync` input_string_collection(label: String, strings: String_Collection)\n action `sync` input_text_line(label: String, text: Ref[String])\n action `sync` input_text_area(label: String, text: Ref[String])\n action `sync` input_password(label: String, password: Ref[String])\n action `sync` input_number(label: String, text: Ref[String], changehandler: Number_Action)\n action `sync` labeled_content(label: String, content: ♻ forms → display_code)\n action `sync` indented_content(content: ♻ forms → display_code)\n action `sync` input_choice(label: String, choices: String_Collection, index: Ref[Number])\n action `sync` input_text_line_w\\u002f_validator(label: String, text: Ref[String], errorcheck: ♻ forms → validator, changehandler: Text_Action)\n }\n}\n#LHF2iIBnkOQcwhcoQKFiR4A2 meta import widgets {\n pub \"abgjb\"\n usage {\n action `sync` message(user: User, dt: DateTime, text: String)\n action `sync` picture(url: String)\n }\n}\n#iDxzKDq4042OKy7IX4V4D91F meta import layout {\n pub \"cwgn\"\n usage {\n action `sync` stretch_and_center()\n action `async` grid_of_squares(cell_content: Number_Action, count: Number, grid_width: Number, grid_height: Number)\n action `async` horizontal_hub_of_squares(cell_content: Number_Action, count: Number, cell_size: Number, group_width: Number, total_height: Number)\n action `async` vertical_hub_of_squares(cell_content: Number_Action, count: Number, cell_size: Number, total_width: Number, group_height: Number)\n }\n}\n", "qexxc": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync,upperplex\";\nmeta name \"blank web api\";\nmeta icon \"Stacks\";\nmeta color \"#ffffffff\";\nmeta rootId \"x4mibwzdISu8zLeLgg7b3IKt\";\nmeta iconArtId \"wyfreugv\";\nmeta isLibrary \"yes\";\nmeta allowExport \"yes\";\nmeta isCloud \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"network,npm,shell\";\nmeta parentIds \"\";\n// An blank web api using Node.JS and Restify. #node #azure #restify\n#czWG9NcXY9uFZHMz\naction \\_init() {\n #rg6M5H46J1bK4x8c data→logger := app→create_logger(\"myweb\");\n #x2Y2gFv2oHeZKjaB code→init_restify;\n #z1Taq8ixDqqUfh2n data→logger→info(\"started...\");\n}\n#FrNAgtgAKnFVC43t\naction GET_\\u002fping() returns(#aM0QoLDaWxwAlfSy millis: Number) {\n #xzy3cNZXu2Lbz9f2 // Returns the number of milliseconds since epoch.\n #IYDlx4xcyWX5wD4m $millis := time→now→milliseconds_since_epoch;\n}\n#a4wL0Lb7xeWxhV4L meta import parallel {\n pub \"fncvb\"\n usage {\n type queue\n action `async` @for(count: Number, @action: Number_Action)\n action `async` for_batched(count: Number, batch_count: Number, item_action: Number_Action, batch_action: Action)\n action `sync` schedule(q: ♻ parallel → queue, task: Action)\n action `sync` create_queue(max_running: Number) returns(queue: ♻ parallel → queue)\n action `async` wait_for_empty(q: ♻ parallel → queue)\n action `async` for_json(js: Json_Object, @action: Json_Action)\n }\n}\n#CW3Wao3uu3Z2Fhe6\nvar logger : App_Logger {\n transient = true;\n}\n#rmfzWWMIFG8Ule9I\naction init_restify() {\n #GL26xBm2sW9gi51S $server := @\\u267b→restify→server;\n #eq0FvCwwbob1i3UD $server→use(@\\u267b→restify→authorization_parser);\n #Ee6qD4jb4Xr4TCYg $server→pre(@\\u267b→restify→sanitize_path);\n #xiHn2sJ7jyfBOFLf $throttle := @\\u267b→restify→throttle;\n #ZU1qf4WMSwf2ZZs8 where rate := 40;\n #S04R2349FF42Rb2O where burst := 100;\n #qa878gtstkVP7tTO where ip := true;\n #kld3kZpnFcZ4TVhB $server→use($throttle);\n #sptEZCs70xCB68CA $server→use(@\\u267b→restify→CORS);\n #mFFPDO74C64OWH8s $server→use(@\\u267b→restify→body_parser);\n #xSqpOmBEP6L2VCFi $server→use(@\\u267b→restify→gzip_response);\n #xR4QGtRsV3hGoSJQ $server→use(@\\u267b→restify→query_parser);\n #x9bNZzJ9tZk0l1Z4 $server→use(@\\u267b→restify→conditional_request);\n #buXcIfKig0apgL4x @\\u267b→restify_touchdevelop→autobind($server);\n #kj30VDMt3gkmKiZM code→init_routes();\n #UAx1DGb27XEqkYO5 $server→use(@\\u267b→restify_touchdevelop→errors_to_log(data→logger));\n meta private;\n meta sync;\n}\n#Png4V3OlrtBkrIAa meta import restify {\n pub \"egzra\"\n usage {\n action `async` `type` Request_Handler(req: ♻ restify → Request, res: ♻ restify → Response)\n #xLPhdjOebDT8w77X\n table Throttle_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #xo6LfV0hyAQtz675 rate : Number\n #yZ2QZAfeW3W74JA1 burst : Number\n #JUlNvDq7Hm9cTUAG ip : Boolean\n #w2h4dcf4I5K5h7kn xff : Boolean\n #RO3Sx6iTt4WsVBm6 username : Boolean\n #VbsYnDvr3t4Xr4VA maxKeys : Number\n #w25h9R5LKJnWiBNu tokensTable : ♻ restify → Tokens_Table\n }\n }\n #xdeuBx505IsZ6eEI\n table Serve_Static_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #NfWLVJBBbHvtMqkl default : String\n #KvIMj1sEoAwQCf22 maxAge : Number\n }\n }\n #mqEMUbizkEp6naSD\n table CORS_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #xMYYV6C3eS7PWsfQ origins : String\n #z5HdpFdSi792e1OX credentials : Boolean\n #Fw1D0A9ZfeMCf5c3 headers : String\n }\n }\n #w2zTzWkfMf01yOko\n table Body_Parser_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #mhaHCLobgUgMrv72 maxBodySize : Number\n #xr4fKleNd4wHHP1l mapParams : Boolean\n #st0ir2vLTxbLTQWB mapFiles : Boolean\n #z5ah2mZWb8c5FmTM overrideParams : Boolean\n }\n }\n #xv4yZciZi2wFoqpM\n table Send_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #svWYln7UIackFIpB status : Number\n }\n }\n type Request\n type Response\n type Tokens_Table\n type Server\n type Middleware\n type Error\n action `sync` use(server: ♻ restify → Server, mid: ♻ restify → Middleware)\n action `sync` get(server: ♻ restify → Server, path: String, @then: ♻ restify → Request_Handler)\n action `sync` post(server: ♻ restify → Server, path: String, @then: ♻ restify → Request_Handler)\n action `sync` server() returns(server: ♻ restify → Server)\n action `sync` send(res: ♻ restify → Response, content: String, options\\u003f: ♻ restify → Send_Options)\n action `sync` status(res: ♻ restify → Response, status: Number)\n action `sync` is(req: ♻ restify → Request, type: String) returns(r: Boolean)\n action `sync` accepts(req: ♻ restify → Request, types: String) returns(type: String)\n action `sync` put(server: ♻ restify → Server, path: String, @then: ♻ restify → Request_Handler)\n action `sync` del(server: ♻ restify → Server, path: String, @then: ♻ restify → Request_Handler)\n action `sync` head(server: ♻ restify → Server, path: String, @then: ♻ restify → Request_Handler)\n action `sync` pre(server: ♻ restify → Server, mid: ♻ restify → Middleware)\n action `sync` CORS(options\\u003f: ♻ restify → CORS_Options) returns(mid: ♻ restify → Middleware)\n action `sync` conditional_request() returns(mid: ♻ restify → Middleware)\n action `sync` route(server: ♻ restify → Server, method: String, path: String, @then: ♻ restify → Request_Handler)\n action `sync` json(res: ♻ restify → Response, content: Json_Object, options\\u003f: ♻ restify → Send_Options)\n action `sync` next(res: ♻ restify → Response)\n action `sync` next_error(res: ♻ restify → Response, error: ♻ restify → Error)\n action `sync` address(server: ♻ restify → Server) returns(address: String)\n action `sync` gzip_response() returns(mid: ♻ restify → Middleware)\n action `sync` header(req: ♻ restify → Request, name: String) returns(value: String)\n action `sync` is_secure(req: ♻ restify → Request) returns(r: Boolean)\n action `sync` is_chunked(req: ♻ restify → Request) returns(r: Boolean)\n action `sync` is_keep_alive(req: ♻ restify → Request) returns(r: Boolean)\n action `sync` set_header(res: ♻ restify → Response, name: String, value: String)\n action `sync` body_parser(options\\u003f: ♻ restify → Body_Parser_Options) returns(mid: ♻ restify → Middleware)\n action `sync` throttle(options\\u003f: ♻ restify → Throttle_Options) returns(middleware: ♻ restify → Middleware)\n action `sync` date_parser(clock_skew: Number) returns(middleware: ♻ restify → Middleware)\n action `sync` serve_static(directory: String, options\\u003f: ♻ restify → Serve_Static_Options) returns(middleware: ♻ restify → Middleware)\n action `sync` query_parser() returns(middleware: ♻ restify → Middleware)\n action `sync` authorization_parser() returns(middleware: ♻ restify → Middleware)\n action `sync` jsonp() returns(middleware: ♻ restify → Middleware)\n action `sync` body_as_json(req: ♻ restify → Request) returns(body: Json_Object)\n action `sync` id(req: ♻ restify → Request) returns(id: String)\n action `sync` param(req: ♻ restify → Request, name: String) returns(value: String)\n action `sync` opts(server: ♻ restify → Server, path: String, @then: ♻ restify → Request_Handler)\n action `sync` patch(server: ♻ restify → Server, path: String, @then: ♻ restify → Request_Handler)\n action `sync` to_string(ser: ♻ restify → Server) returns(s: String)\n action `sync` sanitize_path() returns(middleware: ♻ restify → Middleware)\n action `sync` body(req: ♻ restify → Request) returns(body: String)\n action `sync` send_error(res: ♻ restify → Response, status: Number, message: String)\n action `sync` all(server: ♻ restify → Server, @then: ♻ restify → Request_Handler)\n action `sync` method(req: ♻ restify → Request) returns(method: String)\n action `sync` url(req: ♻ restify → Request) returns(url: String)\n action `sync` query(req: ♻ restify → Request) returns(query: Json_Object)\n action `sync` redirect(res: ♻ restify → Response, status_code: Number, url: String)\n action `sync` send_status(res: ♻ restify → Response, status_code: Number)\n action `sync` charset(res: ♻ restify → Response, encoding: String)\n action `sync` route_regex(server: ♻ restify → Server, method: String, path_regex: String, @then: ♻ restify → Request_Handler)\n action `async` read_body_as_buffer(req: ♻ restify → Request) returns(body: Buffer)\n action `sync` headers(req: ♻ restify → Request) returns(headers: Json_Object)\n action `sync` server_url(req: ♻ restify → Request) returns(url: String)\n action `sync` html(res: ♻ restify → Response, content: String, options\\u003f: ♻ restify → Send_Options)\n }\n}\n#MLbRHC7j0u4Bo4GQ meta import restify_touchdevelop {\n pub \"dvuhb\"\n usage {\n action `sync` autobind(server: ♻ restify → Server)\n action `sync` errors_to_log(logger: App_Logger) returns(middleware: ♻ restify → Middleware)\n }\n #OzaDw2jYXC1r4oMK resolve restify = ♻ restify with {\n }\n}\n#xcZnKOBpfz0lu8jD\naction init_routes() {\n #MxIs21VA5KpTC0F8 $server := @\\u267b→restify→server;\n #B2Ui2S2BrMhefyH4 $server→get(\"/echo\", $@then);\n #c58sWTLqXwkWaboA where @then(req: ♻ restify → Request, res: ♻ restify → Response) {\n #yXsNFxumA3UsfrbL $res→send($req→body);\n }\n meta private;\n meta sync;\n}\n", +"qzky": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync,upperplex\";\nmeta name \"blank minecraft steve\";\nmeta color \"#ffffffff\";\nmeta rootId \"nHs55hVQebfHsdRXLqdn6Z3u\";\nmeta iconArtId \"zpybrwpw\";\nmeta allowExport \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"accelerometer,location,musicandsounds,network,orientation,shell\";\nmeta parentIds \"\";\n// A Minecraft Steve app #minecraft #steve #turtle\n#ew46jSsSq5jX27bx\naction main() {\n #C5Nw6Q63PHrMOwzg @\\u267b→steve→change_block(\"tnt\");\n #PP9GM4o5xyjrF9bc @\\u267b→steve→move_forward(5);\n}\n#xjJWPhuXXYNcd717 meta import steve {\n pub \"skyy\"\n usage {\n\n action `async` move_forward(blocks: Number)\n action `async` turn_left(angle: Number)\n action `async` turn_right(angle: Number)\n action `async` move_back(blocks: Number)\n action `async` change_block(name: String)\n action `async` fly_down(blocks: Number)\n action `async` fly_up(blocks: Number)\n action `async` position() returns(x: Number, z: Number)\n action `async` fly_mode()\n action `async` build_cube(sides: Number)\n action `async` build_tower(sides: Number, height: Number)\n action `async` wipe_out()\n action `async` mine(blocks: Number)\n action `async` ground_height() returns(y: Number)\n action `async` walk_mode()\n action `async` dig_mode()\n action `async` block() returns(kind: String)\n action `async` chat(msg: String)\n action `async` add_checkpoint(id: String)\n action `async` go_to_checkpoint(id: String)\n action `async` build_walls()\n }\n #xmPPKkVEJW5oafB1 resolve turtle = ♻ turtle with {\n }\n #n20JN4HoRDpuPqS7 resolve minecraft_pi = ♻ minecraft_pi with {\n }\n #gkFPFcj0NktKP08U resolve shell = ♻ shell with {\n }\n}\n#avbYmXsE1IUcMn6R meta import turtle {\n pub \"auwmg\"\n usage {\n type Maze\n\n action `async` pen_down()\n action `async` pen_up()\n action `async` move_to(x: Number, y: Number)\n action `async` forward(steps: Number)\n action `async` left_turn(angle: Number)\n action `async` set_pen_color(c: Color)\n action `async` xcor() returns(x: Number)\n action `async` ycor() returns(y: Number)\n action `async` heading() returns(a: Number)\n action `async` world_width() returns(w: Number)\n action `async` world_height() returns(h: Number)\n action `async` set_heading(angle: Number)\n action `async` set_pen_size(thickness: Number)\n action `async` right_turn(angle: Number)\n action `async` circle(radius: Number)\n action `async` world_board() returns(board: Board)\n action `async` turn_to(dx: Number, dy: Number)\n action `async` world_picture() returns(pic: Picture)\n action `async` set_speed(steps_per_second: Number)\n action `async` go_home()\n action `async` back(steps: Number)\n action `async` pen_size() returns(size: Number)\n action `async` clean()\n action `async` clear_screen()\n action `async` speed() returns(v: Number)\n action `async` set_xy(xcor: Number, ycor: Number)\n action `async` set_x(xcor: Number)\n action `async` set_y(ycor: Number)\n action `async` pen_color() returns(c: Color)\n action `async` color_under() returns(c: Color)\n action `async` save_picture()\n action `async` xy() returns(x: Number, y: Number)\n action `async` touch_xy() returns(tx: Number, ty: Number)\n action `async` grid()\n action `async` fast()\n action `async` stamp()\n action `async` set_turtle_picture(pic: Picture)\n action `async` set_turtle_opacity(opacity: Number)\n action `async` trail()\n action `async` add_obstacle(maze: ♻ turtle → Maze, x: Number, y: Number, width: Number, height: Number, c: Color)\n action `async` set_goal(maze: ♻ turtle → Maze, x: Number, y: Number, radius: Number, c: Color)\n action `async` maze() returns(maze: ♻ turtle → Maze)\n action `async` lock(maze: ♻ turtle → Maze)\n action `async` history() returns(commands: String)\n action `async` clear_history()\n action `sync` on_command(command: Text_Action)\n action `async` add_way_point(maze: ♻ turtle → Maze)\n action `async` on_collision(maze: ♻ turtle → Maze, collision: Action)\n action `async` interactive()\n action `async` on_move(@action: Action)\n action `async` set_raster(value: Boolean)\n }\n}\n#N0dQjhcc8OySnSbe meta import minecraft_pi {\n pub \"ogxna\"\n usage {\n #BVGhpbmca\n table Block_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n // Gets the block state\n #xNQF2IfWS5kUTCuC state : Number\n // Picks a wool color if applicable.\n // {hints:white,orange,magenta,light blue,yellow,lime,pink,grey,light grey,cyan,purple,blue,brown,green,red,black}\n #xUNtn4WzFNh0J275 wool_color : String\n }\n }\n #xIIDIryL3GdLzzFH\n table Connect_Options {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n // Minecraft Server internet host\n #IhKVKMjdA949jNr3 host : String\n // Minecraft PI port (default 4711)\n #PQgsvjixlAlu49Bw port : Number\n // Address of the web socket proxy\n #nlMXsJlluWZB1fNN proxy : String\n }\n }\n type Entity\n #umgRs0Idq3y9jRyc\n table Block_Event {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #SCV1txxxrjigP8XC kind : String\n #UIy6UFvY6WJWDDoA x : Number\n #wWASeEjKJDoiqrL2 y : Number\n #MkoIqcTcP3QiIoot z : Number\n #kYCW4sVB0Q5jQy0Q face : Number\n #EayHvTpmMjNF3Sfh entity : ♻ minecraft_pi → Entity\n }\n }\n\n action `async` connect(options\\u003f: ♻ minecraft_pi → Connect_Options)\n action `async` set_block(x: Number, y: Number, z: Number, name: String, options\\u003f: ♻ minecraft_pi → Block_Options)\n action `async` set_blocks(x: Number, y: Number, z: Number, x2: Number, y2: Number, z2: Number, name: String, options\\u003f: ♻ minecraft_pi → Block_Options)\n action `async` block(x: Number, y: Number, z: Number) returns(name: String, state: Number)\n action `async` height(x: Number, z: Number) returns(y: Number)\n action `async` chat(msg: String)\n action `async` position(entity: ♻ minecraft_pi → Entity) returns(x: Number, y: Number, z: Number)\n action `async` set_position(entity: ♻ minecraft_pi → Entity, x: Number, y: Number, z: Number)\n action `async` events_clear()\n action `async` event_block_hits() returns(hits: Collection[ ♻ minecraft_pi → Block_Event])\n action `sync` is_connected() returns(r: Boolean)\n action `async` player_() returns(steve: ♻ minecraft_pi → Entity)\n action `async` players() returns(players: Collection[ ♻ minecraft_pi → Entity])\n action `async` direction(entity: ♻ minecraft_pi → Entity) returns(d: Number)\n action `async` rotation(entity: ♻ minecraft_pi → Entity) returns(d: Number)\n action `async` pitch(entity: ♻ minecraft_pi → Entity) returns(d: Number)\n action `async` player_by_name(name: String) returns(steve: ♻ minecraft_pi → Entity)\n }\n #gNAc4g4iSTkZHWeT resolve shell = ♻ shell with {\n }\n}\n#qCJBh3ACKHsrS9Hz meta import shell {\n pub \"ohymc\"\n usage {\n #BdGhpbmca\n table Exec_Output {\n type = \"Object\";\n exported = true;\n persistent = false;\n fields {\n #YaaLgMz45N5ZuAeU success : Boolean\n #qrwQiGIhHhUhb8AF error : String\n #ijyQCE4KPQL2ziZD code : Number\n #wf4AkGfhLyWkyKhQ stdout : String\n #ZyLfqXXM99R1znCa stderr : String\n }\n }\n type Command_Result\n type Shell_Socket\n\n action `async` write_file(path: String, content: String) returns(res: ♻ shell → Command_Result)\n action `sync` mkpath(folder: String, name: String) returns(path: String)\n action `async` mkdir(path: String) returns(res: ♻ shell → Command_Result)\n action `async` exec(cmd: String, cwd: String) returns(res: ♻ shell → Exec_Output)\n action `sync` logger() returns(logger: App_Logger)\n action `async` exec_file(cmd: String, args: Collection[String], cwd: String) returns(res: ♻ shell → Exec_Output)\n action `async` python_env() returns(res: ♻ shell → Command_Result)\n action `async` tcp_connect(host: String, port: Number) returns(sock: ♻ shell → Shell_Socket)\n action `async` receive(sock: ♻ shell → Shell_Socket) returns(netdata: String)\n action `async` send(sock: ♻ shell → Shell_Socket, netdata: String)\n action `async` close(sock: ♻ shell → Shell_Socket)\n }\n}\n", "sduub": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"game\";\nmeta icon \"controller\";\nmeta color \"#ff9955bb\";\nmeta rootId \"F18otGXDXq4l5kwcjDwwlg1w\";\nmeta isLibrary \"yes\";\nmeta allowExport \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"current\";\nmeta parentIds \"\";\n// A library to create games with physics, life, score and leaderboard. #games\n#Ayu95FKZqA9xPdjQXSANLGvP\naction initialize(#Ef1fU1WP2dp5fv5i width: Number, #CIEvqcj84KymuPB3 height: Number) {\n #bNSXfBcyc1TlFXuk // Call this first with your game board\n #Clk2zqeLTyzvKFNp $ratio := wall→width / wall→height;\n #lHC24tGRfxpXZxgk if $width < 0 `and` $height < 0 then {\n #xZ5BAygKRsMnteqb if $ratio < 1 then {\n #Ye23loceGoB42QXd $width := 800 * $ratio;\n #XOxgQshg475aS5Hk $height := 800;\n }\n else {\n #JqNvfilYjyb1v6dO $width := 800;\n #sEmxz8ZVPjbzQaT5 $height := 800 / $ratio;\n }\n }\n #jhe41v4xeIFpAnXk if $width < $height then {\n #Qe4DsmxnWXWundDd if $width < 0 then {\n #mo0yRpxiwtI2oz42 if $ratio < 1 then {\n #sLJ2pYjNI9NO4jGv $ratio := 1 / $ratio;\n }\n #lohlOvEl2FCCHlN8 $width := $height * $ratio;\n }\n #xZv5qx7QK0pfbIwx data→\\_board := media→create_portrait_board($width, $height);\n }\n else {\n #mbaxWZ8Upqc4dY2m if $height < 0 then {\n #urxU2iGbiBiGNGbM if $ratio < 1 then {\n #xzVsM6nAQXKxe7pq $ratio := 1 / $ratio;\n }\n #Y2iBY1rS8V2IYESl $height := $width / $ratio;\n }\n #IisORl3LBXmnPKgW data→\\_board := media→create_landscape_board($width, $height);\n }\n #cpH4M20Y66Y5LRJs data→\\_score := 0;\n #ekMv5bgzPxBK4CW4 data→\\_life := 3;\n #jbZnUix7Lx1Q7ZDV data→\\_start_time := invalid→datetime;\n #w1UaCIU8Ev4ebPlb data→\\_life_txt := invalid→sprite;\n #JOr3eMPViQ4dHWhw data→\\_score_txt := invalid→sprite;\n #my4nhbFyphwdVePb data→\\_timer_txt := invalid→sprite;\n #jLtQyZzuywVmboyz data→\\_countdown_duration := - 1;\n #ZZUqmmdXH7QdhMrH data→\\_hearts := \"---;❤;❤❤;❤❤❤\" →split(\";\");\n #xKSYee6TFDQOfML9 data→\\_score_txt := code→create_text();\n #Yyg0CzGMYWO9TQ47 data→\\_score_txt→set_pos(data→\\_board→width - 132, 20);\n #CtaIZxAjWA3KSV2x data→\\_score_txt→set_color(colors→orange);\n #kTjf5SscJwSXMOxR data→\\_life_txt := code→create_text;\n #lD26N7zVYcw4OA2B data→\\_life_txt→set_color(colors→red);\n #ShXHDkMQszri4hgi data→\\_life_txt→set_pos(84, 20);\n #DF79Mzy4RLJvr5lu data→\\_timer_txt := code→create_text;\n #flUJeGo9oH4ZKL7k data→\\_timer_txt→set_pos(data→\\_board→width / 2, 20);\n #nvzUAhKiUrDNx9ua if data→\\_board→width < data→\\_board→height then {\n #tprbh6Qbs4RtbWGE data→\\_score_txt→set_y(data→\\_board→height / 10.5);\n #vo1skKgdHy2wqGAI $y := data→\\_score_txt→y;\n #xIiwhrp5beNVxp0W data→\\_timer_txt→y := data→\\_score_txt→y;\n #xRtkSt16gx2kVUQE data→\\_life_txt→set_y($y);\n #xVMKJwJbqH32RaBs data→\\_score_txt→x := data→\\_board→width - 64;\n #sftDMBB4Rc62DLVK data→\\_life_txt→x := 64;\n }\n #lVFXy8tvC2YO5VaY code→set_score(0);\n #u1GLYt6g45euiwLd code→set_life(3);\n meta private;\n}\n#xW5SJ4MKJ44wSSDVuZgZG3iS\nvar \\_board : Board {\n transient = true;\n}\n#oKY8zayGQ3QsufrQiKXXS9sh\naction set_score(#xNzj5Tyy4ubd9CTJ value: Number) {\n #PK9RS22fUTIwMlpW // Sets the current score\n #jia5eGpMgyK70yu7 data→\\_score_txt→text := math→ceiling(data→\\_score)→to_string;\n #xQiqEsIGlVBWEId8 data→\\_score := $value;\n #xolTOrWos40PlDsI if data→\\_score < 0 then {\n #x6X2fk4vDwHtW7kW data→\\_score_txt→hide;\n }\n else {\n #jdbScDz352fC51ZD data→\\_score_txt→show;\n #xK4S7FrNcjoVbrXT $anim := data→\\_score_txt→create_animation;\n #xvRwFDBdhXE6rfYC $anim→text(1, \"cubic\", \"inout\", math→ceiling(data→\\_score)→to_string);\n }\n meta sync;\n}\n#l4svuo4DZFDcDqJbGklzHLTi\naction set_life(#Od5XHbEXJ6mWwB8S value: Number) {\n #jJNGIzmWCGL9Ye5S // Sets the current life points. Set as negative or zero to end the game.\n #HrH1awtB4sa44j1P data→\\_life := math→max(0, $value);\n #KKSJ0NQA0LL2KCCt if data→\\_life ≤ 0 then {\n #UPv3xvSjaIsOHLKO code→evolve;\n #O8ZDpX4rPiqIH7PJ code→end;\n }\n}\n#xR8UEUDLaI6qbCw4GQtfFiwQ\naction start_timer() {\n #PY2vofNQd2BKaT5s // Starts a stopwatch timer\n #lh5CUs6TzxANutck data→\\_start_time := time→now;\n #SOklrsSACxtSyTFU data→\\_countdown_duration := - 1;\n meta sync;\n}\n#uCawjS8UtYJd1W4TZkrVvAE7\naction start_countdown_timer(#sXGZbgouHWzZbxDx seconds: Number) {\n #Y1MYOM224FH40w2J // Starts a countdown timer starting at second.\n #UNJ3mVD9lmnoyJtS // {hints:seconds:30,15}\n #xrYxMpoChJ3q8C4C data→\\_start_time := time→now;\n #xpOkBULYOyu5K6ol data→\\_countdown_duration := $seconds;\n meta sync;\n}\n#YXmGOuliQ2RYyUc3NtRv9DNE\naction life() returns(#ngP5T2tPSB4Euoev r: Number) {\n #xF0BpscALdWMIeMq // Returns the current life points. Negative if not set.\n #X5WbD4tx2QCjM0xZ $r := data→\\_life;\n meta sync;\n}\n#xubkD4SENn7AllzejMhYSTOV\nvar \\_life : Number {\n transient = true;\n}\n#lp3pSLpGr7O3RGbDzuSQiJ5m\nvar \\_score : Number {\n transient = true;\n}\n#xleVEbMbZTbU7BJfeUMUPpMk\naction score() returns(#x2cmZgt88Gtfc90g r: Number) {\n #ZXZChxtbZJ7VM49L // Gets the current score; negative if not set.\n #eM5HsVUk3W4Wjmar $r := data→\\_score;\n meta sync;\n}\n#TzLNjDeJYpMRpdgNFuqgE2PY\nvar \\_start_time : DateTime {\n transient = true;\n}\n#gswamj84uYSwqLED2VvLdKi6\naction evolve() {\n #V02U4MCe9H2MP9DW if `not` data→\\_board→is_invalid then {\n #xtVboJorI0AoA2Ll data→\\_board→evolve;\n #ZyuqlVaK8jZ4RcTi if data→\\_life ≥ 0 then {\n #Zzh3zjzuxyYn2f3X code→evolve_life;\n }\n #fr31zBhiCvv05kR8 if `not` data→\\_start_time→is_invalid then {\n #Im49UQ654OeS2n44 code→evolve_timer;\n }\n }\n meta private;\n}\n#pHEIAaLyqWXgpyUd6dIeYp2X\nvar \\_life_txt : Sprite {\n transient = true;\n}\n#UMupj4ChNfQ8E2uvW694p1tX\naction create_text() returns(#HsWcsHa430EovY0o r: Sprite) {\n #r2pD3YM0AhwqdeoJ $r := data→\\_board→create_text(100, 20, 28, \"\");\n #DfUPvQHARvqZmkPa $r→set_z_index(1000);\n #xvp7IxArcVElQk4H $r→set_friction(1);\n #Sh16Yvgqws3F2ttd $r→set_color(colors→foreground);\n meta private;\n meta sync;\n}\n#XjXM7AL67NDGlzsZgg9s44uq\naction evolve_life() {\n #x69dm0I2qdoTbeEa $l := math→ceiling(data→\\_life);\n #MkDJrwcWdlaEAj5i $s := \"❤ \" ∥ $l→to_string;\n #NnjfQ48F1IZTeEU4 if $l < data→\\_hearts→count then {\n #xUcDUL43eSf74Few $s := data→\\_hearts→at($l);\n }\n #Bv24Vr22toZdfAsj data→\\_life_txt→set_text($s);\n meta private;\n meta sync;\n}\n#PojbQsm32lz5k054APQR8Jb1\naction evolve_timer() {\n #tSYdAJQ9rmGX28Ph $elapsed := code→current_time;\n #zaYbaDOnN52N0y3T data→\\_timer_txt→set_text(math→round_with_precision($elapsed, 1)→to_string);\n #x5HB6TM2gE95ePes if data→\\_countdown_duration > 0 `and` $elapsed = 0 then {\n #M7CIY2SvsjyqZLbG code→end;\n }\n meta private;\n}\n#AejJAmPMk38UG2URZk5hXYh6\nvar \\_score_txt : Sprite {\n transient = true;\n}\n#x2fjfvNmVawvnAWKndzdfxls\nvar \\_timer_txt : Sprite {\n transient = true;\n}\n#x4cIV8c7P0QJsADCfcHm2ApY\nvar \\_countdown_duration : Number {\n transient = true;\n}\n#xK9ECxOm926KPUxdhlTtnYMl\naction example() {\n #akMbxF0YpXNsigw2 // This library lets you build a game with a physics engine, life, score and leaderboard.\n #EsTTE4EYqiiR5mR9 // Let's start by creating a board which we will use for the demo.\n #u3XIthRzNcrktgqo $board := code→start;\n #CB9rVzyFARPTw2L6 // You can use the board as usual.\n #a0rtwTn2G2kZoHic // * you can force landscape or portrait by using `code->start landscape` or `code->start portrait`.\n #HiLltZT9c8Ny7H2E // ### create sprites\n #EP9EIWqKvuc1cX6e // Use ``create sprite`` to create a new moving sprite of width 100.\n #xyZg3wDu5wWFWdW2 // {hide}\n #oPJA0VM7q3Dq7ZEE $pic := media→create_picture(480, 800);\n #iW2dZelc5Tuo2vJY // {/hide}\n #Ng4pLvKyecQ91WR4 $sprite := code→create_sprite($pic);\n #x2HgaAq5uHrc3P8X // ### scores\n #x3VS2BYISO2aappr // Simply call `set score` to display a score on the top right corner of the board. You can use `score` to get back the current value of the score.\n #pMoWowx4j3FkFkkQ code→set_score(3600);\n #Nb4rWtolHuG8aQWe // You can also update the current score by using `add score`.\n #nY0cqPKJNNGoYg2f code→add_score(100);\n #x42VU0bH4Y18mgZ3 // ### life indicator\n #LdsjDYMx4YCgdsld // Use the `set life` action to display a life indicator on the top left corner of the board. You can use `life` to get back the current value of the life.\n #EiPgaOurEAlcymkM code→set_life(1);\n #g9R26zu52v8nG4Lv // You can also update the current life by using `add life` or `remove life`.\n #iuvGvo404RGhd1ty code→add_life(1);\n #x2gRSkPtHp9KAAJY code→remove_life(1);\n #e9hK3ZG8eO2Uue8K // You can hide the life indicator as well.\n #s7Ov2CH1qy9FYASs code→set_life_visible(false);\n #bgcEN9gqslrdaO1M // ### timers and countdowns\n #xt4bAYcodWe3qqgS // You can also display a timer by calling `start timer`. You can use `current time` to get the seconds elapsed since the start of the timer.\n #OSsbR8gZWen9tVtk code→start_timer;\n #dFee6Un3iogCKg9q code→start_countdown_timer(10);\n #ukkrid8JC6KKttr4 // ### game over\n #PWb2EFMyS7uuvzFr // Use the `end` to finish the game\n #d4L7G4RdnmxEcHRl code→end;\n #rCcoUqTjtzJB1J3X // ### splashing text\n #YbAUazcKVtV6qku3 // A quick and easy way to display text to the user.\n #ecGxOhCF2WkgYkcB code→splash_text(\"Bonus round!!\", 1, colors→random, colors→random, $done);\n #bNYLbQktHZxfvVWO where done() {\n #ZTSBMLGC09ze9KUe skip;\n }\n #DRe04VIIWS4rwYnQ // ### parralax background\n #Gi8A6YOMZ7dX42ho // Use ``set background scene`` to create moving backgrounds\n #S2ZNHTg3eKNYn9DK code→set_background_scene(\"horizontal\", $pic);\n meta private;\n meta test;\n}\n#q4EB482ElguyYpuPEwTgQQ4e\naction current_time() returns(#Fh83zvcS14ZK6jNA seconds: Number) {\n #BFdsvunZH1UbuS9L // Current time in timer\n #C4ggpXXT0fM11xJ2 $seconds := time→now→subtract(data→\\_start_time);\n #hAkzFccDnEQ4eexF if data→\\_countdown_duration > 0 then {\n #xlavYFgnlGubTeEu $seconds := math→max(0, data→\\_countdown_duration - $seconds);\n }\n meta sync;\n}\n#emzufgdY6lsG2RaaCYaxwN8m\nvar \\_hearts : String_Collection {\n transient = true;\n}\n#xINhkUFpWzhMPF0ROZX4TSm4\naction add_score(#tAQjhhYZ8ziBD6ez value: Number) {\n #L8MM1n5h3tJq4MAH // Adds value to the current score. Value can be negative.\n #ZwhiUoPbRzDmYy7b // {hints:value:1,10,100}\n #VurwTOF3FLa4ejcU if $value > 0 then {\n #dvQS5eDbxUvHojRk code→set_score(data→\\_score + $value);\n #sfOOtfKb4Xf1BwcX if $value > 1 then {\n #l3wCIj7Pgnwwaxa6 $sprite := code→create_text;\n #SpicJAYTeJmiPCCz $sprite→set_text(math→ceiling($value)→to_string);\n #jsbm2wkw4a611R5L $sprite→set_pos(data→\\_score_txt→x, data→\\_score_txt→y);\n #xoIUTQpKKecgzCBQ $sprite→set_color(data→\\_score_txt→color);\n #A2Yn5zDjzdNo1bNy $anim := $sprite→create_animation;\n #QTO5DnOJkIqirrb8 $anim→puff_out(0.5, \"cubic\", 1.5);\n #A4CmMqj3KJAY3UGU $anim→delete;\n }\n }\n meta sync;\n}\n#l0buJlsN2iCiTbJPwUwTGWmO\naction add_life(#i5ReduzYFUpLFhbF value: Number) {\n #xFocNGxUz72Py6Dg // Adds the value to the current life. Value can be negative.\n #JBypj2Ez1thEbbpC // {hints:value:1}\n #t429gQZTs2Mi64fg code→set_life(data→\\_life + $value);\n}\n#ods2ZuwV9xHaiO5pElQlNyaE\naction clear_timer() {\n #xIt9uxPUZm1DfVjP // Hides the timer.\n #Ra8ZWiOP7bWzSa21 data→\\_start_time := invalid→datetime;\n #UvLafUxbxNZwvjGp data→\\_countdown_duration := - 1;\n meta sync;\n}\n#qoY1RsaFEb0jJJuZq8SkbAp3\naction remove_life(#R2JXjstC7H6C2I7d value: Number) {\n #UDbb3xUmllgAFfrm // Removes the value from the current life. Value can be negative.\n #BOunFP4tltU9M437 // {hints:value:1}\n #YQ51m4VCvuQWTj3G code→set_life(data→\\_life - $value);\n}\n#a14qLDjp7EtajVvdEd1rS18X\naction end() {\n #Ty1H9yFvz689uQKb // Displays a game over animation and finishes the game.\n #GEyVdP7gHEhMYuLh if `not` data→\\_board→is_invalid then {\n #PNm4kHsAAvLeTCPN if `not` data→\\_end_event→is_invalid then {\n #OmNZGM9KWiapFko7 data→\\_end_event→run;\n #xKYF8z0LLaVOQks4 code→reset;\n }\n else {\n #oCdsISU82CsuPzFb if data→\\_score > 0 then {\n #ckNPHuv2TzqnX5lX bazaar→post_leaderboard_score(data→\\_score);\n }\n #WX2o7oS0pkjUgsJI code→game_over;\n #ixtnMJPUsyivodZ2 app→restart(\"\");\n }\n }\n}\n#rUM4WD97vl3DCMmQPvBzb6jc\naction start() returns(#AbFPR1tINAAIzPii board: Board) {\n #cuJu2Z9VQgHn4Yzb // Creates a new empty game board and shows it on the screen.\n #itfyVKsFJ72c4STK $board := code→start_with_fixed_size( - 1, - 1);\n}\n#joFUGC04wxnpsBuC02e32Cvy\naction game_over() {\n #bR2JRRWa79KdtZFj $message := \"game over\";\n #M2lvKKOoUSyjBCSv $text := data→\\_board→create_text(200, 40, 40, $message);\n #JMxAY8MaxP9BJkYm $text→set_opacity(0);\n #G0kMTi3FwR2Te2TL for 0 ≤ i < 720 / 5 do {\n #x8gGwdunz5TOunUX $text→set_opacity($text→opacity + 0.05);\n #UZreYUZJfIfRGKib $text→set_color(colors→random);\n #ceUd1V8yfqAFQqBu $text→set_angle($text→angle + 5);\n #x92Ig40jCZ7U1SyU data→\\_board→update_on_wall;\n #tZWU4KGKKBKVwDn8 time→sleep(0.02);\n }\n #TU2xkLuKEQOh3DbW time→sleep(2);\n #cMsaragG8BtT1kXr $text→delete;\n #uRIMBM6HQm2N2Nxd data→\\_board→update_on_wall;\n meta private;\n}\n#Kv3t1TJgZdpYJpx9reGXtTW2\naction reset() {\n #ypVAHbhYCLxfGrbY // Resets the game engine\n #xLdUoT2qnoqxmytB code→clear_board;\n #JuuhG6ReNJxwspTc data→\\_end_event := invalid→@action;\n meta sync;\n}\n#XQPjg13t37zIEtpt44U6ff92\naction start_with_fixed_size(#x5Z0dR2qabb82pDA width: Number, #vP71QeZJBImfaq42 height: Number) returns(#QOzAYblVxQIXVsKF board: Board) {\n #GIkGM27wDa43LVsh // Initializes the game engine with the given size and returns the game board.\n #xnuJIIH3pQuwhAsw code→clear_board;\n #xUWsaURY4G0KHWcS code→initialize($width, $height);\n #CctsikpPaxGUdxUU data→\\_board→add_on_every_frame($perform);\n #NGgspE16GddTzQpD where perform() {\n #iAVXIMARzmZHG9C4 code→evolve;\n #xp5Ar4dvRYXdJEWH if `not` data→\\_board→is_invalid then {\n #KatnpCQDlegi4a82 data→\\_board→update_on_wall;\n }\n }\n #nggfDbuDWSW8HkO7 data→\\_board→post_to_wall;\n #qe89fHKQxAlM428p $board := data→\\_board;\n #rmmerjSOecJSwDqC app→log(\"game: end initialize\");\n}\n#A69js6TDtOSLAIAQQr6S33zC\naction start_with_background_picture(#IqRuFOf9jijyzGQ6 pic: Picture) returns(#qgW4pkhngSp9yx4t board: Board) {\n #DYuQdVsO2gdze4RK // Starts a game engine with the picture as background\n #KhZxjKvfIr4UkTpf $board := code→start_with_fixed_size($pic→width, $pic→height);\n #x6Z3xF23v2lYG3F2 $board→set_background_picture($pic);\n}\n#y5RrO2ILX7gVIvFQMpo6XjGo\naction board() returns(#y28JfFz47DWDtngG board: Board) {\n #bnTv8HRMWLtLAU9q // Gets the current game board for the game. Invalid if game not started.\n #nXVJcphXOyIll9oE $board := data→\\_board;\n meta sync;\n}\n#Eu2dngMaA73jYqD6d0u8iCju\nvar \\_end_event : Action {\n transient = true;\n}\n#xTv6Ulq3EWIRTV6f6oXlbDh9\naction on_end(#xPcQEigjfypzEgie @action: Action) {\n #hs2S4pK5luKS7Yx7 // Attach code to run when the game ends. Overrides the default behavior.\n #AYzAMJdPbb22r3I4 data→\\_end_event := $@action;\n meta sync;\n}\n#Xd5cD2v2HyMBTyiuwycN9lHa\naction test_on_end() {\n #y2RQOSjYPHCmTn7j code→on_end($@action);\n #XjIoI4kD9LlHrUVX where @action() {\n #fg4t4cENnu22YDnm wall→prompt(\"on end called\");\n }\n #xWqn6Z7usZe5uNhV code→start;\n #xVxjo0kGpkT8Gdob code→end;\n meta private;\n meta test;\n}\n#xOu0vfXrzi94ugA9AcysN2bf\naction test() {\n #mdU4UX4XMXiUvcqM $board := code→start;\n #hyMg45fVM9c4Ek5p $board→set_gravity(0, 200);\n #YeRPrdEXM3lGGTde $board→create_boundary(0);\n #QpoVJddHOtkHw28b $sprite := $board→create_rectangle(20, 20);\n #px6QNcegyYne2apd $sprite→set_color(colors→random);\n #xOLydxzUemgYcA0F code→add_score(100);\n meta private;\n meta test;\n}\n#xpQAnETcU9aowS6g7p1qZZbf\naction clear_board() {\n #otzjU0KwlOeyFv7W if `not` data→\\_board→is_invalid then {\n #xb2iFSOWUmUxd3BO data→\\_board→clear_every_frame_timers;\n }\n #znTtVcKS99o5PuwK data→\\_board := invalid→board;\n meta private;\n meta sync;\n}\n#a7BJpaIAFIQXxK4dh0p7dx24\naction splash_text(#zkkfu4GlLCP2VpR4 message: String, #UhC6GSzz7YIGr7om seconds: Number, #cob5g2NL5WPFJERB foreground: Color, #oE7eANpx6Js6Yy74 background: Color, #CkRu2opZg12ei2aI done: Action) {\n #M0y7c0URhyJonPa7 // Shows a full screen splash message and goes away. Does not block the game loop.\n #GCpZHAzwGv9a96uR // {hints:message:Get Ready!}\n #P4tH0Ut3u2WfkwCG if $seconds < 0.5 then {\n #xCvwguc2te1lLKE4 $seconds := 0.5;\n }\n #gQ2Dt0rq2efvvH49 $back := data→\\_board→create_rectangle(data→\\_board→width, data→\\_board→height);\n #v2gaLx1i4woeKuTv $back→set_color($background);\n #b7dLaPuBaGV7q9Ji $back→set_z_index(1000);\n #YQehWIY2hzAQ2BRj $text := data→\\_board→create_text(data→\\_board→width, 2, 60, $message);\n #z8IJzlBH3NbG5yCh $text→fit_text;\n #uY628hbLD2rnNEiK while $text→width > data→\\_board→width * 0.8 do {\n #rayekD9V5rz4rOzc $text→set_font_size($text→font_size * 0.8);\n #o4KBW2LCw0e1f7WV $text→fit_text;\n }\n #Da9p2BcmQVywBdiG $text→set_color($foreground);\n #ynExTRQQwAvh8hrH $text→set_z_index(1000);\n #mZ1swRJ8KSspXDPA $text_anim := $text→create_animation;\n #sgvsL0eJTKOVKend $text_anim→sleep($seconds);\n #x4Um8LUQYZu74SCo $text_anim→puff_out(0.9, \"cubic\", 1.5);\n #xkjPwiZ0JHuWWu8w $text_anim→delete;\n #QFgsQgBaf4E9eHpD $anim2 := $back→create_animation;\n #lz8Wv4BjDYWWy4PF $anim2→sleep($seconds + 0.7);\n #A6qQu0ahu46t3ECd $anim2→fade_out(0.2, \"cubic\");\n #xkTvtdr2OOieq3m4 $anim2→delete;\n #xby5BLlMaNeEXolS $anim2→on_stop($handler);\n #imcBHmey6h97z8ZZ where handler() {\n #Pn3eKA236i2cd8jR $done→run;\n }\n #IgDWv2ICGGG1fy5T `async` $anim2→wait;\n}\n#dztvp9VA3SKJ2iQhwHi5hOJt\naction test_show_splash() {\n #CdHT5UbOtPNVdpc7 $board := code→start_landscape;\n #FR5BPIwE2h4GLwu0 $board→set_background(colors→random);\n #nJjfk952pY1q4N14 code→splash_text(\"hello wooooooooooooooooooooooorld!\", 1, colors→white, colors→random, $done);\n #pzDNwpKV7UErnreC where done() {\n #SMMW4HxliR2ivls2 code→set_hud_colors(colors→random, colors→random, colors→random);\n #xp9OOz6xZ9cpRJQj code→start_countdown_timer(10);\n #xLR35Dz2Z0dhsZ8s $board→add_on_every_frame($perform);\n #xP1kW44KZzPyGIci where perform() {\n #x0Gtlxg8b5SJMONk code→add_score(1);\n #xT2K3e9qh4XJXL2H code→add_life(1);\n }\n }\n meta private;\n meta test;\n}\n#eIngK72C8H06n0lzszL8yaCm\naction start_landscape() returns(#vGhNIEVWNjf2DMe1 board: Board) {\n #DiW6QoP2oFAWHrdh // Starts a new landscape game\n #or2RSf2CvyV9CGi5 $board := code→start_with_fixed_size(800, - 1);\n}\n#sYve2cIuyW1MMqF3aRO2OZyU\naction start_portrait() returns(#dNtnzA61nztVz7ly board: Board) {\n #RUqcBdXLfT3WLwtI // Starts a portrait game\n #sKZshpWP91TKnlmc $board := code→start_with_fixed_size( - 1, 800);\n}\n#OMEJVlEdU2VpPg82GXpsMZTs\naction set_hud_colors(#ym5U3Gn6Cgc734j4 life: Color, #Ze4lgB3HYaEPaQms timer: Color, #x8GuNE6MswGyW8e8 score: Color) {\n #IQSX7p2v7ihFyRgW // Sets the text color of the life, timer and score text in the head-up display (hud).\n #xdJOASojRtIrV28p data→\\_life_txt→set_color($life);\n #YSRB5T5tGLdTpN6M data→\\_timer_txt→set_color($timer);\n #NRXdOMJdrV4Ktx6J data→\\_score_txt→set_color($score);\n #N8WL5zaLyqFuS7r6 data→\\_board→update_on_wall;\n meta sync;\n}\n#OSUi7mcMXLLJLfNRTez0CgSV\naction hud_sprites() returns(#xS4wU3OeXU6RjZLi sprites: Sprite_Set) {\n #xP1yJJaa18LnCHT0 // Gets the sprites used by the game board to display the head-up display.\n #ICC48H9UA4IZRlyg $sprites := data→\\_board→create_sprite_set;\n #xxzXIsbzTviF5El6 $sprites→add(data→\\_timer_txt);\n #Vx4vvyPFYOWBU33f $sprites→add(data→\\_score_txt);\n #ae9F20KA4qLwlsQG $sprites→add(data→\\_life_txt);\n meta sync;\n}\n#xoAgK46gsSE32UIau4PsRlbw\naction test_score() {\n #INflARm2bc0ire1B $board := code→start;\n #nQ3jWN002Btc09h0 $board→set_debug_mode(true);\n #v7lsr4cRsspdWafA $board→on_tap($tapped);\n #hfu0GsIcIHTumLfm where tapped(x: Number, y: Number) {\n #PI1IuG3owK4henhk code→add_score(100);\n #xWY0qUyGfdmcoj3E if code→score > 1000 then {\n #xmr1ny8p58MtPfHb code→end;\n }\n }\n meta private;\n meta test;\n}\n#qScd7vJgHvp5y6wWRmglDahb\nvar x : Boolean {\n transient = true;\n}\n#QakFM2TVyNr4ziDe1asYvARy\naction life_visible() returns(#AUsSkrVIQdg5hKUl b: Boolean) {\n #xoeItkItCNLhf6tS // Gets a value indicating if the life is visible in the hud.\n #rX1u2cGvGpIlH5cv $b := data→\\_life_txt→is_visible;\n}\n#gf2b0Sz627NLlyAFFj4MeOic\naction set_life_visible(#JTLRihoxN8cxPQ43 visible: Boolean) {\n #sD4OBtrspT0Uh0k8 // Controls the visibility of the life counter.\n #kBruCITydNqICsgy if $visible then {\n #LY35FhMwu25cQBYw data→\\_life_txt→show;\n }\n else {\n #xAsc32ZmZ4mDOFhj data→\\_life_txt→hide;\n }\n}\n#sbBwOOYCaN7mUaF0ZlZyxAYU\naction sprites() returns(#xX6pkmdt8a5KVNiS sprites: Sprite_Set) {\n #xc0QtpSbTXh1GwCV // Gets the sprites of the board, excluding hub sprites.\n #Scb2mfgsd1z4R2G8 $excluded := code→hud_sprites;\n #ws52NEnvj9qCKGjx $sprites := data→\\_board→create_sprite_set;\n #CWr1flThpV1vp2cs foreach sprite in data→\\_board\n #jcgSowlf2GnOKbqi where `not` $excluded→contains($sprite)\n do {\n #SqHBUc15dLrI44tQ $sprites→add($sprite);\n }\n meta sync;\n}\n#x8hRsIT9CAZerwKF\naction set_background_scene(#xxFyAjWYlZqmsd2c direction: String, #xWDQ4yQUS8QWIm2G pic: Picture) {\n #b4qYeJJV5fXmlqL2 // Sets the background picture and the speed of the background.\n #fDC7OSyUxOtiQToM // {hints:direction:horizontal,vertical}\n #cXnTiVb5rm0qSDSX $b := $direction→trim(\" \\t\")→to_lower_case→equals(\"horizontal\");\n #FjQX2QH2ZqBHBOpO $scene := data→\\_board→background_scene;\n #xbEzCcsY22RoPtXj $scene→clear;\n #S7bkh6r4pVcHgV8c $pic := $pic→clone;\n #VxjO3KnRByvOLvVK if $b then {\n #U2a67VkZZO12op2U $pic→resize( - 1, data→\\_board→height);\n }\n else {\n #p7Io8ZWoL2G6yL92 $pic→resize(data→\\_board→width, - 1);\n }\n #ozFKGP79IQraapHB $layer := $scene→create_layer(0, $pic);\n #eGk2b4ExeTM73Kg5 if `not` data→background_scene_move→is_invalid then {\n #TrbtdU7nPhE4r4tN data→background_scene_move→delete;\n }\n #lAeYACw4EOAzqkI9 if $b then {\n #LZGihYJA823COO24 data→background_scene_move := data→\\_board→add_on_every_frame($perform);\n #dDXqnuq6ZX0XYuiq where perform() {\n #OpD6ZCcvZ2IeZrER $scene→view_x := $scene→view_x + 1;\n }\n }\n else {\n #wzNI5zIvycykPz4e data→background_scene_move := data→\\_board→add_on_every_frame($perform);\n #CcNlh4HGCmc6EI44 where perform() {\n #xRSy4Rcl9aKAtAcs $scene→view_y := $scene→view_y + 1;\n }\n }\n}\n#oJd6t0JYUca8Bpha\nvar background_scene_move : Event_Binding {\n transient = true;\n}\n#x7LNZH9OJJV4MHMQ\naction bounce_on_sides() {\n #zDu3lJNCaInFBCJs // Makes all the sprite bounce on thee border of the screen\n #xa1tv4gUnH7S5toZ data→\\_board→create_boundary(0);\n meta sync;\n}\n#xi31jXN7f2tym77g\naction create_sprite(#U0MZEHjiclDl3NQR pic: Picture) returns(#nXzTwbGcDPXL4IbM sprite: Sprite) {\n #DHXP2H45qOOljGtB // Creates a new sprite of width 100 with the given picture.\n #PvmYHlhdUQ7SCbU9 $sprite := data→\\_board→create_picture($pic);\n #foFswt2QK0q4XHqB $sprite→set_width(100);\n meta sync;\n}\n", "spbd": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"blank template\";\nmeta rootId \"s18cNgqmk4qdPwKNK0ppoMp2\";\nmeta allowExport \"yes\";\nmeta platform \"current\";\n#main\naction main() {\n skip;\n}\n", "tiwt": "meta version \"v2.2,js,ctx,refs,localcloud,unicodemodel,allasync\";\nmeta name \"blank script plugin\";\nmeta icon \"Brush\";\nmeta color \"#ffe3256b\";\nmeta rootId \"B1BBU2S1UsnHiEXWlTqkabme\";\nmeta allowExport \"yes\";\nmeta hasIds \"yes\";\nmeta platform \"current,editoronly\";\nmeta parentIds \"\";\n// A TouchDevelop plugin. #scriptPlugin #buttonPlugin\n#gYzBYlK5jAx3Qfv9\naction do_stuff(#fK8mH7TfckAPC9Ui editor: Editor) {\n #dFvzotTJtIW2DkOD code→init_log;\n #x1Y6B2xJRSkIezBw // TODO: this action gets called by the editor!\n}\n#YCEitfuBjl2PqD4f meta import ast {\n pub \"njle\"\n usage {\n action `async` `type` update_node(type: String, node: Json_Builder)\n action `async` update_nodes(ast: Json_Builder, update: ♻ ast → update_node)\n action `async` update_script(id: String, update: ♻ ast → update_node)\n action `async` test_plugin(plugin: Text_Action)\n action `sync` find_decl(@script: Json_Builder, name: String) returns(decl: Json_Builder)\n }\n}\n#xUKJA4AiahTHnwv2\nvar logger : App_Logger {\n transient = true;\n}\n#PNnxmlnhF0t47I8b\naction init_log() {\n #QliVR9SuYlA9GDox if data→logger→is_invalid then {\n #tE4d3cGdvoaUcNRY data→logger := app→create_logger(\"plugin\");\n }\n meta private;\n meta sync;\n}\n", @@ -177,7 +179,7 @@ {"name":"coverage","id":"wcbu","rootid":"dfpo","userid":"jeiv","description":"Investigate code coverage of your script with the built-in code coverage tools. #docs","iconbackground":"#FF0038","icon":"Justified","iconArtId":null,"splashArtId":null,"time":1412666479,"priority":10000,"parentTopic":"advancedtopics"}, {"name":"crazy holiday football tutorial","id":"wnzk","rootid":"qnxj","userid":"jeiv","description":"Tap the screen to creates more pumpkins! #docs","iconbackground":"#FF91A4","icon":"Controller","iconArtId":null,"splashArtId":null,"time":1415066198,"priority":10000,"platforms":["musicandsounds"],"parentTopic":"gametutorials"}, {"name":"crazy pumpkins tutorial","id":"htsu","rootid":"qnxj","userid":"jeiv","description":"Tap the screen to creates more pumpkins! #docs","iconbackground":"#A1CAF1","icon":"Controller","iconArtId":null,"splashArtId":null,"time":1384585198,"priority":10000,"platforms":["musicandsounds"],"screenshot":"https://az31353.vo.msecnd.net/pub/lpjjsove"}, -{"name":"creating interactive tutorials","id":"weboa","rootid":"xniertjj","userid":"jeiv","description":"How to create 'tap here' tutorials. #docs","iconbackground":"#E3256B","icon":"GlobeSA","iconArtId":null,"splashArtId":null,"time":1426043753,"priority":10000,"platforms":["clouddata"],"parentTopic":"teach"}, +{"name":"creating interactive tutorials","id":"cesqe","rootid":"xniertjj","userid":"jeiv","description":"How to create 'tap here' tutorials. #docs","iconbackground":"#E3256B","icon":"GlobeSA","iconArtId":null,"splashArtId":null,"time":1426105468,"priority":10000,"platforms":["clouddata"],"parentTopic":"teach"}, {"name":"cutest voting app tutorial","id":"ajhsb","rootid":"nrdhndao","userid":"jeiv","description":"A tutorial to create an voting app for the cutest cat or dog. #docs #tutorials #stepByStep.","iconbackground":"#FFA500","icon":"CheckCircleAlt","iconArtId":null,"splashArtId":null,"time":1415066416,"priority":10000,"platforms":["musicandsounds","clouddata"],"screenshot":"https://az31353.vo.msecnd.net/pub/akzvrrqu","parentTopic":"socialapptutorials"}, {"name":"data","id":"mhloa","rootid":"jswu","userid":"jeiv","description":"Global variables. #docs #data #language","iconbackground":"#9955BB","icon":"BulletList","iconArtId":null,"splashArtId":null,"time":1412665797,"priority":10000,"parentTopic":"language"}, {"name":"debugging","id":"lzcj","rootid":"aokhb","userid":"jeiv","description":"Debugging your script with the built-in debugger. #docs","iconbackground":"#FF0038","icon":"Settings","iconArtId":null,"splashArtId":null,"time":1412666436,"priority":10000,"parentTopic":"advancedtopics"}, @@ -241,12 +243,12 @@ {"name":"magic 8 ball tutorial","id":"ywrn","rootid":"czxea","userid":"jeiv","description":"A magic 8 ball game tutorial #docs #tutorials","iconbackground":"#00008B","icon":"Tools","iconArtId":null,"splashArtId":null,"time":1415066917,"priority":10000,"platforms":["musicandsounds"],"parentTopic":"gametutorials"}, {"name":"makey makey beatbox tutorial","id":"hgkr","rootid":"upol","userid":"jeiv","description":"A guided to tutorial to build a beatbox driven by Makey Makey #docs","iconbackground":"#FFA500","icon":"Forward","iconArtId":null,"splashArtId":null,"time":1395427717,"priority":10000,"screenshot":"https://az31353.vo.msecnd.net/pub/krrqcmcm"}, {"name":"map of things tutorial","id":"zltx","rootid":"pljua","userid":"jeiv","description":"A tutorial to build a collaborative app that allows users to collect information about things in the world. #docs #tutorials #stepByStep.","iconbackground":"#FFA500","icon":"Map","iconArtId":null,"splashArtId":null,"time":1415066980,"priority":10000,"platforms":["location","maps","clouddata"],"screenshot":"https://az31353.vo.msecnd.net/pub/heknakcs"}, -{"name":"markdown","id":"wxgg","rootid":"pbph","userid":"jeiv","description":"Syntax to create formatted text. #docs #markdown","iconbackground":"#800080","icon":"Shield","iconArtId":null,"splashArtId":null,"time":1422053368,"priority":10000,"parentTopic":"comment"}, +{"name":"markdown","id":"ubeic","rootid":"pbph","userid":"jeiv","description":"Syntax to create formatted text. #docs #markdown","iconbackground":"#800080","icon":"Shield","iconArtId":null,"splashArtId":null,"time":1426103896,"priority":10000,"parentTopic":"comment"}, {"name":"microphone","id":"hjjw","rootid":"hjjw","userid":"jeiv","description":"Access to the #microphone #docs","iconbackground":"#E3256B","icon":"AlignCenter","iconArtId":null,"splashArtId":null,"time":1395425064,"priority":10000,"platforms":["microphone","musicandsounds"]}, {"name":"minecraft pi getting started","id":"iyvza","rootid":"wuuvkimy","userid":"jeiv","description":"Some first steps with Minecraft Pi. #docs #tutorials #stepByStep #minecraft","iconbackground":"#800080","icon":"Erase","iconArtId":"kqezsjdm","splashArtId":null,"time":1426050263,"priority":10000}, {"name":"minecraft pi megajump tutorial","id":"ovfhc","rootid":"wuuvkimy","userid":"jeiv","description":"A Minecraft Pi tutorial to make the player jump really high. #docs #tutorials #stepByStep #minecraft","iconbackground":"#00CC99","icon":"Erase","iconArtId":"kqezsjdm","splashArtId":null,"time":1426050209,"priority":10000}, {"name":"minecraft pi pitfall tutorial","id":"srxpa","rootid":"wuuvkimy","userid":"jeiv","description":"A Minecraft Pi tutorial to make the player jump really high. #docs #tutorials #stepByStep #minecraft","iconbackground":"#DAA520","icon":"Erase","iconArtId":"kqezsjdm","splashArtId":null,"time":1426050897,"priority":10000}, -{"name":"minecraft pi setup","id":"oyzy","rootid":"ypgksxfl","userid":"jeiv","description":"Explains how to setup TouchDevelop and Minecraft Pi. #docs #minecraft","iconbackground":"#E25822","icon":"Funnel","iconArtId":"kqezsjdm","splashArtId":null,"time":1426047912,"priority":10000}, +{"name":"minecraft pi setup","id":"iiwqg","rootid":"ypgksxfl","userid":"jeiv","description":"Explains how to setup TouchDevelop and Minecraft Pi. #docs #minecraft","iconbackground":"#E25822","icon":"Funnel","iconArtId":"kqezsjdm","splashArtId":null,"time":1426096976,"priority":10000}, {"name":"minecraft pi tutorials","id":"ysxp","rootid":"ggrw","userid":"jeiv","description":"A set of tutorials for Minecraft. #docs #minecraft","iconbackground":"#A1CAF1","icon":"GPS","iconArtId":"kqezsjdm","splashArtId":null,"time":1426050942,"priority":10000,"parentTopic":"tutorials"}, {"name":"monster slicer tutorial","id":"rebp","rootid":"cxwjqvmo","userid":"jeiv","description":"A step-by-step tutorial on creating a game with bouncing monsters #docs #tutorials #stepByStep #HourOfCode #tutorial","iconbackground":"#008000","icon":"Controller","iconArtId":null,"splashArtId":null,"time":1416508877,"priority":10000,"platforms":["musicandsounds"],"screenshot":"https://az31353.vo.msecnd.net/pub/dwhkdiwe","parentTopic":"gametutorials"}, {"name":"move to library","id":"uvthb","rootid":"igxk","userid":"jeiv","description":"Explains the move to library refactoring that allows you to easily identify and move a set of script elements to a library.\r\n#docs #refactorings","iconbackground":"#FDEE00","icon":"DocumentsAlt","iconArtId":null,"splashArtId":null,"time":1412701848,"priority":10000,"parentTopic":"refactorings"}, @@ -357,9 +359,11 @@ {"title":"blank","id":"blank","icon":"ABC","description":"An empty script, which doesn't do anything.","section":"templates","name":"ADJ script","scriptid":"spbd","editorMode":1}, {"title":"blank game","id":"game","icon":"Controller","name":"ADJ game","description":"Boiler plate code to create a game.","section":"templates","scriptid":"djjlc","editorMode":1}, {"title":"blank app","id":"pages","icon":"AddressBook","name":"ADJ app","description":"An empty app using pages and boxes.","section":"templates","scriptid":"qetpa","editorMode":2}, -{"title":"blank turtle","id":"blankturtle","icon":"Controller","name":"ADJ drawing","description":"An turtle app.","section":"beginners","scriptid":"parp","editorMode":1}, +{"title":"blank turtle","id":"blankturtle","icon":"Controller","name":"ADJ turtle","description":"An turtle app.","section":"beginners","scriptid":"parp","editorMode":1}, {"title":"blank scratch","id":"blankscratch","icon":"Controller","name":"ADJ app","description":"An empty app using the scratch library.","section":"beginners","scriptid":"enyra","editorMode":1}, {"title":"blank pixel art","id":"blankpixelart","icon":"NineColumn","name":"ADJ art","description":"A pixel art app.","section":"beginners","scriptid":"mdrw","editorMode":1}, +{"title":"blank minecraft pi","id":"blankminecraftpi","icon":"NineColumn","name":"ADJ craft","description":"A Minecraft Pi app.","section":"Minecraft","scriptid":"cptje","editorMode":1}, +{"title":"blank minecraft steve","id":"blankminecraftsteve","icon":"NineColumn","name":"ADJ steve","description":"A Minecraft Steve app.","section":"Minecraft","scriptid":"qzky","editorMode":1}, {"title":"blank cordova library","id":"blankcordovalibrary","icon":"ApproveButton","name":"cordova ADJ plugin","description":"An wrapper around an Apache Cordova plugin.","section":"apps","scriptid":"gtfla","editorMode":3}, {"title":"blank web api","id":"blankwebapi","icon":"Stacks","name":"ADJ api","description":"A web API using node.js and restify.","section":"web sites","scriptid":"qexxc","editorMode":3}, {"title":"blank azure web api","id":"blankazurewebapi","icon":"Stacks","name":"azure ADJ api","description":"A web API using azure services, node.js and restify.","section":"web sites","scriptid":"gexxa","editorMode":3}, diff --git a/lib/App.ts b/lib/App.ts index c02dc983..0c044abe 100644 --- a/lib/App.ts +++ b/lib/App.ts @@ -307,6 +307,7 @@ module TDev.RT { } //? Interact with the app runtime + //@ skill(3) export module App { export function createInfoMessage(s: string) : LogMessage { diff --git a/lib/Bazaar.ts b/lib/Bazaar.ts index cfd18b2c..7f89ba08 100644 --- a/lib/Bazaar.ts +++ b/lib/Bazaar.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? Browse and review scripts from the bazaar + //@ skill(3) export module Bazaar { //? Returns a user object for a specified user id diff --git a/lib/Bits.ts b/lib/Bits.ts index 2a300002..7bbd7ab6 100644 --- a/lib/Bits.ts +++ b/lib/Bits.ts @@ -2,6 +2,7 @@ module TDev.RT { //? Arithmetic and bitwise operations on 32 bit integers + //@ skill(3) export module Bits { //? Add two unsigned 32 bit numbers diff --git a/lib/Box.ts b/lib/Box.ts index 87981abe..818cdac9 100644 --- a/lib/Box.ts +++ b/lib/Box.ts @@ -2,6 +2,7 @@ module TDev { export module RT { //? Current box element in the page. + //@ skill(2) export module Box { var R = HTML; @@ -387,7 +388,7 @@ module TDev { export module RT { } //? Current html element in the page. - //@ betaOnly + //@ betaOnly skill(2) export module Dom { //? Use CSS for layout and import additional CSS stylesheets. Use string art resource to import urls. //@ betaOnly diff --git a/lib/CloudSessions.ts b/lib/CloudSessions.ts index d8b1e4c9..441e970e 100644 --- a/lib/CloudSessions.ts +++ b/lib/CloudSessions.ts @@ -1,8 +1,5 @@ /// module TDev.RT { - - - //? A cloud data session //@ ctx(general) stem("session") cap(cloudData) serializable export class CloudSession @@ -143,7 +140,7 @@ module TDev.RT { } //? Cloud session management - //@ cap(cloudData) + //@ cap(cloudData) skill(3) export module CloudData { diff --git a/lib/Collection.ts b/lib/Collection.ts index a3df59fd..7f256a77 100644 --- a/lib/Collection.ts +++ b/lib/Collection.ts @@ -308,41 +308,23 @@ module TDev.RT { //? Ask user to pick an entry from this collection //@ uiAsync returns(T) - public pick_entry(text: string, r: ResumeCtx) { + public pick_entry(text: string, r: ResumeCtx) { var rt = r.rt; - var getView = (o:any) => { + var getView = (o: any) => { if (o.getIndexCard) return o.getIndexCard(r.stackframe) else if (o.getViewCore) return o.getViewCore(r.stackframe, null) else if (o.toString) return o.toString() else return o + "" }; - if (rt.useModalWallDialogs()) { - var m = new ModalDialog(); - var chosen = null; - var btns = this.a.map((o: any) => div('modalDialogChooseItem', getView(o)).withClick(() => { - chosen = o; - m.dismiss(); - })); - m.add([div("wall-dialog-header", text)/* ,div("wall-dialog-body", caption)*/]); - m.onDismiss = () => r.resumeVal(chosen); - m.choose(btns); - } else { - var btnsDiv: HTMLElement; - var btns2 = this.a.map((o: any) => { - var btn = HTML.mkButtonElt("wall-button", getView(o)); - Util.clickHandler(btn, () => - { - r.resumeVal(o); - btnsDiv.removeSelf(); - }); - return btn; - }); - var elt = div("wall-dialog", - [div("wall-dialog-header", text), - /*div("wall-dialog-body", caption),*/ - btnsDiv = div("wall-dialog-buttons", btns2)]); - rt.postHtml(elt, rt.current.pc); - } + var m = new ModalDialog(); + var chosen = null; + var btns = this.a.map((o: any) => div('modalDialogChooseItem', getView(o)).withClick(() => { + chosen = o; + m.dismiss(); + })); + m.add([div("wall-dialog-header", text)/* ,div("wall-dialog-body", caption)*/]); + m.onDismiss = () => r.resumeVal(chosen); + m.choose(btns); } //? Computes the sum of the key of the elements in the collection diff --git a/lib/Collections.ts b/lib/Collections.ts index 0c784664..4ecbc83b 100644 --- a/lib/Collections.ts +++ b/lib/Collections.ts @@ -1,7 +1,7 @@ /// //? Create collections of items. -//@ robust +//@ robust skill(3) module TDev.RT.Collections { diff --git a/lib/Contract.ts b/lib/Contract.ts index 4755acec..6f41b1d8 100644 --- a/lib/Contract.ts +++ b/lib/Contract.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? Correctness helpers + //@ skill(3) export module Contract { //? Specifies a precondition contract for the action; if the condition is false, execution fails. Does nothing for published scripts. diff --git a/lib/Create.ts b/lib/Create.ts index 622892ab..20fee171 100644 --- a/lib/Create.ts +++ b/lib/Create.ts @@ -1,7 +1,7 @@ /// //? Create collections of items. -//@ robust +//@ robust skill(2) module TDev.RT.Create { //? Creates an empty collection of arbitrary type diff --git a/lib/Invalid.ts b/lib/Invalid.ts index 323f29f6..c0e53e7f 100644 --- a/lib/Invalid.ts +++ b/lib/Invalid.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? Create invalid values + //@ skill(3) export module Invalid { diff --git a/lib/Languages.ts b/lib/Languages.ts index af966dc9..890156c2 100644 --- a/lib/Languages.ts +++ b/lib/Languages.ts @@ -188,6 +188,7 @@ module TDev.RT { } //? Translation, speech to text, ... + //@ skill(2) export module Languages { diff --git a/lib/LiveConnect.ts b/lib/LiveConnect.ts index d711e15c..7bcb4409 100644 --- a/lib/LiveConnect.ts +++ b/lib/LiveConnect.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? OneDrive, OneNote operations + //@ skill(3) export module CloudStorage { //? Prompts the user to upload a picture to OneDrive. If the filename is empty, a default filename gets generated. //@ async returns(CloudPicture) cap(cloudservices) diff --git a/lib/Locations.ts b/lib/Locations.ts index 68074ba8..767808d6 100644 --- a/lib/Locations.ts +++ b/lib/Locations.ts @@ -1,9 +1,9 @@ /// module TDev.RT { //? Geo coordinates + //@ skill(3) export module Locations { - //? Creates a new geo coordinate location export function create_location(latitude:number, longitude:number) : Location_ { return Location_.mk(latitude, longitude, undefined, undefined, undefined, undefined, undefined) } diff --git a/lib/Maps.ts b/lib/Maps.ts index c9d73007..a7f3f297 100644 --- a/lib/Maps.ts +++ b/lib/Maps.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? Maps, location to address, address to location + //@ skill(3) export module Maps { //? Creates a Bing map. Use 'post to wall' to display it. diff --git a/lib/Media.ts b/lib/Media.ts index e37ad842..6be9f186 100644 --- a/lib/Media.ts +++ b/lib/Media.ts @@ -2,6 +2,7 @@ module TDev.RT { //? Pictures and music... + //@ skill(2) export module Media { diff --git a/lib/Phone.ts b/lib/Phone.ts index f0af053c..c9ee8302 100644 --- a/lib/Phone.ts +++ b/lib/Phone.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? Phone numbers, vibrate, etc... + //@ skill(2) export module Phone { //? Starts a phone call diff --git a/lib/Player.ts b/lib/Player.ts index 1bb7d2fc..3adf5a0b 100644 --- a/lib/Player.ts +++ b/lib/Player.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? Play, stop or resume songs, ... + //@ skill(3) export module Player { var _rt: Runtime; diff --git a/lib/Radio.ts b/lib/Radio.ts index be6177c0..6e810042 100644 --- a/lib/Radio.ts +++ b/lib/Radio.ts @@ -1,6 +1,7 @@ /// module TDev { export module RT { //? Access to the radio + //@ skill(3) export module Radio { //? Indicates if the radio is on diff --git a/lib/Social.ts b/lib/Social.ts index 3d1b9ef6..1ea3e852 100644 --- a/lib/Social.ts +++ b/lib/Social.ts @@ -1,9 +1,9 @@ /// module TDev.RT { //? Emails, sms, contacts, calendar, ... + //@ skill(2) export module Social { - //? Opens the mail client //@ flow(SinkSharing) uiAsync export function send_email(to:string, subject:string, body:string, r : ResumeCtx) : void diff --git a/lib/Tags.ts b/lib/Tags.ts index d4c658f7..92b0ea0a 100644 --- a/lib/Tags.ts +++ b/lib/Tags.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? 2D barcodes, QR codes and NFC tags + //@ skill(3) export module Tags { export var sendNFC = (writeTag:boolean, type : string, value: string, sent : (id : number) => void, transferred : () => void) => diff --git a/lib/Tiles.ts b/lib/Tiles.ts index 1e1af1d1..42af64a4 100644 --- a/lib/Tiles.ts +++ b/lib/Tiles.ts @@ -12,7 +12,7 @@ module TDev.RT { } //? tiles and notifications for Windows and Windows Phone - //@ cap(tiles) + //@ cap(tiles) skill(3) export module Tiles { export var updateTileAsync = (fragment : string, data : ITileData) : Promise => diff --git a/lib/Time.ts b/lib/Time.ts index b2e8481f..6e59eedb 100644 --- a/lib/Time.ts +++ b/lib/Time.ts @@ -1,7 +1,7 @@ /// module TDev.RT { //? time and dates - //@ robust + //@ robust skill(2) export module Time { var _rt : Runtime; diff --git a/lib/Tutorial.ts b/lib/Tutorial.ts index 5aa11869..b52885ce 100644 --- a/lib/Tutorial.ts +++ b/lib/Tutorial.ts @@ -1,6 +1,7 @@ /// module TDev.RT { //? Support for interactive tutorials. + //@ skill(3) export module Tutorial { //? Signal that the step is done. diff --git a/lib/Wall.ts b/lib/Wall.ts index 27ed6fd4..744df61c 100644 --- a/lib/Wall.ts +++ b/lib/Wall.ts @@ -24,133 +24,64 @@ module TDev.RT { //? Prompts the user with a ok button //@ tandre2 //@ uiAsync - export function prompt(text:string, r: ResumeCtx) : void - { + export function prompt(text: string, r: ResumeCtx): void { var rt = r.rt; - if (rt.useModalWallDialogs()) { - var m = new ModalDialog(); - m.add([body(text), - div("wall-dialog-buttons", - [R.mkButtonOnce("ok", () => m.dismiss())]) - ]); - m.onDismiss = () => r.resume(); - m.show(); - } else { - var btns; - var elt = div("wall-dialog", - [body(text), - btns = div("wall-dialog-buttons", - [R.mkButtonOnce("ok", () => { - Screen.popModalHash("wall"); - r.resume(); - })]) - ]); - rt.postHtml(elt, rt.current.pc); - Screen.pushModalHash("wall", () => { - btns.removeSelf(); - r.resume(); - }); - } + var m = new ModalDialog(); + m.add([body(text), + div("wall-dialog-buttons", + [R.mkButtonOnce("ok",() => m.dismiss())]) + ]); + m.onDismiss = () => r.resume(); + m.show(); } //? Prompts the user with ok and cancel buttons //@ returns(boolean) //@ tandre2 //@ uiAsync - export function ask_boolean(text:string, caption:string, r:ResumeCtx) - { + export function ask_boolean(text: string, caption: string, r: ResumeCtx) { var rt = r.rt; - if (rt.useModalWallDialogs()) { - var value = false; - var m = new ModalDialog(); - m.add([div("wall-dialog-header", text), - body(caption), - div("wall-dialog-buttons", - [R.mkButton(lf("no"), () => { - value = false; - m.dismiss(); - }), - R.mkButton(lf("yes"), () => { - value = true; - m.dismiss(); - })]) - ]); - m.onDismiss = () => r.resumeVal(value); - m.show(); - } else { - var btns; - var elt = div("wall-dialog", - [div("wall-dialog-header", text), - body(caption), - btns = div("wall-dialog-buttons", - [R.mkButtonOnce("no", () => { - Screen.popModalHash("wall"); - r.resumeVal(false) - }, true), - R.mkButtonOnce("yes", () => { - Screen.popModalHash("wall"); - r.resumeVal(true) - }, true)]) - ]); - rt.postHtml(elt, rt.current.pc); - Screen.pushModalHash("wall", () => { - btns.removeSelf(); - r.resumeVal(false); - }); - } + var value = false; + var m = new ModalDialog(); + m.add([div("wall-dialog-header", text), + body(caption), + div("wall-dialog-buttons", + [R.mkButton(lf("no"),() => { + value = false; + m.dismiss(); + }), + R.mkButton(lf("yes"),() => { + value = true; + m.dismiss(); + })]) + ]); + m.onDismiss = () => r.resumeVal(value); + m.show(); } //? Prompts the user to input a number //@ returns(number) //@ tandre2 //@ uiAsync - export function ask_number(text:string, r:ResumeCtx) - { + export function ask_number(text: string, r: ResumeCtx) { var rt = r.rt; var t = R.mkTextInput("number", lf("enter a decimal number")); t.value = ""; - if (rt.useModalWallDialogs()) { - var value = 0; - var m = new ModalDialog(); - m.add([ - body(text), - div("wall-dialog-input", t), - div("wall-dialog-buttons", - [R.mkButton(lf("ok"), () => { - value = t.valueAsNumber; - if (!isFinite(value)) value = parseFloat(t.value); // Firefox - if (!isFinite(value)) value = undefined; - m.dismiss(); - })]) - ]); - m.onDismiss = () => r.resumeVal(value); - m.show(); - } else { - var btns; - var elt = div("wall-dialog", - [body(text), - div("wall-dialog-input", t), - btns = div("wall-dialog-buttons", - [R.mkButtonOnce("ok", () => { - Screen.popModalHash("wall"); - btns.removeSelf(); - var x = t.valueAsNumber; - if (!isFinite(x)) x = parseFloat(t.value); // Firefox - if (!isFinite(x)) x = undefined; - t.blur(); - t.setAttribute("readonly", "true"); - // popup keyboard takes a while to dissapear in wp - Util.setTimeout(500, () => r.resumeVal(x)); - })]) - ]); - rt.postHtml(elt, rt.current.pc); - Screen.pushModalHash("wall", () => { - btns.removeSelf(); - t.blur(); - t.setAttribute("readonly", "true"); - Util.setTimeout(500, () => r.resumeVal(undefined)); - }); - } + var value = 0; + var m = new ModalDialog(); + m.add([ + body(text), + div("wall-dialog-input", t), + div("wall-dialog-buttons", + [R.mkButton(lf("ok"),() => { + value = t.valueAsNumber; + if (!isFinite(value)) value = parseFloat(t.value); // Firefox + if (!isFinite(value)) value = undefined; + m.dismiss(); + })]) + ]); + m.onDismiss = () => r.resumeVal(value); + m.show(); Util.setKeyboardFocus(t); } @@ -158,48 +89,22 @@ module TDev.RT { //@ returns(string) //@ tandre2 //@ uiAsync - export function ask_string(text:string, r:ResumeCtx) - { + export function ask_string(text: string, r: ResumeCtx) { var rt = r.rt; var t = R.mkTextArea("variableDesc"); t.value = ""; - if (rt.useModalWallDialogs()) { - var value = ""; - var m = new ModalDialog(); - m.add([body(text), - div("wall-dialog-input", t), - div("wall-dialog-buttons", - [R.mkButton(lf("ok"), () => { - value = t.value; - m.dismiss(); - })]) - ]); - m.onDismiss = () => r.resumeVal(value); - m.show(); - } else { - var btns; - var elt = div("wall-dialog", - [body(text), - div("wall-dialog-input", t), - btns = div("wall-dialog-buttons", - [R.mkButtonOnce("ok", () => { - Screen.popModalHash("wall"); - t.blur(); - t.setAttribute("readonly", "true"); - var v = t.value; - // popup keyboard takes a while to dissapear in wp - Util.setTimeout(500, () => r.resumeVal(v)); - })]) - ]); - Screen.pushModalHash("wall", () => { - btns.removeSelf(); - t.blur(); - t.setAttribute("readonly", "true"); - // popup keyboard takes a while to dissapear in wp - Util.setTimeout(500, () => r.resumeVal("")); - }); - rt.postHtml(elt, rt.current.pc); - } + var value = ""; + var m = new ModalDialog(); + m.add([body(text), + div("wall-dialog-input", t), + div("wall-dialog-buttons", + [R.mkButton(lf("ok"),() => { + value = t.value; + m.dismiss(); + })]) + ]); + m.onDismiss = () => r.resumeVal(value); + m.show(); Util.setKeyboardFocusTextArea(t); } @@ -226,37 +131,18 @@ module TDev.RT { //@ returns(number) //@ tandre2 //@ uiAsync - export function pick_string(text:string, caption:string, values:Collection, r:ResumeCtx) - { + export function pick_string(text: string, caption: string, values: Collection, r: ResumeCtx) { var rt = r.rt; - if (rt.useModalWallDialogs()) { - var m = new ModalDialog(); - var index = -1; - var btns = values.a.map((st: string, i: number) => div('modalDialogChooseItem', st).withClick(() => { - index = i; - m.dismiss(); - })); - m.add([div("wall-dialog-header", text), - body(caption)]); - m.onDismiss = () => r.resumeVal(index); - m.choose(btns); - } else { - var btnsDiv : HTMLElement; - var btns2 = values.a.map((st:string, i:number) => R.mkButton(st, () => { - r.resumeVal(i); - Screen.popModalHash("wall"); - btnsDiv.removeSelf(); - })); - var elt = div("wall-dialog", - [div("wall-dialog-header", text), - body(caption), - btnsDiv = div("wall-dialog-buttons", btns2)]); - rt.postHtml(elt, rt.current.pc); - Screen.pushModalHash("wall", () => { - btnsDiv.removeSelf(); - r.resumeVal(-1); - }); - } + var m = new ModalDialog(); + var index = -1; + var btns = values.a.map((st: string, i: number) => div('modalDialogChooseItem', st).withClick(() => { + index = i; + m.dismiss(); + })); + m.add([div("wall-dialog-header", text), + body(caption)]); + m.onDismiss = () => r.resumeVal(index); + m.choose(btns); } //? Prompts the user to pick a time. Returns a datetime whose time is set, the date is undefined. @@ -270,53 +156,25 @@ module TDev.RT { var t = R.mkTextInput("time", lf("enter a time")); t.style.borderStyle = 'hidden'; t.style.borderColor = 'red'; - t.onkeyup = (ev : Event) => { + t.onkeyup = (ev: Event) => { t.style.borderStyle = String_.to_time(t.value) != null ? 'hidden' : 'solid'; }; - if (rt.useModalWallDialogs()) { - var value: DateTime = undefined; - var m = new ModalDialog(); - m.add([div("wall-dialog-header", text), - body(caption), - div("wall-dialog-input", t), - body("Enter a time like 15:43 or 3:43pm or 15:43:20 or 3:43:20pm"), - div("wall-dialog-buttons", - [R.mkButton(lf("ok"), () => { - var tt = String_.to_time(t.value); - if (tt != null) - value = Time.today().add_seconds(tt); - m.dismiss(); - })]) - ]); - m.onDismiss = () => r.resumeVal(value); - m.show(); - } else { - var btns; - var elt = div("wall-dialog", - [div("wall-dialog-header", text), - body(caption), - div("wall-dialog-input", t), - body("Enter a time like 15:43 or 3:43pm or 15:43:20 or 3:43:20pm"), - btns = div("wall-dialog-buttons", - [R.mkButtonOnce("ok", () => { - Screen.popModalHash("wall"); - t.blur(); - t.setAttribute("readonly", "true"); - var tt = String_.to_time(t.value); - var ti = (tt != null) ? Time.today().add_seconds(tt) : undefined; - // popup keyboard takes a while to dissapear in wp - Util.setTimeout(500, () => r.resumeVal(ti)); - })]) - ]); - rt.postHtml(elt, rt.current.pc); - Screen.pushModalHash("wall", () => { - btns.removeSelf(); - t.blur(); - t.setAttribute("readonly", "true"); - // popup keyboard takes a while to dissapear in wp - Util.setTimeout(500, () => r.resumeVal(undefined)); - }); - } + var value: DateTime = undefined; + var m = new ModalDialog(); + m.add([div("wall-dialog-header", text), + body(caption), + div("wall-dialog-input", t), + body("Enter a time like 15:43 or 3:43pm or 15:43:20 or 3:43:20pm"), + div("wall-dialog-buttons", + [R.mkButton(lf("ok"),() => { + var tt = String_.to_time(t.value); + if (tt != null) + value = Time.today().add_seconds(tt); + m.dismiss(); + })]) + ]); + m.onDismiss = () => r.resumeVal(value); + m.show(); Util.setKeyboardFocus(t); } @@ -334,45 +192,19 @@ module TDev.RT { t.onkeyup = (ev: Event) => { t.style.borderStyle = DateTime.parse(t.value) != null ? 'hidden' : 'solid'; }; - if (rt.useModalWallDialogs()) { - var value: DateTime = undefined; - var m = new ModalDialog(); - m.add([div("wall-dialog-header", text), - body(caption), - div("wall-dialog-input", t), - div("wall-dialog-buttons", - [R.mkButton(lf("ok"), () => { - value = DateTime.parse(t.value); - m.dismiss(); - })]) - ]); - m.onDismiss = () => r.resumeVal(value); - m.show(); - } else { - var btns; - var elt = div("wall-dialog", - [div("wall-dialog-header", text), - body(caption), - div("wall-dialog-input", t), - btns = div("wall-dialog-buttons", - [R.mkButtonOnce("ok", () => { - Screen.popModalHash("wall"); - t.blur(); - t.setAttribute("readonly", "true"); - var dt = DateTime.parse(t.value); - // popup keyboard takes a while to dissapear in wp - Util.setTimeout(500, () => r.resumeVal(dt)); - })]) - ]); - rt.postHtml(elt, rt.current.pc); - Screen.pushModalHash("wall", () => { - btns.removeSelf(); - t.blur(); - t.setAttribute("readonly", "true"); - // popup keyboard takes a while to dissapear in wp - Util.setTimeout(500, () => r.resumeVal(undefined)); - }); - } + var value: DateTime = undefined; + var m = new ModalDialog(); + m.add([div("wall-dialog-header", text), + body(caption), + div("wall-dialog-input", t), + div("wall-dialog-buttons", + [R.mkButton(lf("ok"),() => { + value = DateTime.parse(t.value); + m.dismiss(); + })]) + ]); + m.onDismiss = () => r.resumeVal(value); + m.show(); Util.setKeyboardFocus(t); } diff --git a/lib/Web.ts b/lib/Web.ts index 10092b24..3b7ede08 100644 --- a/lib/Web.ts +++ b/lib/Web.ts @@ -138,6 +138,7 @@ module TDev.RT { } //? Search and browse the web... + //@ skill(2) export module Web { export interface MessageWaiter { origin: string; diff --git a/node-webkit/package.json b/node-webkit/package.json index a953b360..b8862347 100644 --- a/node-webkit/package.json +++ b/node-webkit/package.json @@ -20,12 +20,12 @@ "type": "MIT" }], "bugs":"http://github.com/microsoft/TouchDevelop/issues", - "repositories": [{ + "repository": { "type": "git", "url": "http://github.com/microsoft/TouchDevelop.git", "path": "node-webkit" - }], + }, "dependencies": { - "faye-websocket": "0.8.1" + "faye-websocket": "0.9.*" } } diff --git a/rt/rt.ts b/rt/rt.ts index 13a1de7a..6a95faae 100644 --- a/rt/rt.ts +++ b/rt/rt.ts @@ -314,6 +314,7 @@ module TDev public webState: RT.Web.State = {}; private state: RtState = RtState.Stopped; + private stateMsg: string = undefined; // when an event is executing, no other event can start private eventExecuting = false; // used to prevent recursive invocations of mainLoop @@ -456,8 +457,6 @@ module TDev else return [r.result]; } - private isReplaying = false; - private eventCategory: string = null; private eventVariable: string = null; public setNextEvent(c: string, v: string) { @@ -469,19 +468,6 @@ module TDev this.eventVariable = null; } - - - private replayStartTime: number; - private currentOffset: number; - public startReplay() { - this.isReplaying = true; - this.replayStartTime = new Date().getTime(); - } - public stopReplayAsync() { - var p = this.stopAsync(); - this.isReplaying = false; - return p; - } public currentTime() { return Util.perfNow(); } @@ -526,13 +512,6 @@ module TDev //////////////////////////////////////////////////////////////////////// // Wall methods //////////////////////////////////////////////////////////////////////// - public useModalWallDialogs(): boolean { - - if (this.rendermode) - Util.userError(lf("cannot ask user in page display code")); - return this.host.isFullScreen() || - !this.mayPostToWall(this.getCurrentPage()); - } public mayPostToWall(p: WallPage): boolean { return !this.headlessPluginMode && (!p.isAuto() || this.rendermode || p.crashed) @@ -1089,6 +1068,7 @@ module TDev HistoryMgr.instance.clearModalStack(); } if (this.state != RtState.Stopped) { + this.setState(RtState.Stopped, "stopAsync"); if (!isPause) { this.versionNumber++; if (this.eventQ) this.eventQ.clear(); @@ -1099,7 +1079,6 @@ module TDev ProgressOverlay.hide() this.asyncStack = []; this.asyncTasks = []; - this.setState(RtState.Stopped, "stopAsync"); this.compiled.stopFn(this); if (!isPause && !this.resumeAllowed && !this.handlingException) { var profilingData = this.compiled._getProfilingResults(); @@ -1490,6 +1469,7 @@ module TDev if (this.state == RtState.Stopped || s == RtState.Stopped) Util.log("runtime state: {0} -> {1}, {2}", this.state, s, msg) this.state = s; + this.stateMsg = msg; } private getResumeCtxCore(isBlocking: boolean, cont: IContinuationFunction) { @@ -2053,8 +2033,8 @@ module TDev return; } - // var lastBreak = Date.now(); var continueLater = false; + var continueLaterVersion = 0; var numCheck = 0; this.mainLoopRunning = true; @@ -2102,6 +2082,7 @@ module TDev var now = Date.now(); if (now - this.lastBreak > (Browser.isNodeJS ? 1000 : 50)) { continueLater = true; + continueLaterVersion = this.versionNumber; break; } numCheck = 0; @@ -2112,7 +2093,7 @@ module TDev } this.mainLoopRunning = false; - if (continueLater) { + if (continueLater && continueLaterVersion == this.versionNumber && this.state != RtState.Stopped) { this.setState(RtState.Paused, "continue later"); var ver = this.versionNumber; var curr = this.current diff --git a/rt/sizemgr.ts b/rt/sizemgr.ts index d933691e..6d4082c7 100644 --- a/rt/sizemgr.ts +++ b/rt/sizemgr.ts @@ -47,7 +47,7 @@ module TDev { export function canSplitScreen() { - return !phoneMode && windowWidth*1.2 > windowHeight; + return !phoneMode && !portraitMode && windowWidth*1.2 > windowHeight; } export function setSplitScreen(isSplit:boolean) diff --git a/rt/util.ts b/rt/util.ts index e0feebaa..e13e7849 100644 --- a/rt/util.ts +++ b/rt/util.ts @@ -749,13 +749,20 @@ module TDev{ } export function userError(msg:string, pc = "", statusCode?:number) : any - { + { var e = new Error(msg); (e).programCounter = pc; (e).isUserError = true; if (statusCode) - (e).statusCode = 500; - throw e; + (e).statusCode = statusCode; + try { + throw e; + } + catch (err) { + Util.log('error: {0}, {1}, {2}', msg, pc, statusCode); + Util.log(err.stack + ""); + throw e; + } } export function syntaxError(msg:string, declName:string) : any diff --git a/shell/shell.ts b/shell/shell.ts index f6422abd..0acb0610 100644 --- a/shell/shell.ts +++ b/shell/shell.ts @@ -1,6 +1,18 @@ /// import fs = require('fs'); + +var fileLog: (msg: string) => void = undefined; +if (process.env["TD_SHELL_LOG_FILE"]) { + var logPath = process.env["TD_SHELL_LOG_FILE"]; + fileLog = (msg) => { + var fl = fs.openSync(logPath, "a"); + var b = new Buffer(msg + '\r\n'); + fs.writeSync(fl, b, 0, b.length, 0); + fs.closeSync(fl); + } +} + import url = require('url'); import http = require('http'); import https = require('https'); @@ -53,10 +65,9 @@ class Logger { logIdx = -1; logMsgs:LogMessage[] = []; logSz = 1000; - - constructor(public level:number) - { - } + + constructor(public name : string, public level:number) + {} addMsg(s:string) { @@ -64,6 +75,7 @@ class Logger { timestamp: Date.now(), msg: s } + if (fileLog) fileLog(s); if (!inAzure) console.log(s) if (this.logIdx >= 0) { this.logMsgs[this.logIdx++] = m; @@ -108,9 +120,9 @@ class Logger { } } -var error = new Logger(3) -var info = new Logger(6) -var debug = new Logger(7) +var error = new Logger("error", 3) +var info = new Logger("info", 6) +var debug = new Logger("debug", 7) class ApiRequest { data:any = {} @@ -296,7 +308,6 @@ function downloadFile(u:string, f:(err:any, s:NodeBuffer, h?:any)=>void) g.on('end', () => { var total = Buffer.concat(bufs) - //console.log("download file: " + u + " " + total.length) f(null, total, (res).headers) }) @@ -652,7 +663,7 @@ function clone(obj: T): T { function createProcess(d:RunCliOptions) { var isWin = /^win/.test(os.platform()) - debug.log("running: " + d.command + (d.args ? (" " + d.args.join(" ")) : "")) + debug.log("running: " + (d.cwd || "") + ">" + d.command + (d.args ? (" " + d.args.join(" ")) : "")) var env = clone(d.env || process.env); if (pythonEnv) Object.keys(pythonEnv).forEach(k => env[k] = pythonEnv[k]); var proc = child_process.spawn(d.args ? d.command : isWin ? "cmd" : "sh", d.args || [isWin ? "/c" : "-c", d.command], { @@ -1576,7 +1587,6 @@ function proxyEditor(cmds:string[], req, resp) s = (s).replace(/(browsers|error)Url = .*/g, (a, b) => b + "Url = \"" + selfUrl + "/" + specRel + "/" + b + "\"") } s = s.replace(/localProxy = ".*"/, 'localProxy = "yes"') - //console.log(specRel) if (rel == "local") { s = s.replace(/betaFriendlyId = ".*"/, "betaFriendlyId = \"(local)\"") } else if (specRel == "current") { @@ -1886,7 +1896,7 @@ function respawnLoop() console.error("Too many failures, aborting. Please retry manually."); process.exit(); } else { - console.log("Failure, retrying in 5s..."); + debug.log("Failure, retrying in 5s..."); setTimeout(startOne, 5000); } } diff --git a/storage/world.ts b/storage/world.ts index c4484cf2..eb572dbb 100644 --- a/storage/world.ts +++ b/storage/world.ts @@ -423,7 +423,8 @@ module TDev { time("readdb1"); if (syncVersion != mySyncVersion) return canceled; data.items = data.indexTable.getItemsAsync(data.keys) - data.scriptVersionsInCloudItems = data.scriptsTable.getItemsAsync(data.keys.map((guid) => guid + "-scriptVersionInCloud")); + if (!Cloud.lite) + data.scriptVersionsInCloudItems = data.scriptsTable.getItemsAsync(data.keys.map((guid) => guid + "-scriptVersionInCloud")); return Promise.join(data); }).then(function (data/*: SyncData*/) { time("readdb2"); diff --git a/tools/client.ts b/tools/client.ts index a9708cc5..48c04cfe 100644 --- a/tools/client.ts +++ b/tools/client.ts @@ -3651,6 +3651,7 @@ var sectAzure = lf("web sites"); var sectMakers = lf("makers"); var sectTouchDevelop = lf("touchdevelop"); var sectOthers = lf("others"); +var sectMinecraft = "Minecraft"; /* editorMode: 1 = block, 2 = coder, 3 = expert @@ -3687,7 +3688,7 @@ var templates: ScriptTemplate[] = [{ title: lf("blank turtle"), id: 'blankturtle', icon: 'Controller', - name: 'ADJ drawing', + name: 'ADJ turtle', description: lf("An turtle app."), section: sectBeginners, scriptid: 'oobxb', @@ -3710,8 +3711,25 @@ var templates: ScriptTemplate[] = [{ section: sectBeginners, scriptid: 'mdrw', editorMode: 1, -}, - +}, { + title: lf("blank minecraft pi"), + id: 'blankminecraftpi', + icon: 'NineColumn', + name: 'ADJ craft', + description: lf("A Minecraft Pi app."), + section: sectMinecraft, + scriptid: 'cptje', + editorMode: 1, +}, { + title: lf("blank minecraft steve"), + id: 'blankminecraftsteve', + icon: 'NineColumn', + name: 'ADJ steve', + description: lf("A Minecraft Steve app."), + section: sectMinecraft, + scriptid: 'qzky', + editorMode: 1, +}, /*{ title: lf("blank boostrap app"), id: 'blankbootstrapapp', diff --git a/www/editor.css b/www/editor.css index 6feb0e32..9a5e8243 100644 --- a/www/editor.css +++ b/www/editor.css @@ -5345,6 +5345,7 @@ img.tracking-pixel { .tutProgress { background: #09b; + color:white; position: absolute; right: 0; top: 0;