UNPKG

canvace

Version:

The Canvace Visual Development Environment.

2 lines 31 kB
#!/usr/bin/env node !function(a,b){function c(a,b){var c=this;this.realpath=function(){var a={};return function(d,e){h.realpath(d,a,function(a,d){if(a)b.json(400,a.toString());else try{e.call(c,d)}catch(f){b.json(400,f.toString())}})}}(),this.stat=function(a,d){h.stat(a,function(a,e){if(a)b.json(400,a.toString());else try{d.call(c,e)}catch(f){b.json(400,f.toString())}})},this.readdir=function(a,d){h.readdir(a,function(a,e){if(a)b.json(400,a.toString());else try{d.call(c,e)}catch(f){b.json(400,f.toString())}})},this.mkdir=function(a,d){h.mkdir(a,function(a){if(a)b.json(400,a.toString());else try{d.call(c)}catch(e){b.json(400,e.toString())}})},this.putJSON=function(a,d,e){h.writeFile(a,JSON.stringify(d),function(a){if(a)b.json(400,a.toString());else try{e.call(c)}catch(d){b.json(400,d.toString())}})},this.createSession=function(b){a.session.projectPath=b,x.of("/poll/"+y(a)).on("connection",function(){})},this.getProjectId=function(){return y(a)}}function d(a,b,d){"string"==typeof a&&(a=[a]);for(var e in a)v[b](a[e],function(a,b){try{d.call(new c(a,b),a,b)}catch(e){b.json(400,e.toString())}})}function e(){var a=function(){var a={};return function(b,c){return h.realpath(g.normalize(b),a,c)}}(),b=new l;this.readLock=function(c,d){a(c,function(a,c){a?d(a):b.readLock(c,function(a){d(!1,a)})})},this.writeLock=function(c,d){a(c,function(a,c){a?d(a):b.writeLock(c,function(a){d(!1,a)})})}}function f(a,b,c){"string"==typeof a&&(a=[a]);for(var d in a)v[b](a[d],function(a,b){if(a.session&&a.session.projectPath)try{c.call(new z(a,b),a,b)}catch(d){b.json(400,d.toString())}else b.json(400,"Invalid request, no stage selected")})}b.exports=a;var g=require("path"),h=require("fs"),i=require("util"),j=require("npm"),k=require("multiset"),l=require("rwlock"),m=require("express"),n=require("consolidate"),o=require("http"),p=function(){try{return require(g.join(__dirname,"..","package.json"))}catch(a){return{version:"unknown"}}}(),q=function(a){var b;if(b=a,!h.existsSync(b)||!h.statSync(b).isDirectory())return __dirname;if(b=g.join(b,".Canvace"),!h.existsSync(b)||!h.statSync(b).isDirectory())try{h.mkdirSync(b)}catch(c){return __dirname}if(b=g.join(b,"Darblast"),!h.existsSync(b)||!h.statSync(b).isDirectory())try{h.mkdirSync(b)}catch(c){return __dirname}return b}(g.normalize(process.env["win32"==process.platform?"USERPROFILE":"HOME"])),r=function(){try{return require(g.join(q,"config.json"))}catch(a){return{}}}(),s=function(){var a;try{a=h.readFileSync(g.join(q,"users.json"),"ascii")}catch(b){return null}try{return JSON.parse(a)}catch(b){console.log("invalid syntax in users.json"),process.exit(2)}}();!function(){function a(a){a?console.log("Invalid command. Available commands:"):console.log("Available commands:"),console.log(""),console.log("canvace"),console.log(" Starts the Canvace Development Environment."),console.log(""),console.log("canvace help"),console.log(" Shows this screen."),console.log(""),console.log("canvace config browser <bool>"),console.log(" Enables or disables the automatic launching of the browser."),console.log(""),console.log("canvace setuser <username> <password>"),console.log(" Creates or updates user credentials."),console.log(""),console.log("canvace removeuser <username>"),console.log(" Removes an existing user from Canvace's user database."),console.log(""),console.log("canvace clearusers"),console.log(" Completely erases Canvace's user database, authentication will not be required any more unless new users are added using setuser."),console.log(""),process.exit(1)}function b(b){process.argv.length!=b&&a(!0)}function c(){null===s&&(s={})}function d(){h.writeFileSync(g.join(q,"users.json"),JSON.stringify(s),"ascii")}if(process.argv.length>2){switch(process.argv[2]){case"help":a(!1);break;case"config":b(5),"browser"!==process.argv[3]?a(!0):(r.browser="true"===process.argv[4],h.writeFileSync(g.join(q,"config.json"),JSON.stringify(r)));break;case"setuser":b(5),c(),s[process.argv[3]]=process.argv[4],d();break;case"removeuser":b(4),c(),delete s[process.argv[3]],d();break;case"clearusers":b(3),s=null,h.unlinkSync(g.join(q,"users.json"));break;default:a(!0)}process.exit(0)}}();var t=!1,u=!1;r.dontCheckForUpdates||("versions"in r||(r.versions={}),j.load(function(){j.commands.view(["canvace","versions"],!0,function(a,b){var c={};for(var d in b)for(var e in b[d].versions){var f=b[d].versions[e];f in r.versions||(r.versions[f]=!0,c[f]=!0)}Object.keys(c).length&&h.writeFile(g.join(q,"config.json"),JSON.stringify(r))})}));var v=m();v.enable("strict routing"),v.use(m.cookieParser()),r.debug?v.use(m.cookieSession({secret:"darblast"})):v.use(m.session({secret:"darblast"})),v.use(m.static(__dirname+"/static")),v.use("/directories/root/",function(a,b,c){function d(a){return g.normalize(a).replace(g.sep,"/")}var e=d(decodeURIComponent(a.path));h.stat(e,function(a,f){!a&&f.isDirectory()?h.readdir(e,function(a,c){if(a)b.send(500,a.toString());else{c=c.filter(function(a){return!/^\./.test(a)});var f=[],i=c.length;c.forEach(function(a){h.stat(g.join(e,a),function(c,h){!c&&h.isDirectory()&&f.push({id:d(g.join("root",e,a)),baseName:a,fullPath:g.normalize(g.join(e,a)),text:a,leaf:!1,expandable:!0,expanded:!1}),--i||b.json({success:!0,data:f})})})}}):c()})}),v.use(m.query()),v.use(m.bodyParser()),v.set("views",__dirname+"/views"),v.engine("handlebars",n.handlebars),null!==s&&v.use(m.basicAuth(function(a,b){return a in s&&s[a]===b}));var w=o.createServer(v),x=require("socket.io").listen(w);r.debug||(x.set("log level",1),x.enable("browser client minification"));var y=function(){var a={},b=0;return function(c){return c.session.projectPath in a||(a[c.session.projectPath]=b++),a[c.session.projectPath]}}();d("/","post",function(a,b){function c(){var a=arguments,b=this;!function c(d){d<a.length&&a[d].call(b,function(){c(d+1)})}(0)}if("path"in a.body){var d=g.normalize(a.body.path),e=g.dirname(d),f=g.basename(d);this.realpath(e,function(d){var e=["","/images","/tiles","/entities","/stages"].map(function(a){return function(b){this.mkdir(d+"/"+f+a,b)}});e.push(function(b){this.putJSON(d+"/"+f+"/info",{matrix:[[parseFloat(a.body.matrix11),parseFloat(a.body.matrix12),parseFloat(a.body.matrix13)],[parseFloat(a.body.matrix21),parseFloat(a.body.matrix22),parseFloat(a.body.matrix23)],[parseFloat(a.body.matrix31),parseFloat(a.body.matrix32),parseFloat(a.body.matrix33)]],imageCounter:0,tileCounter:0,entityCounter:0},b)},function(a){this.putJSON(d+"/"+f+"/stages/Stage 1",{x0:0,y0:0,map:{},marks:{},instances:[],properties:{}},a)},function(){this.createSession(d+"/"+f+"/"),b.json({projectId:this.getProjectId(),stageId:"Stage 1"})}),c.apply(this,e)})}else b.json(400,"Missing project path")}),d("/","put",function(a,b){this.realpath(g.normalize(a.body.path),function(c){this.stat(c,function(d){d.isDirectory()?(/[\\\/]$/.test(c)||(c+="/"),this.createSession(c),this.readdir(a.session.projectPath+"stages",function(a){b.cookie("last-path",c.replace(/^\w\:[\\\/]/i,"/").replace(/[\\\/]$/,"").replace(/\\/g,"/"),{expires:new Date(Date.now()+31536e6)}).json({projectId:this.getProjectId(),stageId:a[0]})})):b.json(404,"Invalid path")})})}),v.get("/update",function(a,b){j.commands.update(["canvace"],function(a){a?b.json(500,a.toString()):b.json(!0)})}),v.get("/install",function(a,b){j.commands.install(["canvace@"+a.query.version],function(a){a?b.json(500,a.toString()):b.json(!0)})}),d("/","get",function(a,b){"projectPath"in a.session?this.readdir(a.session.projectPath+"stages",function(c){if("stage"in a.query){var d=c.indexOf(a.query.stage);0>d||b.render("main.handlebars",{version:p.version,projectId:JSON.stringify(this.getProjectId()),stageId:JSON.stringify(c[d]),newMinorVersion:t,newMajorVersion:u})}else b.render("main.handlebars",{version:p.version,projectId:JSON.stringify(this.getProjectId()),stageId:JSON.stringify(c[0]),newMinorVersion:t,newMajorVersion:u})}):b.render("main.handlebars",{version:p.version,newMinorVersion:t,newMajorVersion:u})});var z=function(){var a=new e;return function(b,c){function d(){l.fastForEach(function(a){a()}),l.clear()}function e(a){d(),c.json(400,a.toString())}function f(c,d){a.readLock(b.session.projectPath+c,function(a,b){if(a)e(a);else{var c=l.add(b);try{d.call(j,function(){c(),b()})}catch(a){e(a)}}})}function g(c,d){a.writeLock(b.session.projectPath+c,function(a,b){if(a)e(a);else{var c=l.add(b);try{d.call(j,function(){c(),b()})}catch(a){e(a)}}})}function i(a){this.globalReadLock=function(b){f(a,b)},this.globalWriteLock=function(b){g(a,b)},this.individualReadLock=function(b,c){f(a+"/"+b,c)},this.individualWriteLock=function(b,c){g(a+"/"+b,c)},this.get=function(b,d){d||(d=function(){c.json(!0)}),f(a+"/"+b,function(c){j.getJSON(a+"/"+b,function(a){c(),d.call(j,a)})})},this.put=function(b,e,f){f||(f=function(){d(),c.json(!0)}),g(a+"/"+b,function(c){j.putJSON(a+"/"+b,e,function(){c(),f.call(j)})})},this.modify=function(b,e,f){f||(f=function(){d(),c.json(!0)}),g(a+"/"+b,function(c){j.getJSON(a+"/"+b,function(d){e.call(j,d,function(){j.putJSON(a+"/"+b,d,function(){c(),f.call(j)})})})})},this.modifySync=function(b,e,f){f||(f=function(){d(),c.json(!0)}),g(a+"/"+b,function(c){j.getJSON(a+"/"+b,function(d){e.call(j,d),j.putJSON(a+"/"+b,d,function(){c(),f.call(j)})})})},this.rename=function(b,e,f){f||(f=function(){d(),c.json(!0)}),g(a,function(c){j.exists(a+"/"+e,function(d){d?(c(),f.call(j,!1)):j.rename(a+"/"+b,a+"/"+e,function(){c(),f.call(j,!0)})})})}}var j=this,l=new k;this.removePendingLocks=d,this.error=e,this.readLock=f,this.writeLock=g,this.stages=new i("stages"),this.images=new i("images"),this.tiles=new i("tiles"),this.entities=new i("entities"),this.exists=function(a,c){h.exists(b.session.projectPath+a,function(a){try{c.call(j,a)}catch(b){e(b)}})},this.rename=function(a,c,d){h.rename(b.session.projectPath+a,b.session.projectPath+c,function(a){if(a)e(a);else try{d.call(j)}catch(a){e(a)}})},this.unlink=function(a,c){h.unlink(b.session.projectPath+a,function(a){if(a)e(a);else try{c.call(j)}catch(a){e(a)}})},this.mkdir=function(a,c){h.mkdir(b.session.projectPath+a,function(a){if(a)e(a);else try{c.call(j)}catch(a){e(a)}})},this.readdir=function(a,c){h.readdir(b.session.projectPath+a,function(a,b){if(a)e(a);else try{c.call(j,b)}catch(a){e(a)}})},this.deleteTree=function(a,c){!function d(a,b){var c=h.statSync(a);c.isDirectory()?h.readdir(a,function(c,f){if(c)e(c);else{var g=f.length;f.forEach(function(c){d(a+"/"+c,function(){--g||h.rmdir(a,function(a){if(a)e(a);else try{b.call(j)}catch(a){e(a)}})})})}}):h.unlink(a,function(a){if(a)e(a);else try{b.call(j)}catch(a){e(a)}})}(b.session.projectPath+a,c)},this.realpath=function(){var a={};return function(b,c){h.realpath(b,a,function(a,b){if(a)e(a);else try{c.call(j,b)}catch(a){e(a)}})}}(),this.readFile=function(a,c){h.readFile(b.session.projectPath+a,function(a,b){if(a)e(a);else try{c.call(j,b)}catch(a){e(a)}})},this.writeFile=function(a,c,d){h.writeFile(b.session.projectPath+a,c,function(a){if(a)e(a);else try{d.call(j)}catch(a){e(a)}})},this.getJSON=function(a,c){h.readFile(b.session.projectPath+a,"ascii",function(a,b){if(a)e(a);else try{c.call(j,JSON.parse(b))}catch(a){e(a)}})},this.putJSON=function(a,c,d){h.writeFile(b.session.projectPath+a,JSON.stringify(c),function(a){if(a)e(a);else try{d.call(j)}catch(a){e(a)}})},this.newIds=function(a,b,c){arguments.length<3&&(c=b,b=1),j.writeLock("info",function(d){j.getJSON("info",function(e){var f=e[a+"Counter"];e[a+"Counter"]+=b,j.putJSON("info",e,function(){d(),c.call(j,f)})})})},this.refImage=function(a,b){j.images.individualWriteLock(a,function(c){j.getJSON("images/"+a+"/info",function(d){var e=++d.refCount;j.putJSON("images/"+a+"/info",d,function(){c(),b.call(j,e)})})})},this.unrefImage=function(a,b){j.images.individualWriteLock(a,function(c){j.getJSON("images/"+a+"/info",function(d){var e=--d.refCount;j.putJSON("images/"+a+"/info",d,function(){c(),b.call(j,e)})})})},this.getProjectId=function(){return y(b)},this.broadcast=function(a,c,d){x.of("/poll/"+y(b)).emit(a+"/"+c,d)}}}();!function(){function a(a){"string"==typeof a&&(a=a.split(",")),function(){var b=[];a.filter(function(a){var c=a.split(",");return c.length>1?(b.push.apply(b,c),!1):!0}),a.push.apply(a,b)}();var b,c={};for(var d in a)if(b=a[d].toString().trim(),""!==b){if(!/^\w+$/.test(b))throw"One or more labels contain invalid characters";c[b]=!0}var e=[];for(b in c)e.push(b);return e}f(["/images/","/stages/:stageId/images/"],"get",function(a,b){this.images.globalReadLock(function(a){this.readdir("images",function(c){var d={};if(c.length){var e=c.length;c.forEach(function(c){this.images.individualReadLock(c,function(f){this.getJSON("images/"+c+"/info",function(g){f(),d[c]=g.labels,--e||(a(),b.json(d))})})},this)}else a(),b.json({})})})}),f(["/images/:imageId","/stages/:stageId/images/:imageId"],"get",function(a,b){this.images.individualReadLock(a.params.imageId,function(c){this.getJSON("images/"+a.params.imageId+"/info",function(d){this.readFile("images/"+a.params.imageId+"/data",function(a){c(),b.type(d.type).send(a)})})})}),f(["/images/","/stages/:stageId/images/"],"post",function(b,c){function d(a,b,c){this.images.globalWriteLock(function(d){this.mkdir("images/"+b,function(){this.images.individualWriteLock(b,function(f){d(),this.putJSON("images/"+b+"/info",{refCount:0,type:a.type,labels:e},function(){var d=this;h.readFile(a.path,function(a,h){a?d.error():d.writeFile("images/"+b+"/data",h,function(){this.broadcast("images","create",{id:b,labels:e}),f(),g.push(b),c.call(this)})})})})})})}c.type("html");var e;if("labels"in b.body)try{e=a(b.body.labels)}catch(f){return c.json(400,f.toString()),void 0}else e=[];var g=[];i.isArray(b.files.images)?this.newIds("image",b.files.images.length,function(a){var e=0;for(var f in b.files.images)e++,d.call(this,b.files.images[f],a++,function(){--e||c.json(g)})}):this.newIds("image",function(a){d.call(this,b.files.images,a,function(){c.json([a])})})}),f(["/images/:imageId","/stages/:stageId/images/:imageId"],"put",function(b,c){this.images.individualWriteLock(b.params.imageId,function(d){this.getJSON("images/"+b.params.imageId+"/info",function(e){e.labels=a(b.body.labels),this.putJSON("images/"+b.params.imageId+"/info",e,function(){this.broadcast("images","update",{id:b.params.imageId,labels:e.labels}),d(),c.json(!0)})})})}),f(["/images/:imageId","/stages/:stageId/images/:imageId"],"delete",function(a,b){this.images.individualReadLock(a.params.imageId,function(c){this.getJSON("images/"+a.params.imageId+"/info",function(d){d.refCount>0?(c(),b.json(403,"The image is still in use")):this.images.globalWriteLock(function(d){this.deleteTree("images/"+a.params.imageId,function(){this.broadcast("images","delete",{id:a.params.imageId}),c(),d(),b.json(!0)})})})})})}(),f(["/tiles/","/stages/:stageId/tiles/"],"get",function(a,b){this.tiles.globalReadLock(function(a){this.readdir("tiles",function(c){a(),b.json(c)})})}),f(["/tiles/","/stages/:stageId/tiles/"],"post",function(a,b){this.newIds("tile",function(c){this.tiles.globalWriteLock(function(d){var e={solid:!1,"static":!0,layout:{ref:{i:parseInt(a.body.layout.ref.i,10),j:parseInt(a.body.layout.ref.j,10)},span:{i:parseInt(a.body.layout.span.i,10),j:parseInt(a.body.layout.span.j,10)}},offset:{x:0,y:0},frames:{},frameCounter:0,properties:{}};"static"in a.body&&(e.static=!!a.body.static),"solid"in a.body&&(e.solid=!!a.body.solid),"offset"in a.body&&(e.offset.x=parseFloat(a.body.offset.x),e.offset.y=parseFloat(a.body.offset.y)),function(b){if("firstFrameId"in a.body){var c=parseInt(a.body.firstFrameId,10);this.refImage(c,function(){e.frames[e.frameCounter++]={id:c},b.call(this)})}else b.call(this)}.call(this,function(){this.putJSON("tiles/"+c,e,function(){delete e.frames,delete e.frameCounter,delete e.properties,this.broadcast("tiles","create",{id:c,descriptor:e}),d(),b.json(c)})})})})}),f(["/tiles/:tileId","/stages/:stageId/tiles/:tileId"],"get",function(a,b){this.tiles.get(a.params.tileId,function(a){delete a.frames,delete a.frameCounter,delete a.properties,b.json(a)})}),f(["/tiles/:tileId","/stages/:stageId/tiles/:tileId"],"put",function(a){this.tiles.modifySync(a.params.tileId,function(b){var c={};"static"in a.body&&(c.static=b.static=!!a.body.static),"solid"in a.body&&(c.solid=b.solid=!!a.body.solid),"offset"in a.body&&(c.offset={x:b.offset.x=parseFloat(a.body.offset.x),y:b.offset.y=parseFloat(a.body.offset.y)}),this.broadcast("tiles","update",{id:a.params.tileId,descriptor:c})})}),f(["/tiles/:tileId","/stages/:stageId/tiles/:tileId"],"delete",function(a,b){this.tiles.globalWriteLock(function(c){var d=function(){this.unlink("tiles/"+a.params.tileId,function(){this.broadcast("tiles","delete",{id:a.params.tileId}),c(),b.json(!0)})}.bind(this);a.body.force?this.stages.globalReadLock(function(b){this.readdir("stages",function(c){var e=c.length;c.forEach(function(c){this.stages.modifySync(c,function(b){for(var c in b.map)for(var d in b.map[c])for(var e in b.map[c][d])b.map[c][d][e]==a.params.tileId&&(delete b.map[c][d][e],Object.keys(b.map[c][d]).length||delete b.map[c][d],Object.keys(b.map[c]).length||delete b.map[c])},function(){--e||(b(),d())})},this)})}):this.stages.globalReadLock(function(b){this.readdir("stages",function(c){var e=c.length;c.forEach(function(c){this.getJSON("stages/"+c,function(f){for(var g in f.map)for(var h in f.map[g])for(var i in f.map[g][h])if(f.map[g][h][i]==a.params.tileId)throw"Cannot delete the specified tile, it's used by the stage \""+c+'".';--e||(b(),d())})},this)})})})}),f(["/tiles/:tileId/frames/","/stages/:stageId/tiles/:tileId/frames/"],"get",function(a,b){this.tiles.get(a.params.tileId,function(a){var c=Object.keys(a.frames).map(function(a){return parseInt(a,10)});c.sort(),b.json(c)})}),f(["/tiles/:tileId/frames/","/stages/:stageId/tiles/:tileId/frames/"],"post",function(a,b){var c;this.tiles.modify(a.params.tileId,function(b,d){this.refImage(a.body.imageId,function(){c=b.frameCounter++,b.frames[c]={id:a.body.imageId},"duration"in a.body&&(b.frames[c].duration=parseInt(a.body.duration,10));var e={id:parseInt(a.params.tileId,10),frameId:c,imageId:a.body.imageId};"duration"in a.body&&(e.duration=a.body.duration),this.broadcast("tiles/frames","create",e),d()})},function(){b.json(c)})}),f(["/tiles/:tileId/frames/:frameId","/stages/:stageId/tiles/:tileId/frames/:frameId"],"get",function(a,b){this.tiles.get(a.params.tileId,function(c){a.params.frameId in c.frames?b.json(c.frames[a.params.frameId]):b.json(400,"Invalid frame ID: "+a.params.frameId)})}),f(["/tiles/:tileId/frames/:frameId","/stages/:stageId/tiles/:tileId/frames/:frameId"],"put",function(a,b){this.tiles.individualWriteLock(a.params.tileId,function(c){this.getJSON("tiles/"+a.params.tileId,function(d){if(a.params.frameId in d.frames){var e;a.body.duration!==!1?(e=d.frames[a.params.frameId].duration=parseInt(a.body.duration,10),this.putJSON("tiles/"+a.params.tileId,d,function(){this.broadcast("tiles/frames","update",{id:a.params.tileId,frameId:a.params.frameId,duration:e}),c(),b.json(!0)})):(delete d.frames[a.params.frameId].duration,this.putJSON("tiles/"+a.params.tileId,d,function(){this.broadcast("tiles/frames","update",{id:a.params.tileId,frameId:a.params.frameId}),c(),b.json(!0)}))}else c(),b.json(400,"Invalid frame ID: "+a.params.frameId)})})}),f(["/tiles/:tileId/frames/:frameId","/stages/:stageId/tiles/:tileId/frames/:frameId"],"delete",function(a){this.tiles.modify(a.params.tileId,function(b,c){if(!(a.params.frameId in b.frames))throw"Invalid frame ID: "+a.params.frameId;this.unrefImage(b.frames[a.params.frameId].id,function(){delete b.frames[a.params.frameId],this.broadcast("tiles/frames","delete",{id:a.params.tileId,frameId:a.params.frameId}),c()})})}),f(["/tiles/:tileId/properties/","/stages/:stageId/tiles/:tileId/properties/"],"get",function(a,b){this.tiles.get(a.params.tileId,function(a){b.json(a.properties)})}),f(["/tiles/:tileId/properties/:name","/stages/:stageId/tiles/:tileId/properties/:name"],"get",function(a,b){this.tiles.get(a.params.tileId,function(c){a.params.name in c.properties?b.json(c.properties[a.params.name]):b.json(400,"Invalid property name: "+a.params.name)})}),f(["/tiles/:tileId/properties/:name","/stages/:stageId/tiles/:tileId/properties/:name"],"put",function(a){this.tiles.modifySync(a.params.tileId,function(b){b.properties[a.params.name]=a.body.value,this.broadcast("tiles/properties","put",{id:a.params.tileId,name:a.params.name,value:a.body.value})})}),f(["/tiles/:tileId/properties/:name","/stages/:stageId/tiles/:tileId/properties/:name"],"delete",function(a){this.tiles.modifySync(a.params.tileId,function(b){if(!(a.params.name in b.properties))throw"Invalid property name: "+a.params.name;delete b.properties[a.params.name],this.broadcast("tiles/properties","delete",{id:a.params.tileId,name:a.params.name})})}),f(["/entities/","/stages/:stageId/entities/"],"get",function(a,b){this.entities.globalReadLock(function(a){this.readdir("entities",function(c){a(),b.json(c)})})}),f(["/entities/","/stages/:stageId/entities/"],"post",function(a,b){this.newIds("entity",function(c){this.entities.globalWriteLock(function(d){var e={offset:{x:0,y:0},box:{i0:0,j0:0,iSpan:1,jSpan:1},hasPhysics:!1,frames:{},frameCounter:0,properties:{}};"hasPhysics"in a.body&&(e.hasPhysics=!!a.body.hasPhysics),"offset"in a.body&&(e.offset.x=parseFloat(a.body.offset.x),e.offset.y=parseFloat(a.body.offset.y)),function(b){if("firstFrameId"in a.body){var c=parseInt(a.body.firstFrameId,10);this.refImage(c,function(){e.frames[e.frameCounter++]={id:c},b.call(this)})}else b.call(this)}.call(this,function(){this.putJSON("entities/"+c,e,function(){delete e.frames,delete e.frameCounter,delete e.properties,this.broadcast("entities","create",{id:c,descriptor:e}),d(),b.json(c)})})})})}),f(["/entities/:entityId","/stages/:stageId/entities/:entityId"],"get",function(a,b){this.entities.get(a.params.entityId,function(a){delete a.frames,delete a.frameCounter,delete a.properties,b.json(a)})}),f(["/entities/:entityId","/stages/:stageId/entities/:entityId"],"put",function(a){this.entities.modifySync(a.params.entityId,function(b){var c={};"offset"in a.body&&(c.offset={x:b.offset.x=parseFloat(a.body.offset.x),y:b.offset.y=parseFloat(a.body.offset.y)}),"box"in a.body&&(c.box=b.box={i0:parseFloat(a.body.box.i0),j0:parseFloat(a.body.box.j0),iSpan:parseFloat(a.body.box.iSpan),jSpan:parseFloat(a.body.box.jSpan)}),"hasPhysics"in a.body&&(c.hasPhysics=b.hasPhysics=!!a.body.hasPhysics),this.broadcast("entities","update",{id:a.params.entityId,descriptor:c})})}),f(["/entities/:entityId","/stages/:stageId/entities/:entityId"],"delete",function(a,b){this.entities.globalWriteLock(function(c){var d=function(){this.unlink("entities/"+a.params.entityId,function(){this.broadcast("entities","delete",{id:a.params.entityId}),c(),b.json(!0)})}.bind(this);a.body.force?this.stages.globalReadLock(function(b){this.readdir("stages",function(c){var e=c.length;c.forEach(function(c){this.stages.modifySync(c,function(b){b.instances=b.instances.filter(function(b){return b.id!=a.params.entityId})},function(){--e||(b(),d())})},this)})}):this.stages.globalReadLock(function(b){this.readdir("stages",function(c){var e=c.length;c.forEach(function(c){this.getJSON("stages/"+c,function(f){for(var g=0;g<f.instances.length;){if(f.instances[g].id==a.params.entityId)throw"Cannot delete the specified entity, it's used by the stage \""+c+'".';g++}--e||(b(),d())})},this)})})})}),f(["/entities/:entityId/frames/","/stages/:stageId/entities/:entityId/frames/"],"get",function(a,b){this.entities.get(a.params.entityId,function(a){var c=Object.keys(a.frames).map(function(a){return parseInt(a,10)});c.sort(),b.json(c)})}),f(["/entities/:entityId/frames/","/stages/:stageId/entities/:entityId/frames/"],"post",function(a,b){var c;this.entities.modify(a.params.entityId,function(b,d){this.refImage(a.body.imageId,function(){c=b.frameCounter++,b.frames[c]={id:a.body.imageId},"duration"in a.body&&(b.frames[c].duration=parseInt(a.body.duration,10));var e={id:parseInt(a.params.entityId,10),frameId:c,imageId:a.body.imageId};"duration"in a.body&&(e.duration=a.body.duration),this.broadcast("entities/frames","create",e),d()})},function(){b.json(c)})}),f(["/entities/:entityId/frames/:frameId","/stages/:stageId/entities/:entityId/frames/:frameId"],"get",function(a,b){this.entities.get(a.params.entityId,function(c){a.params.frameId in c.frames?b.json(c.frames[a.params.frameId]):b.json(400,"Invalid frame ID: "+a.params.frameId)})}),f(["/entities/:entityId/frames/:frameId","/stages/:stageId/entities/:entityId/frames/:frameId"],"put",function(a,b){this.entities.individualWriteLock(a.params.entityId,function(c){this.getJSON("entities/"+a.params.entityId,function(d){if(a.params.frameId in d.frames){var e;a.body.duration!==!1?(e=d.frames[a.params.frameId].duration=parseInt(a.body.duration,10),this.putJSON("entities/"+a.params.entityId,d,function(){this.broadcast("entities/frames","update",{id:a.params.entityId,frameId:a.params.frameId,duration:e}),c(),b.json(!0)})):(delete d.frames[a.params.frameId].duration,this.putJSON("entities/"+a.params.entityId,d,function(){this.broadcast("entities/frames","update",{id:a.params.entityId,frameId:a.params.frameId}),c(),b.json(!0)}))}else c(),b.json(400,"Invalid frame ID: "+a.params.frameId)})})}),f(["/entities/:entityId/frames/:frameId","/stages/:stageId/entities/:entityId/frames/:frameId"],"delete",function(a){this.entities.modify(a.params.entityId,function(b,c){if(!(a.params.frameId in b.frames))throw"Invalid frame ID: "+a.params.frameId;this.unrefImage(b.frames[a.params.frameId].id,function(){delete b.frames[a.params.frameId],this.broadcast("entities/frames","delete",{id:a.params.entityId,frameId:a.params.frameId}),c()})})}),f(["/entities/:entityId/properties/","/stages/:stageId/entities/:entityId/properties/"],"get",function(a,b){this.entities.get(a.params.entityId,function(a){b.json(a.properties)})}),f(["/entities/:entityId/properties/:name","/stages/:stageId/entities/:entityId/properties/:name"],"get",function(a,b){this.entities.get(a.params.entityId,function(c){a.params.name in c.properties?b.json(c.properties[a.params.name]):b.json(400,"Invalid property name: "+a.params.name)})}),f(["/entities/:entityId/properties/:name","/stages/:stageId/entities/:entityId/properties/:name"],"put",function(a){this.entities.modifySync(a.params.entityId,function(b){b.properties[a.params.name]=a.body.value,this.broadcast("entities/properties","put",{id:a.params.entityId,name:a.params.name,value:a.body.value})})}),f(["/entities/:entityId/properties/:name","/stages/:stageId/entities/:entityId/properties/:name"],"delete",function(a){this.entities.modifySync(a.params.entityId,function(b){if(!(a.params.name in b.properties))throw"Invalid property name: "+a.params.name;delete b.properties[a.params.name],this.broadcast("entities/properties","delete",{id:a.params.entityId,name:a.params.name})})}),f("/stages/","get",function(a,b){this.stages.globalReadLock(function(a){this.readdir("stages",function(c){a(),b.json(c)})})}),f("/export","get",function(a,b){a.query.single&&this.getJSON("info",function(a){function c(a,b){this[a].globalReadLock(function(c){this.readdir(a,function(e){var f=e.length;e.forEach(function(e){this[a].get(e,function(g){d[a][e]=g,--f||(c(),b())})},this)})})}var d={matrix:a.matrix,images:{},tiles:{},entities:{},stages:{}};!function(a){this.images.globalReadLock(function(b){this.readdir("images",function(c){var e=c.length;c.forEach(function(c){this.getJSON("images/"+c+"/info",function(f){this.readFile("images/"+c+"/data",function(g){d.images[c]={info:f,data:g},--e||(b(),a())})})},this)})})}.bind(this)(c.bind(this,"tiles",c.bind(this,"entities",c.bind(this,"stages",function(){b.json(b)}))))})}),f("/import","post",function(){}),f("/stages/","post",function(a,b){/^[\w \.]+$/.test(a.body.name)?this.stages.globalWriteLock(function(c){this.exists("stages/"+a.body.name,function(d){d?(c(),b.json(400,"A stage with the specified name already exists.")):this.putJSON("stages/"+a.body.name,{x0:0,y0:0,map:{},marks:{},instances:[],properties:{}},function(){this.broadcast("stages","create",{id:a.body.name}),c(),b.json(!0)})})}):b.json(400,'The specified stage name "'+a.body.name+'" contains invalid characters.')}),f("/stages/:stageId","get",function(a,b){this.getJSON("info",function(c){this.stages.get(a.params.stageId,function(a){b.json({matrix:c.matrix,name:a.name,x0:a.x0,y0:a.y0,map:a.map,instances:a.instances})})})}),f("/stages/:stageId","put",function(a){function b(a){var b={};return a.forEach(function(a){b[a]=!0}),b}function c(b){var c={};for(var d in a.body.map){c[d]={};for(var e in a.body.map[d]){c[d][e]={};for(var f in a.body.map[d][e]){var g=parseInt(a.body.map[d][e][f],10);if(!(g in b))throw"Invalid tile ID: "+g;c[d][e][f]=g}}}return c}function d(b){var c=[];for(var d in a.body.instances){var e=a.body.instances[d];if(e.id=parseInt(e.id,10),!(e.id in b))throw"Invalid entity ID: "+e.id;c.push({id:e.id,i:parseFloat(e.i),j:parseFloat(e.j),k:parseFloat(e.k),properties:e.properties})}return c}this.tiles.globalReadLock(function(){this.readdir("tiles",function(e){var f=c(b(e));this.entities.globalReadLock(function(){this.readdir("entities",function(c){var e=d(b(c));this.stages.modifySync(a.params.stageId,function(b){"x0"in a.body&&(b.x0=parseFloat(a.body.x0)),"y0"in a.body&&(b.y0=parseFloat(a.body.y0)),b.map=f,b.instances=e})})})})})}),f("/stages/:stageId","delete",function(a,b){this.stages.globalWriteLock(function(c){this.stages.individualWriteLock(a.params.stageId,function(d){this.unlink("stages/"+a.params.stageId,function(){this.broadcast("stages","delete",{id:a.params.stageId}),d(),c(),b.json(!0)})})})}),f("/stages/:stageId/id","put",function(a,b){this.stages.rename(a.params.stageId,a.body.newId,function(c){c?(this.broadcast("stages","rename",{oldId:a.params.stageId,newId:a.body.newId}),b.json(!0)):b.json(400,"A stage with the specified name already exists.")})}),f("/stages/:stageId/properties/","get",function(a,b){this.stages.get(a.params.stageId,function(a){b.json(a.properties)})}),f("/stages/:stageId/properties/:name","get",function(a,b){this.stages.get(a.params.stageId,function(c){a.params.name in c.properties?b.json(c.properties[a.params.name]):b.json(400,"Invalid property name: "+a.params.name)})}),f("/stages/:stageId/properties/:name","put",function(a){this.stages.modifySync(a.params.stageId,function(b){b.properties[a.params.name]=a.body.value,this.broadcast("stages/properties","put",{id:a.params.stageId,name:a.params.name,value:a.body.value})})}),f("/stages/:stageId/properties/:name","delete",function(a){this.stages.modifySync(a.params.stageId,function(b){if(!(a.params.name in b.properties))throw"Invalid property name: "+a.params.name;delete b.properties[a.params.name],this.broadcast("stages/properties","delete",{id:a.params.stageId,name:a.params.name})})}),w.listen(process.env.PORT||7104,function(){var a=w.address().port;console.log("Canvace Development Environment running on port "+a),r.hasOwnProperty("browser")&&r.browser===!1||require("openurl").open("http://localhost:"+a+"/")})}({},function(){return this}());