diff --git a/app.js b/app.js
new file mode 100644
index 0000000..83fefb3
--- /dev/null
+++ b/app.js
@@ -0,0 +1,60 @@
+var express = require('express');
+var path = require('path');
+var favicon = require('serve-favicon');
+var logger = require('morgan');
+var cookieParser = require('cookie-parser');
+var bodyParser = require('body-parser');
+
+var routes = require('./routes/index');
+var users = require('./routes/users');
+
+var app = express();
+
+// view engine setup
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'ejs');
+
+// uncomment after placing your favicon in /public
+//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
+app.use(logger('dev'));
+app.use(bodyParser.json());
+app.use(bodyParser.urlencoded({ extended: false }));
+app.use(cookieParser());
+app.use(express.static(path.join(__dirname, 'public')));
+
+app.use('/', users);
+app.use('/api', routes);
+
+// catch 404 and forward to error handler
+app.use(function(req, res, next) {
+ var err = new Error('Not Found');
+ err.status = 404;
+ next(err);
+});
+
+// error handlers
+
+// development error handler
+// will print stacktrace
+if (app.get('env') === 'development') {
+ app.use(function(err, req, res, next) {
+ res.status(err.status || 500);
+ res.render('error', {
+ message: err.message,
+ error: err
+ });
+ });
+}
+
+// production error handler
+// no stacktraces leaked to user
+app.use(function(err, req, res, next) {
+ res.status(err.status || 500);
+ res.render('error', {
+ message: err.message,
+ error: {}
+ });
+});
+
+
+module.exports = app;
diff --git a/bin/www b/bin/www
new file mode 100755
index 0000000..eafbd45
--- /dev/null
+++ b/bin/www
@@ -0,0 +1,90 @@
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var app = require('../app');
+var debug = require('debug')('manager:server');
+var http = require('http');
+
+/**
+ * Get port from environment and store in Express.
+ */
+
+var port = normalizePort(process.env.PORT || '2000');
+app.set('port', port);
+
+/**
+ * Create HTTP server.
+ */
+
+var server = http.createServer(app);
+
+/**
+ * Listen on provided port, on all network interfaces.
+ */
+
+server.listen(port);
+server.on('error', onError);
+server.on('listening', onListening);
+
+/**
+ * Normalize a port into a number, string, or false.
+ */
+
+function normalizePort(val) {
+ var port = parseInt(val, 10);
+
+ if (isNaN(port)) {
+ // named pipe
+ return val;
+ }
+
+ if (port >= 0) {
+ // port number
+ return port;
+ }
+
+ return false;
+}
+
+/**
+ * Event listener for HTTP server "error" event.
+ */
+
+function onError(error) {
+ if (error.syscall !== 'listen') {
+ throw error;
+ }
+
+ var bind = typeof port === 'string'
+ ? 'Pipe ' + port
+ : 'Port ' + port;
+
+ // handle specific listen errors with friendly messages
+ switch (error.code) {
+ case 'EACCES':
+ console.error(bind + ' requires elevated privileges');
+ process.exit(1);
+ break;
+ case 'EADDRINUSE':
+ console.error(bind + ' is already in use');
+ process.exit(1);
+ break;
+ default:
+ throw error;
+ }
+}
+
+/**
+ * Event listener for HTTP server "listening" event.
+ */
+
+function onListening() {
+ var addr = server.address();
+ var bind = typeof addr === 'string'
+ ? 'pipe ' + addr
+ : 'port ' + addr.port;
+ debug('Listening on ' + bind);
+}
diff --git a/lxc.js b/lxc.js
new file mode 100644
index 0000000..73098a5
--- /dev/null
+++ b/lxc.js
@@ -0,0 +1,125 @@
+module.exports = function(config){
+
+ var obj = {};
+ var child = require('child'),
+ sshBind = config.sshBind || false;
+
+ //http://stackoverflow.com/questions/10530532/
+ function textToArgs(s){
+ var words = [];
+ s.replace(/"([^"]*)"|'([^']*)'|(\S+)/g,function(g0,g1,g2,g3){ words.push(g1 || g2 || g3 || '')});
+ return words;
+ }
+
+ var sysExec = function(command, onData, onClose){
+
+ onData = onData || function(){};
+ onClose = onClose || function(){};
+
+ if (sshBind != false)
+ {
+ var runCommand = sshBind.slice();
+ runCommand.push(command);
+ } else {
+ var runCommand = textToArgs(command);
+ }
+
+ var errors = '';
+
+ child({
+ command: runCommand.slice(0,1)[0],
+ args: runCommand.slice(1),
+ cbStdout: function(data){ onData(''+data) },
+ cbStderr: function(data){ errors+=data; onData(''+data) },
+ cbClose: function(exitCode){ onClose(exitCode == 0 ? null:exitCode, errors) }
+ }).start();
+ };
+
+
+ obj.create = function(name, template, config, cbComplete, cbData){
+ sysExec('lxc-create -n '+name+' -t '+template, cbComplete, cbData);
+ };
+
+ obj.clone = function(name, base_name, cbComplete, cbData){
+ sysExec('lxc-clone -o '+base_name+ ' -n '+name +' -B overlayfs -s', cbComplete, cbData);
+ };
+
+ obj.destroy = function(name, cbComplete, cbData){
+ sysExec('lxc-destroy -n '+ name, cbComplete, cbData);
+ };
+
+
+ obj.start = function(name, cbComplete, cbData){
+ var cmd = 'lxc-start --name '+name+' --daemon';
+ console.log('start cmd\n', cmd, '\n');
+ sysExec(cmd, cbComplete, cbData);
+ };
+
+ obj.startEphemeral = function(name, base_name, cbComplete, cbData){
+
+ var output = '';
+ sysExec('lxc-start-ephemeral -o '+base_name+ ' -n '+name +' --union-type overlayfs -d', function(data){output+=data}, function(error){
+ if(output.match("doesn't exist.")) return cbData({status: 500, error: "doesn't exist."});
+ if(output.match("already exists.")) return cbData({status: 500, error: "already exists"});
+ if(output.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)) return cbData({status: 200, state:'RUNNING', ip: output.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)[0]});
+ cbData({'?': '?', data: output, name: name, base_name: base_name});
+ });
+ };
+
+ obj.stop = function(name, cbComplete, cbData){
+ sysExec('lxc-stop -n '+ name, cbComplete, cbData);
+ };
+
+
+ obj.freeze = function(name, cbComplete, cbData){
+ sysExec('lxc-freeze -n '+name, cbComplete, cbData);
+ };
+
+ obj.unfreeze = function(name, cbComplete, cbData){
+ sysExec('lxc-unfreeze -n '+name, cbComplete, cbData);
+ };
+
+ obj.info = function(name, cbComplete, cbData){
+
+ var output = '';
+ sysExec('lxc-info -n'+name, function(data){output+=data}, function(error){
+ if(output.match("doesn't exist")) return cbData({state: 'NULL'});
+ var info = {};
+ output = output.replace(/\suse/ig, '').replace(/\sbytes/ig, '').split("\n").slice(0,-1);
+ for(var i in output){
+ var temp = output[i].split(/\:\s+/);
+ info[temp[0].toLowerCase().trim()] = temp[1].trim();
+ }
+ cbData(info);
+ });
+ };
+
+ obj.list = function(cbData){
+
+ var output = '';
+ sysExec('lxc-ls --fancy', function(data){output+=data}, function(error){
+
+ output = output.split("\n");
+ var keys = output.splice(0,1)[0].split(/\s+/).slice(0,-1);
+ keys = keys.map(function(v){return v.toLowerCase()});
+ output = output.slice(0).splice(1).slice(0,-1);
+
+ var info = [];
+
+ for (var i in output)
+ {
+
+ var aIn = output[i].split(/\s+/).slice(0,-1),
+ mapOut = {};
+ aIn.map( function(v,i){ mapOut[keys[i]] = v; } );
+ info.push(mapOut);
+
+ }
+
+ cbData(info);
+ });
+ };
+
+
+ return obj;
+};
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..dde6f7f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "manager",
+ "version": "0.0.0",
+ "private": true,
+ "scripts": {
+ "start": "node ./bin/www"
+ },
+ "dependencies": {
+ "body-parser": "~1.13.2",
+ "cookie-parser": "~1.3.5",
+ "debug": "~2.2.0",
+ "ejs": "~2.3.3",
+ "express": "~4.13.1",
+ "morgan": "~1.6.1",
+ "serve-favicon": "~2.3.0"
+ }
+}
\ No newline at end of file
diff --git a/public/images/gears.gif b/public/images/gears.gif
new file mode 100644
index 0000000..6c51c2f
Binary files /dev/null and b/public/images/gears.gif differ
diff --git a/public/images/load.gif b/public/images/load.gif
new file mode 100644
index 0000000..ab67ac0
--- /dev/null
+++ b/public/images/load.gif
@@ -0,0 +1,24 @@
+
loading.io - Your SVG + GIF Ajax Loading Icons
Build Your Ajax Loading
Icons with SVG / CSS / GIF !Recording Generating {{build.percent}}%
Examples SVG Loader You can use SVG loader just like using an image. For example, with <img> tag:
or as background image:
CSS Loader CSS loader has two parts: stylesheet and HTML part . Stylesheet is embraced in <style> tag so you can copy the file content into the place you want the icon to show.
To increase reusability, you can separate stylesheet from html part into a standalone css file. For example:
<link rel="stylesheet" type="text/css" href="examples/battery.css">
+<div class='uil-battery-demo-css' style='-webkit-transform:scale(0.6)'>
+ <outer></outer>
+ <inner></inner>
+ <inner></inner>
+ <inner></inner>
+ <inner></inner>
+</div>
will look like this:
GIF Loader Use GIF loader in an <img> tag or as background of another element:
<img src="spinner.gif">
+<div style="background:url(spinner.gif) no-repeat center center;width:32px;height:32px;"></div>
+For example:
Browser Compatibility tl;dr
+Use GIF loader if you need compatibility in Internet Explorer.
SVG Loader ( not for IE ) All SVG loaders use SMIL to animate elements. Modern browsers support SVG and SMIL except Internet Explorer:
SVG: IE ≥ 9.0 SMIL: IE doesn't Support CSS Loader ( IE ≥ 10.0 ) All CSS loaders use CSS3 Animation to animate elements. Modern browsers support CSS3 except Internet Explorer:
CSS3 Animation: IE ≥ 10.0 CSS3 Transform: IE ≥ 10.0 (partially)
+GIF Loader ( cross-platform ) All modern browsers support GIF loader. Use GIF loader to ensure optimized browser compatibility.
This Tool This tool is tested against following browsers:
Google Chrome 34.0. Firefox 28.0 Safari 7.03 Opera 18.0. Internet Explorer 11.0 It's built upon bootstrap , angularjs , canvg , gif.js and web workers . It's known that some browsers ( e.g., IE10 ) are not supported, so please upgrade your browser if you want to use this tool.
Here is the requested {{mode}}
Comments
\ No newline at end of file
diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css
new file mode 100644
index 0000000..9453385
--- /dev/null
+++ b/public/stylesheets/style.css
@@ -0,0 +1,8 @@
+body {
+ padding: 50px;
+ font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
+}
+
+a {
+ color: #00B7FF;
+}
diff --git a/routes/index.js b/routes/index.js
new file mode 100644
index 0000000..1c75508
--- /dev/null
+++ b/routes/index.js
@@ -0,0 +1,81 @@
+var express = require('express');
+var router = express.Router();
+var extend = require('node.extend');
+var redis = require("redis");
+var client = redis.createClient();
+var lxc = require('../lxc')({sshBind: ['/usr/bin/ssh', 'virt@127.0.0.1']});
+//lxc.startEphemeral('ubuntu_template', 'ue0', function(){console.log('cb1', arguments)}, function(){console.log('cb2', arguments)})
+
+router.get('/start/:name', function(req, res, next){
+ lxc.start(req.params.name, null, function(status, message){
+ if(status){
+ res.json({status: 500, name: req.params.name, message: message});
+ }else{
+ setTimeout(function() {
+ lxc.info(req.params.name, null, function(data){
+ var domain = req.query.domain || 'vm42.us';
+ domain = req.params.name+'.'+domain;
+ client.SADD("hosts", domain, function(){});
+
+ var ip = data.ip + ':5000';
+ client.HSET(domain, "ip", ip, redis.print);
+ client.HSET(domain, "updated", (new Date).getTime(), redis.print);
+ client.hset(domain, "include", "proxy.include");
+ res.json({status: 200, info: data});
+ });
+ }, 5000);
+
+ }
+ });
+});
+
+router.get('/live/:template/:name', function(req, res, next){
+ lxc.startEphemeral(req.params.name, req.params.template, null, function (data) {
+ res.json(data);
+ });
+});
+
+router.get('/stop/:name', function(req, res, next){
+ lxc.stop(req.params.name, null, function(data, message){
+ if(data){
+ res.json({status: 500, name: req.params.name, message: message});
+ }else{
+ res.json({status: 200});
+ }
+ });
+});
+
+router.get('/clone/:template/:name', function(req, res, next){
+ lxc.clone(req.params.name, req.params.template, function(message){
+ if( message.match(/Created container/) ){
+ res.json({status: 200});
+ }else{
+ res.json({status: 500, message: message});
+ }
+ });
+});
+
+router.get('/destroy/:name', function(req, res, next){
+ lxc.destroy(req.params.name, null, function(data, message){
+ if(data){
+ res.json({status: 500, message: message});
+ }else{
+ res.json({status: 200});
+ }
+ });
+});
+
+router.get('/info/:name', function(req, res, next){
+ lxc.info(req.params.name, null, function(data){
+ res.json(data);
+ });
+});
+
+router.get('/list', function(req, res, next) {
+ lxc.list(function(data){
+ res.json(data);
+ });
+});
+
+module.exports = router;
+// {"changed":true,"filter":false,"title":"index.js","tooltip":"/routes/index.js","value":"var express = require('express');\nvar router = express.Router();\nvar extend = require('node.extend');\nvar redis = require(\"redis\");\nvar client = redis.createClient();\nvar lxc = require('../lxc')({sshBind: ['/usr/bin/ssh', 'virt@127.0.0.1']});\n//lxc.startEphemeral('ubuntu_template', 'ue0', function(){console.log('cb1', arguments)}, function(){console.log('cb2', arguments)})\n\nrouter.get('/start/:name', function(req, res, next){\n lxc.start(req.params.name, null, function(status, message){\n if(status){\n res.json({status: 500, name: req.params.name, message: message});\n }else{\n setTimeout(function() {\n lxc.info(req.params.name, null, function(data){\n var domain = req.query.domain || 'vm42.us';\n domain = req.params.name+'.'+domain;\n client.SADD(\"hosts\", domain, function(){});\n \n var ip = data.ip + ':5000';\n client.HSET(domain, \"ip\", ip, redis.print);\n client.HSET(domain, \"updated\", (new Date).getTime(), redis.print);\n client.hset(domain, \"include\", \"proxy.include\");\n res.json({status: 200, info: data});\n });\n }, 5000);\n\n }\n });\n});\n\nrouter.get('/live/:template/:name', function(req, res, next){\n lxc.startEphemeral(req.params.name, req.params.template, null, function (data) {\n res.json(data);\n });\n});\n\nrouter.get('/stop/:name', function(req, res, next){\n lxc.stop(req.params.name, null, function(data, message){\n if(data){\n res.json({status: 500, name: req.params.name, message: message});\n }else{\n res.json({status: 200});\n }\n });\n});\n\nrouter.get('/clone/:template/:name', function(req, res, next){\n lxc.clone(req.params.name, req.params.template, function(message){\n if( message.match(/Created container/) ){\n res.json({status: 200});\n }else{\n res.json({status: 500, message: message});\n }\n });\n});\n\nrouter.get('/destroy/:name', function(req, res, next){\n lxc.destroy(req.params.name, null, function(data, message){\n if(data){\n res.json({status: 500, message: message});\n }else{\n res.json({status: 200});\n }\n });\n});\n\nrouter.get('/info/:name', function(req, res, next){\n lxc.info(req.params.name, null, function(data){\n res.json(data);\n });\n});\n\nrouter.get('/list', function(req, res, next) {\n lxc.list(function(data){\n res.json(data); \n });\n});\n\nmodule.exports = router;","undoManager":{"mark":90,"position":100,"stack":[[{"start":{"row":32,"column":27},"end":{"row":32,"column":30},"action":"remove","lines":["par"],"id":37},{"start":{"row":32,"column":27},"end":{"row":32,"column":33},"action":"insert","lines":["params"]}],[{"start":{"row":32,"column":33},"end":{"row":32,"column":34},"action":"insert","lines":["."],"id":38}],[{"start":{"row":32,"column":34},"end":{"row":32,"column":35},"action":"insert","lines":["n"],"id":39}],[{"start":{"row":32,"column":35},"end":{"row":32,"column":36},"action":"insert","lines":["a"],"id":40}],[{"start":{"row":32,"column":36},"end":{"row":32,"column":37},"action":"insert","lines":["m"],"id":41}],[{"start":{"row":32,"column":37},"end":{"row":32,"column":38},"action":"insert","lines":["e"],"id":42}],[{"start":{"row":32,"column":38},"end":{"row":32,"column":39},"action":"insert","lines":[","],"id":43}],[{"start":{"row":32,"column":39},"end":{"row":32,"column":40},"action":"insert","lines":[" "],"id":44}],[{"start":{"row":32,"column":40},"end":{"row":32,"column":41},"action":"insert","lines":["p"],"id":45}],[{"start":{"row":32,"column":41},"end":{"row":32,"column":42},"action":"insert","lines":["a"],"id":46}],[{"start":{"row":32,"column":42},"end":{"row":32,"column":43},"action":"insert","lines":["q"],"id":47}],[{"start":{"row":32,"column":42},"end":{"row":32,"column":43},"action":"remove","lines":["q"],"id":48}],[{"start":{"row":32,"column":41},"end":{"row":32,"column":42},"action":"remove","lines":["a"],"id":49}],[{"start":{"row":32,"column":40},"end":{"row":32,"column":41},"action":"remove","lines":["p"],"id":50}],[{"start":{"row":32,"column":40},"end":{"row":32,"column":41},"action":"insert","lines":["r"],"id":51}],[{"start":{"row":32,"column":41},"end":{"row":32,"column":42},"action":"insert","lines":["e"],"id":52}],[{"start":{"row":32,"column":42},"end":{"row":32,"column":43},"action":"insert","lines":["q"],"id":53}],[{"start":{"row":32,"column":43},"end":{"row":32,"column":44},"action":"insert","lines":[","],"id":54}],[{"start":{"row":32,"column":43},"end":{"row":32,"column":44},"action":"remove","lines":[","],"id":55}],[{"start":{"row":32,"column":43},"end":{"row":32,"column":44},"action":"insert","lines":["."],"id":56}],[{"start":{"row":32,"column":44},"end":{"row":32,"column":45},"action":"insert","lines":["p"],"id":57}],[{"start":{"row":32,"column":44},"end":{"row":32,"column":45},"action":"remove","lines":["p"],"id":58},{"start":{"row":32,"column":44},"end":{"row":32,"column":50},"action":"insert","lines":["params"]}],[{"start":{"row":32,"column":50},"end":{"row":32,"column":51},"action":"insert","lines":[","],"id":59}],[{"start":{"row":32,"column":50},"end":{"row":32,"column":51},"action":"remove","lines":[","],"id":60}],[{"start":{"row":32,"column":50},"end":{"row":32,"column":51},"action":"insert","lines":["."],"id":61}],[{"start":{"row":32,"column":51},"end":{"row":32,"column":52},"action":"insert","lines":["t"],"id":62}],[{"start":{"row":32,"column":52},"end":{"row":32,"column":53},"action":"insert","lines":["e"],"id":63}],[{"start":{"row":32,"column":51},"end":{"row":32,"column":53},"action":"remove","lines":["te"],"id":64},{"start":{"row":32,"column":51},"end":{"row":32,"column":59},"action":"insert","lines":["template"]}],[{"start":{"row":32,"column":59},"end":{"row":32,"column":60},"action":"insert","lines":[","],"id":65}],[{"start":{"row":32,"column":60},"end":{"row":32,"column":61},"action":"insert","lines":[" "],"id":66}],[{"start":{"row":32,"column":61},"end":{"row":32,"column":62},"action":"insert","lines":["n"],"id":67}],[{"start":{"row":32,"column":62},"end":{"row":32,"column":63},"action":"insert","lines":["u"],"id":68}],[{"start":{"row":32,"column":63},"end":{"row":32,"column":64},"action":"insert","lines":["k"],"id":69}],[{"start":{"row":32,"column":64},"end":{"row":32,"column":65},"action":"insert","lines":["k"],"id":70}],[{"start":{"row":32,"column":64},"end":{"row":32,"column":65},"action":"remove","lines":["k"],"id":71}],[{"start":{"row":32,"column":63},"end":{"row":32,"column":64},"action":"remove","lines":["k"],"id":72}],[{"start":{"row":32,"column":63},"end":{"row":32,"column":64},"action":"insert","lines":["l"],"id":73}],[{"start":{"row":32,"column":64},"end":{"row":32,"column":65},"action":"insert","lines":["l"],"id":74}],[{"start":{"row":32,"column":65},"end":{"row":32,"column":66},"action":"insert","lines":["m"],"id":75}],[{"start":{"row":32,"column":65},"end":{"row":32,"column":66},"action":"remove","lines":["m"],"id":76}],[{"start":{"row":32,"column":64},"end":{"row":32,"column":65},"action":"remove","lines":["l"],"id":77}],[{"start":{"row":32,"column":63},"end":{"row":32,"column":64},"action":"remove","lines":["l"],"id":78}],[{"start":{"row":32,"column":62},"end":{"row":32,"column":63},"action":"remove","lines":["u"],"id":79}],[{"start":{"row":32,"column":61},"end":{"row":32,"column":62},"action":"remove","lines":["n"],"id":80}],[{"start":{"row":32,"column":60},"end":{"row":32,"column":61},"action":"remove","lines":[" "],"id":81}],[{"start":{"row":32,"column":60},"end":{"row":32,"column":61},"action":"insert","lines":[" "],"id":82}],[{"start":{"row":32,"column":61},"end":{"row":32,"column":62},"action":"insert","lines":["n"],"id":83}],[{"start":{"row":32,"column":62},"end":{"row":32,"column":63},"action":"insert","lines":["u"],"id":84}],[{"start":{"row":32,"column":63},"end":{"row":32,"column":64},"action":"insert","lines":["l"],"id":85}],[{"start":{"row":32,"column":64},"end":{"row":32,"column":65},"action":"insert","lines":["l"],"id":86}],[{"start":{"row":32,"column":65},"end":{"row":32,"column":66},"action":"insert","lines":[","],"id":87}],[{"start":{"row":32,"column":66},"end":{"row":32,"column":67},"action":"insert","lines":[" "],"id":88}],[{"start":{"row":32,"column":67},"end":{"row":32,"column":68},"action":"insert","lines":["f"],"id":89}],[{"start":{"row":32,"column":68},"end":{"row":32,"column":69},"action":"insert","lines":["i"],"id":90}],[{"start":{"row":32,"column":68},"end":{"row":32,"column":69},"action":"remove","lines":["i"],"id":91}],[{"start":{"row":32,"column":68},"end":{"row":32,"column":69},"action":"insert","lines":["u"],"id":92}],[{"start":{"row":32,"column":69},"end":{"row":32,"column":70},"action":"insert","lines":["n"],"id":93}],[{"start":{"row":32,"column":67},"end":{"row":32,"column":70},"action":"remove","lines":["fun"],"id":94},{"start":{"row":32,"column":67},"end":{"row":34,"column":5},"action":"insert","lines":["function function_name(argument) {"," // body..."," }"]}],[{"start":{"row":32,"column":76},"end":{"row":32,"column":89},"action":"remove","lines":["function_name"],"id":95}],[{"start":{"row":32,"column":77},"end":{"row":32,"column":85},"action":"remove","lines":["argument"],"id":96},{"start":{"row":32,"column":77},"end":{"row":32,"column":78},"action":"insert","lines":["d"]}],[{"start":{"row":32,"column":78},"end":{"row":32,"column":79},"action":"insert","lines":["a"],"id":97}],[{"start":{"row":32,"column":79},"end":{"row":32,"column":80},"action":"insert","lines":["t"],"id":98}],[{"start":{"row":32,"column":80},"end":{"row":32,"column":81},"action":"insert","lines":["a"],"id":99}],[{"start":{"row":33,"column":9},"end":{"row":33,"column":18},"action":"remove","lines":["/ body..."],"id":100}],[{"start":{"row":33,"column":8},"end":{"row":33,"column":9},"action":"remove","lines":["/"],"id":101}],[{"start":{"row":33,"column":8},"end":{"row":33,"column":9},"action":"insert","lines":["r"],"id":102}],[{"start":{"row":33,"column":9},"end":{"row":33,"column":10},"action":"insert","lines":["e"],"id":103}],[{"start":{"row":33,"column":9},"end":{"row":33,"column":10},"action":"remove","lines":["e"],"id":104}],[{"start":{"row":33,"column":9},"end":{"row":33,"column":10},"action":"insert","lines":["s"],"id":105}],[{"start":{"row":33,"column":9},"end":{"row":33,"column":10},"action":"remove","lines":["s"],"id":106}],[{"start":{"row":33,"column":8},"end":{"row":33,"column":9},"action":"remove","lines":["r"],"id":107}],[{"start":{"row":33,"column":8},"end":{"row":33,"column":9},"action":"insert","lines":["r"],"id":108}],[{"start":{"row":33,"column":9},"end":{"row":33,"column":10},"action":"insert","lines":["e"],"id":109}],[{"start":{"row":33,"column":10},"end":{"row":33,"column":11},"action":"insert","lines":["s"],"id":110}],[{"start":{"row":33,"column":11},"end":{"row":33,"column":12},"action":"insert","lines":["."],"id":111}],[{"start":{"row":33,"column":12},"end":{"row":33,"column":13},"action":"insert","lines":["j"],"id":112}],[{"start":{"row":33,"column":13},"end":{"row":33,"column":14},"action":"insert","lines":["s"],"id":113}],[{"start":{"row":33,"column":12},"end":{"row":33,"column":14},"action":"remove","lines":["js"],"id":114},{"start":{"row":33,"column":12},"end":{"row":33,"column":16},"action":"insert","lines":["json"]}],[{"start":{"row":33,"column":16},"end":{"row":33,"column":18},"action":"insert","lines":["()"],"id":115}],[{"start":{"row":33,"column":17},"end":{"row":33,"column":18},"action":"insert","lines":["d"],"id":116}],[{"start":{"row":33,"column":18},"end":{"row":33,"column":19},"action":"insert","lines":["a"],"id":117}],[{"start":{"row":33,"column":19},"end":{"row":33,"column":20},"action":"insert","lines":["t"],"id":118}],[{"start":{"row":33,"column":20},"end":{"row":33,"column":21},"action":"insert","lines":["a"],"id":119}],[{"start":{"row":33,"column":22},"end":{"row":33,"column":23},"action":"insert","lines":["l"],"id":120}],[{"start":{"row":33,"column":22},"end":{"row":33,"column":23},"action":"remove","lines":["l"],"id":121}],[{"start":{"row":33,"column":22},"end":{"row":33,"column":23},"action":"insert","lines":[";"],"id":122}],[{"start":{"row":34,"column":6},"end":{"row":34,"column":7},"action":"insert","lines":[";"],"id":123}],[{"start":{"row":52,"column":53},"end":{"row":52,"column":54},"action":"insert","lines":[";"],"id":124}],[{"start":{"row":62,"column":35},"end":{"row":62,"column":36},"action":"insert","lines":[";"],"id":125}],[{"start":{"row":22,"column":67},"end":{"row":22,"column":68},"action":"insert","lines":[";"],"id":126}],[{"start":{"row":5,"column":19},"end":{"row":5,"column":20},"action":"insert","lines":["."],"id":127}],[{"start":{"row":23,"column":0},"end":{"row":23,"column":4},"action":"remove","lines":[" "],"id":128}],[{"start":{"row":23,"column":0},"end":{"row":23,"column":4},"action":"remove","lines":[" "],"id":129}],[{"start":{"row":23,"column":0},"end":{"row":23,"column":4},"action":"remove","lines":[" "],"id":130}],[{"start":{"row":23,"column":0},"end":{"row":23,"column":4},"action":"remove","lines":[" "],"id":131}],[{"start":{"row":23,"column":0},"end":{"row":23,"column":3},"action":"remove","lines":[" "],"id":132}],[{"start":{"row":23,"column":0},"end":{"row":23,"column":4},"action":"insert","lines":[" "],"id":133}],[{"start":{"row":23,"column":4},"end":{"row":23,"column":8},"action":"insert","lines":[" "],"id":134}],[{"start":{"row":23,"column":8},"end":{"row":23,"column":12},"action":"insert","lines":[" "],"id":135}],[{"start":{"row":23,"column":12},"end":{"row":23,"column":16},"action":"insert","lines":[" "],"id":136}],[{"start":{"row":23,"column":16},"end":{"row":23,"column":20},"action":"insert","lines":[" "],"id":137}]]},"ace":{"folds":[],"scrolltop":0,"scrollleft":0,"selection":{"start":{"row":23,"column":20},"end":{"row":23,"column":20},"isBackwards":false},"options":{"guessTabSize":true,"useWrapMode":false,"wrapToView":true},"firstLineState":{"row":92,"mode":"ace/mode/javascript"}},"timestamp":1448259407910}
\ No newline at end of file
diff --git a/routes/users.js b/routes/users.js
new file mode 100644
index 0000000..d30f494
--- /dev/null
+++ b/routes/users.js
@@ -0,0 +1,9 @@
+var express = require('express');
+var router = express.Router();
+
+/* GET users listing. */
+router.get('/', function(req, res, next) {
+ res.render('index')
+});
+
+module.exports = router;
diff --git a/stuff.md b/stuff.md
new file mode 100644
index 0000000..92a1987
--- /dev/null
+++ b/stuff.md
@@ -0,0 +1,5 @@
+## Auto start
+`@reboot /usr/local/bin/forever start -o /var/log/forver.out.log -e /var/log/sorver.err.log -c "/usr/local/bin/codebox run -p 5000" /workspace/`
+http://stackoverflow.com/a/13388741/3140931
+
+
diff --git a/views/error.ejs b/views/error.ejs
new file mode 100644
index 0000000..7cf94ed
--- /dev/null
+++ b/views/error.ejs
@@ -0,0 +1,3 @@
+<%= message %>
+<%= error.status %>
+<%= error.stack %>
diff --git a/views/index.ejs b/views/index.ejs
new file mode 100644
index 0000000..2ff58d5
--- /dev/null
+++ b/views/index.ejs
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Start will take atlest 5 seconds!
+
+
+
+ {{ name }} | {{ state }} | {{ ip }}
+
+
+ Stop
+ Start
+ Destroy
+
+ {{{ url }}}
+ {{{ clone }}}
+ {{{ message }}}
+
+
+
+
+