CB-4548 Implement the `run` command using node-firefox-* modules
diff --git a/bin/lib/update.js b/bin/lib/update.js
index 8f674a1..3e0100d 100755
--- a/bin/lib/update.js
+++ b/bin/lib/update.js
@@ -42,6 +42,7 @@
     shell.rm('-rf', destScriptsDir);
     // Copy in the new ones.
     shell.cp('-r', srcScriptsDir, projectPath);
+    shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
     // Make sure they are executable.
     shell.find(destScriptsDir).forEach(function(entry) {
         shell.chmod(755, entry);
diff --git a/bin/templates/project/cordova/lib/common.js b/bin/templates/project/cordova/lib/common.js
new file mode 100644
index 0000000..3f8eb1a
--- /dev/null
+++ b/bin/templates/project/cordova/lib/common.js
@@ -0,0 +1,105 @@
+var path = require('path');
+var fs = require('fs');
+
+var Promise = require('es6-promise').Promise;
+
+var findSimulators = require('node-firefox-find-simulators');
+var findPorts = require('node-firefox-find-ports');
+var connect = require('node-firefox-connect');
+var installApp = require('node-firefox-install-app');
+var findApp = require('node-firefox-find-app');
+var launchApp = require('node-firefox-launch-app');
+var uninstallApp = require('node-firefox-uninstall-app');
+var startSimulator = require('node-firefox-start-simulator');
+
+var common = exports;
+
+common.collectSimulatorVersions = function() {
+    // There can be multiple Firefox installations, each with their own set of
+    // FxOS simulator addons. But, they're only unique by version. So, this
+    // just collects versions.
+    return findSimulators().then(function (simulators) {
+        var versions = {};
+        simulators.forEach(function (simulator) {
+            versions[simulator.version] = true;
+        });
+        return Object.keys(versions).sort();
+    });
+};
+
+common.collectRunningSimulatorsByVersion = function () {
+    return findPorts({
+        firefoxOSSimulator: true,
+        detailed: true 
+    }).then(function(results) {
+        var ports_by_version = {};
+        results.forEach(function (result) {
+            var release_parts = result.release.split(/\./g);
+            result.version = release_parts[0] + '.' + release_parts[1];
+            ports_by_version[result.version] = result;
+        });
+        return ports_by_version;
+    });
+};
+
+common.findOrStartSimulatorTarget = function (install_target) {
+    return common.collectRunningSimulatorsByVersion().then(function (running) {
+        if (!install_target) {
+            install_target = Object.keys(running)[0];
+        }
+        if (!install_target) {
+            throw new Error('no emulator target found');
+        }
+        if (install_target in running) {
+            return running[install_target];
+        }
+        return common.collectSimulatorVersions().then(function (versions) {
+            if (install_target && versions.indexOf(install_target) === -1) {
+                throw new Error('emulator \'' + install_target + '\' does not exist.');
+            }
+            return startSimulator({
+                version: install_target,
+                detached: true
+            }).then(function (simulator) {
+                return common.collectRunningSimulatorsByVersion();
+            }).then(function (running) {
+                return running[install_target];
+            });
+        });
+    });
+};
+
+common.pushApp = function (client) {
+
+    var appPath = path.join(path.dirname(path.dirname(__dirname)), 'www');
+    var manifest = JSON.parse(fs.readFileSync(appPath + '/manifest.webapp'));
+
+    // TODO: replace most of this with node-firefox-push-app when it exists
+    // https://github.com/mozilla/node-firefox/issues/37
+    return findApp({
+        client: client,
+        manifest: manifest
+    }).then(function(apps) {
+        return Promise.all(apps.map(function (app) {
+          return uninstallApp({
+              client: client,
+              manifestURL: app.manifestURL
+          });
+        }));
+    }).then(function(uninstalled) {
+        return installApp({
+            client: client,
+            appPath: appPath
+        });
+    }).then(function(result) {
+        return findApp({
+            client: client,
+            manifest: manifest
+        });
+    }).then(function(apps) {
+        return launchApp({
+            client: client,
+            manifestURL: apps[0].manifestURL
+        });
+    });
+}
diff --git a/bin/templates/project/cordova/lib/install-device b/bin/templates/project/cordova/lib/install-device
new file mode 100755
index 0000000..115aadf
--- /dev/null
+++ b/bin/templates/project/cordova/lib/install-device
@@ -0,0 +1,69 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 path = require('path');
+
+var Promise = require('es6-promise').Promise;
+
+var common = require('./common');
+
+var findPorts = require('node-firefox-find-ports');
+var findDevices = require('node-firefox-find-devices');
+var forwardPorts = require('node-firefox-forward-ports');
+var connect = require('node-firefox-connect');
+
+var args = process.argv;
+var install_target;
+if(args.length > 2) {
+    if (args[2].substring(0, 9) == '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+     } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+     }
+}
+
+
+return forwardPorts([
+    { id: install_target }
+]).then(function() {
+    return findPorts({ firefoxOSDevice: true });
+}).then(function(ports) {
+
+    var targetPorts = ports.filter(function (port) {
+        return port.deviceId === install_target;
+    });
+    if (targetPorts.length === 0) {
+        throw new Error('Could not find device \'' + install_target + '\'.');
+    }
+    return connect(targetPorts[0].port);
+
+}).then(common.pushApp).then(function(result) {
+
+    process.exit(0);
+
+}).catch(function(err) {
+
+    console.error('ERROR: ' + err);
+    process.exit(2);
+
+});
diff --git a/bin/templates/project/cordova/lib/install-device.bat b/bin/templates/project/cordova/lib/install-device.bat
new file mode 100644
index 0000000..ac7214a
--- /dev/null
+++ b/bin/templates/project/cordova/lib/install-device.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you 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.
+
+@ECHO OFF
+SET script_path="%~dp0install-device"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'install-device' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/bin/templates/project/cordova/lib/install-emulator b/bin/templates/project/cordova/lib/install-emulator
new file mode 100755
index 0000000..c70720f
--- /dev/null
+++ b/bin/templates/project/cordova/lib/install-emulator
@@ -0,0 +1,58 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 path = require('path');
+
+var Promise = require('es6-promise').Promise;
+
+var common = require('./common');
+
+var findPorts = require('node-firefox-find-ports');
+var connect = require('node-firefox-connect');
+
+var args = process.argv;
+var install_target;
+if(args.length > 2) {
+    if (args[2].substring(0, 9) == '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+     } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+     }
+}
+
+common.findOrStartSimulatorTarget(install_target).then(function (simulator) {
+
+    var port = simulator.port;
+    console.log('Connecting to simulator on ' + port);
+    return connect(port);
+
+}).then(common.pushApp).then(function(result) {
+
+    process.exit(0);
+
+}).catch(function(err) {
+
+    console.error('ERROR: ' + err);
+    process.exit(2);
+
+});
diff --git a/bin/templates/project/cordova/lib/install-emulator.bat b/bin/templates/project/cordova/lib/install-emulator.bat
new file mode 100644
index 0000000..1ec6779
--- /dev/null
+++ b/bin/templates/project/cordova/lib/install-emulator.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you 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.
+
+@ECHO OFF
+SET script_path="%~dp0install-emulator"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'install-emulator' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/bin/templates/project/cordova/lib/list-devices b/bin/templates/project/cordova/lib/list-devices
new file mode 100755
index 0000000..902dca7
--- /dev/null
+++ b/bin/templates/project/cordova/lib/list-devices
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 common = require('./common');
+var findDevices = require('node-firefox-find-devices');
+
+findDevices().then(function (devices) {
+    devices.forEach(function (device) {
+        console.log(device.id);
+    });
+}).catch(function(err) {
+    console.error('ERROR: ' + err);
+    process.exit(2);
+});
diff --git a/bin/templates/project/cordova/lib/list-devices.bat b/bin/templates/project/cordova/lib/list-devices.bat
new file mode 100644
index 0000000..c0bcdd9
--- /dev/null
+++ b/bin/templates/project/cordova/lib/list-devices.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you 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.
+
+@ECHO OFF
+SET script_path="%~dp0list-devices"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'list-devices' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/bin/templates/project/cordova/lib/list-emulator-images b/bin/templates/project/cordova/lib/list-emulator-images
new file mode 100755
index 0000000..7b91fd4
--- /dev/null
+++ b/bin/templates/project/cordova/lib/list-emulator-images
@@ -0,0 +1,31 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 common = require('./common');
+
+common.collectSimulatorVersions().then(function (versions) {
+    versions.forEach(function (version) {
+        console.log(version);
+    });
+}).catch(function(err) {
+    console.error('ERROR: ' + err);
+    process.exit(2);
+});
diff --git a/bin/templates/project/cordova/lib/list-emulator-images.bat b/bin/templates/project/cordova/lib/list-emulator-images.bat
new file mode 100644
index 0000000..661cbf9
--- /dev/null
+++ b/bin/templates/project/cordova/lib/list-emulator-images.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you 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.
+
+@ECHO OFF
+SET script_path="%~dp0list-emulator-images"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
diff --git a/bin/templates/project/cordova/lib/list-started-emulators b/bin/templates/project/cordova/lib/list-started-emulators
new file mode 100755
index 0000000..53c6513
--- /dev/null
+++ b/bin/templates/project/cordova/lib/list-started-emulators
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 common = require('./common');
+
+common.collectRunningSimulatorsByVersion().then(function(running) {
+    for (var version in running) {
+        var simulator = running[version];
+        console.log([version, simulator.port, simulator.type, simulator.pid].join(' '));
+    }
+}).catch(function(err) {
+    console.error('ERROR: ' + err);
+    process.exit(2);
+});
diff --git a/bin/templates/project/cordova/lib/list-started-emulators.bat b/bin/templates/project/cordova/lib/list-started-emulators.bat
new file mode 100644
index 0000000..a4e88f7
--- /dev/null
+++ b/bin/templates/project/cordova/lib/list-started-emulators.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you 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.
+
+@ECHO OFF
+SET script_path="%~dp0list-started-emulators"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/bin/templates/project/cordova/lib/run.js b/bin/templates/project/cordova/lib/run.js
new file mode 100644
index 0000000..127023e
--- /dev/null
+++ b/bin/templates/project/cordova/lib/run.js
@@ -0,0 +1,140 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 shell = require('shelljs');
+
+exports.help = function(args) {
+    console.log('Usage: ' + path.relative(process.cwd(), args[1]) + ' [options]');
+    console.log('Deploy options :');
+    console.log('    --device : Will deploy the built project to a device');
+    console.log('    --emulator : Will deploy the built project to an emulator if one exists');
+    console.log('    --list : List available device and emulator target ids');
+    console.log('    --target=<target_id> : Installs to the target with the specified id.');
+    process.exit(0);
+}
+
+exports.run = function(args) {
+
+    var install_target = null;
+    var use_emulator = null;
+    var list = false;
+
+    for (var i=2; i<args.length; i++) {
+        if (args[i] == '--device') {
+            use_emulator = false;
+        } else if (args[i] == '--emulator') {
+            use_emulator = true;
+        } else if (/^--target=/.exec(args[i])) {
+            install_target = args[i].substring(9, args[i].length);
+        } else if (args[i] == '--list') {
+            list = true;
+        } else {
+            console.warn('Option \'' + args[i] + '\' not recognized (ignoring).');
+        }
+    }
+
+    try {
+
+        var devices = runHelperScript('list-devices');
+        var emulators = runHelperScript('list-emulator-images');
+
+        if (list) {
+            if (!install_target || install_target == '--emulator') {
+                console.log('Available Firefox OS Simulators:');
+                console.log(emulators.map(function(item) { return "\t" + item }).join("\n"));
+            }
+            if (!install_target || install_target == '--device') {
+                console.log('Available Firefox OS Devices:');
+                console.log(devices.map(function(item) { return "\t" + item }).join("\n"));
+            }
+            return;
+        }
+
+        if (install_target) {
+            
+            // We have an install target, so figure out if it's device or emulator.
+            if (emulators.indexOf(install_target) !== -1) {
+                use_emulator = true;
+            } else if (devices.indexOf(install_target) !== -1) {
+                use_emulator = false;
+            } else {
+                throw new Error('target \'' + install_target + '\' is neither a device nor an emulator'); 
+            }
+
+        } else {
+
+            // No explicit install target. If neither device nor emulator was
+            // called for specifically, we'll look for a device first and then
+            // fall back to an emulator. Otherwise, we'll limit looking for
+            // whichever was explictly called for.
+            
+            if ((use_emulator === null || use_emulator === false)) {
+                if (devices.length) {
+                    // Found a device, so use it as default target
+                    install_target = devices[devices.length - 1];
+                    use_emulator = false;
+                    console.log('WARNING : No target specified, deploying to device \'' + install_target + '\'.');
+                }
+            }
+
+            if ((use_emulator === null || use_emulator === true)) {
+                var running_emulators = runHelperScript('list-started-emulators');
+                if (running_emulators.length) {
+                    // Found a running emulator, so use it as default target.
+                    install_target = emulators[emulators.length - 1];
+                    use_emulator = true;
+                    console.log('WARNING : No target specified, deploying to running emulator \'' + install_target + '\'.');
+                } else if (emulators.length) {
+                    // Found an emulator, so use it as default target.
+                    install_target = emulators[emulators.length - 1];
+                    use_emulator = true;
+                    console.log('WARNING : No target specified, starting and deploying to emulator \'' + install_target + '\'.');
+                }
+            }
+
+        }
+
+        if (!install_target || use_emulator === null) {
+            // Something went wrong in the selection process above, and we have
+            // no installation target.
+            throw new Error('no installation target could be found');
+        }
+        
+        var install_script = use_emulator ? 'install-emulator' : 'install-device';
+        console.log(runHelperScript(install_script + ' --target=' + install_target, true));
+
+    } catch (err) {
+        console.error('' + err);
+    }
+
+}
+
+function runHelperScript(script, skipParse) {
+    var result = shell.exec(path.join(__dirname, script), {silent:true});
+    if (result.code !== 0) {
+        throw new Error(script + ' failed with exit code ' + result.code + ' - ' + result.output);
+    }
+    if (skipParse) {
+        return result.output;
+    }
+    return result.output.split(/\n/)
+        .filter(function(line) { return line != ''; })
+        .map(function(line) { return line.split(/\s/)[0]; });
+}
diff --git a/bin/templates/project/cordova/lib/start-emulator b/bin/templates/project/cordova/lib/start-emulator
new file mode 100755
index 0000000..f40bd25
--- /dev/null
+++ b/bin/templates/project/cordova/lib/start-emulator
@@ -0,0 +1,43 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 common = require('./common');
+
+var args = process.argv;
+
+var install_target;
+if(args.length > 2) {
+    if (args[2].substring(0, 9) == '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+     } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+     }
+}
+
+common.findOrStartSimulatorTarget(install_target).then(function(simulator) {
+    console.log(simulator.port + 
+                " FirefoxOS simulator running, PID " + simulator.pid);
+    process.exit(0);
+}).catch(function(err) {
+    console.error('ERROR: ' + err);
+    process.exit(2);
+});
diff --git a/bin/templates/project/cordova/lib/start-emulator.bat b/bin/templates/project/cordova/lib/start-emulator.bat
new file mode 100644
index 0000000..9329d95
--- /dev/null
+++ b/bin/templates/project/cordova/lib/start-emulator.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you 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.
+
+@ECHO OFF
+SET script_path="%~dp0start-emulator"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/bin/templates/project/cordova/run b/bin/templates/project/cordova/run
index 7b8e621..8ea228c 100755
--- a/bin/templates/project/cordova/run
+++ b/bin/templates/project/cordova/run
@@ -1,20 +1,31 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
+#!/usr/bin/env node
 
-echo "run not implemented, please use firefoxos simulator to launch app"
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 run  = require('./lib/run'),
+    args = process.argv;
+
+// Support basic help commands
+if (args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
+                    args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
+    run.help(args);
+} else {
+    run.run(args);
+}
diff --git a/bin/templates/project/cordova/run.bat b/bin/templates/project/cordova/run.bat
new file mode 100644
index 0000000..56c5296
--- /dev/null
+++ b/bin/templates/project/cordova/run.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you 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.
+
+@ECHO OFF
+SET script_path="%~dp0run"
+IF EXIST %script_path% (
+	node %script_path% %*
+) ELSE (
+	ECHO.
+    ECHO ERROR: Could not find 'run' script in 'cordova' folder, aborting...>&2
+    EXIT /B 1
+)