diff --git a/.gitignore b/.gitignore
index e51ebc5468..8fe91862fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 .swp
 build
 dist
+installer
 node_modules
 coverage
 npm-debug.log
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000000..062ff65461
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,281 @@
+var path = require('path');
+var execFile = require('child_process').execFile;
+var packagejson = require('./package.json');
+var electron = require('electron-prebuilt');
+
+var WINDOWS_DOCKER_URL = 'https://get.docker.com/builds/Windows/x86_64/docker-1.6.2.exe';
+var DARWIN_DOCKER_URL = 'https://get.docker.com/builds/Darwin/x86_64/docker-' + packagejson['docker-version'];
+var WINDOWS_DOCKER_MACHINE_URL = 'https://github.com/docker/machine/releases/download/v' + packagejson['docker-machine-version'] + '/docker-machine_windows-amd64.exe';
+var DARWIN_DOCKER_MACHINE_URL = 'https://github.com/docker/machine/releases/download/v' + packagejson['docker-machine-version'] + '/docker-machine_darwin-amd64';
+var DARWIN_COMPOSE_URL = 'https://github.com/docker/compose/releases/download/' + packagejson['docker-compose-version'] + '/docker-compose-Darwin-x86_64';
+var BOOT2DOCKER_ISO_URL = 'https://github.com/boot2docker/boot2docker/releases/download/v' + packagejson['docker-version'] + '/boot2docker.iso';
+
+module.exports = function (grunt) {
+  require('load-grunt-tasks')(grunt);
+  var target = grunt.option('target') || 'development';
+  var beta = grunt.option('beta') || false;
+  var env = process.env;
+  env.NODE_PATH = '..:' + env.NODE_PATH;
+  env.NODE_ENV = target;
+
+  var version = function (str) {
+    var match = str.match(/(\d+\.\d+\.\d+)/);
+    return match ? match[1] : null;
+  };
+
+  grunt.registerMultiTask('download-binary', 'Downloads binary unless version up to date', function () {
+    var target = grunt.task.current.target;
+    var done = this.async();
+    var config = grunt.config('download-binary')[target];
+    execFile(config.binary, ['--version'], function (err, stdout) {
+      var currentVersion = version(stdout);
+      if (!currentVersion || currentVersion !== version(config.version)) {
+        grunt.task.run('curl:' + target);
+        grunt.task.run('chmod');
+      }
+      done();
+    });
+  });
+
+  var APPNAME = beta ? 'Kitematic (Beta)' : 'Kitematic';
+  var OSX_OUT = './dist/osx';
+  var OSX_FILENAME = OSX_OUT + '/' + APPNAME + '.app';
+
+  grunt.initConfig({
+    IDENTITY: 'Developer ID Application: Docker Inc',
+    APPNAME: APPNAME,
+    OSX_OUT: OSX_OUT,
+    OSX_FILENAME: OSX_FILENAME,
+    OSX_FILENAME_ESCAPED: OSX_FILENAME.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)'),
+
+    // electron
+    electron: {
+      windows: {
+        options: {
+          name: '<%= APPNAME %>',
+          dir: 'build/',
+          out: 'dist/',
+          version: packagejson['electron-version'],
+          platform: 'win32',
+          arch: 'x64',
+          asar: true,
+          icon: 'util/kitematic.ico'
+        }
+      },
+      osx: {
+        options: {
+          name: '<%= APPNAME %>',
+          dir: 'build/',
+          out: '<%= OSX_OUT %>',
+          version: packagejson['electron-version'],
+          platform: 'darwin',
+          arch: 'x64',
+          asar: true,
+          'app-bundle-id': 'com.kitematic.kitematic'
+        }
+      }
+    },
+
+    'create-windows-installer': {
+      appDirectory: 'dist/Kitematic-win32/',
+      authors: 'Docker Inc.',
+      loadingGif: 'util/loading.gif',
+      setupIcon: 'util/kitematic.ico'
+    },
+
+    // docker binaries
+    'download-binary': {
+      docker: {
+        version: packagejson['docker-version'],
+        binary: path.join('resources', 'docker'),
+        download: 'curl:docker'
+      },
+      'docker-machine': {
+        version: packagejson['docker-machine-version'],
+        binary: path.join('resources', 'docker-machine'),
+        download: 'curl:docker-machine'
+      }
+    },
+
+    // images
+    copy: {
+      dev: {
+        files: [{
+          expand: true,
+          cwd: '.',
+          src: ['package.json', 'settings.json', 'index.html'],
+          dest: 'build/'
+        }, {
+          expand: true,
+          cwd: 'images/',
+          src: ['**/*'],
+          dest: 'build/'
+        }, {
+          expand: true,
+          cwd: 'fonts/',
+          src: ['**/*'],
+          dest: 'build/'
+        }, {
+          cwd: 'node_modules/',
+          src: Object.keys(packagejson.dependencies).map(function (dep) { return dep + '/**/*';}),
+          dest: 'build/node_modules/',
+          expand: true
+        }]
+      },
+      windows: {
+        files: [{
+          expand: true,
+          cwd: 'resources',
+          src: ['docker*'],
+          dest: 'dist/Kitematic-win32/resources/resources/'
+        }],
+        options: {
+          mode: true
+        }
+      },
+      osx: {
+        files: [{
+          expand: true,
+          cwd: 'resources',
+          src: ['**/*'],
+          dest: '<%= OSX_FILENAME %>/Contents/Resources/resources/'
+        }, {
+          src: 'util/kitematic.icns',
+          dest: '<%= OSX_FILENAME %>/Contents/Resources/atom.icns'
+        }],
+        options: {
+          mode: true
+        }
+      }
+    },
+
+    rename: {
+      installer: {
+        src: 'installer/Setup.exe',
+        dest: 'installer/KitematicSetup.exe'
+      }
+    },
+
+    // download binaries
+    curl: {
+      docker: {
+        src: process.platform === 'win32' ? WINDOWS_DOCKER_URL : DARWIN_DOCKER_URL,
+        dest: process.platform === 'win32' ? path.join('resources', 'docker.exe') : path.join('resources', 'docker')
+      },
+      'docker-machine': {
+        src: process.platform === 'win32' ? WINDOWS_DOCKER_MACHINE_URL : DARWIN_DOCKER_MACHINE_URL,
+        dest: process.platform === 'win32' ? path.join('resources', 'docker-machine.exe') : path.join('resources', 'docker-machine')
+      },
+      'docker-compose': {
+        src: DARWIN_COMPOSE_URL,
+        dest: 'resources/docker-compose'
+      },
+      'boot2docker-iso': {
+        src: BOOT2DOCKER_ISO_URL,
+        dest: path.join('resources', 'boot2docker-' + packagejson['docker-version'])
+      }
+    },
+
+    chmod: {
+      binaries: {
+        options: {
+          mode: '755'
+        },
+        src: ['resources/docker*']
+      }
+    },
+
+    // styles
+    less: {
+      options: {
+        sourceMapFileInline: true
+      },
+      dist: {
+        files: {
+          'build/main.css': 'styles/main.less'
+        }
+      }
+    },
+
+    // javascript
+    babel: {
+      options: {
+        sourceMap: 'inline',
+        blacklist: 'regenerator'
+      },
+      dist: {
+        files: [{
+          expand: true,
+          cwd: 'src/',
+          src: ['**/*.js'],
+          dest: 'build/',
+        }]
+      }
+    },
+
+    shell: {
+      electron: {
+        command: electron + ' ' + 'build',
+        options: {
+          async: true,
+          execOptions: {
+            env: env
+          }
+        }
+      },
+      sign: {
+        options: {
+          failOnError: false,
+        },
+        command: [
+          'codesign --deep -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>/Contents/Frameworks/*',
+          'codesign -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>',
+          'codesign -vvv --display <%= OSX_FILENAME_ESCAPED %>',
+          'codesign -v --verify <%= OSX_FILENAME_ESCAPED %>',
+        ].join(' && '),
+      },
+      zip: {
+        command: 'ditto -c -k --sequesterRsrc --keepParent <%= OSX_FILENAME_ESCAPED %> <%= OSX_OUT %>/Kitematic-' + packagejson.version + '.zip',
+      }
+    },
+
+    clean: {
+      release: ['build/', 'dist/', 'installer/'],
+    },
+
+    // livereload
+    watchChokidar: {
+      options: {
+        spawn: true
+      },
+      livereload: {
+        options: {livereload: true},
+        files: ['build/**/*']
+      },
+      js: {
+        files: ['src/**/*.js'],
+        tasks: ['newer:babel']
+      },
+      less: {
+        files: ['styles/**/*.less'],
+        tasks: ['newer:less']
+      },
+      copy: {
+        files: ['images/*', 'index.html', 'fonts/*'],
+        tasks: ['newer:copy:dev']
+      }
+    }
+  });
+  grunt.registerTask('default', ['download-binary', 'newer:babel', 'newer:less', 'newer:copy:dev', 'shell:electron', 'watchChokidar']);
+
+  if (process.platform === 'win32') {
+    grunt.registerTask('release', ['clean', 'download-binary', 'babel', 'less', 'copy:dev', 'electron:windows', 'copy:windows', 'create-windows-installer', 'rename:installer']);
+  } else {
+    grunt.registerTask('release', ['clean:dist', 'clean:build', 'download-binary', 'babel', 'less', 'copy:dev', 'electron:osx', 'copy:osx', 'shell:sign', 'shell:zip']);
+  }
+
+  process.on('SIGINT', function () {
+    grunt.task.run(['shell:electron:kill']);
+    process.exit(1);
+  });
+};
diff --git a/package.json b/package.json
index a2ee190495..f77fa685af 100644
--- a/package.json
+++ b/package.json
@@ -14,8 +14,8 @@
     "start": "gulp",
     "test": "jest -c jest-unit.json",
     "integration": "jest -c jest-integration.json",
-    "release": "gulp release",
-    "release:beta": "gulp release --beta",
+    "release": "grunt release",
+    "release:beta": "grunt release --beta=true",
     "lint": "jsxhint src",
     "reset": "gulp reset"
   },
@@ -67,25 +67,30 @@
   "devDependencies": {
     "babel": "^5.1.10",
     "babel-jest": "^5.2.0",
-    "gulp": "^3.8.11",
-    "gulp-babel": "^5.1.0",
-    "gulp-changed": "^1.2.1",
-    "gulp-concat": "^2.5.2",
-    "gulp-cssmin": "^0.1.6",
-    "gulp-download-electron": "^0.0.5",
-    "gulp-if": "^1.2.5",
-    "gulp-insert": "^0.4.0",
-    "gulp-less": "^3.0.2",
-    "gulp-livereload": "^3.8.0",
-    "gulp-plumber": "^1.0.0",
-    "gulp-shell": "^0.4.1",
-    "gulp-sourcemaps": "^1.5.2",
-    "gulp-util": "^3.0.4",
+    "electron-prebuilt": "^0.27.3",
+    "grunt": "^0.4.5",
+    "grunt-babel": "^5.0.1",
+    "grunt-chmod": "^1.0.3",
+    "grunt-cli": "^0.1.13",
+    "grunt-contrib-clean": "^0.6.0",
+    "grunt-contrib-copy": "^0.8.0",
+    "grunt-contrib-less": "^1.0.1",
+    "grunt-contrib-watch-chokidar": "^1.0.0",
+    "grunt-curl": "^2.2.0",
+    "grunt-download-electron": "^2.1.1",
+    "grunt-electron": "^1.0.0",
+    "grunt-electron-installer": "^0.33.0",
+    "grunt-newer": "^1.1.1",
+    "grunt-rename": "^0.1.4",
+    "grunt-shell": "^1.1.2",
+    "grunt-shell-spawn": "^0.3.8",
     "jest-cli": "^0.4.5",
     "jsxhint": "^0.14.0",
+    "load-grunt-tasks": "^3.2.0",
     "minimist": "^1.1.1",
     "react-tools": "^0.13.1",
     "run-sequence": "^1.0.2",
+    "shell-escape": "^0.2.0",
     "source-map-support": "^0.2.10"
   }
 }
diff --git a/src/browser.js b/src/browser.js
index a9f087e7c8..bc0979d16b 100644
--- a/src/browser.js
+++ b/src/browser.js
@@ -5,9 +5,8 @@ var fs = require('fs');
 var ipc = require('ipc');
 var path = require('path');
 
-process.env.NODE_PATH = path.join(__dirname, '/../node_modules');
+process.env.NODE_PATH = path.join(__dirname, 'node_modules');
 process.env.RESOURCES_PATH = path.join(__dirname, '/../resources');
-process.chdir(path.join(__dirname, '..'));
 process.env.PATH = '/usr/local/bin:' + process.env.PATH;
 
 var size = {}, settingsjson = {};
@@ -15,9 +14,49 @@ try {
   size = JSON.parse(fs.readFileSync(path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], 'Library', 'Application\ Support', 'Kitematic', 'size')));
 } catch (err) {}
 try {
-  settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
+  settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, 'settings.json'), 'utf8'));
 } catch (err) {}
 
+var handleStartupEvent = function() {
+  if (process.platform !== 'win32') {
+    return false;
+  }
+
+  var squirrelCommand = process.argv[1];
+  switch (squirrelCommand) {
+    case '--squirrel-install':
+    case '--squirrel-updated':
+
+      // Optionally do things such as:
+      //
+      // - Install desktop and start menu shortcuts
+      // - Add your .exe to the PATH
+      // - Write to the registry for things like file associations and
+      //   explorer context menus
+
+      // Always quit when done
+      app.quit();
+
+      return true;
+    case '--squirrel-uninstall':
+      // Undo anything you did in the --squirrel-install and
+      // --squirrel-updated handlers
+
+      // Always quit when done
+      app.quit();
+
+      return true;
+    case '--squirrel-obsolete':
+      // This is called on the outgoing version of your app before
+      // we update to the new version - it's the opposite of
+      // --squirrel-updated
+      app.quit();
+      return true;
+  }
+};
+
+handleStartupEvent();
+
 var openURL = null;
 app.on('open-url', function (event, url) {
   event.preventDefault();
@@ -36,7 +75,7 @@ app.on('ready', function () {
     show: false,
   });
 
-  mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/index.html')));
+  mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, 'index.html')));
 
   app.on('activate-with-no-open-windows', function () {
     if (mainWindow) {
@@ -52,7 +91,8 @@ app.on('ready', function () {
   });
 
   app.on('before-quit', function () {
-    if (!updating) {
+    // TODO: make this work for right click + close
+    if (!updating && mainWindow.webContents) {
       mainWindow.webContents.send('application:quitting');
     }
   });
diff --git a/src/components/ContainerDetailsSubheader.react.js b/src/components/ContainerDetailsSubheader.react.js
index f0cedecc95..e4793d6d5b 100644
--- a/src/components/ContainerDetailsSubheader.react.js
+++ b/src/components/ContainerDetailsSubheader.react.js
@@ -1,13 +1,18 @@
+var $ = require('jquery');
 var _ = require('underscore');
 var React = require('react');
 var exec = require('exec');
 var shell = require('shell');
 var metrics = require('../utils/MetricsUtil');
 var ContainerUtil = require('../utils/ContainerUtil');
+var util = require('../utils/Util');
 var machine = require('../utils/DockerMachineUtil');
+var RetinaImage = require('react-retina-image');
 var classNames = require('classnames');
 var resources = require('../utils/ResourcesUtil');
+var dockerUtil = require('../utils/DockerUtil');
 var containerActions = require('../actions/ContainerActions');
+var dockerMachineUtil = require('../utils/DockerMachineUtil');
 
 var ContainerDetailsSubheader = React.createClass({
   contextTypes: {
@@ -101,15 +106,7 @@ var ContainerDetailsSubheader = React.createClass({
       if(!shell) {
         shell = 'sh';
       }
-      machine.ip().then(ip => {
-        var cmd = [resources.terminal(), 'ssh', '-p', '22', '-o', 'UserKnownHostsFile=/dev/null', '-o', 'LogLevel=quiet', '-o', 'StrictHostKeyChecking=no', '-i', '~/.docker/machine/machines/' + machine.name() + '/id_rsa', 'docker@' + ip, '-t', 'docker', 
-          'exec', '-i', '-t', container.Name, shell];
-        exec(cmd, function (stderr, stdout, code) {
-          if (code) {
-            console.log(stderr);
-          }
-        });
-      });
+      dockerMachineUtil.dockerTerminal(`docker exec -it ${this.props.container.Name} ${shell}`);
     }
   },
   render: function () {
diff --git a/src/components/ContainerHomeFolders.react.js b/src/components/ContainerHomeFolders.react.js
index e2fbf89e78..f2b9912684 100644
--- a/src/components/ContainerHomeFolders.react.js
+++ b/src/components/ContainerHomeFolders.react.js
@@ -29,12 +29,7 @@ var ContainerHomeFolder = React.createClass({
           volumes[containerVolume] = newHostVolume;
           var binds = _.pairs(volumes).map(function (pair) {
             if(util.isWindows()) {
-              var home = util.home();
-              home = home.charAt(0).toLowerCase() + home.slice(1);
-              home = '/' + home.replace(':', '').replace(/\\/g, '/');
-              var fullPath = path.join(home, 'Kitematic', pair[1], pair[0]);
-              fullPath = fullPath.replace(/\\/g, '/');
-              return fullPath + ':' + pair[0];
+             return util.windowsToLinuxPath(pair[1]) + ':' + pair[0];
             }
             return pair[1] + ':' + pair[0];
           });
diff --git a/src/components/ContainerSettingsVolumes.react.js b/src/components/ContainerSettingsVolumes.react.js
index b1b828b686..fe2572eae7 100644
--- a/src/components/ContainerSettingsVolumes.react.js
+++ b/src/components/ContainerSettingsVolumes.react.js
@@ -3,6 +3,7 @@ var React = require('react/addons');
 var remote = require('remote');
 var dialog = remote.require('dialog');
 var shell = require('shell');
+var util = require('../utils/Util');
 var metrics = require('../utils/MetricsUtil');
 var containerActions = require('../actions/ContainerActions');
 
@@ -15,7 +16,10 @@ var ContainerSettingsVolumes = React.createClass({
       }
       var directory = filenames[0];
       if (directory) {
-        metrics.track('Chose Directory for Volume');
+        metrics.track('Choose Directory for Volume');
+        if(util.isWindows()) {
+             directory = util.windowsToLinuxPath(directory);
+        }
         var volumes = _.clone(self.props.container.Volumes);
         volumes[dockerVol] = directory;
         var binds = _.pairs(volumes).map(function (pair) {
@@ -47,6 +51,7 @@ var ContainerSettingsVolumes = React.createClass({
     if (!this.props.container) {
       return false;
     }
+
     var volumes = _.map(this.props.container.Volumes, (val, key) => {
       if (!val || val.indexOf(process.env.HOME) === -1) {
         val = (
diff --git a/src/components/Containers.react.js b/src/components/Containers.react.js
index 449afb4835..521001629a 100644
--- a/src/components/Containers.react.js
+++ b/src/components/Containers.react.js
@@ -6,6 +6,7 @@ var containerStore = require('../stores/ContainerStore');
 var ContainerList = require('./ContainerList.react');
 var Header = require('./Header.react');
 var metrics = require('../utils/MetricsUtil');
+var RetinaImage = require('react-retina-image');
 var shell = require('shell');
 var machine = require('../utils/DockerMachineUtil');
 
diff --git a/src/stores/SetupStore.js b/src/stores/SetupStore.js
index 588d2c07e8..7c99a0ff64 100644
--- a/src/stores/SetupStore.js
+++ b/src/stores/SetupStore.js
@@ -42,14 +42,14 @@ var _steps = [{
       progressCallback(50); // TODO: detect when the installation has started so we can simulate progress
       try {
         if (util.isWindows()) {
-          yield util.exec([path.join(util.supportDir(), virtualBox.filename())]);
+          yield util.exec([path.join(util.supportDir(), virtualBox.filename()), '-msiparams', 'REBOOT=ReallySuppress', 'LIMITUI=INSTALLUILEVEL_PROGRESSONLY']);
         } else {
           yield util.exec(setupUtil.macSudoCmd(setupUtil.installVirtualBoxCmd()));
         }
       } catch (err) {
         throw null;
       }
-    } else if (!virtualBox.active()) {
+    } else if (util.isWindows() && !virtualBox.active()) {
       yield util.exec(setupUtil.macSudoCmd(util.escapePath('/Library/Application Support/VirtualBox/LaunchDaemons/VirtualBoxStartup.sh') + ' restart'));
     }
   })
@@ -59,7 +59,7 @@ var _steps = [{
   message: 'To run Docker containers on your computer, Kitematic is starting a Linux virtual machine. This may take a minute...',
   totalPercent: 60,
   percent: 0,
-  seconds: 72,
+  seconds: 80,
   run: Promise.coroutine(function* (progressCallback) {
     setupUtil.simulateProgress(this.seconds, progressCallback);
     var exists = yield machine.exists();
@@ -68,16 +68,6 @@ var _steps = [{
         yield machine.rm();
       }
       yield machine.create();
-      if(util.isWindows()) {
-        let home = util.home();
-        let driveLetter = home.charAt(0);
-        let parts = home.split('\\').slice(0, -1);
-        let usersDirName = parts[parts.length-1];
-        let usersDirPath = parts.join('\\');
-        let shareName = driveLetter + '/' + usersDirName;
-        yield virtualBox.mountSharedDir(machine.name(), shareName, usersDirPath);
-        yield machine.start();
-      }
       return;
     }
 
@@ -159,7 +149,7 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
     var vboxNeedsInstall = !virtualBox.installed();
 
     required.download = vboxNeedsInstall && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== virtualBox.checksum());
-    required.install = vboxNeedsInstall || !virtualBox.active();
+    required.install = vboxNeedsInstall || (util.isWindows() && !virtualBox.active());
     required.init = required.install || !(yield machine.exists()) || (yield machine.state()) !== 'Running' || !isoversion || util.compareVersions(isoversion, packagejson['docker-version']) < 0;
 
     var exists = yield machine.exists();
diff --git a/src/utils/DockerMachineUtil.js b/src/utils/DockerMachineUtil.js
index 0875882d5c..37532dc690 100644
--- a/src/utils/DockerMachineUtil.js
+++ b/src/utils/DockerMachineUtil.js
@@ -153,14 +153,23 @@ var DockerMachine = {
       });
     });
   },
-  dockerTerminal: function () {
+  dockerTerminal: function (cmd) {
     if(util.isWindows()) {
+      cmd = cmd || '';
       this.info().then(machine => {
-        util.execProper(`start cmd.exe /k "SET DOCKER_HOST=${machine.url}&& SET DOCKER_CERT_PATH=${path.join(util.home(), '.docker/machine/machines/' + machine.name)}&& SET DOCKER_TLS_VERIFY=1`);
+        util.exec('start powershell.exe ' + cmd,
+          {env: {
+            'DOCKER_HOST' : machine.url,
+            'DOCKER_CERT_PATH' : path.join(util.home(), '.docker/machine/machines/' + machine.name),
+            'DOCKER_TLS_VERIFY': 1,
+            'PATH': resources.resourceDir()
+          }
+        });
       });
     } else {
+      cmd = cmd || '$SHELL';
       this.info().then(machine => {
-        var cmd = [resources.terminal(), `DOCKER_HOST=${machine.url} DOCKER_CERT_PATH=${path.join(util.home(), '.docker/machine/machines/' + machine.name)} DOCKER_TLS_VERIFY=1 $SHELL`];
+        var cmd = [resources.terminal(), `DOCKER_HOST=${machine.url} DOCKER_CERT_PATH=${path.join(util.home(), '.docker/machine/machines/' + machine.name)} DOCKER_TLS_VERIFY=1 ${cmd}`];
         util.exec(cmd).then(() => {});
       });
     }
diff --git a/src/utils/MetricsUtil.js b/src/utils/MetricsUtil.js
index e7083989fd..8b19edfbd0 100644
--- a/src/utils/MetricsUtil.js
+++ b/src/utils/MetricsUtil.js
@@ -7,7 +7,7 @@ var util = require('./Util');
 var settings;
 
 try {
-  settings = JSON.parse(fs.readFileSync(path.join(__dirname, '../..', 'settings.json'), 'utf8'));
+  settings = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
 } catch (err) {
   settings = {};
 }
diff --git a/src/utils/RegHubUtil.js b/src/utils/RegHubUtil.js
index bb7b1f5734..cf00640249 100644
--- a/src/utils/RegHubUtil.js
+++ b/src/utils/RegHubUtil.js
@@ -5,6 +5,7 @@ var util = require('../utils/Util');
 var hubUtil = require('../utils/HubUtil');
 var repositoryServerActions = require('../actions/RepositoryServerActions');
 var tagServerActions = require('../actions/TagServerActions');
+var Promise = require('bluebird');
 
 let REGHUB2_ENDPOINT = process.env.REGHUB2_ENDPOINT || 'https://registry.hub.docker.com/v2';
 let searchReq = null;
@@ -61,7 +62,7 @@ module.exports = {
       let data = JSON.parse(body);
       let repos = data.repos;
       async.map(repos, (repo, cb) => {
-        var name = repo.repo;
+        let name = repo.repo;
         if (util.isOfficialRepo(name)) {
           name = 'library/' + name;
         }
diff --git a/src/utils/Util.js b/src/utils/Util.js
index 47d54b16f4..4566025bf5 100644
--- a/src/utils/Util.js
+++ b/src/utils/Util.js
@@ -1,4 +1,5 @@
 var exec = require('exec');
+var child_process = require('child_process');
 var Promise = require('bluebird');
 var fs = require('fs');
 var path = require('path');
@@ -9,11 +10,12 @@ var app = remote.require('app');
 module.exports = {
   exec: function (args, options) {
     options = options || {};
+    let fn = Array.isArray(args) ? exec : child_process.exec;
     return new Promise((resolve, reject) => {
-      exec(args, options, (stderr, stdout, code) => {
+      fn(args, options, (stderr, stdout, code) => {
         if (code) {
           var cmd = Array.isArray(args) ? args.join(' ') : args;
-          reject(new Error(cmd + ' returned non zero exit code.\n===== Stderr =====\n ' + stderr + '\n===== Stdout =====\n' + stdout));
+          reject(new Error(cmd + ' returned non zero exit code. Stderr: ' + stderr));
         } else {
           resolve(stdout);
         }
@@ -59,12 +61,12 @@ module.exports = {
       .replace(/\/Users\/[^\/]*\//mg, '/Users/<redacted>/');
   },
   packagejson: function () {
-    return JSON.parse(fs.readFileSync(path.join(__dirname, '../..', 'package.json'), 'utf8'));
+    return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
   },
   settingsjson: function () {
     var settingsjson = {};
     try {
-      settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../..', 'settings.json'), 'utf8'));
+      settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
     } catch (err) {}
     return settingsjson;
   },
@@ -132,5 +134,12 @@ module.exports = {
   randomId: function () {
     return crypto.randomBytes(32).toString('hex');
   },
+  windowsToLinuxPath: function(windowsAbsPath) {
+    var fullPath = windowsAbsPath.replace(':', '').split(path.sep).join('/');
+    if(fullPath.charAt(0) !== '/'){
+      fullPath = '/' + fullPath.charAt(0).toLowerCase() + fullPath.substring(1);
+    }
+    return fullPath;
+  },
   webPorts: ['80', '8000', '8080', '3000', '5000', '2368', '9200', '8983']
 };
diff --git a/util/kitematic.ico b/util/kitematic.ico
new file mode 100644
index 0000000000..ec7dab48ab
Binary files /dev/null and b/util/kitematic.ico differ
diff --git a/util/loading.gif b/util/loading.gif
new file mode 100644
index 0000000000..3f6d3b671a
Binary files /dev/null and b/util/loading.gif differ