Initial commit for OpenECOMP SDN-C OA&M

Change-Id: I7ab579fd0d206bf356f36d52dcdf4f71f1fa2680
Signed-off-by: Timoney, Daniel (dt5972) <dtimoney@att.com>

Former-commit-id: 2a9f0edd09581f907e62ec4689b5ac94dd5382ba
diff --git a/dgbuilder/red/cli/lib/config.js b/dgbuilder/red/cli/lib/config.js
new file mode 100644
index 0000000..3cd5244
--- /dev/null
+++ b/dgbuilder/red/cli/lib/config.js
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var path = require("path");
+var fs = require("fs");
+
+var userHome = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
+
+var configDir = path.join(userHome,".nodered");
+var configFile = path.join(configDir,"config.json");
+
+var config;
+
+function load() {
+    if (config == null) {
+        try {
+            config = JSON.parse(fs.readFileSync(configFile));
+        } catch(err) {
+            config = {};
+        }
+    }
+}
+
+function save() {
+    try {
+        fs.mkdirSync(configDir);
+    } catch(err) {
+        if (err.code != "EEXIST") {
+            throw err;
+        }
+    }
+    fs.writeFileSync(configFile,JSON.stringify(config,null,4));
+}
+module.exports = {
+    unload: function() {
+        config = null;
+    }
+};
+module.exports.__defineGetter__('target',function() { load(); return config.target|| "http://localhost:1880" });
+module.exports.__defineSetter__('target',function(v) { load(); config.target = v; save();});
diff --git a/dgbuilder/red/cli/lib/request.js b/dgbuilder/red/cli/lib/request.js
new file mode 100644
index 0000000..fbbe3dc
--- /dev/null
+++ b/dgbuilder/red/cli/lib/request.js
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+ 
+var when = require("when");
+var request = require("request");
+var config = require("./config");
+
+module.exports = function(path, options) {
+    var basePath = config.target;
+    return when.promise(function(resolve,reject) {
+        options.headers = options.headers||{};
+        options.headers['Accept'] = 'application/json';
+        if (options.method == 'PUT' || options.method == "POST") {
+            options.headers['content-type'] = 'application/json';
+        }
+        options.url = basePath+path;
+        
+        // Pull out the request function so we can stub it in the tests
+        var requestFunc = request.get;
+        
+        if (options.method == 'PUT') {
+            requestFunc = request.put;
+        } else if (options.method == 'POST') {
+            requestFunc = request.post;
+        } else if (options.method == 'DELETE') {
+            requestFunc = request.del;
+        }
+        requestFunc(options, function(error,response,body) {
+            if (!error && response.statusCode == 200) {
+                resolve(JSON.parse(body));
+            } else if (error) {
+                reject(error.toString());
+            } else {
+                reject(response.statusCode+": "+body)
+            }
+        });
+    });
+}
diff --git a/dgbuilder/red/cli/nr-cli.js b/dgbuilder/red/cli/nr-cli.js
new file mode 100755
index 0000000..6d62f05
--- /dev/null
+++ b/dgbuilder/red/cli/nr-cli.js
@@ -0,0 +1,151 @@
+#!/usr/bin/env node
+;(function() {
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+ 
+var util = require("util");
+var request = require("request");
+var colors = require('colors');
+var apiRequest = require("./lib/request");
+var config = require("./lib/config");
+
+var commands = {
+    "target": function() {
+        var target = process.argv[3];
+        if (target) {
+            if (!/^https?:\/\/.+/.test(target)) {
+                console.warn("Invalid target url");
+                return;
+            }
+            if (target.slice(-1) == "/") {
+                target = target.slice(0,target.length-1);
+            }
+            var oldTarget = config.target;
+            config.target = target;
+        } else {
+            console.log("Target: ".yellow+config.target);
+        }
+        
+    },
+    "nodes": function() {
+        apiRequest('/nodes',{}).then(logNodeList).otherwise(logFailure);
+    },
+    "node": function() {
+        apiRequest('/nodes/'+process.argv[3],{}).then(logNodeList).otherwise(logFailure);
+    },
+    "enable-node": function() {
+        apiRequest('/nodes/'+process.argv[3],{
+            method: "PUT",
+            body: JSON.stringify({enabled:true})
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "disable-node": function() {
+        apiRequest('/nodes/'+process.argv[3],{
+            method: "PUT",
+            body: JSON.stringify({enabled:false})
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "install": function() {
+        apiRequest('/nodes',{
+            method: "POST",
+            body: JSON.stringify({module:process.argv[3]})
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "remove": function() {
+        apiRequest('/nodes/'+process.argv[3],{
+            method: "DELETE"
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "search": function() {
+        var options = {
+            method: "GET",
+            url: 'https://registry.npmjs.org/-/_view/byKeyword?startkey=["node-red"]&amp;endkey=["node-red",{}]&amp;group_level=3' ,
+            headers: {
+                'Accept': 'application/json',
+            }
+        };
+        request(options, function (error, response, body) {
+            if (!error && response.statusCode == 200) {
+                var info = (JSON.parse(body)).rows;
+                var filter = null;
+                if (process.argv[3]) {
+                    filter = new RegExp(process.argv[3]);
+                }
+                for (var i=0;i<info.length;i++) {
+                    var n = info[i];
+                    if (!filter || filter.test(n.key[1]) || filter.test(n.key[2])) {
+                        console.log(n.key[1] + (" - "+ n.key[2]).grey);
+                    }
+                }
+            } else if (error) {
+                console.log(error.toString().red);
+            } else {
+                console.log((response.statusCode+": "+body).red);
+            }
+        });   
+    }
+}
+
+function logNodeList(nodes) {
+    if (!util.isArray(nodes)) {
+        nodes = [nodes];
+    }
+    for (var i=0;i<nodes.length;i++) {
+        var n = nodes[i];
+        console.log(formatNodeInfo(n))
+    }
+}
+
+function logFailure(msg) {
+    console.log(msg.red);
+}
+
+function formatBoolean(v,c) {
+    if (v) {
+        return ("["+c+"]");
+    } else {
+        return ("[ ]");
+    }
+}
+
+function formatNodeInfo(n) {
+    var inError = n.hasOwnProperty("err");
+    
+    var str = formatBoolean(n.enabled,"X")+formatBoolean(n.loaded,"L")+" ";
+    str += n.id;
+    if (n.enabled && n.loaded) {
+        str = str.green;
+    } else if (n.enabled && n.err) {
+        str = str.red;
+    } else {
+        str = str.yellow;
+    }
+    if (n.module) {
+        str += " ["+n.module+"]";
+    }
+    str += " "+n.types.join(", ");
+    if (n.err) {
+        str+=" "+n.err.red;
+    }
+    return str;
+}
+
+if (commands[process.argv[2]]) {
+    commands[process.argv[2]].call();
+}
+
+
+})();
diff --git a/dgbuilder/red/comms.js b/dgbuilder/red/comms.js
new file mode 100644
index 0000000..5828c99
--- /dev/null
+++ b/dgbuilder/red/comms.js
@@ -0,0 +1,132 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var ws = require("ws");
+var util = require("util");
+
+var server;
+var settings;
+
+var wsServer;
+var activeConnections = [];
+
+var retained = {};
+
+var heartbeatTimer;
+var lastSentTime;
+
+
+function init(_server,_settings) {
+    server = _server;
+    settings = _settings;
+}
+
+function start() {
+
+    if (!settings.disableEditor) {
+        var webSocketKeepAliveTime = settings.webSocketKeepAliveTime || 15000;
+        var path = settings.httpAdminRoot || "/";
+        path = path + (path.slice(-1) == "/" ? "":"/") + "comms";
+        wsServer = new ws.Server({server:server,path:path});
+        
+        wsServer.on('connection',function(ws) {
+            activeConnections.push(ws);
+            ws.on('close',function() {
+                for (var i=0;i<activeConnections.length;i++) {
+                    if (activeConnections[i] === ws) {
+                        activeConnections.splice(i,1);
+                        break;
+                    }
+                }
+            });
+            ws.on('message', function(data,flags) {
+                var msg = null;
+                try {
+                    msg = JSON.parse(data);
+                } catch(err) {
+                    util.log("[red:comms] received malformed message : "+err.toString());
+                    return;
+                }
+                if (msg.subscribe) {
+                    handleRemoteSubscription(ws,msg.subscribe);
+                }
+            });
+            ws.on('error', function(err) {
+                util.log("[red:comms] error : "+err.toString());
+            });
+        });
+        
+        wsServer.on('error', function(err) {
+            util.log("[red:comms] server error : "+err.toString());
+        });
+         
+        lastSentTime = Date.now();
+        
+        heartbeatTimer = setInterval(function() {
+            var now = Date.now();
+            if (now-lastSentTime > webSocketKeepAliveTime) {
+                publish("hb",lastSentTime);
+            }
+        }, webSocketKeepAliveTime);
+    }
+}
+
+function stop() {
+    if (heartbeatTimer) {
+        clearInterval(heartbeatTimer);
+    }
+    if (wsServer) {
+        wsServer.close();
+    }
+}
+
+function publish(topic,data,retain) {
+    if (retain) {
+        retained[topic] = data;
+    } else {
+        delete retained[topic];
+    }
+    lastSentTime = Date.now();
+    activeConnections.forEach(function(conn) {
+        publishTo(conn,topic,data);
+    });
+}
+
+function publishTo(ws,topic,data) {
+    var msg = JSON.stringify({topic:topic,data:data});
+    try {
+        ws.send(msg);
+    } catch(err) {
+        util.log("[red:comms] send error : "+err.toString());
+    }
+}
+
+function handleRemoteSubscription(ws,topic) {
+    var re = new RegExp("^"+topic.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
+    for (var t in retained) {
+        if (re.test(t)) {
+            publishTo(ws,t,retained[t]);
+        }
+    }
+}
+
+
+module.exports = {
+    init:init,
+    start:start,
+    stop:stop,
+    publish:publish,
+}
diff --git a/dgbuilder/red/events.js b/dgbuilder/red/events.js
new file mode 100644
index 0000000..8959049
--- /dev/null
+++ b/dgbuilder/red/events.js
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var events = require("events"); 
+
+module.exports = new events.EventEmitter(); 
diff --git a/dgbuilder/red/library.js b/dgbuilder/red/library.js
new file mode 100644
index 0000000..cc4199f
--- /dev/null
+++ b/dgbuilder/red/library.js
@@ -0,0 +1,117 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+
+var redApp = null;
+var storage = null;
+
+function init() {
+    redApp = require("./server").app;
+    storage = require("./storage");
+    
+    // -------- Flow Library --------
+    redApp.post(new RegExp("/library/flows\/(.*)"), function(req,res) {
+            var fullBody = '';
+            req.on('data', function(chunk) {
+                fullBody += chunk.toString();
+            });
+            req.on('end', function() {
+                storage.saveFlow(req.params[0],fullBody).then(function() {
+                    res.send(204);
+                }).otherwise(function(err) {
+                    util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
+                    if (err.message.indexOf('forbidden') === 0) {
+                        res.send(403);
+                        return;
+                    }
+                    res.send(500);
+                });
+            });
+    });
+    
+    redApp.get("/library/flows",function(req,res) {
+            storage.getAllFlows().then(function(flows) {
+                res.json(flows);
+            });
+    });
+    
+    redApp.get(new RegExp("/library/flows\/(.*)"), function(req,res) {
+            storage.getFlow(req.params[0]).then(function(data) {
+                res.set('Content-Type', 'application/json');
+                res.send(data);
+            }).otherwise(function(err) {
+                if (err) {
+                    util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
+                    if (err.message.indexOf('forbidden') === 0) {
+                        res.send(403);
+                        return;
+                    }
+                }
+                res.send(404);
+            });
+    });
+    
+    // ------------------------------
+}    
+
+function createLibrary(type) {
+    
+    redApp.get(new RegExp("/library/"+type+"($|\/(.*))"),function(req,res) {
+            var path = req.params[1]||"";
+            storage.getLibraryEntry(type,path).then(function(result) {
+                if (typeof result === "string") {
+                    res.writeHead(200, {'Content-Type': 'text/plain'});
+                    res.write(result);
+                    res.end(); 
+                } else {
+                    res.json(result);
+                }
+            }).otherwise(function(err) {
+                if (err) {
+                    util.log("[red] Error loading library entry '"+path+"' : "+err);
+                    if (err.message.indexOf('forbidden') === 0) {
+                        res.send(403);
+                        return;
+                    }
+                }
+                res.send(404);
+            });
+    });
+    
+    redApp.post(new RegExp("/library/"+type+"\/(.*)"),function(req,res) {
+            var path = req.params[0];
+            var fullBody = '';
+            req.on('data', function(chunk) {
+                    fullBody += chunk.toString();
+            });
+            req.on('end', function() {
+                    storage.saveLibraryEntry(type,path,req.query,fullBody).then(function() {
+                        res.send(204);
+                    }).otherwise(function(err) {
+                        util.log("[red] Error saving library entry '"+path+"' : "+err);
+                        if (err.message.indexOf('forbidden') === 0) {
+                            res.send(403);
+                            return;
+                        }
+                        res.send(500);
+                    });
+            });
+    });
+}
+
+module.exports.init = init;
+module.exports.register = createLibrary;
diff --git a/dgbuilder/red/log.js b/dgbuilder/red/log.js
new file mode 100644
index 0000000..236e6df
--- /dev/null
+++ b/dgbuilder/red/log.js
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var EventEmitter = require("events").EventEmitter;
+
+var logHandlers = [];
+
+var ConsoleLogHandler = new EventEmitter();
+ConsoleLogHandler.on("log",function(msg) {
+        util.log("["+msg.level+"] ["+msg.type+":"+(msg.name||msg.id)+"] "+msg.msg);
+});
+
+var log = module.exports = {
+    addHandler: function(func) {
+        logHandlers.push(func);
+    },
+    
+    log: function(msg) {
+        logHandlers.forEach(function(handler) {
+            handler.emit("log",msg);
+        });
+    }
+}
+
+log.addHandler(ConsoleLogHandler);
diff --git a/dgbuilder/red/nodes/Node.js b/dgbuilder/red/nodes/Node.js
new file mode 100644
index 0000000..0e6fc52
--- /dev/null
+++ b/dgbuilder/red/nodes/Node.js
@@ -0,0 +1,147 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var EventEmitter = require("events").EventEmitter;
+var clone = require("clone");
+var when = require("when");
+
+var flows = require("./flows");
+var comms = require("../comms");
+
+function Node(n) {
+    this.id = n.id;
+    flows.add(this);
+    this.type = n.type;
+    if (n.name) {
+        this.name = n.name;
+    }
+    this.wires = n.wires||[];
+}
+
+util.inherits(Node,EventEmitter);
+
+Node.prototype._on = Node.prototype.on;
+
+Node.prototype.on = function(event,callback) {
+    var node = this;
+    if (event == "close") {
+        if (callback.length == 1) {
+            this.close = function() {
+                return when.promise(function(resolve) {
+                    callback.call(node,function() {
+                        resolve();
+                    });
+                });
+            }
+        } else {
+            this.close = callback;
+        }
+    } else {
+        this._on(event,callback);
+    }
+}
+
+Node.prototype.close = function() {
+}
+
+Node.prototype.send = function(msg) {
+    // instanceof doesn't work for some reason here
+    if (msg == null) {
+        return;
+    } else if (!util.isArray(msg)) {
+        msg = [msg];
+    }
+    for (var i=0;i<this.wires.length;i++) {
+        var wires = this.wires[i];
+        if (i < msg.length) {
+            if (msg[i] != null) {
+                var msgs = msg[i];
+                if (!util.isArray(msg[i])) {
+                    msgs = [msg[i]];
+                }
+                //if (wires.length == 1) {
+                //    // Single recipient, don't need to clone the message
+                //    var node = flows.get(wires[0]);
+                //    if (node) {
+                //        for (var k in msgs) {
+                //            var mm = msgs[k];
+                //            node.receive(mm);
+                //        }
+                //    }
+                //} else {
+                    // Multiple recipients, must send message copies
+                    for (var j=0;j<wires.length;j++) {
+                        var node = flows.get(wires[j]);
+                        if (node) {
+                            for (var k=0;k<msgs.length;k++) {
+                                var mm = msgs[k];
+                                // Temporary fix for #97
+                                // TODO: remove this http-node-specific fix somehow
+                                var req = mm.req;
+                                var res = mm.res;
+                                delete mm.req;
+                                delete mm.res;
+                                var m = clone(mm);
+                                if (req) {
+                                    m.req = req;
+                                    mm.req = req;
+                                }
+                                if (res) {
+                                    m.res = res;
+                                    mm.res = res;
+                                }
+                                node.receive(m);
+                            }
+                        }
+                    }
+                //}
+            }
+        }
+    }
+}
+
+Node.prototype.receive = function(msg) {
+    this.emit("input",msg);
+}
+
+function log_helper(self, level, msg) {
+    var o = {level:level, id:self.id, type:self.type, msg:msg};
+    if (self.name) {
+        o.name = self.name;
+    }
+    self.emit("log",o);
+}
+
+Node.prototype.log = function(msg) {
+    log_helper(this, 'log', msg);
+}
+
+Node.prototype.warn = function(msg) {
+    log_helper(this, 'warn', msg);
+}
+
+Node.prototype.error = function(msg) {
+    log_helper(this, 'error', msg);
+}
+
+/**
+ * status: { fill:"red|green", shape:"dot|ring", text:"blah" }
+ */
+Node.prototype.status = function(status) {
+    comms.publish("status/"+this.id,status,true);
+}
+module.exports = Node;
diff --git a/dgbuilder/red/nodes/credentials.js b/dgbuilder/red/nodes/credentials.js
new file mode 100644
index 0000000..22e78d8
--- /dev/null
+++ b/dgbuilder/red/nodes/credentials.js
@@ -0,0 +1,208 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var when = require("when");
+
+var credentialCache = {};
+var storage = null;
+var credentialsDef = {};
+var redApp = null;
+
+/**
+ * Adds an HTTP endpoint to allow look up of credentials for a given node id.
+ */
+function registerEndpoint(type) {
+    redApp.get('/credentials/' + type + '/:id', function (req, res) {
+        // TODO: This could be a generic endpoint with the type value
+        //       parameterised.
+        //
+        // TODO: It should verify the given node id is of the type specified -
+        //       but that would add a dependency from this module to the
+        //       registry module that knows about node types.
+        var nodeType = type;
+        var nodeID = req.params.id;
+
+        var credentials = credentialCache[nodeID];
+        if (credentials === undefined) {
+            res.json({});
+            return;
+        }
+        var definition = credentialsDef[nodeType];
+
+        var sendCredentials = {};
+        for (var cred in definition) {
+            if (definition.hasOwnProperty(cred)) {
+                if (definition[cred].type == "password") {
+                    var key = 'has_' + cred;
+                    sendCredentials[key] = credentials[cred] != null && credentials[cred] !== '';
+                    continue;
+                }
+                sendCredentials[cred] = credentials[cred] || '';
+            }
+        }
+        res.json(sendCredentials);
+
+    });
+}
+
+
+module.exports = {
+    init: function (_storage) {
+        storage = _storage;
+        // TODO: this should get passed in init function call rather than
+        //       required directly.
+        redApp = require("../server").app;
+    },
+    
+    /**
+     * Loads the credentials from storage.
+     */
+    load: function () {
+        return storage.getCredentials().then(function (creds) {
+            credentialCache = creds;
+        }).otherwise(function (err) {
+            util.log("[red] Error loading credentials : " + err);
+        });
+    },
+    
+    /**
+     * Adds a set of credentials for the given node id.
+     * @param id the node id for the credentials
+     * @param creds an object of credential key/value pairs
+     * @return a promise for the saving of credentials to storage
+     */
+    add: function (id, creds) {
+        credentialCache[id] = creds;
+        return storage.saveCredentials(credentialCache);
+    },
+
+    /**
+     * Gets the credentials for the given node id.
+     * @param id the node id for the credentials
+     * @return the credentials
+     */
+    get: function (id) {
+        return credentialCache[id];
+    },
+
+    /**
+     * Deletes the credentials for the given node id.
+     * @param id the node id for the credentials
+     * @return a promise for the saving of credentials to storage
+     */
+    delete: function (id) {
+        delete credentialCache[id];
+        storage.saveCredentials(credentialCache);
+    },
+
+    /**
+     * Deletes any credentials for nodes that no longer exist
+     * @param getNode a function that can return a node for a given id
+     * @return a promise for the saving of credentials to storage
+     */
+    clean: function (getNode) {
+        var deletedCredentials = false;
+        for (var c in credentialCache) {
+            if (credentialCache.hasOwnProperty(c)) {
+                var n = getNode(c);
+                if (!n) {
+                    deletedCredentials = true;
+                    delete credentialCache[c];
+                }
+            }
+        }
+        if (deletedCredentials) {
+            return storage.saveCredentials(credentialCache);
+        } else {
+            return when.resolve();
+        }
+    },
+    
+    /**
+     * Registers a node credential definition.
+     * @param type the node type
+     * @param definition the credential definition
+     */
+    register: function (type, definition) {
+        var dashedType = type.replace(/\s+/g, '-');
+        credentialsDef[dashedType] = definition;
+        registerEndpoint(dashedType);
+    },
+    
+    /**
+     * Extracts and stores any credential updates in the provided node.
+     * The provided node may have a .credentials property that contains
+     * new credentials for the node.
+     * This function loops through the credentials in the definition for
+     * the node-type and applies any of the updates provided in the node.
+     * 
+     * This function does not save the credentials to disk as it is expected
+     * to be called multiple times when a new flow is deployed.
+     *
+     * @param node the node to extract credentials from
+     */
+    extract: function(node) {
+        var nodeID = node.id;
+        var nodeType = node.type;
+        var newCreds = node.credentials;
+        if (newCreds) {
+            var savedCredentials = credentialCache[nodeID] || {};
+            
+            var dashedType = nodeType.replace(/\s+/g, '-');
+            var definition = credentialsDef[dashedType];
+            
+            if (!definition) {
+                util.log('Credential Type ' + nodeType + ' is not registered.');
+                return;
+            }
+            
+            for (var cred in definition) {
+                if (definition.hasOwnProperty(cred)) {
+                    if (newCreds[cred] === undefined) {
+                        continue;
+                    }
+                    if (definition[cred].type == "password" && newCreds[cred] == '__PWRD__') {
+                        continue;
+                    }
+                    if (0 === newCreds[cred].length || /^\s*$/.test(newCreds[cred])) {
+                        delete savedCredentials[cred];
+                        continue;
+                    }
+                    savedCredentials[cred] = newCreds[cred];
+                }
+            }
+            credentialCache[nodeID] = savedCredentials;
+        }
+    },
+    
+    /**
+     * Saves the credentials to storage
+     * @return a promise for the saving of credentials to storage
+     */
+    save: function () {
+        return storage.saveCredentials(credentialCache);
+    },
+    
+    /**
+     * Gets the credential definition for the given node type
+     * @param type the node type
+     * @return the credential definition
+     */
+    getDefinition: function (type) {
+        return credentialsDef[type];
+    }
+}
diff --git a/dgbuilder/red/nodes/flows.js b/dgbuilder/red/nodes/flows.js
new file mode 100644
index 0000000..b0b5d51
--- /dev/null
+++ b/dgbuilder/red/nodes/flows.js
@@ -0,0 +1,220 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var when = require("when");
+
+var typeRegistry = require("./registry");
+var credentials = require("./credentials");
+var log = require("../log");
+var events = require("../events");
+
+var storage = null;
+
+var nodes = {};
+var activeConfig = [];
+var missingTypes = [];
+
+events.on('type-registered',function(type) {
+        if (missingTypes.length > 0) {
+            var i = missingTypes.indexOf(type);
+            if (i != -1) {
+                missingTypes.splice(i,1);
+                util.log("[red] Missing type registered: "+type);
+                if (missingTypes.length === 0) {
+                    parseConfig();
+                }
+            }
+        }
+});
+
+/**
+ * Parses the current activeConfig and creates the required node instances
+ */ 
+function parseConfig() {
+    var i;
+    var nt;
+    missingTypes = [];
+    
+    // Scan the configuration for any unknown node types
+    for (i=0;i<activeConfig.length;i++) {
+        var type = activeConfig[i].type;
+        // TODO: remove workspace in next release+1
+        if (type != "workspace" && type != "tab") {
+            nt = typeRegistry.get(type);
+            if (!nt && missingTypes.indexOf(type) == -1) {
+                missingTypes.push(type);
+            }
+        }
+    }
+    // Abort if there are any missing types
+    if (missingTypes.length > 0) {
+        util.log("[red] Waiting for missing types to be registered:");
+        for (i=0;i<missingTypes.length;i++) {
+            util.log("[red]  - "+missingTypes[i]);
+        }
+        return;
+    }
+
+    util.log("[red] Starting flows");
+    events.emit("nodes-starting");
+    
+    // Instantiate each node in the flow
+    for (i=0;i<activeConfig.length;i++) {
+        var nn = null;
+        // TODO: remove workspace in next release+1
+        if (activeConfig[i].type != "workspace" && activeConfig[i].type != "tab") {
+            nt = typeRegistry.get(activeConfig[i].type);
+            if (nt) {
+                try {
+                    nn = new nt(activeConfig[i]);
+                }
+                catch (err) {
+                    util.log("[red] "+activeConfig[i].type+" : "+err);
+                }
+            }
+            // console.log(nn);
+            if (nn === null) {
+                util.log("[red] unknown type: "+activeConfig[i].type);
+            }
+        }
+    }
+    // Clean up any orphaned credentials
+    credentials.clean(flowNodes.get);
+    events.emit("nodes-started");
+}
+
+/**
+ * Stops the current activeConfig
+ */
+function stopFlows() {
+    if (activeConfig&&activeConfig.length > 0) {
+        util.log("[red] Stopping flows");
+    }
+    return flowNodes.clear();
+}
+
+var flowNodes = module.exports = {
+    init: function(_storage) {
+        storage = _storage;
+    },
+    
+    /**
+     * Load the current activeConfig from storage and start it running
+     * @return a promise for the loading of the config
+     */
+    load: function() {
+        return storage.getFlows().then(function(flows) {
+            return credentials.load().then(function() {
+                activeConfig = flows;
+                if (activeConfig && activeConfig.length > 0) {
+                    parseConfig();
+                }
+            });
+        }).otherwise(function(err) {
+            util.log("[red] Error loading flows : "+err);
+        });
+    },
+    
+    /**
+     * Add a node to the current active set
+     * @param n the node to add
+     */
+    add: function(n) {
+        nodes[n.id] = n;
+        n.on("log",log.log);
+    },
+    
+    /**
+     * Get a node
+     * @param i the node id
+     * @return the node
+     */
+    get: function(i) {
+        return nodes[i];
+    },
+    
+    /**
+     * Stops all active nodes and clears the active set
+     * @return a promise for the stopping of all active nodes
+     */
+    clear: function() {
+        return when.promise(function(resolve) {
+            events.emit("nodes-stopping");
+            var promises = [];
+            for (var n in nodes) {
+                if (nodes.hasOwnProperty(n)) {
+                    try {
+                        var p = nodes[n].close();
+                        if (p) {
+                            promises.push(p);
+                        }
+                    } catch(err) {
+                        nodes[n].error(err);
+                    }
+                }
+            }
+            when.settle(promises).then(function() {
+                events.emit("nodes-stopped");
+                nodes = {};
+                resolve();
+            });
+        });
+    },
+    
+    /**
+     * Provides an iterator over the active set of nodes
+     * @param cb a function to be called for each node in the active set
+     */
+    each: function(cb) {
+        for (var n in nodes) {
+            if (nodes.hasOwnProperty(n)) {
+                cb(nodes[n]);
+            }
+        }
+    },
+
+    /**
+     * @return the active configuration
+     */
+    getFlows: function() {
+        return activeConfig;
+    },
+    
+    /**
+     * Sets the current active config.
+     * @param config the configuration to enable
+     * @return a promise for the starting of the new flow
+     */
+    setFlows: function (config) {
+        // Extract any credential updates
+        for (var i=0; i<config.length; i++) {
+            var node = config[i];
+            if (node.credentials) {
+                credentials.extract(node);
+                delete node.credentials;
+            }
+        }
+        return credentials.save()
+            .then(function() { return storage.saveFlows(config);})
+            .then(function() { return stopFlows();})
+            .then(function () {
+                activeConfig = config;
+                parseConfig();
+            });
+    },
+    stopFlows: stopFlows
+};
diff --git a/dgbuilder/red/nodes/index.js b/dgbuilder/red/nodes/index.js
new file mode 100644
index 0000000..3d5ad71
--- /dev/null
+++ b/dgbuilder/red/nodes/index.js
@@ -0,0 +1,134 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var registry = require("./registry");
+var credentials = require("./credentials");
+var flows = require("./flows");
+var Node = require("./Node");
+
+/**
+ * Registers a node constructor
+ * @param type - the string type name
+ * @param constructor - the constructor function for this node type
+ * @param opts - optional additional options for the node
+ */
+function registerType(type,constructor,opts) {
+    if (opts && opts.credentials) {
+        credentials.register(type,opts.credentials);
+    }
+    registry.registerType(type,constructor);    
+}
+
+/**
+ * Called from a Node's constructor function, invokes the super-class
+ * constructor and attaches any credentials to the node.
+ * @param node the node object being created
+ * @param def the instance definition for the node 
+ */
+function createNode(node,def) {
+    Node.call(node,def);
+    var creds = credentials.get(node.id);
+    if (creds) {
+        node.credentials = creds;
+    }
+}
+
+function init(_settings,storage) {
+    credentials.init(storage);
+    flows.init(storage);
+    registry.init(_settings);
+}
+
+function checkTypeInUse(id) {
+    var nodeInfo = registry.getNodeInfo(id);
+    if (!nodeInfo) {
+        throw new Error("Unrecognised id: "+info);
+    }
+    var inUse = {};
+    flows.each(function(n) {
+        inUse[n.type] = (inUse[n.type]||0)+1;
+    });
+    var nodesInUse = [];
+    nodeInfo.types.forEach(function(t) {
+        if (inUse[t]) {
+            nodesInUse.push(t);
+        }
+    });
+    if (nodesInUse.length > 0) {
+        var msg = nodesInUse.join(", ");
+        throw new Error("Type in use: "+msg);
+    }
+}
+
+function removeNode(id) {
+    checkTypeInUse(id);
+    return registry.removeNode(id);
+}
+
+function removeModule(module) {
+    var info = registry.getNodeModuleInfo(module);
+    for (var i=0;i<info.nodes.length;i++) {
+        checkTypeInUse(info.nodes[i]);
+    }
+    return registry.removeModule(module);
+}
+
+
+function disableNode(id) {
+    checkTypeInUse(id);
+    return registry.disableNode(id);
+}
+
+module.exports = {
+    // Lifecycle
+    init: init,
+    load: registry.load,
+    
+    // Node registry
+    createNode: createNode,
+    getNode: flows.get,
+    
+    addNode: registry.addNode,
+    removeNode: removeNode,
+    
+    addModule: registry.addModule,
+    removeModule: removeModule,
+    
+    enableNode: registry.enableNode,
+    disableNode: disableNode,
+    
+    // Node type registry
+    registerType: registerType,
+    getType: registry.get,
+    getNodeInfo: registry.getNodeInfo,
+    getNodeModuleInfo: registry.getNodeModuleInfo,
+    getNodeList: registry.getNodeList,
+    getNodeConfigs: registry.getNodeConfigs,
+    getNodeConfig: registry.getNodeConfig,
+    clearRegistry: registry.clear,
+    cleanNodeList: registry.cleanNodeList,
+    
+    // Flow handling
+    loadFlows: flows.load,
+    stopFlows: flows.stopFlows,
+    setFlows: flows.setFlows,
+    getFlows: flows.getFlows,
+    
+    // Credentials
+    addCredentials: credentials.add,
+    getCredentials: credentials.get,
+    deleteCredentials: credentials.delete
+}
+
diff --git a/dgbuilder/red/nodes/registry.js b/dgbuilder/red/nodes/registry.js
new file mode 100644
index 0000000..f2073af
--- /dev/null
+++ b/dgbuilder/red/nodes/registry.js
@@ -0,0 +1,693 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+ 
+var util = require("util");
+var when = require("when");
+var whenNode = require('when/node');
+var fs = require("fs");
+var path = require("path");
+var crypto = require("crypto"); 
+var UglifyJS = require("uglify-js");
+
+var events = require("../events");
+
+var Node;
+var settings;
+
+function filterNodeInfo(n) {
+    var r = {
+        id: n.id,
+        name: n.name,
+        types: n.types,
+        enabled: n.enabled
+    }
+    if (n.hasOwnProperty("loaded")) {
+        r.loaded = n.loaded;
+    }
+    if (n.hasOwnProperty("module")) {
+        r.module = n.module;
+    }
+    if (n.hasOwnProperty("err")) {
+        r.err = n.err.toString();
+    }
+    return r;
+}
+
+var registry = (function() {
+    var nodeConfigCache = null;
+    var nodeConfigs = {};
+    var nodeList = [];
+    var nodeConstructors = {};
+    var nodeTypeToId = {};
+    var nodeModules = {};
+    
+    function saveNodeList() {
+        var nodeList = {};
+        
+        for (var i in nodeConfigs) {
+            if (nodeConfigs.hasOwnProperty(i)) {
+                var nodeConfig = nodeConfigs[i];
+                var n = filterNodeInfo(nodeConfig);
+                n.file = nodeConfig.file;
+                delete n.loaded;
+                delete n.err;
+                delete n.file;
+                delete n.id;
+                nodeList[i] = n;
+            }
+        }
+        if (settings.available()) {
+            return settings.set("nodes",nodeList);
+        } else {
+            return when.reject("Settings unavailable");
+        }
+    }
+    
+    return {
+        init: function() {
+            if (settings.available()) {
+                nodeConfigs = settings.get("nodes")||{};
+                // Restore the node id property to individual entries
+                for (var id in nodeConfigs) {
+                    if (nodeConfigs.hasOwnProperty(id)) {
+                        nodeConfigs[id].id = id;
+                    }
+                }
+            } else {
+                nodeConfigs = {};
+            }
+            nodeModules = {};
+            nodeTypeToId = {};
+            nodeConstructors = {};
+            nodeList = [];
+            nodeConfigCache = null;
+        },
+        
+        addNodeSet: function(id,set) {
+            if (!set.err) {
+                set.types.forEach(function(t) {
+                    nodeTypeToId[t] = id;
+                });
+            }
+            
+            if (set.module) {
+                nodeModules[set.module] = nodeModules[set.module]||{nodes:[]};
+                nodeModules[set.module].nodes.push(id);
+            }
+            
+            nodeConfigs[id] = set;
+            nodeList.push(id);
+            nodeConfigCache = null;
+        },
+        removeNode: function(id) {
+            var config = nodeConfigs[id];
+            if (!config) {
+                throw new Error("Unrecognised id: "+id);
+            }
+            delete nodeConfigs[id];
+            var i = nodeList.indexOf(id);
+            if (i > -1) {
+                nodeList.splice(i,1);
+            }
+            config.types.forEach(function(t) {
+                delete nodeConstructors[t];
+                delete nodeTypeToId[t];
+            });
+            config.enabled = false;
+            config.loaded = false;
+            nodeConfigCache = null;
+            return filterNodeInfo(config);
+        },
+        removeModule: function(module) {
+            if (!settings.available()) {
+                throw new Error("Settings unavailable");
+            }
+            var nodes = nodeModules[module];
+            if (!nodes) {
+                throw new Error("Unrecognised module: "+module);
+            }
+            var infoList = [];
+            for (var i=0;i<nodes.nodes.length;i++) {
+                infoList.push(registry.removeNode(nodes.nodes[i]));
+            }
+            delete nodeModules[module];
+            saveNodeList();
+            return infoList;
+        },
+        getNodeInfo: function(typeOrId) {
+            if (nodeTypeToId[typeOrId]) {
+                return filterNodeInfo(nodeConfigs[nodeTypeToId[typeOrId]]);
+            } else if (nodeConfigs[typeOrId]) {
+                return filterNodeInfo(nodeConfigs[typeOrId]);
+            }
+            return null;
+        },
+        getNodeList: function() {
+            var list = [];
+            for (var id in nodeConfigs) {
+                if (nodeConfigs.hasOwnProperty(id)) {
+                    list.push(filterNodeInfo(nodeConfigs[id]))
+                }
+            }
+            return list;
+        },
+        registerNodeConstructor: function(type,constructor) {
+            if (nodeConstructors[type]) {
+                throw new Error(type+" already registered");
+            }
+            //TODO: Ensure type is known - but doing so will break some tests
+            //      that don't have a way to register a node template ahead
+            //      of registering the constructor
+            util.inherits(constructor,Node);
+            nodeConstructors[type] = constructor;
+            events.emit("type-registered",type);
+        },
+        
+        
+        /**
+         * Gets all of the node template configs
+         * @return all of the node templates in a single string
+         */
+        getAllNodeConfigs: function() {
+            if (!nodeConfigCache) {
+                var result = "";
+                var script = "";
+                for (var i=0;i<nodeList.length;i++) {
+                    var config = nodeConfigs[nodeList[i]];
+                    if (config.enabled && !config.err) {
+                        result += config.config;
+                        script += config.script;
+                    }
+                }
+                if (script.length > 0) {
+                    result += '<script type="text/javascript">';
+                    result += UglifyJS.minify(script, {fromString: true}).code;
+                    result += '</script>';
+                }
+                nodeConfigCache = result;
+            }
+            return nodeConfigCache;
+        },
+        
+        getNodeConfig: function(id) {
+            var config = nodeConfigs[id];
+            if (config) {
+                var result = config.config;
+                if (config.script) {
+                    result += '<script type="text/javascript">'+config.script+'</script>';
+                }
+                return result;
+            } else {
+                return null;
+            }
+        },
+        
+        getNodeConstructor: function(type) {
+            var config = nodeConfigs[nodeTypeToId[type]];
+            if (!config || (config.enabled && !config.err)) {
+                return nodeConstructors[type];
+            }
+            return null;
+        },
+        
+        clear: function() {
+            nodeConfigCache = null;
+            nodeConfigs = {};
+            nodeList = [];
+            nodeConstructors = {};
+            nodeTypeToId = {};
+        },
+        
+        getTypeId: function(type) {
+            return nodeTypeToId[type];
+        },
+        
+        getModuleInfo: function(type) {
+            return nodeModules[type];
+        },
+        
+        enableNodeSet: function(id) {
+            if (!settings.available()) {
+                throw new Error("Settings unavailable");
+            }
+            var config = nodeConfigs[id];
+            if (config) {
+                delete config.err;
+                config.enabled = true;
+                if (!config.loaded) {
+                    // TODO: honour the promise this returns
+                    loadNodeModule(config);
+                }
+                nodeConfigCache = null;
+                saveNodeList();
+            } else {
+                throw new Error("Unrecognised id: "+id);
+            }
+            return filterNodeInfo(config);
+        },
+        
+        disableNodeSet: function(id) {
+            if (!settings.available()) {
+                throw new Error("Settings unavailable");
+            }
+            var config = nodeConfigs[id];
+            if (config) {
+                // TODO: persist setting
+                config.enabled = false;
+                nodeConfigCache = null;
+                saveNodeList();
+            } else {
+                throw new Error("Unrecognised id: "+id);
+            }
+            return filterNodeInfo(config);
+        },
+        
+        saveNodeList: saveNodeList,
+        
+        cleanNodeList: function() {
+            var removed = false;
+            for (var id in nodeConfigs) {
+                if (nodeConfigs.hasOwnProperty(id)) {
+                    if (nodeConfigs[id].module && !nodeModules[nodeConfigs[id].module]) {
+                        registry.removeNode(id);
+                        removed = true;
+                    }
+                }
+            }
+            if (removed) {
+                saveNodeList();
+            }
+        }
+    }
+})();
+
+
+
+function init(_settings) {
+    Node = require("./Node");
+    settings = _settings;
+    registry.init();
+}
+
+/**
+ * Synchronously walks the directory looking for node files.
+ * Emits 'node-icon-dir' events for an icon dirs found
+ * @param dir the directory to search
+ * @return an array of fully-qualified paths to .js files
+ */
+function getNodeFiles(dir) {
+    var result = [];
+    var files = [];
+    try {
+        files = fs.readdirSync(dir);
+    } catch(err) {
+        return result;
+    }
+    files.sort();
+    files.forEach(function(fn) {
+        var stats = fs.statSync(path.join(dir,fn));
+        if (stats.isFile()) {
+            if (/\.js$/.test(fn)) {
+                var valid = true;
+                if (settings.nodesExcludes) {
+                    for (var i=0;i<settings.nodesExcludes.length;i++) {
+                        if (settings.nodesExcludes[i] == fn) {
+                            valid = false;
+                            break;
+                        }
+                    }
+                }
+                valid = valid && fs.existsSync(path.join(dir,fn.replace(/\.js$/,".html")))
+                
+                if (valid) {
+                    result.push(path.join(dir,fn));
+                }
+            }
+        } else if (stats.isDirectory()) {
+            // Ignore /.dirs/, /lib/ /node_modules/ 
+            if (!/^(\..*|lib|icons|node_modules|test)$/.test(fn)) {
+                result = result.concat(getNodeFiles(path.join(dir,fn)));
+            } else if (fn === "icons") {
+                events.emit("node-icon-dir",path.join(dir,fn));
+            }
+        }
+    });
+    return result;
+}
+
+/**
+ * Scans the node_modules path for nodes
+ * @param moduleName the name of the module to be found
+ * @return a list of node modules: {dir,package}
+ */
+function scanTreeForNodesModules(moduleName) {
+    var dir = __dirname+"/../../nodes";
+    var results = [];
+    var up = path.resolve(path.join(dir,".."));
+    while (up !== dir) {
+        var pm = path.join(dir,"node_modules");
+        try {
+            var files = fs.readdirSync(pm);
+            for (var i=0;i<files.length;i++) {
+                var fn = files[i];
+                if (!registry.getModuleInfo(fn)) {
+                    if (!moduleName || fn == moduleName) {
+                        var pkgfn = path.join(pm,fn,"package.json");
+                        try {
+                            var pkg = require(pkgfn);
+                            if (pkg['node-red']) {
+                                var moduleDir = path.join(pm,fn);
+                                results.push({dir:moduleDir,package:pkg});
+                            }
+                        } catch(err) {
+                            if (err.code != "MODULE_NOT_FOUND") {
+                                // TODO: handle unexpected error
+                            }
+                        }
+                        if (fn == moduleName) {
+                            break;
+                        }
+                    }
+                }
+            }
+        } catch(err) {
+        }
+        
+        dir = up;
+        up = path.resolve(path.join(dir,".."));
+    }
+    return results;
+}
+
+/**
+ * Loads the nodes provided in an npm package.
+ * @param moduleDir the root directory of the package
+ * @param pkg the module's package.json object
+ */
+function loadNodesFromModule(moduleDir,pkg) {
+    var nodes = pkg['node-red'].nodes||{};
+    var results = [];
+    var iconDirs = [];
+    for (var n in nodes) {
+        if (nodes.hasOwnProperty(n)) {
+            var file = path.join(moduleDir,nodes[n]);
+            try {
+                results.push(loadNodeConfig(file,pkg.name,n));
+            } catch(err) {
+            }
+            var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons");
+            if (iconDirs.indexOf(iconDir) == -1) {
+                if (fs.existsSync(iconDir)) {
+                    events.emit("node-icon-dir",iconDir);
+                    iconDirs.push(iconDir);
+                }
+            }
+        }
+    }
+    return results;
+}
+
+
+/**
+ * Loads a node's configuration
+ * @param file the fully qualified path of the node's .js file
+ * @param name the name of the node
+ * @return the node object
+ *         {
+ *            id: a unqiue id for the node file
+ *            name: the name of the node file, or label from the npm module
+ *            file: the fully qualified path to the node's .js file
+ *            template: the fully qualified path to the node's .html file
+ *            config: the non-script parts of the node's .html file
+ *            script: the script part of the node's .html file
+ *            types: an array of node type names in this file
+ *         }
+ */
+function loadNodeConfig(file,module,name) {
+    var id = crypto.createHash('sha1').update(file).digest("hex");
+    if (module && name) {
+        var newid = crypto.createHash('sha1').update(module+":"+name).digest("hex");
+        var existingInfo = registry.getNodeInfo(id);
+        if (existingInfo) {
+            // For a brief period, id for modules were calculated incorrectly.
+            // To prevent false-duplicates, this removes the old id entry
+            registry.removeNode(id);
+            registry.saveNodeList();
+        }
+        id = newid;
+
+    }
+    var info = registry.getNodeInfo(id);
+    
+    var isEnabled = true;
+
+    if (info) {
+        if (info.hasOwnProperty("loaded")) {
+            throw new Error(file+" already loaded");
+        }
+        isEnabled = info.enabled;
+    }
+    
+    var node = {
+        id: id,
+        file: file,
+        template: file.replace(/\.js$/,".html"),
+        enabled: isEnabled,
+        loaded:false
+    }
+    
+    if (module) {
+        node.name = module+":"+name;
+        node.module = module;
+    } else {
+        node.name = path.basename(file)
+    }
+    try {
+        var content = fs.readFileSync(node.template,'utf8');
+        
+        var types = [];
+        
+        var regExp = /<script ([^>]*)data-template-name=['"]([^'"]*)['"]/gi;
+        var match = null;
+        
+        while((match = regExp.exec(content)) !== null) {
+            types.push(match[2]);
+        }
+        node.types = types;
+        node.config = content;
+        
+        // TODO: parse out the javascript portion of the template
+        node.script = "";
+        
+        for (var i=0;i<node.types.length;i++) {
+            if (registry.getTypeId(node.types[i])) {
+                node.err = node.types[i]+" already registered";
+                break;
+            }
+        }
+    } catch(err) {
+        node.types = [];
+        if (err.code === 'ENOENT') {
+            node.err = "Error: "+file+" does not exist";
+        } else {
+            node.err = err.toString();
+        }
+    }
+    registry.addNodeSet(id,node);
+    return node;
+}
+
+/**
+ * Loads all palette nodes
+ * @param defaultNodesDir optional parameter, when set, it overrides the default
+ *                        location of nodeFiles - used by the tests
+ * @return a promise that resolves on completion of loading
+ */
+function load(defaultNodesDir,disableNodePathScan) {
+    return when.promise(function(resolve,reject) {
+        // Find all of the nodes to load
+        var nodeFiles;
+        if(defaultNodesDir) {
+            nodeFiles = getNodeFiles(path.resolve(defaultNodesDir));
+        } else {
+            nodeFiles = getNodeFiles(__dirname+"/../../nodes");
+        }
+        
+        if (settings.nodesDir) {
+            var dir = settings.nodesDir;
+            if (typeof settings.nodesDir == "string") {
+                dir = [dir];
+            }
+            for (var i=0;i<dir.length;i++) {
+                nodeFiles = nodeFiles.concat(getNodeFiles(dir[i]));
+            }
+        }
+        var nodes = [];
+        nodeFiles.forEach(function(file) {
+            try {
+                nodes.push(loadNodeConfig(file));
+            } catch(err) {
+                // 
+            }
+        });
+        
+        // TODO: disabling npm module loading if defaultNodesDir set
+        //       This indicates a test is being run - don't want to pick up
+        //       unexpected nodes.
+        //       Urgh.
+        if (!disableNodePathScan) {
+            // Find all of the modules containing nodes
+            var moduleFiles = scanTreeForNodesModules();
+            moduleFiles.forEach(function(moduleFile) {
+                nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package));
+            });
+        }
+        var promises = [];
+        nodes.forEach(function(node) {
+            if (!node.err) {
+                promises.push(loadNodeModule(node));
+            }
+        });
+        
+        //resolve([]);
+        when.settle(promises).then(function(results) {
+            // Trigger a load of the configs to get it precached
+            registry.getAllNodeConfigs();
+            
+            if (settings.available()) {
+                resolve(registry.saveNodeList());
+            } else {
+                resolve();
+            }
+        }); 
+    });
+}
+
+/**
+ * Loads the specified node into the runtime
+ * @param node a node info object - see loadNodeConfig
+ * @return a promise that resolves to an update node info object. The object
+ *         has the following properties added:
+ *            err: any error encountered whilst loading the node
+ *            
+ */
+function loadNodeModule(node) {
+    var nodeDir = path.dirname(node.file);
+    var nodeFn = path.basename(node.file);
+    if (!node.enabled) {
+        return when.resolve(node);
+    }
+    try {
+        var loadPromise = null;
+        var r = require(node.file);
+        if (typeof r === "function") {
+            var promise = r(require('../red'));
+            if (promise != null && typeof promise.then === "function") {
+                loadPromise = promise.then(function() {
+                    node.enabled = true;
+                    node.loaded = true;
+                    return node;
+                }).otherwise(function(err) {
+                    node.err = err;
+                    return node;
+                });
+            }
+        }
+        if (loadPromise == null) {
+            node.enabled = true;
+            node.loaded = true;
+            loadPromise = when.resolve(node);
+        }
+        return loadPromise;
+    } catch(err) {
+        node.err = err;
+        return when.resolve(node);
+    }
+}
+
+function loadNodeList(nodes) {
+    var promises = [];
+    nodes.forEach(function(node) {
+        if (!node.err) {
+            promises.push(loadNodeModule(node));
+        } else {
+            promises.push(node);
+        }
+    });
+    
+    return when.settle(promises).then(function(results) {
+        return registry.saveNodeList().then(function() {
+            var list = results.map(function(r) {
+                return filterNodeInfo(r.value);
+            });
+            return list;
+        });
+    });
+}
+
+function addNode(file) {
+    if (!settings.available()) {
+        throw new Error("Settings unavailable");
+    }
+    var nodes = [];
+    try { 
+        nodes.push(loadNodeConfig(file));
+    } catch(err) {
+        return when.reject(err);
+    }
+    return loadNodeList(nodes);
+}
+
+function addModule(module) {
+    if (!settings.available()) {
+        throw new Error("Settings unavailable");
+    }
+    var nodes = [];
+    if (registry.getModuleInfo(module)) {
+        return when.reject(new Error("Module already loaded"));
+    }
+    var moduleFiles = scanTreeForNodesModules(module);
+    if (moduleFiles.length === 0) {
+        var err = new Error("Cannot find module '" + module + "'");
+        err.code = 'MODULE_NOT_FOUND';
+        return when.reject(err);
+    }
+    moduleFiles.forEach(function(moduleFile) {
+        nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package));
+    });
+    return loadNodeList(nodes);
+}
+
+module.exports = {
+    init:init,
+    load:load,
+    clear: registry.clear,
+    registerType: registry.registerNodeConstructor,
+    get: registry.getNodeConstructor,
+    getNodeInfo: registry.getNodeInfo,
+    getNodeModuleInfo: registry.getModuleInfo,
+    getNodeList: registry.getNodeList,
+    getNodeConfigs: registry.getAllNodeConfigs,
+    getNodeConfig: registry.getNodeConfig,
+    addNode: addNode,
+    removeNode: registry.removeNode,
+    enableNode: registry.enableNodeSet,
+    disableNode: registry.disableNodeSet,
+    
+    addModule: addModule,
+    removeModule: registry.removeModule,
+    cleanNodeList: registry.cleanNodeList
+}
diff --git a/dgbuilder/red/red.js b/dgbuilder/red/red.js
new file mode 100644
index 0000000..2735e0d
--- /dev/null
+++ b/dgbuilder/red/red.js
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var server = require("./server");
+var nodes = require("./nodes");
+var library = require("./library");
+var comms = require("./comms");
+var log = require("./log");
+var util = require("./util");
+var fs = require("fs");
+var settings = require("./settings");
+var credentials = require("./nodes/credentials");
+
+var path = require('path');
+
+process.env.NODE_RED_HOME = process.env.NODE_RED_HOME || path.resolve(__dirname+"/..");
+
+var events = require("events");
+
+var RED = {
+
+    init: function(httpServer,userSettings) {
+        userSettings.version = this.version();
+        settings.init(userSettings);
+        server.init(httpServer,settings);
+        library.init();
+        return server.app;
+    },
+    
+    start: server.start,
+    stop: server.stop,
+    nodes: nodes,
+    library: library,
+    credentials: credentials,
+    events: events,
+    log: log,
+    comms: comms,
+    settings:settings,
+    util: util,
+    version: function () {
+        var p = require(path.join(process.env.NODE_RED_HOME,"package.json"));
+        if (fs.existsSync(path.join(process.env.NODE_RED_HOME,".git"))) {
+            return p.version+".git";
+        } else {
+            return p.version;
+        }
+    }
+};
+
+RED.__defineGetter__("app", function() { console.log("Deprecated use of RED.app - use RED.httpAdmin instead"); return server.app });
+RED.__defineGetter__("httpAdmin", function() { return server.app });
+RED.__defineGetter__("httpNode", function() { return server.nodeApp });
+RED.__defineGetter__("server", function() { return server.server });
+
+module.exports = RED;
diff --git a/dgbuilder/red/server.js b/dgbuilder/red/server.js
new file mode 100644
index 0000000..01a769e
--- /dev/null
+++ b/dgbuilder/red/server.js
@@ -0,0 +1,1317 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var express = require('express');
+var util = require('util');
+var multer = require('multer');
+var when = require('when');
+var exec = require('child_process').exec;
+
+var createUI = require("./ui");
+var redNodes = require("./nodes");
+var comms = require("./comms");
+var storage = require("./storage");
+var fs=require('fs');
+var path = require("path");
+var app = null;
+var nodeApp = null;
+var server = null;
+var settings = null;
+
+var flowShareUsers = require("../flowShareUsers");
+	
+//console.dir(flowShareUsers);
+
+function createServer(_server,_settings) {
+    server = _server;
+    settings = _settings;
+
+    comms.init(_server,_settings);
+    
+    nodeApp = express();
+    app = express();
+        
+    if (settings.httpAdminRoot !== false) {
+        
+        
+        if (!settings.disableEditor) {
+            createUI(settings,app);
+        }
+        
+	var slaActions = require("./sla");
+
+        app.get("/flows",function(req,res) {
+            res.json(redNodes.getFlows());
+        });
+
+        app.get("/loadJSFiles",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var generatedJSDir=appDir + "/generatedJS";
+		var glob = require("glob")
+		glob(generatedJSDir + "/**/*.js", null, function (er, files) {
+			  // files is an array of filenames.
+			 // If the `nonull` option is set, and nothing
+  			// was found, then files is ["**/*.js"]
+  			// er is an error object or null.
+			//console.dir(files);
+			var sliValuesObj =[];
+			for(var i=0;files!= null && i<files.length;i++){
+				var f = files[i].replace( new RegExp(generatedJSDir + "/", "g" ), "" );
+				console.log("loading file " + f);
+				try{
+					sliValuesObj.push(require(files[i]));
+					//console.dir(sliValuesObj);
+				}catch(err){
+					console.log("Error:Could not load file " + files[i]);
+				}
+			}
+			res.json({"sliValuesObj" : sliValuesObj});
+        	});
+        });
+
+        app.get("/loadSelectedModules",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var generatedJSDir=appDir + "/generatedJS";
+		//console.dir(req);
+		var selectedModulesStr = req.query.selectedModules;
+		var selectedModules = [];
+		if(selectedModulesStr != undefined && selectedModulesStr != null){ 
+		 	selectedModules = selectedModulesStr.split(",");		
+		}
+		console.log(selectedModules);
+		var loaded_modules = {"selected_modules" :selectedModules};
+		var file = userDir + "/selected_modules";
+		var content = "module.exports=\n" + JSON.stringify(loaded_modules);
+		try{
+			fs.writeFileSync(file, content, 'utf8');
+		}catch(err){
+			console.log("could not write to file " + file);
+		}
+		var sliValuesObj =[];
+		for(var i=0;selectedModules!= null && i<selectedModules.length;i++){
+			var f = generatedJSDir + "/" + selectedModules[i] + "_inputs.js";
+			try{
+				delete require.cache[require.resolve(f)]
+				require.resolve();
+			}catch(err){
+				console.log("error deleting loaded module " + f + " from cache");
+			}
+			//console.log("loading file " + f);
+			try{
+				sliValuesObj.push(require(f));
+			}catch(err){
+				console.log("Error:Could not load file " + f);
+			}
+		}
+		//console.dir(sliValuesObj);
+		res.json({"sliValuesObj" : sliValuesObj});
+        });
+
+        app.get("/initialLoadSelectedModules",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var generatedJSDir=appDir + "/generatedJS";
+		var file = userDir + "/selected_modules";
+		var sliValuesObj =[];
+		var selected_modules = [];
+		var selectedModules;
+		try{
+			selectedModules = require(file);	
+			selected_modules=selectedModules["selected_modules"];
+			//console.log("selected_modules are ");
+			//console.dir(selected_modules);
+		}catch(err){
+			console.log("Could not load the file " + file);
+		}
+		for(var i=0;selected_modules!= null && i<selected_modules.length;i++){
+			var f = generatedJSDir + "/" + selected_modules[i] + "_inputs.js";
+			console.log("loading file " + f);
+			try{
+				sliValuesObj.push(require(f));
+			}catch(err){
+				console.log("Error:Could not load file " + f);
+			}
+		}
+		res.json({"sliValuesObj" : sliValuesObj});
+        });
+
+        app.get("/listAvailableModules",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var generatedJSDir=appDir + "/generatedJS";
+		var glob = require("glob")
+		var file = userDir + "/selected_modules";
+		var selected_modules = [];
+		var selectedModules;
+		try{
+			delete require.cache[require.resolve(file)]
+			require.resolve();
+		}catch(err){
+			console.log("error deleting loaded module " + file + " from cache");
+		}
+		try{
+			selectedModules = require(file);	
+			selected_modules=selectedModules["selected_modules"];
+			console.log("selected_modules are ");
+			//console.dir(selected_modules);
+		}catch(err){
+			console.log("Could not load the file " + file);
+		}
+		glob(generatedJSDir + "/**/*.js", null, function (er, files) {
+			var filesList =[];
+			for(var i=0;files!= null && i<files.length;i++){
+				var f = files[i].replace( new RegExp(generatedJSDir + "/", "g" ), "" );
+				f = f.replace("_inputs.js","");
+				if(selected_modules != undefined && selected_modules != null && selected_modules.indexOf(f) != -1){
+					filesList.push(f + ":checked");
+				}else{
+					filesList.push(f + ":unchecked");
+				}
+			}
+			res.json({"files" : filesList});
+		});
+        });
+
+        app.get("/listSLA",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var settingsFile = userDir + "/customSettings.js"; 
+		var jsonObj = require(settingsFile);
+                slaActions.listSLA(jsonObj,req,res);
+        });
+
+        app.get("/listCurrentDGs",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var settingsFile = userDir + "/customSettings.js"; 
+		var jsonObj = require(settingsFile);
+                slaActions.listCurrentDGs(jsonObj,req,res);
+        });
+
+        app.get("/activateDG",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var settingsFile = userDir + "/customSettings.js"; 
+		var jsonObj = require(settingsFile);
+            slaActions.activateDG(jsonObj,req,res);
+        });
+
+        app.get("/deActivateDG",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var settingsFile = userDir + "/customSettings.js"; 
+		var jsonObj = require(settingsFile);
+            slaActions.deActivateDG(jsonObj,req,res);
+        });
+
+        app.get("/deleteDG",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		var settingsFile = userDir + "/customSettings.js"; 
+		var jsonObj = require(settingsFile);
+            slaActions.deleteDG(jsonObj,req,res);
+        });
+
+        app.get("/getCurrentSettings",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		//console.log("userDir:" + userDir);
+		var settingsFile = userDir + "/customSettings.js"; 
+		var jsonObj = require(settingsFile);
+            	res.json(jsonObj);
+        });
+
+        app.get("/getCommitsInfo", function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		//console.dir(req);
+                var filePath = req.query.filePath;
+                var fullFilePath = userDir + "/codecloud/" + filePath ;
+		//console.log("fullFilePath:" + fullFilePath);	
+		var exec = require('child_process').exec;
+		var commandToExec = appDir + "/git_scripts/gitlog " + fullFilePath ;
+		console.log("commandToExec:" + commandToExec);
+        	var child = exec(commandToExec ,function (error,stdout,stderr){
+                if(error){
+			console.log("Error occured:" + error);
+			if(stderr){
+				//console.log("stderr:" + stderr);
+				res.send(500,{'error':error,'stderr':stderr});
+			}else{
+				res.send(500,{'error':error});
+			}
+			//console.log("stdout :" + stdout);
+                }else{
+			if(stderr){
+				console.log("stderr:" + stderr);
+			}
+			if(stdout){
+				//console.log("output:" + stdout);
+				res.send(200,{'stdout':stdout,'stderr':stderr});
+                	}
+		}
+		});
+	});
+
+        app.get("/importCodeCloudFlow",
+		 function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir = appDir + "/" + settings.userDir;
+		//console.dir(req);
+                var commitId = req.query.commitId;
+                var filePath = req.query.filePath;
+                var fullFilePath = userDir + "/codecloud/" + filePath ;
+		//console.log("fullFilePath:" + fullFilePath);	
+		var exec = require('child_process').exec;
+		var commandToExec = appDir + "/git_scripts/gitckout " + commitId + " " + fullFilePath ;
+		console.log("commandToExec:" + commandToExec);
+        	var child = exec(commandToExec ,{maxBuffer: 1024 * 1024 * 16}, function (error,stdout,stderr){
+                if(error){
+			console.log("Error occured:" + error);
+			if(stderr){
+				//console.log("stderr:" + stderr);
+				res.send(500,{'error':error,'stderr':stderr});
+			}else{
+				res.send(500,{'error':error});
+			}
+                }else{
+			if(stderr){
+				console.log("stderr:" + stderr);
+			}
+			if(stdout){
+				//console.log("output:" + stdout);
+				res.send(200,{'stdout':stdout,'stderr':stderr});
+                	}
+		}
+		});
+	});
+
+        app.get("/importGitLocalFlow",
+ 		function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var gitLocalRepository =  settings.gitLocalRepository;
+		//console.dir(req);
+                var filePath = req.query.filePath;
+                var fullFilePath = gitLocalRepository +"/" + filePath ;
+		//console.log("fullFilePath:" + fullFilePath);	
+		var exec = require('child_process').exec;
+		var commandToExec =  "cat " + fullFilePath ;
+		console.log("commandToExec:" + commandToExec);
+        	var child = exec(commandToExec ,{maxBuffer: 1024 * 1024 * 16}, function (error,stdout,stderr){
+                if(error){
+			console.log("Error occured:" + error);
+			if(stderr){
+				//console.log("stderr:" + stderr);
+				res.send(500,{'error':error,'stderr':stderr});
+			}else{
+				res.send(500,{'error':error});
+			}
+                }else{
+			if(stderr){
+				console.log("stderr:" + stderr);
+			}
+			if(stdout){
+				//console.log("output:" + stdout);
+				res.send(200,{'stdout':stdout,'stderr':stderr});
+                	}
+		}
+		});
+	});
+
+
+        app.get("/gitcheckout", function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var gitLocalRepository =  settings.gitLocalRepository;
+		//console.dir(req);
+                var branch = req.query.branch;
+		//console.log("fullFilePath:" + fullFilePath);	
+		var exec = require('child_process').exec;
+		var commandToExec = appDir + "/git_scripts/gitcheckout " + gitLocalRepository + " " + branch ;
+		console.log("commandToExec:" + commandToExec);
+        	var child = exec(commandToExec ,function (error,stdout,stderr){
+                		if(error){
+					console.log("Error occured:" + error);
+					if(stderr){
+						console.log("stderr:" + stderr);
+						res.json({"output":stderr});
+					}else{
+						res.json({"output":error});
+					}
+                		}else{
+					if(stderr){
+						console.log("stderr:" + stderr);
+					}
+					if(stdout){
+						res.json({"output": stderr + " " + stdout});
+					}
+				}
+			});
+	});
+
+        app.get("/gitpull", function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var gitLocalRepository =  settings.gitLocalRepository;
+		//console.dir(req);
+                var branch = req.query.branch;
+		//console.log("fullFilePath:" + fullFilePath);	
+		var exec = require('child_process').exec;
+		var commandToExec = appDir + "/git_scripts/gitpull " + gitLocalRepository ;
+		console.log("commandToExec:" + commandToExec);
+        	var child = exec(commandToExec ,function (error,stdout,stderr){
+                		if(error){
+					console.log("Error occured:" + error);
+					if(stderr){
+						console.log("stderr:" + stderr);
+						res.json({"output":stderr});
+					}else{
+						res.json({"output":error});
+					}
+                		}else{
+					if(stderr){
+						console.log("stderr:" + stderr);
+					}
+					if(stdout){
+						res.json({"output": stderr + " " + stdout});
+					}
+				}
+			});
+	});
+
+        app.get("/gitstatus", function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var gitLocalRepository =  settings.gitLocalRepository;
+		//console.dir(req);
+                var branch = req.query.branch;
+		//console.log("fullFilePath:" + fullFilePath);	
+		var exec = require('child_process').exec;
+		var commandToExec = appDir + "/git_scripts/gitstatus " + gitLocalRepository ;
+		console.log("commandToExec:" + commandToExec);
+        	var child = exec(commandToExec ,function (error,stdout,stderr){
+                		if(error){
+					console.log("Error occured:" + error);
+					if(stderr){
+						console.log("stderr:" + stderr);
+						res.json({"output":stderr});
+					}else{
+						res.json({"output":error});
+					}
+                		}else{
+					if(stderr){
+						console.log("stderr:" + stderr);
+					}
+					if(stdout){
+						res.json({"output": stderr + " " + stdout});
+					}
+				}
+			});
+	});
+	
+        app.post("/getSharedFlow",
+            express.json(),
+            function(req,res) {
+		var qs = require('querystring');
+		var body = '';
+        	req.on('data', function (data) {
+            		body += data;
+        	});
+        	req.on('end', function () {
+			var post = qs.parse(body);
+			//console.log("body:" + body);
+			fs.readFile(post.filePath, 'utf8', function (err,data) {
+  				if (err) {
+    					return console.log(err);
+  				}
+				res.json(data);
+  				//console.log(data);
+			});
+            	//res.sendFile(body.filePath);
+        	});
+        });
+        
+        app.post("/downloadYang",
+            express.json(),
+            function(req,res) {
+		var qs = require('querystring');
+		var body = '';
+        	req.on('data', function (data) {
+            		body += data;
+        	});
+        	req.on('end', function () {
+			var post = qs.parse(body);
+			var fileName = post.fileName;
+			var appDir = path.dirname(require.main.filename);
+			var yangDir = appDir + "/yangFiles" ;
+			var fullPathToFile = yangDir + "/" + fileName;
+			res.setHeader('Content-disposition', 'attachment; filename=' + fileName);
+			res.setHeader('Content-type', 'application/yang');
+			res.download(fullPathToFile);
+        	});
+        });
+
+	function writeToFile(fullPathToFileName,str){
+        	try{
+           		fs.writeFileSync(fullPathToFileName,str);
+        	}catch(e){
+                	console.log("Error:" + e);
+        	}
+    	}
+	function getCurrentDate(){
+        	var d = new Date();
+        	var mm = d.getMonth() + 1;
+        	var dd =   d.getDate();
+        	var yyyy = d.getYear() + 1900;
+        	var hr = d.getHours();
+        	var min = d.getMinutes();
+        	var sec = d.getSeconds();
+        	if(mm<10) mm = "0" + mm;
+        	if(dd<10) dd = "0" + dd;
+        	if(hr<10) hr = "0" + hr;
+        	if(min<10) min = "0" + min;
+        	if(sec<10) sec = "0" + sec;
+        	var formatedValue = mm + "-" + dd + "-" + yyyy + "_" + hr + "" + min + "" + sec;
+        	return formatedValue;
+	}
+
+
+        app.post("/downloadXml",
+            express.json({'limit':'16mb'}),
+            function(req,res) {
+		//console.log("Received request and processing:" + new Date());
+        	var qs = require('querystring');
+        	var body = '';
+        	//var msecs1= Date.now();
+        	req.on('data', function (data) {
+            		body += data;
+        	});
+        	req.on('end', function () {
+			var appDir = path.dirname(require.main.filename);
+			var xmlDir = appDir + "/" + settings.xmlPath;
+                	//var msecs2= Date.now();
+                	//console.log("Time taken to get request body:" + (msecs2 - msecs1));
+                	var msecs3= Date.now();
+                	var post = qs.parse(body);
+                	var msecs4= Date.now();
+                	//console.log("Time taken to parse body:" + (msecs4 - msecs3));
+                	var xml = post['flowXml'];
+			//var pd = require('pretty-data').pd;
+			//var formatted_xml = pd.xml(xml);
+                	var moduleName = post['moduleName'];
+                	var methodName = post['methodName'];
+                	if(moduleName == "" || methodName == ""){
+                        	res.send({"ERROR":"ServiceLogic Module Name and method name are required."});
+                	}else{
+                        	//var formatted_date = getCurrentDate();
+                        	//var fileNameForServer=moduleName + "_" +methodName+ "_" +  formatted_date + ".xml";
+                        	//var fileName=moduleName + "_method_" +methodName+ ".xml";
+                        	var fileName=moduleName + "_" +methodName+ ".xml";
+                        	var file = xmlDir + "/" + fileName;
+
+                        	//var msecs2= Date.now();
+                        	writeToFile(file,xml);
+                        	//var msecs3= Date.now();
+                        	//console.log("Time taken to write File:" + (msecs3 - msecs2));
+                        	res.setHeader('Content-disposition', 'attachment; filename=' + fileName);
+                        	res.setHeader('Content-type', 'text/xml');
+                        	res.end(xml);
+                        	//console.log("Response sent:" + new Date());
+			}
+        	});
+	});
+
+        app.post("/downloadJson",
+            express.json({'limit':'16mb'}),
+            function(req,res) {
+			var appDir = path.dirname(require.main.filename);
+			var sharedDir = appDir + "/" + settings.sharedDir;
+		 	var qs = require('querystring');
+        		var body = '';
+        		req.on('data', function (data) {
+            			body += data;
+        		});
+        		req.on('end', function () {
+                		var post = qs.parse(body);
+                		var jsonStr = post['flowJson'];
+                		var moduleName = post['moduleName'];
+                		var methodName = post['methodName'];
+                		//console.log("jsonStr:" + jsonStr);
+                		if(moduleName == "" || methodName == ""){
+                        		res.send({"ERROR":"ServiceLogic Module Name and method name are required."});
+                		}else{
+                        		var formatted_date = getCurrentDate();
+                        		//console.log("moduleName:" + moduleName);
+                        		//console.log("methodName:" + methodName);
+
+                        		//var fileName=moduleName + "_method_" +methodName + ".json";
+                        		//var renameOldfileTo=moduleName + "_method_" +methodName+ "_" +  formatted_date + ".json";
+                        		var fileName=moduleName + "_" +methodName + ".json";
+                        		var renameOldfileTo=moduleName + "_" +methodName+ "_" +  formatted_date + ".json";
+                        		var file = sharedDir + "/" + fileName;
+                        		//console.log("fileName:" + fileName);
+                        		var renameFilePath = sharedDir + "/backups/" + renameOldfileTo;
+                        		//console.log("localfile:" + localfile);
+                        		fs.rename(file,renameFilePath, function (err) {
+                                		if(err){
+                                        		console.log('Error :' + err);
+                                		}
+                                		//write the newer version
+                                		writeToFile(file,jsonStr);
+                                		res.setHeader('Content-disposition', 'attachment; filename=' + fileName);
+                                		res.setHeader('Content-type', 'application/json');
+                                		//res.download(file);
+                                		res.end(jsonStr);
+					});
+				}
+	   		});
+	});
+
+        app.post("/flows",
+            express.json({'limit':'16mb'}),
+            function(req,res) {
+		//console.log("Processing Request");
+                var flows = req.body;
+                redNodes.setFlows(flows).then(function() {
+                    res.send(204);
+                }).otherwise(function(err) {
+                    util.log("[red] Error saving flows : "+err);
+                    res.send(500,err.message);
+                });
+            },
+            function(error,req,res,next) {
+                res.send(400,"Invalid Flow.  Error " + error);
+            }
+        );
+            
+        app.get("/nodes",function(req,res) {
+            if (req.get("accept") == "application/json") {
+                res.json(redNodes.getNodeList());
+            } else {
+                res.send(redNodes.getNodeConfigs());
+            }
+        });
+        
+        app.post("/nodes",
+            express.json(),
+            function(req,res) {
+                if (!settings.available()) {
+                    res.send(400,new Error("Settings unavailable").toString());
+                    return;
+                }
+                var node = req.body;
+                var promise;
+                if (node.file) {
+                    promise = redNodes.addNode(node.file).then(reportAddedModules);
+                } else if (node.module) {
+                    var module = redNodes.getNodeModuleInfo(node.module);
+                    if (module) {
+                        res.send(400,"Module already loaded");
+                        return;
+                    }
+                    promise = installModule(node.module);
+                } else {
+                    res.send(400,"Invalid request");
+                    return;
+                }
+                promise.then(function(info) {
+                    res.json(info);
+                }).otherwise(function(err) {
+                    if (err.code === 404) {
+                        res.send(404);
+                    } else {
+                        res.send(400,err.toString());
+                    }
+                });
+            },
+            function(err,req,res,next) {
+                console.log(err.toString());
+                res.send(400,err);
+            }
+        );
+        
+        app.delete("/nodes/:id",
+            function(req,res) {
+                if (!settings.available()) {
+                    res.send(400,new Error("Settings unavailable").toString());
+                    return;
+                }
+                var id = req.params.id;
+                var removedNodes = [];
+                try {
+                    var node = redNodes.getNodeInfo(id);
+                    var promise = null;
+                    if (!node) {
+                        var module = redNodes.getNodeModuleInfo(id);
+                        if (!module) {
+                            res.send(404);
+                            return;
+                        } else {
+                            promise = uninstallModule(id);
+                        }
+                    } else {
+                        promise = when.resolve([redNodes.removeNode(id)]).then(reportRemovedModules);
+                    }
+                    
+                    promise.then(function(removedNodes) {
+                        res.json(removedNodes);
+                    }).otherwise(function(err) {
+                        console.log(err.stack);
+                        res.send(400,err.toString());
+                    });
+                } catch(err) {
+                    res.send(400,err.toString());
+                }
+            },
+            function(err,req,res,next) {
+                res.send(400,err);
+            }
+        );
+        
+        app.get("/nodes/:id", function(req,res) {
+            var id = req.params.id;
+            var result = null;
+            if (req.get("accept") == "application/json") {
+                result = redNodes.getNodeInfo(id);
+            } else {
+                result = redNodes.getNodeConfig(id);
+            }
+            if (result) {
+                res.send(result);
+            } else {
+                res.send(404);
+            }
+        });
+        
+        app.put("/nodes/:id", 
+            express.json(),
+            function(req,res) {
+                if (!settings.available()) {
+                    res.send(400,new Error("Settings unavailable").toString());
+                    return;
+                }
+                var body = req.body;
+                if (!body.hasOwnProperty("enabled")) {
+                    res.send(400,"Invalid request");
+                    return;
+                }
+                try {
+                    var info;
+                    var id = req.params.id;
+                    var node = redNodes.getNodeInfo(id);
+                    if (!node) {
+                        res.send(404);
+                    } else if (!node.err && node.enabled === body.enabled) {
+                        res.json(node);
+                    } else {
+                        if (body.enabled) {
+                            info = redNodes.enableNode(id);
+                        } else {
+                            info = redNodes.disableNode(id);
+                        }
+                        if (info.enabled == body.enabled && !info.err) {
+                            comms.publish("node/"+(body.enabled?"enabled":"disabled"),info,false);
+                            util.log("[red] "+(body.enabled?"Enabled":"Disabled")+" node types:");
+                            for (var i=0;i<info.types.length;i++) {
+                                util.log("[red] - "+info.types[i]);
+                            }
+                        } else if (body.enabled && info.err) {
+                            util.log("[red] Failed to enable node:");
+                            util.log("[red] - "+info.name+" : "+info.err);
+                        }
+                        res.json(info);
+                    }
+                } catch(err) {
+                    res.send(400,err.toString());
+                }            
+            }
+        );
+        app.get("/getCodeCloudFlows",function(req,res) {
+		var userDir=settings.userDir;
+		var codeCloudDir=userDir + "/codecloud";
+		var glob = require("glob")
+		glob(codeCloudDir + "/**/*.json", null, function (er, files) {
+			  // files is an array of filenames.
+			 // If the `nonull` option is set, and nothing
+  			// was found, then files is ["**/*.js"]
+  			// er is an error object or null.
+			//console.dir(files);
+			var filesList =[];
+			for(var i=0;files!= null && i<files.length;i++){
+				var f = files[i].replace( new RegExp(codeCloudDir + "/", "g" ), "" );
+				filesList.push(f);
+
+			}
+			res.json({"files" : filesList});
+		});
+        });
+
+        app.get("/getCurrentGitBranch",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir=settings.userDir;
+		var settingsFile = appDir + "/" +  userDir + "/customSettings.js"; 
+		//console.log("settingsFile:" + settingsFile);
+		var jsonObj = require(settingsFile);
+		var gitLocalRepository=jsonObj.gitLocalRepository;
+		if(gitLocalRepository == undefined || gitLocalRepository == null || gitLocalRepository == ''){
+			res.json({"output" : "GIT_LOCAL_REPOSITORY_NOT_SET"});
+			return;
+		}
+		var exec = require('child_process').exec;
+		var commandToExec = appDir + "/git_scripts/gitcurbranch " + gitLocalRepository ;
+			console.log("commandToExec:" + commandToExec);
+        		var child = exec(commandToExec ,function (error,stdout,stderr){
+                		if(error){
+					console.log("Error occured:" + error);
+					if(stderr){
+						console.log("stderr:" + stderr);
+						res.json({"output":stderr});
+					}else{
+						res.json({"output":error});
+					}
+                		}else{
+					if(stderr){
+						console.log("stderr:" + stderr);
+					}
+					if(stdout){
+						res.json({"output":stdout});
+					}
+				}
+			});
+				
+	});
+
+        app.get("/getGitLocalFlows",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var userDir=settings.userDir;
+		var settingsFile = appDir + "/" +  userDir + "/customSettings.js"; 
+		//console.log("settingsFile:" + settingsFile);
+		var jsonObj = require(settingsFile);
+		var performGitPull = jsonObj.performGitPull;
+		if(performGitPull == undefined || performGitPull == null) {
+			performGitPull="N";
+		}
+		var gitLocalRepository=jsonObj.gitLocalRepository;
+		if(gitLocalRepository == undefined || gitLocalRepository == null || gitLocalRepository == ''){
+			res.json({"files" : ["GIT_LOCAL_REPOSITORY_NOT_SET"]});
+			return;
+				
+		   }
+
+		if(performGitPull == "Y"){	
+			var exec = require('child_process').exec;
+			var commandToExec = appDir + "/git_scripts/gitpull " + gitLocalRepository ;
+			console.log("commandToExec:" + commandToExec);
+        		var child = exec(commandToExec ,function (error,stdout,stderr){
+                		if(error){
+					console.log("Error occured:" + error);
+					if(stderr){
+						console.log("stderr:" + stderr);
+						res.json({"files":[]});
+					}else{
+						res.json({"files":[]});
+					}
+                		}else{
+					if(stderr){
+						console.log("stderr:" + stderr);
+					}
+					if(stdout){
+						var glob = require("glob")
+						glob(gitLocalRepository + "/**/*.json", null, function (er, files) {
+			  			// files is an array of filenames.
+			 			// If the `nonull` option is set, and nothing
+  						// was found, then files is ["**/*.js"]
+  						// er is an error object or null.
+						//console.dir(files);
+						var filesList =[];
+						for(var i=0;files!= null && i<files.length;i++){
+							var f = files[i].replace( new RegExp(gitLocalRepository + "/", "g" ), "" );
+							filesList.push(f);
+
+						}
+						res.json({"files" : filesList});
+						});
+                			}
+				}
+			});
+		}else{//git pull not requested
+			var glob = require("glob")
+			glob(gitLocalRepository + "/**/*.json", null, function (er, files) {
+			// files is an array of filenames.
+			// If the `nonull` option is set, and nothing
+  			// was found, then files is ["**/*.js"]
+  			// er is an error object or null.
+			//console.dir(files);
+			var filesList =[];
+			for(var i=0;files!= null && i<files.length;i++){
+				var f = files[i].replace( new RegExp(gitLocalRepository + "/", "g" ), "" );
+				filesList.push(f);
+
+			}
+			res.json({"files" : filesList});
+			});
+		}
+	
+        });
+
+        app.get("/flowShareUsers",function(req,res) {
+            res.json(flowShareUsers);
+        });
+        app.get("/getRelease",function(req,res) {
+		var userDir = settings.userDir;
+		//var release = userDir.replace(/releases/g,"release");
+            	res.json({"release" : userDir});
+        });
+        app.post("/getFiles/:id",function(req,res) {
+            var id = req.params.id;
+		//console.log("id:" + id);
+		var userDir=settings.userDir;
+		var flowDir= userDir + "/../" + id + "/flows/shared"; 
+		//console.log("flowDir:" + flowDir);
+		fs.readdir(flowDir,function(err, files){
+			if(err){
+				res.json({"files": []});
+			}else{
+				var onlyFilesArr =[];
+				if(files != null && files.length>0){
+					files.sort(function(a,b){
+						//console.log("file1:" + a);	
+						//console.log("file2:" + b);	
+						var fileStat1=fs.statSync(flowDir+ "/" + a);	
+						var fileStat2=fs.statSync(flowDir+ "/" + b);	
+						if(fileStat1.mtime > fileStat2.mtime){
+							return 1;
+						}else if(fileStat1.mtime < fileStat2.mtime){
+							return -1;
+						}else{
+							return 0;
+						}
+					});
+					for(var i=0;i<files.length;i++){
+						var fileStat=fs.statSync(flowDir+ "/" + files[i]);
+						if(fileStat.isFile()){
+						    onlyFilesArr.push({"filePath":flowDir+ "/" + files[i],"name":files[i]});
+						}
+					}
+					res.json(onlyFilesArr);
+				}else{
+					res.json({"files": []});
+				}
+			}
+		});
+        });
+
+        app.post("/updateConfiguration",
+            express.json(),
+            function(req,res) {
+		var qs = require('querystring');
+		//console.log("Received the request:");
+		var body ="";
+		 req.on('data', function (data) {
+            		body += data;
+        	});
+		req.on('end',function(){
+			var post = qs.parse(body);
+                	var dbHost = post["dbHost"];
+                	var dbPort = post["dbPort"];
+                	var dbName = post["dbName"];
+                	var dbUser = post["dbUser"];
+                	var dbPassword = post["dbPassword"];
+                	var gitLocalRepository = post["gitLocalRepository"];
+                	var performGitPull = post["performGitPull"];
+			var appDir = path.dirname(require.main.filename);
+			var userDir = appDir + "/" + settings.userDir;
+			console.log("userDir:" + userDir);
+			try{
+				var settingsFile = userDir + "/customSettings.js"; 
+				var jsonObj = require(settingsFile);
+				jsonObj.flowFile = jsonObj.flowFile.replace(appDir + "/",'');
+				jsonObj.dbHost = dbHost;
+				jsonObj.dbPort = dbPort;
+				jsonObj.dbName = dbName;
+				jsonObj.dbUser = dbUser;
+				jsonObj.dbPassword = dbPassword;
+				jsonObj.gitLocalRepository = gitLocalRepository;
+				jsonObj.performGitPull = performGitPull;
+				var updatedSettings = jsonObj;
+
+				var settingsStr= "module.exports=" + JSON.stringify(updatedSettings,null,4);
+				//console.log("settingsStr:" + settingsStr);
+           			fs.writeFileSync(settingsFile,settingsStr);
+				var svcLogicPropStr = "" ;
+					svcLogicPropStr += "org.openecomp.sdnc.sli.dbtype=jdbc" + "\n";
+					svcLogicPropStr += "org.openecomp.sdnc.sli.jdbc.url=jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName + "\n";
+					svcLogicPropStr += "org.openecomp.sdnc.sli.jdbc.database=" + dbName + "\n";
+					svcLogicPropStr += "org.openecomp.sdnc.sli.jdbc.user=" + dbUser  + "\n";
+					svcLogicPropStr += "org.openecomp.sdnc.sli.jdbc.password=" + dbPassword;
+				
+				//create svclogic.properties file in the conf dir
+				var svcPropFile = userDir + "/conf/svclogic.properties";
+           			fs.writeFileSync(svcPropFile,svcLogicPropStr);
+
+				res.send({"status": "success"});
+        		}catch(e){
+                		console.log("Error:" + e);
+				res.send({"status": "error"});
+        		}
+		});
+            }
+	);
+
+        app.post("/deleteYangFile",
+            express.json(),
+            function(req,res) {
+		var qs = require('querystring');
+		//console.log("Received the request:");
+		var body ="";
+		 req.on('data', function (data) {
+            		body += data;
+        	});
+		req.on('end',function(){
+			var post = qs.parse(body);
+			//console.dir(body);
+                	var fileName = post["fileName"];
+			var appDir = path.dirname(require.main.filename);
+			var yangFilePath = appDir + "/yangFiles/" + fileName;
+			try{
+				fs.unlinkSync(yangFilePath);
+				res.send({"status" :"SUCCESS"});
+			}catch(err){
+				console.log("error" + err);
+				res.send({"status" :"ERROR"});
+			}
+			//console.log("prevPassword:" + settings.httpAuth.pass );
+		});
+            }
+	);
+
+        app.post("/updatePassword",
+            express.json(),
+            function(req,res) {
+		var qs = require('querystring');
+		//console.log("Received the request:");
+		var body ="";
+		 req.on('data', function (data) {
+            		body += data;
+        	});
+		req.on('end',function(){
+			var post = qs.parse(body);
+			//console.dir(body);
+                	var password = post["password"];
+			//console.log("prevPassword:" + settings.httpAuth.pass );
+			//console.log("New password:" + password);
+			var crypto = require("crypto");
+			var cryptPasswd = crypto.createHash('md5').update(password,'utf8').digest('hex')
+			var appDir = path.dirname(require.main.filename);
+			var userDir = appDir + "/" + settings.userDir;
+			//console.log("userDir:" + userDir);
+			/*var newSettings = settings;
+			newSettings.httpAuth.pass = cryptPasswd;
+			var updatedSettings = JSON.stringify(settings,null,4);
+			var settingsStr = "module.exports=" + updatedSettings;
+			console.log(updatedSettings);
+			*/
+			try{
+				var settingsFile = userDir + "/customSettings.js"; 
+				//console.log("settingsFile:" + settingsFile);
+				//var buf = fs.readFileSync(settingsFile, "utf8");
+				var jsonObj = require(settingsFile);
+				//console.log("jsonObj:" + JSON.stringify(jsonObj));
+				jsonObj.httpAuth.pass = cryptPasswd;
+				jsonObj.httpAdminAuth.pass = cryptPasswd;
+				jsonObj.httpNodeAuth.pass = cryptPasswd;
+				jsonObj.flowFile = jsonObj.flowFile.replace(appDir + "/",'');
+				var updatedSettings = jsonObj;
+				/*
+    				delete updatedSettings.httpRoot;
+    				delete updatedSettings.disableEditor;
+    				delete updatedSettings.httpAdminRoot;
+    				delete updatedSettings.httpAdminAuth;
+    				delete updatedSettings.httpNodeRoot;
+    				delete updatedSettings.httpNodeAuth;
+    				delete updatedSettings.uiHost;
+    				delete updatedSettings.version;
+				*/
+				var settingsStr= "module.exports=" + JSON.stringify(updatedSettings,null,4);
+				//console.log("settingsStr:" + settingsStr);
+           			fs.writeFileSync(settingsFile,settingsStr);
+				settings.httpAuth.pass = cryptPasswd;
+				res.send({"status": "success"});
+        		}catch(e){
+                		console.log("Error:" + e);
+				res.send({"status": "error"});
+        		}
+		});
+            }
+	);
+
+	var appDir = path.dirname(require.main.filename);
+	var yangDir = appDir + "/yangFiles" ;
+	var diskStorage =   multer.diskStorage({
+  			destination: function (req, file, callback) {
+    						callback(null, yangDir);
+  			},
+  			filename: function (req, file, callback) {
+    				//callback(null, file.fieldname + '-' + Date.now());
+    				callback(null, file.originalname);
+  			}
+	});
+	var upload = multer({ storage : diskStorage}).single('yangFile');
+
+	app.post('/api/uploadyang',function(req,res){
+    		upload(req,res,function(err) {
+        		if(err) {
+				console.log(err);
+            			return res.end("Error uploading file." + err);
+        		}
+			//console.dir(req);	
+			var fileName = req.file.originalname;
+			var yangFileFullPath =  appDir + "/yangFiles/" + fileName;
+			console.log("yangFileFullPath:" + yangFileFullPath);
+			var commandToExec =""; 
+			if(fileName != null){
+				var matchedArr = fileName.match(/.zip$/);
+				if(matchedArr != null && matchedArr.length >0){
+					console.log("uploaded zip file" + fileName);
+					commandToExec = appDir + "/tools/generate_props_from_yangs_zip.sh " + yangFileFullPath ;
+				}else{
+					commandToExec = appDir + "/tools/generate_props_from_yang.sh " + yangFileFullPath ;
+					console.log("uploaded file" + fileName);
+				}
+			}
+			var exec = require('child_process').exec;
+			console.log("commandToExec:" + commandToExec);
+        		var child = exec(commandToExec ,function (error,stdout,stderr){
+                		if(error){
+					console.log("Error occured:" + error);
+					var msg = "File " + fileName + " could not be processed successfully.";
+					if(stderr){
+						console.log("stderr:" + stderr);
+						res.json({"sliValuesObj" : [],"message":msg});
+					}else{
+						res.json({"sliValuesObj" : [],"message":msg});
+					}
+                		}else{
+					if(stderr){
+						console.log("stderr:" + stderr);
+					}
+					if(stdout){
+						console.log("stdout:" + stdout);
+					}
+					var msg = "File " + fileName + " processed successfully.";
+					var generatedJSDir=appDir + "/generatedJS";
+					var sliValuesObj =[];
+					//var glob = require("glob");
+					//glob(generatedJSDir + "/**/*.js", null, function (er, files) {
+					/*
+						var sliValuesObj =[];
+						for(var i=0;files!= null && i<files.length;i++){
+							var f = files[i].replace( new RegExp(generatedJSDir + "/", "g" ), "" );
+							console.log("loading file " + f);
+							try{
+								sliValuesObj.push(require(files[i]));
+								//console.dir(sliValuesObj);
+							}catch(err){
+								console.log("Error:Could not load file " + files[i]);
+							}
+						} 
+						res.json({"sliValuesObj" : sliValuesObj,"message":msg});
+                			});
+					*/
+					res.json({"sliValuesObj" : sliValuesObj,"message":msg});
+    	                	}
+        		});
+		});
+        });
+        app.get("/getYangFiles",function(req,res) {
+		var appDir = path.dirname(require.main.filename);
+		var yangFilesDir=appDir + "/yangFiles";
+		var glob = require("glob")
+		glob(yangFilesDir + "/**/*.yang", null, function (er, files) {
+			var filesList =[];
+			for(var i=0;files!= null && i<files.length;i++){
+				var f = files[i].replace( new RegExp(yangFilesDir + "/", "g" ), "" );
+				filesList.push(f);
+
+			}
+			res.json({"files" : filesList});
+		});
+        });
+	}
+}
+
+function reportAddedModules(info) {
+    comms.publish("node/added",info,false);
+    if (info.length > 0) {
+        util.log("[red] Added node types:");
+        for (var i=0;i<info.length;i++) {
+            for (var j=0;j<info[i].types.length;j++) {
+                util.log("[red] - "+
+                    (info[i].module?info[i].module+":":"")+
+                    info[i].types[j]+
+                    (info[i].err?" : "+info[i].err:"")
+                    );
+            }
+        }
+    }
+    return info;
+}
+
+function reportRemovedModules(removedNodes) {
+    comms.publish("node/removed",removedNodes,false);
+    util.log("[red] Removed node types:");
+    for (var j=0;j<removedNodes.length;j++) {
+        for (var i=0;i<removedNodes[j].types.length;i++) {
+            util.log("[red] - "+(removedNodes[i].module?removedNodes[i].module+":":"")+removedNodes[j].types[i]);
+        }
+    }
+    return removedNodes;
+}
+
+function installModule(module) { 
+    //TODO: ensure module is 'safe'
+    return when.promise(function(resolve,reject) {
+        if (/[\s;]/.test(module)) {
+            reject(new Error("Invalid module name"));
+            return;
+        }
+        util.log("[red] Installing module: "+module);
+        var child = exec('npm install --production '+module, function(err, stdin, stdout) {
+            if (err) {
+                var lookFor404 = new RegExp(" 404 .*"+module+"$","m");
+                if (lookFor404.test(stdout)) {
+                    util.log("[red] Installation of module "+module+" failed: module not found");
+                    var e = new Error();
+                    e.code = 404;
+                    reject(e);
+                } else {
+                    util.log("[red] Installation of module "+module+" failed:");
+                    util.log("------------------------------------------");
+                    console.log(err.toString());
+                    util.log("------------------------------------------");
+                    reject(new Error("Install failed"));
+                }
+            } else {
+                util.log("[red] Installed module: "+module);
+                resolve(redNodes.addModule(module).then(reportAddedModules));
+            }
+        });
+    });
+}
+
+function uninstallModule(module) {
+    var list = redNodes.removeModule(module);
+    return when.promise(function(resolve,reject) {
+        if (/[\s;]/.test(module)) {
+            reject(new Error("Invalid module name"));
+            return;
+        }
+        util.log("[red] Removing module: "+module);
+        var child = exec('npm remove '+module, function(err, stdin, stdout) {
+            if (err) {
+                util.log("[red] Removal of module "+module+" failed:");
+                util.log("------------------------------------------");
+                console.log(err.toString());
+                util.log("------------------------------------------");
+                reject(new Error("Removal failed"));
+            } else {
+                util.log("[red] Removed module: "+module);
+                reportRemovedModules(list);
+                resolve(list);
+            }
+        });
+    });
+}
+
+function start() {
+    var defer = when.defer();
+    
+    storage.init(settings).then(function() {
+        settings.load(storage).then(function() {
+            console.log("\nWelcome to Node-RED\n===================\n");
+            if (settings.version) {
+                util.log("[red] Version: "+settings.version);
+            }
+            util.log("[red] Loading palette nodes");
+            redNodes.init(settings,storage);
+            redNodes.load().then(function() {
+                var i;
+                var nodes = redNodes.getNodeList();
+                var nodeErrors = nodes.filter(function(n) { return n.err!=null;});
+                var nodeMissing = nodes.filter(function(n) { return n.module && n.enabled && !n.loaded && !n.err;});
+                if (nodeErrors.length > 0) {
+                    util.log("------------------------------------------");
+                    if (settings.verbose) {
+                        for (i=0;i<nodeErrors.length;i+=1) {
+                            util.log("["+nodeErrors[i].name+"] "+nodeErrors[i].err);
+                        }
+                    } else {
+                        util.log("[red] Failed to register "+nodeErrors.length+" node type"+(nodeErrors.length==1?"":"s"));
+                        util.log("[red] Run with -v for details");
+                    }
+                    util.log("------------------------------------------");
+                }
+                if (nodeMissing.length > 0) {
+                    util.log("[red] Missing node modules:");
+                    var missingModules = {};
+                    for (i=0;i<nodeMissing.length;i++) {
+                        var missing = nodeMissing[i];
+                        missingModules[missing.module] = (missingModules[missing.module]||[]).concat(missing.types);
+                    }
+                    var promises = [];
+                    for (i in missingModules) {
+                        if (missingModules.hasOwnProperty(i)) {
+                            util.log("[red] - "+i+": "+missingModules[i].join(", "));
+                            if (settings.autoInstallModules) {
+                                installModule(i).otherwise(function(err) {
+                                    // Error already reported. Need the otherwise handler
+                                    // to stop the error propagating any further
+                                });
+                            }
+                        }
+                    }
+                    if (!settings.autoInstallModules) {
+                        util.log("[red] Removing modules from config");
+                        redNodes.cleanNodeList();
+                    }
+                }
+                defer.resolve();
+                
+                redNodes.loadFlows();
+            }).otherwise(function(err) {
+                console.log(err);
+            });
+            comms.start();
+        });
+    }).otherwise(function(err) {
+        defer.reject(err);
+    });
+    
+    return defer.promise;
+}
+
+function stop() {
+    redNodes.stopFlows();
+    comms.stop();
+}
+
+module.exports = { 
+    init: createServer,
+    start: start,
+    stop: stop
+}
+
+module.exports.__defineGetter__("app", function() { return app });
+module.exports.__defineGetter__("nodeApp", function() { return nodeApp });
+module.exports.__defineGetter__("server", function() { return server });
diff --git a/dgbuilder/red/settings.js b/dgbuilder/red/settings.js
new file mode 100644
index 0000000..4994953
--- /dev/null
+++ b/dgbuilder/red/settings.js
@@ -0,0 +1,84 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var when = require("when");
+
+var assert = require("assert");
+
+var userSettings = null;
+var globalSettings = null;
+var storage = null;
+
+var persistentSettings = {
+    init: function(settings) {
+        userSettings = settings;
+        
+        for (var i in settings) {
+            if (settings.hasOwnProperty(i)) {
+                (function() {
+                    var j = i;
+                    persistentSettings.__defineGetter__(j,function() { return userSettings[j]; });
+                    persistentSettings.__defineSetter__(j,function() { throw new Error("Property '"+i+"' is read-only"); });
+                })();
+            }
+        }
+        globalSettings = null;
+    },
+    load: function(_storage) {
+        storage = _storage;
+        return storage.getSettings().then(function(_settings) {
+            globalSettings = _settings;
+        });
+    },
+    get: function(prop) {
+        if (userSettings.hasOwnProperty(prop)) {
+            return userSettings[prop];
+        }
+        if (globalSettings === null) {
+            throw new Error("Settings not available");
+        }
+        return globalSettings[prop];
+    },
+    
+    set: function(prop,value) {
+        if (userSettings.hasOwnProperty(prop)) {
+            throw new Error("Property '"+prop+"' is read-only");
+        }
+        if (globalSettings === null) {
+            throw new Error("Settings not available");
+        }
+        var current = globalSettings[prop];
+        globalSettings[prop] = value;
+        try {
+            assert.deepEqual(current,value);
+            return when.resolve();
+        } catch(err) {
+            return storage.saveSettings(globalSettings);
+        }
+    },
+    
+    available: function() {
+        return (globalSettings !== null);
+    },
+    
+    reset: function() {
+        userSettings = null;
+        globalSettings = null;
+        storage = null;
+    }
+}
+
+module.exports = persistentSettings;
diff --git a/dgbuilder/red/sla.js b/dgbuilder/red/sla.js
new file mode 100644
index 0000000..1729ecb
--- /dev/null
+++ b/dgbuilder/red/sla.js
@@ -0,0 +1,249 @@
+exports.listSLA =  function(settings,req,res) {
+try{
+	var mysql = require('mysql');
+
+	//console.dir(settings);
+ 
+	var connection = mysql.createConnection(
+    	{
+      	host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+	var sqlQuery = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+	//console.log("sqlQuery:" + sqlQuery);
+         connection.query(sqlQuery, function(err, rows) {
+            if(!err) {
+                if ( rows.length > 0 )
+                {
+                        res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                }else{
+                        res.send({'rows': [],'dbHost':settings.dbHost});
+                }
+            } else {
+			console.log("error:" + err);
+            	    res.send({error: "Connection to DB failed.",'dbHost':settings.dbHost});
+            }
+		//console.dir(rows);
+		connection.end();
+        }); //end query
+}catch(error){
+	console.log(error);
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+exports.listCurrentDGs =  function(settings,req,res) {
+	var _module = req.query.module;
+	var rpc = req.query.rpc;
+	console.log("_module:" + _module);
+	console.log("rpc:" + rpc);
+try{
+	var mysql = require('mysql');
+
+	//console.dir(settings);
+ 
+	var connection = mysql.createConnection(
+    	{
+      	host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+	var sqlQuery = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC where module ='" + _module + "' and rpc ='" + rpc + "'";
+	console.log("sqlQuery:" + sqlQuery);
+         connection.query(sqlQuery, function(err, rows) {
+            if(!err) {
+                if ( rows.length > 0 )
+                {
+                        res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                }else{
+                        res.send({'rows': [],'dbHost':settings.dbHost});
+                }
+            } else {
+			console.log("error:" + err);
+            	    res.send({error: "Connection to DB failed.",'dbHost':settings.dbHost});
+            }
+		//console.dir(rows);
+		connection.end();
+        }); //end query
+}catch(error){
+	console.log(error);
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+exports.activateDG = function(settings,req,res){
+	var _module = req.query.module;
+	var rpc = req.query.rpc;
+	var version = req.query.version;
+	var mode = req.query.mode;
+	var displayOnlyCurrent = req.query.displayOnlyCurrent;
+
+try{
+	var mysql = require('mysql');
+ 
+	var connection = mysql.createConnection(
+    	{
+      	host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+	var updateStmt = "UPDATE SVC_LOGIC SET active=\'Y\' WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version=\'"
+                        +  version + "' AND mode=\'"
+                        +  mode + "'";
+
+         connection.query(updateStmt, function(err, result) {
+		var nextUpdateStmt = "UPDATE SVC_LOGIC SET active=\'N\' WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version !=\'"
+                        +  version + "'";
+         	connection.query(nextUpdateStmt, function(err, result) {
+			var query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+			if(displayOnlyCurrent == 'true'){
+				query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC WHERE module=\'"
+					+  _module + "' and rpc=\'" + rpc + "'";
+			}
+         		connection.query(query, function(err, rows) {
+            			if(!err) {
+                			if ( rows.length > 0 )
+                			{
+                        			res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                			}else{
+                        			res.send({'rows': [],'dbHost':settings.dbHost});
+                			}
+            			} else {
+            	    			res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+            			}
+				connection.end();
+        		}); //end query
+        	}); //end query
+       	}); //end query
+}catch(error){
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+
+exports.deActivateDG = function(settings,req,res){
+
+	var _module = req.query.module;
+	var rpc = req.query.rpc;
+	var version = req.query.version;
+	var mode = req.query.mode;
+	var displayOnlyCurrent = req.query.displayOnlyCurrent;
+
+try{
+	var mysql = require('mysql');
+ 
+	var connection = mysql.createConnection(
+    	{
+      	host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+	var updateStmt = "UPDATE SVC_LOGIC SET active=\'N\' WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version=\'"
+                        +  version + "' AND mode=\'"
+                        +  mode + "'";
+
+         connection.query(updateStmt, function(err, result) {
+		var query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+		if(displayOnlyCurrent == 'true'){
+			query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC WHERE module=\'"
+				+  _module + "' and rpc=\'" + rpc + "'";
+		}
+         	connection.query(query, function(err, rows) {
+            	if(!err) {
+                	if ( rows.length > 0 )
+                	{
+                        	res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                	}else{
+                        	res.send({'rows': [],'dbHost':settings.dbHost});
+                	}
+            	} else {
+            	    	res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+            	}
+		connection.end();
+        	}); //end query
+       	}); //end query
+}catch(error){
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+exports.deleteDG = function(settings,req,res){
+
+	var _module = req.query.module;
+	var rpc = req.query.rpc;
+	var version = req.query.version;
+	var mode = req.query.mode;
+	var displayOnlyCurrent = req.query.displayOnlyCurrent;
+
+try{
+	var mysql = require('mysql');
+ 
+	var connection = mysql.createConnection(
+    	{
+      	host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+	var deleteStmt = "DELETE FROM SVC_LOGIC  WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version=\'"
+                        +  version + "' AND mode=\'"
+                        +  mode + "'";
+	 console.log(deleteStmt);
+
+         connection.query(deleteStmt, function(err, result) {
+		var query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+		if(displayOnlyCurrent == 'true'){
+			query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC WHERE module=\'"
+				+  _module + "' and rpc=\'" + rpc + "'";
+		}
+         	connection.query(query, function(err, rows) {
+            	if(!err) {
+                	if ( rows.length > 0 )
+                	{
+                        	res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                	}else{
+                        	res.send({'rows': [],'dbHost':settings.dbHost});
+                	}
+            	} else {
+            	    	res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+            	}
+		connection.end();
+        	}); //end query
+       	}); //end query
+}catch(error){
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
diff --git a/dgbuilder/red/storage/index.js b/dgbuilder/red/storage/index.js
new file mode 100644
index 0000000..ba93962
--- /dev/null
+++ b/dgbuilder/red/storage/index.js
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var when = require('when');
+
+var storageModule;
+var settingsAvailable;
+
+function moduleSelector(aSettings) {
+    var toReturn;
+    if (aSettings.storageModule) {
+        if (typeof aSettings.storageModule === "string") {
+            // TODO: allow storage modules to be specified by absolute path
+            toReturn = require("./"+aSettings.storageModule);
+        } else {
+            toReturn = aSettings.storageModule;
+        }
+    } else {
+        toReturn = require("./localfilesystem");
+    }
+    return toReturn;
+}
+
+function is_malicious(path) {
+    return path.indexOf('../') != -1 || path.indexOf('..\\') != -1;
+}
+
+var storageModuleInterface = {
+        init: function(settings) {
+            try {
+                storageModule = moduleSelector(settings);
+                settingsAvailable = storageModule.hasOwnProperty("getSettings") && storageModule.hasOwnProperty("saveSettings");
+            } catch (e) {
+                return when.reject(e);
+            }
+            return storageModule.init(settings);
+        },
+        getFlows: function() {
+            return storageModule.getFlows();
+        },
+        saveFlows: function(flows) {
+            return storageModule.saveFlows(flows);
+        },
+        getCredentials: function() {
+            return storageModule.getCredentials();
+        },
+        saveCredentials: function(credentials) {
+            return storageModule.saveCredentials(credentials);
+        },
+        getSettings: function() {
+            if (settingsAvailable) {
+                return storageModule.getSettings();
+            } else {
+                return when.resolve(null);
+            }
+        },
+        saveSettings: function(settings) {
+            if (settingsAvailable) {
+                return storageModule.saveSettings(settings);
+            } else {
+                return when.resolve();
+            }
+        },
+        /* Library Functions */
+        getAllFlows: function() {
+            return storageModule.getAllFlows();
+        },
+        getFlow: function(fn) {
+            if (is_malicious(fn)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.getFlow(fn);
+        },
+        saveFlow: function(fn, data) {
+            if (is_malicious(fn)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.saveFlow(fn, data);
+        },
+        getLibraryEntry: function(type, path) {
+            if (is_malicious(path)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.getLibraryEntry(type, path);
+        },
+        saveLibraryEntry: function(type, path, meta, body) {
+            if (is_malicious(path)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.saveLibraryEntry(type, path, meta, body);
+        }
+}
+
+module.exports = storageModuleInterface;
diff --git a/dgbuilder/red/storage/localfilesystem.js b/dgbuilder/red/storage/localfilesystem.js
new file mode 100644
index 0000000..4825533
--- /dev/null
+++ b/dgbuilder/red/storage/localfilesystem.js
@@ -0,0 +1,309 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var fs = require('fs');
+var when = require('when');
+var nodeFn = require('when/node/function');
+var keys = require('when/keys');
+var util = require('util');
+var fspath = require("path");
+var mkdirp = require("mkdirp");
+
+var promiseDir = nodeFn.lift(mkdirp);
+
+var settings;
+var flowsFile;
+var flowsFullPath;
+var flowsPrev;
+var credentialsFile;
+var oldCredentialsFile;
+var userDir;
+var libDir;
+var libFlowsDir;
+var globalSettingsFile;
+
+function listFiles(dir) {
+    var dirs = {};
+    var files = [];
+    var dirCount = 0;
+    return nodeFn.call(fs.readdir, dir).then(function (contents) {
+        contents.sort().forEach(function(fn) {
+            var stats = fs.lstatSync(dir+"/"+fn);
+            if (stats.isDirectory()) {
+                dirCount += 1;
+                dirs[fn] = listFiles(dir+"/"+fn)
+            } else {
+                files.push(fn.split(".")[0]);
+            }
+        })
+        var result = {};
+        if (dirCount > 0) { result.d = keys.all(dirs); }
+        if (files.length > 0) { result.f = when.resolve(files); }
+        return keys.all(result);
+    })
+}
+
+function getFileMeta(root,path) {
+    var fn = fspath.join(root,path);
+    var fd = fs.openSync(fn,"r");
+    var size = fs.fstatSync(fd).size;
+    var meta = {};
+    var read = 0;
+    var length = 10;
+    var remaining = "";
+    var buffer = Buffer(length);
+    while(read < size) {
+        read+=fs.readSync(fd,buffer,0,length);
+        var data = remaining+buffer.toString();
+        var parts = data.split("\n");
+        remaining = parts.splice(-1);
+        for (var i=0;i<parts.length;i+=1) {
+            var match = /^\/\/ (\w+): (.*)/.exec(parts[i]);
+            if (match) {
+                meta[match[1]] = match[2];
+            } else {
+                read = size;
+                break;
+            }
+        }
+    }
+    fs.closeSync(fd);
+    return meta;
+}
+
+function getFileBody(root,path) {
+    var body = "";
+    var fn = fspath.join(root,path);
+    var fd = fs.openSync(fn,"r");
+    var size = fs.fstatSync(fd).size;
+    var scanning = true;
+    var read = 0;
+    var length = 50;
+    var remaining = "";
+    var buffer = Buffer(length);
+    while(read < size) {
+        var thisRead = fs.readSync(fd,buffer,0,length);
+        read += thisRead;
+        if (scanning) {
+            var data = remaining+buffer.slice(0,thisRead).toString();
+            var parts = data.split("\n");
+            remaining = parts.splice(-1)[0];
+            for (var i=0;i<parts.length;i+=1) {
+                if (! /^\/\/ \w+: /.test(parts[i])) {
+                    scanning = false;
+                    body += parts[i]+"\n";
+                }
+            }
+            if (! /^\/\/ \w+: /.test(remaining)) {
+                scanning = false;
+            }
+            if (!scanning) {
+                body += remaining;
+            }
+        } else {
+            body += buffer.slice(0,thisRead).toString();
+        }
+    }
+    fs.closeSync(fd);
+    return body;
+}
+
+var localfilesystem = {
+    init: function(_settings) {
+        settings = _settings;
+        userDir = settings.userDir || process.env.NODE_RED_HOME;
+
+        if (settings.flowFile) {
+            flowsFile = settings.flowFile;
+            flowsFullPath = flowsFile;
+        } else {
+            flowsFile = 'flows_'+require('os').hostname()+'.json';
+            flowsFullPath = fspath.join(userDir,flowsFile);
+        }
+        var fsext = fspath.extname(flowsFile);
+        credentialsFile = fspath.join(userDir,fspath.basename(flowsFile,fsext)+"_cred"+fsext);
+        oldCredentialsFile = fspath.join(userDir,"credentials.json");
+        flowsPrev = fspath.join(userDir,"flows.backup");
+
+        libDir = fspath.join(userDir,"lib");
+        libFlowsDir = fspath.join(libDir,"flows");
+
+        
+        globalSettingsFile = fspath.join(userDir,".config.json");
+        
+        return promiseDir(libFlowsDir);
+    },
+
+    getFlows: function() {
+        var defer = when.defer();
+        fs.exists(flowsFullPath, function(exists) {
+            if (exists) {
+                util.log("[red] Loading flows : "+flowsFile);
+                defer.resolve(nodeFn.call(fs.readFile,flowsFullPath,'utf8').then(function(data) {
+                    return JSON.parse(data);
+                }));
+            } else {
+                util.log("[red] Flows file not found : "+flowsFile   );
+                defer.resolve([]);
+            }
+        });
+        return defer.promise;
+    },
+
+    saveFlows: function(flows) {
+        if (fs.existsSync(flowsFullPath)) {
+            fs.renameSync(flowsFullPath,flowsPrev);
+        }
+        
+        var flowData;
+        
+        if (settings.flowFilePretty) {
+            flowData = JSON.stringify(flows,null,4);
+        } else {
+            flowData = JSON.stringify(flows);
+        }
+       	console.log("Writing to file:" + flowsFullPath); 
+        return nodeFn.call(fs.writeFile, flowsFullPath, flowData);
+    },
+
+    getCredentials: function() {
+        var defer = when.defer();
+        fs.exists(credentialsFile, function(exists) {
+            if (exists) {
+                defer.resolve(nodeFn.call(fs.readFile, credentialsFile, 'utf8').then(function(data) {
+                    return JSON.parse(data)
+                }));
+            } else {
+                fs.exists(oldCredentialsFile, function(exists) {
+                    if (exists) {
+                        defer.resolve(nodeFn.call(fs.readFile, oldCredentialsFile, 'utf8').then(function(data) {
+                            return JSON.parse(data)
+                        }));
+                    } else {
+                        defer.resolve({});
+                    }
+                });
+            }
+        });
+        return defer.promise;
+    },
+
+    saveCredentials: function(credentials) {
+        var credentialData;
+        if (settings.flowFilePretty) {
+            credentialData = JSON.stringify(credentials,null,4);
+        } else {
+            credentialData = JSON.stringify(credentials);
+        }
+        
+        return nodeFn.call(fs.writeFile, credentialsFile, credentialData)
+    },
+    
+    getSettings: function() {
+        if (fs.existsSync(globalSettingsFile)) {
+            return nodeFn.call(fs.readFile,globalSettingsFile,'utf8').then(function(data) {
+                if (data) {
+                    try {
+                        return JSON.parse(data);
+                    } catch(err) {
+                        util.log("[red] Corrupted config detected - resetting");
+                        return {};
+                    }
+                } else {
+                    return {};
+                }
+            });
+        }
+        return when.resolve({});
+    },
+    saveSettings: function(settings) {
+        return nodeFn.call(fs.writeFile,globalSettingsFile,JSON.stringify(settings,null,1),'utf8');
+    },
+    
+    
+    getAllFlows: function() {
+        return listFiles(libFlowsDir);
+    },
+
+    getFlow: function(fn) {
+        var defer = when.defer();
+        var file = fspath.join(libFlowsDir,fn+".json");
+        fs.exists(file, function(exists) {
+            if (exists) {
+                defer.resolve(nodeFn.call(fs.readFile,file,'utf8'));
+            } else {
+                defer.reject();
+            }
+        });
+        return defer.promise;
+    },
+
+    saveFlow: function(fn,data) {
+        var file = fspath.join(libFlowsDir,fn+".json");
+        return promiseDir(fspath.dirname(file)).then(function () {
+            return nodeFn.call(fs.writeFile, file, data);
+        });
+    },
+
+    getLibraryEntry: function(type,path) {
+        var root = fspath.join(libDir,type);
+        var rootPath = fspath.join(libDir,type,path);
+        return promiseDir(root).then(function () {
+            return nodeFn.call(fs.lstat, rootPath).then(function(stats) {
+                if (stats.isFile()) {
+                    return getFileBody(root,path);
+                }
+                if (path.substr(-1) == '/') {
+                    path = path.substr(0,path.length-1);
+                }
+                return nodeFn.call(fs.readdir, rootPath).then(function(fns) {
+                    var dirs = [];
+                    var files = [];
+                    fns.sort().filter(function(fn) {
+                        var fullPath = fspath.join(path,fn);
+                        var absoluteFullPath = fspath.join(root,fullPath);
+                        if (fn[0] != ".") {
+                            var stats = fs.lstatSync(absoluteFullPath);
+                            if (stats.isDirectory()) {
+                                dirs.push(fn);
+                            } else {
+                                var meta = getFileMeta(root,fullPath);
+                                meta.fn = fn;
+                                files.push(meta);
+                            }
+                        }
+                    });
+                    return dirs.concat(files);
+                });
+            });
+        });
+    },
+
+    saveLibraryEntry: function(type,path,meta,body) {
+        var fn = fspath.join(libDir, type, path);
+        var headers = "";
+        for (var i in meta) {
+            if (meta.hasOwnProperty(i)) {
+                headers += "// "+i+": "+meta[i]+"\n";
+            }
+        }
+        return promiseDir(fspath.dirname(fn)).then(function () {
+            nodeFn.call(fs.writeFile, fn, headers+body);
+        });
+    }
+};
+
+module.exports = localfilesystem;
diff --git a/dgbuilder/red/ui.js b/dgbuilder/red/ui.js
new file mode 100644
index 0000000..16580bf
--- /dev/null
+++ b/dgbuilder/red/ui.js
@@ -0,0 +1,77 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var express = require('express');
+var fs = require("fs");
+var events = require("./events");
+var path = require("path");
+
+var icon_paths = [path.resolve(__dirname + '/../public/icons')];
+
+var settings; // settings has to be global, otherwise variable not in scope for express
+
+events.on("node-icon-dir",function(dir) {
+    icon_paths.push(path.resolve(dir));
+});
+
+
+function setupUI(_settings,app) {
+    
+    settings = _settings;
+    
+    // Need to ensure the url ends with a '/' so the static serving works
+    // with relative paths
+    app.get("/",function(req,res) {
+        if (req.originalUrl.slice(-1) != "/") {
+            res.redirect(req.originalUrl+"/");
+        } else {
+            req.next();
+        }
+    });
+    
+    var iconCache = {};
+    //TODO: create a default icon
+    var defaultIcon = path.resolve(__dirname + '/../public/icons/arrow-in.png');
+    
+    app.get("/icons/:icon",function(req,res) {
+        if (iconCache[req.params.icon]) {
+            res.sendfile(iconCache[req.params.icon]); // if not found, express prints this to the console and serves 404
+        } else { 
+            for (var p=0;p<icon_paths.length;p++) {
+                var iconPath = path.join(icon_paths[p],req.params.icon);
+                if (fs.existsSync(iconPath)) {
+                    res.sendfile(iconPath);
+                    iconCache[req.params.icon] = iconPath;
+                    return;
+                }
+            }
+            res.sendfile(defaultIcon);
+        }
+    });
+    
+    app.get("/settings", function(req,res) {
+        var safeSettings = {
+            httpNodeRoot: settings.httpNodeRoot,
+            version: settings.version
+        };
+        res.json(safeSettings);
+    });
+    
+    app.use("/",express.static(__dirname + '/../public'));
+    
+    return app;
+}
+
+module.exports = setupUI;
diff --git a/dgbuilder/red/util.js b/dgbuilder/red/util.js
new file mode 100644
index 0000000..7ca72b0
--- /dev/null
+++ b/dgbuilder/red/util.js
@@ -0,0 +1,43 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+function ensureString(o) {
+    if (Buffer.isBuffer(o)) {
+        return o.toString();
+    } else if (typeof o === "object") {
+        return JSON.stringify(o);
+    } else if (typeof o === "string") {
+        return o;
+    }
+    return ""+o;
+}
+
+function ensureBuffer(o) {
+    if (Buffer.isBuffer(o)) {
+        return o;
+    } else if (typeof o === "object") {
+        o = JSON.stringify(o);
+    } else if (typeof o !== "string") {
+        o = ""+o;
+    }
+    return new Buffer(o);
+}
+
+module.exports = {
+    ensureString: ensureString,
+    ensureBuffer: ensureBuffer,
+};
+