(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*
   * CommonJS module that exports EventSource polyfill version 0.9.6
   * This module is intended for browser side use
   * =====================================================================
   * THIS IS A POLYFILL MODULE, SO IT HAS SIDE EFFECTS
   * IT AUTOMATICALLY CHECKS IF window OBJECT DEFINES EventSource
   * AND ADD THE EXPORTED ONE IN CASE IT IS UNDEFINED
   * =====================================================================
   * Supported by sc AmvTek srl
   * :email: devel@amvtek.com
 */


var PolyfillEventSource = require('./eventsource.js').EventSource;
module.exports = PolyfillEventSource;

// Add EventSource to window if it is missing...
if (window && !window.EventSource){
    window.EventSource = PolyfillEventSource;
    if (console){
	console.log("polyfill-eventsource added missing EventSource to window");
    }
}

},{"./eventsource.js":2}],2:[function(require,module,exports){
/*
   * EventSource polyfill version 0.9.6
   * Supported by sc AmvTek srl
   * :email: devel@amvtek.com
 */
;(function (global) {

    if (global.EventSource && !global._eventSourceImportPrefix){
        return;
    }

    var evsImportName = (global._eventSourceImportPrefix||'')+"EventSource";

    var EventSource = function (url, options) {

        if (!url || typeof url != 'string') {
            throw new SyntaxError('Not enough arguments');
        }

        this.URL = url;
        this.setOptions(options);
        var evs = this;
        setTimeout(function(){evs.poll()}, 0);
    };

    EventSource.prototype = {

        CONNECTING: 0,

        OPEN: 1,

        CLOSED: 2,

        defaultOptions: {

            loggingEnabled: false,

            loggingPrefix: "eventsource",

            interval: 500, // milliseconds

            bufferSizeLimit: 256*1024, // bytes

            silentTimeout: 300000, // milliseconds

            getArgs:{
                'evs_buffer_size_limit': 256*1024
            },

            xhrHeaders:{
                'Accept': 'text/event-stream',
                'Cache-Control': 'no-cache',
                'X-Requested-With': 'XMLHttpRequest'
            }
        },

        setOptions: function(options){

            var defaults = this.defaultOptions;
            var option;

            // set all default options...
            for (option in defaults){

                if ( defaults.hasOwnProperty(option) ){
                    this[option] = defaults[option];
                }
            }

            // override with what is in options
            for (option in options){

                if (option in defaults && options.hasOwnProperty(option)){
                    this[option] = options[option];
                }
            }

            // if getArgs option is enabled
            // ensure evs_buffer_size_limit corresponds to bufferSizeLimit
            if (this.getArgs && this.bufferSizeLimit) {

                this.getArgs['evs_buffer_size_limit'] = this.bufferSizeLimit;
            }

            // if console is not available, force loggingEnabled to false
            if (typeof console === "undefined" || typeof console.log === "undefined") {

                this.loggingEnabled = false;
            }
        },

        log: function(message) {

            if (this.loggingEnabled) {

                console.log("[" + this.loggingPrefix +"]:" + message)
            }
        },

        poll: function() {

            try {

                if (this.readyState == this.CLOSED) {
                    return;
                }

                this.cleanup();
                this.readyState = this.CONNECTING;
                this.cursor = 0;
                this.cache = '';
                this._xhr = new this.XHR(this);
                this.resetNoActivityTimer();

            }
            catch (e) {

                // in an attempt to silence the errors
                this.log('There were errors inside the pool try-catch');
                this.dispatchEvent('error', { type: 'error', data: e.message });
            }
        },

        pollAgain: function (interval) {

            // schedule poll to be called after interval milliseconds
            var evs = this;
            evs.readyState = evs.CONNECTING;
            evs.dispatchEvent('error', {
                type: 'error',
                data: "Reconnecting "
            });
            this._pollTimer = setTimeout(function(){evs.poll()}, interval||0);
        },


        cleanup: function() {

            this.log('evs cleaning up')

            if (this._pollTimer){
                clearInterval(this._pollTimer);
                this._pollTimer = null;
            }

            if (this._noActivityTimer){
                clearInterval(this._noActivityTimer);
                this._noActivityTimer = null;
            }

            if (this._xhr){
                this._xhr.abort();
                this._xhr = null;
            }
        },

        resetNoActivityTimer: function(){

            if (this.silentTimeout){

                if (this._noActivityTimer){
                    clearInterval(this._noActivityTimer);
                }
                var evs = this;
                this._noActivityTimer = setTimeout(
                        function(){ evs.log('Timeout! silentTImeout:'+evs.silentTimeout); evs.pollAgain(); },
                        this.silentTimeout
                        );
            }
        },

        close: function () {

            this.readyState = this.CLOSED;
            this.log('Closing connection. readyState: '+this.readyState);
            this.cleanup();
        },

        ondata: function() {

            var request = this._xhr;

            if (request.isReady() && !request.hasError() ) {
                // reset the timer, as we have activity
                this.resetNoActivityTimer();

                // move this EventSource to OPEN state...
                if (this.readyState == this.CONNECTING) {
                    this.readyState = this.OPEN;
                    this.dispatchEvent('open', { type: 'open' });
                }

                var buffer = request.getBuffer();

                if (buffer.length > this.bufferSizeLimit) {
                    this.log('buffer.length > this.bufferSizeLimit');
                    this.pollAgain();
                }

                if (this.cursor == 0 && buffer.length > 0){

                    // skip byte order mark \uFEFF character if it starts the stream
                    if (buffer.substring(0,1) == '\uFEFF'){
                        this.cursor = 1;
                    }
                }

                var lastMessageIndex = this.lastMessageIndex(buffer);
                if (lastMessageIndex[0] >= this.cursor){

                    var newcursor = lastMessageIndex[1];
                    var toparse = buffer.substring(this.cursor, newcursor);
                    this.parseStream(toparse);
                    this.cursor = newcursor;
                }

                // if request is finished, reopen the connection
                if (request.isDone()) {
                    this.log('request.isDone(). reopening the connection');
                    this.pollAgain(this.interval);
                }
            }
            else if (this.readyState !== this.CLOSED) {

                this.log('this.readyState !== this.CLOSED');
                this.pollAgain(this.interval);

                //MV: Unsure why an error was previously dispatched
            }
        },

        parseStream: function(chunk) {

            // normalize line separators (\r\n,\r,\n) to \n
            // remove white spaces that may precede \n
            chunk = this.cache + this.normalizeToLF(chunk);

            var events = chunk.split('\n\n');

            var i, j, eventType, datas, line, retry;

            for (i=0; i < (events.length - 1); i++) {

                eventType = 'message';
                datas = [];
                parts = events[i].split('\n');

                for (j=0; j < parts.length; j++) {

                    line = this.trimWhiteSpace(parts[j]);

                    if (line.indexOf('event') == 0) {

                        eventType = line.replace(/event:?\s*/, '');
                    }
                    else if (line.indexOf('retry') == 0) {

                        retry = parseInt(line.replace(/retry:?\s*/, ''));
                        if(!isNaN(retry)) {
                            this.interval = retry;
                        }
                    }
                    else if (line.indexOf('data') == 0) {

                        datas.push(line.replace(/data:?\s*/, ''));
                    }
                    else if (line.indexOf('id:') == 0) {

                        this.lastEventId = line.replace(/id:?\s*/, '');
                    }
                    else if (line.indexOf('id') == 0) { // this resets the id

                        this.lastEventId = null;
                    }
                }

                if (datas.length) {
                    // dispatch a new event
                    var event = new MessageEvent(eventType, datas.join('\n'), window.location.origin, this.lastEventId);
                    this.dispatchEvent(eventType, event);
                }
            }

            this.cache = events[events.length - 1];
        },

        dispatchEvent: function (type, event) {
            var handlers = this['_' + type + 'Handlers'];

            if (handlers) {

                for (var i = 0; i < handlers.length; i++) {
                    handlers[i].call(this, event);
                }
            }

            if (this['on' + type]) {
                this['on' + type].call(this, event);
            }

        },

        addEventListener: function (type, handler) {
            if (!this['_' + type + 'Handlers']) {
                this['_' + type + 'Handlers'] = [];
            }

            this['_' + type + 'Handlers'].push(handler);
        },

        removeEventListener: function (type, handler) {
            var handlers = this['_' + type + 'Handlers'];
            if (!handlers) {
                return;
            }
            for (var i = handlers.length - 1; i >= 0; --i) {
                if (handlers[i] === handler) {
                    handlers.splice(i, 1);
                    break;
                }
            }
        },

        _pollTimer: null,

        _noactivityTimer: null,

        _xhr: null,

        lastEventId: null,

        cache: '',

        cursor: 0,

        onerror: null,

        onmessage: null,

        onopen: null,

        readyState: 0,

        // ===================================================================
        // helpers functions
        // those are attached to prototype to ease reuse and testing...

        urlWithParams: function (baseURL, params) {

            var encodedArgs = [];

            if (params){

                var key, urlarg;
                var urlize = encodeURIComponent;

                for (key in params){
                    if (params.hasOwnProperty(key)) {
                        urlarg = urlize(key)+'='+urlize(params[key]);
                        encodedArgs.push(urlarg);
                    }
                }
            }

            if (encodedArgs.length > 0){

                if (baseURL.indexOf('?') == -1)
                    return baseURL + '?' + encodedArgs.join('&');
                return baseURL + '&' + encodedArgs.join('&');
            }
            return baseURL;
        },

        lastMessageIndex: function(text) {

            var ln2 =text.lastIndexOf('\n\n');
            var lr2 = text.lastIndexOf('\r\r');
            var lrln2 = text.lastIndexOf('\r\n\r\n');

            if (lrln2 > Math.max(ln2, lr2)) {
                return [lrln2, lrln2+4];
            }
            return [Math.max(ln2, lr2), Math.max(ln2, lr2) + 2]
        },

        trimWhiteSpace: function(str) {
            // to remove whitespaces left and right of string

            var reTrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
            return str.replace(reTrim, '');
        },

        normalizeToLF: function(str) {

            // replace \r and \r\n with \n
            return str.replace(/\r\n|\r/g, '\n');
        }

    };

    if (!isOldIE()){

        EventSource.isPolyfill = "XHR";

        // EventSource will send request using XMLHttpRequest
        EventSource.prototype.XHR = function(evs) {

            request = new XMLHttpRequest();
            this._request = request;
            evs._xhr = this;

            // set handlers
            request.onreadystatechange = function(){
                if (request.readyState > 1 && evs.readyState != evs.CLOSED) {
                    if (request.status == 200 || (request.status>=300 && request.status<400)){
                        evs.ondata();
                    }
                    else {
                        request._failed = true;
                        evs.readyState = evs.CLOSED;
                        evs.dispatchEvent('error', {
                            type: 'error',
                            data: "The server responded with "+request.status
                        });
                        evs.close();
                    }
                }
            };

            request.onprogress = function () {
            };

            request.open('GET', evs.urlWithParams(evs.URL, evs.getArgs), true);

            var headers = evs.xhrHeaders; // maybe null
            for (var header in headers) {
                if (headers.hasOwnProperty(header)){
                    request.setRequestHeader(header, headers[header]);
                }
            }
            if (evs.lastEventId) {
                request.setRequestHeader('Last-Event-Id', evs.lastEventId);
            }

            request.send();
        };

        EventSource.prototype.XHR.prototype = {

            useXDomainRequest: false,

            _request: null,

            _failed: false, // true if we have had errors...

            isReady: function() {


                return this._request.readyState >= 2;
            },

            isDone: function() {

                return (this._request.readyState == 4);
            },

            hasError: function() {

                return (this._failed || (this._request.status >= 400));
            },

            getBuffer: function() {

                var rv = '';
                try {
                    rv = this._request.responseText || '';
                }
                catch (e){}
                return rv;
            },

            abort: function() {

                if ( this._request ) {
                    this._request.abort();
                }
            }
        };
    }
    else {

	EventSource.isPolyfill = "IE_8-9";

        // patch EventSource defaultOptions
        var defaults = EventSource.prototype.defaultOptions;
        defaults.xhrHeaders = null; // no headers will be sent
        defaults.getArgs['evs_preamble'] = 2048 + 8;

        // EventSource will send request using Internet Explorer XDomainRequest
        EventSource.prototype.XHR = function(evs) {

            request = new XDomainRequest();
            this._request = request;

            // set handlers
            request.onprogress = function(){
                request._ready = true;
                evs.ondata();
            };

            request.onload = function(){
                this._loaded = true;
                evs.ondata();
            };

            request.onerror = function(){
                this._failed = true;
                evs.readyState = evs.CLOSED;
                evs.dispatchEvent('error', {
                    type: 'error',
                    data: "XDomainRequest error"
                });
            };

            request.ontimeout = function(){
                this._failed = true;
                evs.readyState = evs.CLOSED;
                evs.dispatchEvent('error', {
                    type: 'error',
                    data: "XDomainRequest timed out"
                });
            };

            // XDomainRequest does not allow setting custom headers
            // If EventSource has enabled the use of GET arguments
            // we add parameters to URL so that server can adapt the stream...
            var reqGetArgs = {};
            if (evs.getArgs) {

                // copy evs.getArgs in reqGetArgs
                var defaultArgs = evs.getArgs;
                    for (var key in defaultArgs) {
                        if (defaultArgs.hasOwnProperty(key)){
                            reqGetArgs[key] = defaultArgs[key];
                        }
                    }
                if (evs.lastEventId){
                    reqGetArgs['evs_last_event_id'] = evs.lastEventId;
                }
            }
            // send the request

            request.open('GET', evs.urlWithParams(evs.URL,reqGetArgs));
            request.send();
        };

        EventSource.prototype.XHR.prototype = {

            useXDomainRequest: true,

            _request: null,

            _ready: false, // true when progress events are dispatched

            _loaded: false, // true when request has been loaded

            _failed: false, // true if when request is in error

            isReady: function() {

                return this._request._ready;
            },

            isDone: function() {

                return this._request._loaded;
            },

            hasError: function() {

                return this._request._failed;
            },

            getBuffer: function() {

                var rv = '';
                try {
                    rv = this._request.responseText || '';
                }
                catch (e){}
                return rv;
            },

            abort: function() {

                if ( this._request){
                    this._request.abort();
                }
            }
        };
    }

    function MessageEvent(type, data, origin, lastEventId) {

        this.bubbles = false;
        this.cancelBubble = false;
        this.cancelable = false;
        this.data = data || null;
        this.origin = origin || '';
        this.lastEventId = lastEventId || '';
        this.type = type || 'message';
    }

    function isOldIE () {

        //return true if we are in IE8 or IE9
        return (window.XDomainRequest && (window.XMLHttpRequest && new XMLHttpRequest().responseType === undefined)) ? true : false;
    }

    global[evsImportName] = EventSource;
})(this);

},{}],3:[function(require,module,exports){
'use strict';

var inserted = {};

module.exports = function(css, options) {

  if (inserted[css]) return;
  inserted[css] = true;

  var elm = document.createElement('style');
  elm.setAttribute('type', 'text/css');

  if ('textContent' in elm) {
    elm.textContent = css;
  }
  else {
    elm.styleSheet.cssText = css;
  }

  var head = document.getElementsByTagName('head')[0];
  if (options && options.prepend) {
    head.insertBefore(elm, head.childNodes[0]);
  } else {
    head.appendChild(elm);
  }

  return function() {
    delete inserted[css];
    head.removeChild(elm);
  };
};
},{}],4:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  '$log',
  '$q',
  '$rootScope',
  '$state',
  '$window',
  '$localStorage',
  '$modalInstance',
  '$mdSidenav',
  '$timeout',
  'ProjectsServices',
  'Project',
  'ConfigServices',
  'Workspace',
  function AddLoopbackProjectController(
  $scope,
  $log,
  $q,
  $rootScope,
  $state,
  $window,
  $localStorage,
  $modalInstance,
  $mdSidenav,
  $timeout,
  ProjectsServices,
  Project,
  ConfigServices,
  Workspace
) {
  'use strict';

  $scope.newProject = {};
  $scope.projectsFilepicker = { show: false, flow: 'add-loopback' };
  $scope.isSubmittingProject = false;
  $scope.projectTemplates = [];
  $scope.versions = [];
  $scope.logs = [];
  $scope.status = {};
  $scope.status.isLogsVisible = true;

  Workspace.getAvailableTemplates().$promise
    .then(function(data) {
      $scope.projectTemplates = data.templates;
      $scope.newProject.templateName = $scope.projectTemplates[1];
    })
    .then(function(){
      Workspace.availableLBVersions().$promise
        .then(function(data){
          $scope.versions = data.versions;
          $scope.newProject.version = $scope.versions[0].value;
        });
    });


  // attach duplicate project to scope for error messages
  $scope.$watch('newProject', function(newObj){
    ProjectsServices.getDuplicateProjects($scope, newObj);
  }, true);

  $scope.$watch('newProject.displayName', function(newName) {
    if (!newName) return;

    $scope.newProject.name = $rootScope.generateProjectName(newName);
  });

  $scope.showLogs = function(){
    $scope.status.isLogsVisible = !$scope.status.isLogsVisible;
  };

  $scope.addLoopbackProject = function(form) {
    if (form.$invalid) {
      return;
    }

    $scope.isSubmittingProject = true;
    $scope.isProjectFinished = false;
    $scope.projectCreationError = null;

    //add projectType and type to newProject object
    $scope.newProject.type = 'project';
    $scope.newProject.projectType = 'loopback';

    // backup current project incase of error adding new one
    $rootScope.originalProject = $rootScope.activeProject;

    // change project environment to new path as a work around
    // for not being able to specify path in createFromTemplate call
    // see: https://github.com/strongloop/loopback-workspace/issues/279
    ProjectsServices.setProjectEnvironment($scope.newProject)
      .then(function(project) {
        $rootScope.activeProject = project;
        $rootScope.workspaceDir = project;
      })
      .then(function(project){
        // create project and subscribe to event stream for updates
        var def = $q.defer();
        var url = '/pm/api/Projects/createFromTemplate?name='+encodeURIComponent($scope.newProject.name)+'&templateName='+encodeURIComponent($scope.newProject.templateName)+'&basePath='+encodeURIComponent($scope.newProject.path)+'&loopbackVersion='+encodeURIComponent($scope.newProject.version);
        var stream = new EventSource(url);
        var rawLines = [];
        var done = false;

        var flushLines = function () {
            var lines = [];

            rawLines.forEach(function (msg) {
                var raw = JSON.parse(msg);

                if (!raw) {
                    return;
                }

                // last message with project path
                if (raw.done && raw.projectDir) {
                    $scope.newProject.path = raw.projectDir;
                }

                if (raw.done && !raw.error) {
                    stream.close();
                    return def.resolve();
                }

                if (raw.error) {
                    stream.close();
                    return def.reject(raw.error);
                }

                if (raw.data) {
                    raw = raw.data;
                }

                raw.toString().split('\n').forEach(function (line) {
                    lines.push(line);
                });
            });

            lines.forEach(function (line) {
                var htm = ansi_up.ansi_to_html(line, { use_classes: true });
                $scope.logs.push(htm);
            });

            rawLines = [];
        };

        var scheduleUpdate = function() {
            flushLines();

            if (!done) {
                $timeout(scheduleUpdate, 2500);
            }
        };

        scheduleUpdate();

        def.promise.then(function() {
            flushLines();
            done = true;
        })

        stream.addEventListener('data', function(msg) {
            rawLines.push(msg.data);
        });

        stream.addEventListener('error', function(err){
          $log.error(err);
          $scope.isSubmittingProject = true;
          def.reject(err);
        });

        // resolve the promise when finished installing
        stream.addEventListener('end', function(msg){
          $log.log('projected created', msg);
          def.resolve();
        });

        return def.promise;
      })
      .then(function(){
        return ProjectsServices.addProject($scope.newProject);
      })
      .then(function(project){
        return ProjectsServices.setProjectEnvironment(project.data);
      })
      .then(ProjectsServices.getProjects)
      .then(function(result) {
        var activeProject = $localStorage.getItem('activeProject');

        $rootScope.projects = result.data;

        return ProjectsServices.setProjectEnvironment(activeProject)
          .then(function(project) {
            $rootScope.activeProject = project;
            $rootScope.workspaceDir = project;
            $scope.isProjectFinished = true;

            $rootScope.$emit('event:track', 'project', 'createNewLoopbackProject', { templateName: project.templateName });

            if (!$scope.status.isLogsVisible){
              $modalInstance.close();
            }
          });
      })
      .then(function() {
        $scope.isSubmittingProject = false;

        $mdSidenav('mainNav').close();

        if ($state.current.name === 'apis') {
          return $state.reload();
        }

        $state.go('apis');
      })
      .catch(function(err) {
        $scope.isSubmittingProject = false;
        $scope.isProjectFinished = false;
        $scope.status.isLogsVisible = true;
        $scope.projectCreationError = err;
        $rootScope.activeProject = $rootScope.originalProject;
        $rootScope.workspaceDir = $rootScope.originalProject;

        // revert back to previous project environment in case of error
        ProjectsServices.setProjectEnvironment($rootScope.originalProject)
          .then(function(data){
            $state.reload();
          });
      });
  };

  $scope.cancelAddProject = function(closeModal) {
    $scope.projectsFilepicker.show = false;

    if (closeModal){
      $modalInstance.close();
    }
  };

  $scope.closeAddProject = $modalInstance.close;

  $scope.updatePath = function(path) {
    $scope.newProject.path = path;
  };

  $scope.openFilepicker = function() {
    $scope.projectsFilepicker.show = true;
  }
}];


},{}],5:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  '$log',
  '$rootScope',
  '$state',
  '$window',
  '$mdSidenav',
  '$localStorage',
  'ProjectsServices',
  'OpenAPIWorkspace',
  'ConfigServices',
  'Workspace',
  '$modalInstance',
  function AddOpenApiProjectController(
  $scope,
  $log,
  $rootScope,
  $state,
  $window,
  $mdSidenav,
  $localStorage,
  ProjectsServices,
  OpenAPIWorkspace,
  ConfigServices,
  Workspace,
  $modalInstance
) {
  'use strict';

  $scope.newProject = {};
  $scope.projectsFilepicker = {show: false, flow: 'add-openapi'};
  $scope.isSubmittingProject = false;
  $scope.projectTemplates = [];
  // todo remove this flag when we have more templates
  $scope.enableTemplateSelection = false;
  $scope.newProject.templateName = 'default';

  OpenAPIWorkspace.getAvailableTemplates().$promise
    .then(function(data) {
      $scope.projectTemplates = data.templates;
    });

  // attach duplicate project to scope for error messages
  $scope.$watch('newProject', function(newObj){
    ProjectsServices.getDuplicateProjects($scope, newObj);
  }, true);

  $scope.$watch('newProject.displayName', function(newName) {
    if (!newName) return;

    $scope.newProject.name = $rootScope.generateProjectName(newName);
  });

  $scope.addOpenApiProject = function(form) {
    if (form.$invalid) {
      return;
    }

    $scope.isSubmittingProject = true;

    //add projectType and type to newProject object
    $scope.newProject.type = 'project';
    $scope.newProject.projectType = 'unknown';

    // change project environment to new path as a work around
    // for not being able to specify path in createFromTemplate call
    // see: https://github.com/strongloop/loopback-workspace/issues/279
    ProjectsServices.setProjectEnvironment($scope.newProject)
      .then(function(project) {
        $rootScope.activeProject = project;
        $rootScope.workspaceDir = project;
        return project;
      })
      .then(function(project){
        // make openapi app via api call
        return OpenAPIWorkspace.createFromTemplate({
          name: $scope.newProject.name,
          templateName: $scope.newProject.templateName,
          basePath: $scope.newProject.path
        }).$promise;
      })
      .then(function(project){
        // set the path to newly created path
        $scope.newProject.path = project.path;
        return ProjectsServices.addProject($scope.newProject);
      })
      .then(function(project){
        return ProjectsServices.setProjectEnvironment(project.data);
      })
      .then(ProjectsServices.getProjects)
      .then(function(result) {
        var activeProject = $localStorage.getItem('activeProject');

        $rootScope.projects = result.data;

        return ProjectsServices.setProjectEnvironment(activeProject)
          .then(function(project) {
            $rootScope.activeProject = project;
            $rootScope.workspaceDir = project;

            $rootScope.$emit('event:track', 'project', 'createNewOpenAPIProject', { templateName: project.templateName });

            $modalInstance.close();
          });
      })
      .then(function() {
        $scope.isSubmittingProject = false;

        $mdSidenav('mainNav').close();

        if ($state.current.name === 'apis') {
          return $state.reload();
        }

        $state.go('apis');
      })
      .catch(function(err) {
        $scope.isSubmittingProject = false;
        $rootScope.$emit('event:showError', {
          responseText: 'Creating a new project has failed.'
        });
      });
  };

  $scope.cancelAddProject = function(closeModal) {
    $scope.projectsFilepicker.show = false;

    if (closeModal){
      $modalInstance.close();
    }
  };

  $scope.updatePath = function(path) {
    $scope.newProject.path = path;
  };

  $scope.openFilepicker = function() {
    $scope.projectsFilepicker.show = true;
  }
}];


},{}],6:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  '$log',
  '$rootScope',
  '$state',
  '$window',
  '$mdSidenav',
  '$localStorage',
  'ProjectsServices',
  'ConfigServices',
  '$modalInstance',
  function AddProjectController(
  $scope,
  $log,
  $rootScope,
  $state,
  $window,
  $mdSidenav,
  $localStorage,
  ProjectsServices,
  ConfigServices,
  $modalInstance
) {
  'use strict';

  $scope.newProject = {};
  $scope.projectsFilepicker = { show: true, flow: 'add-existing' };
  $scope.isSubmittingProject = false;

  // attach duplicate project to scope for error messages
  $scope.$watch('newProject', function(newObj){
    ProjectsServices.getDuplicateProjects($scope, newObj);
  }, true);


  $scope.addProject = function(form){
    if ( form.$invalid ) {
      return;
    }

    $scope.isSubmittingProject = true;

    //inspect path to figure out what type of project it is
    ConfigServices.inspectPath($scope.newProject.path)
      .then(function(result){
        var project = result;

        //add projectType and type to newProject object
        $scope.newProject.type = project.type;
        $scope.newProject.projectType = project.projectType;
        $scope.newProject.name = project.name;

        ProjectsServices.addProject($scope.newProject)
          .then(ProjectsServices.getProjects)
          .then(function(result){
            var activeProject = $localStorage.getItem('activeProject');

            $rootScope.projects = result.data;

            return ProjectsServices.setProjectEnvironment(activeProject)
              .then(function(project){
                $rootScope.activeProject = project;
                $rootScope.workspaceDir = project;
                $modalInstance.close();
              });
          })
          .then(function(){
            $scope.isSubmittingProject = false;

            $mdSidenav('mainNav').close();

            $rootScope.$emit('event:track', 'project', 'addExistingProject');

            if ($state.current.name === 'apis') {
              return $state.reload();
            }

            $state.go('apis');
          })
          .catch(function(err){
            $scope.isSubmittingProject = false;
            $rootScope.$emit('event:showError', {
              responseText: 'Creating a new project has failed.'
            });
          });
      });
  };

  $scope.cancelAddProject = function(){
    $modalInstance.close();
  };

  $scope.updatePath = function(path){
    $scope.newProject.path = path;
  };

  $scope.updateName = function(file){
    $scope.newProject.name = file.name;
  };

  $scope.openFilepicker = function(){
    $scope.projectsFilepicker.show = true;
  }
}];


},{}],7:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$http',
  '$log',
  '$q',
  function ConfigServices(
    $http,
    $log,
    $q
  ){
  'use strict';

  var svc = this;

  svc.inspectPath = function(path) {
    var def = $q.defer();

    $http.get('/apic-config/inspectPath', {
      params: {
        path: path
      }
    })
      .then(function(result){
        var project = result.data;
        project.displayName = project.name || project.basePath;

        def.resolve(project);
      })
      .catch(function(err){
        $log.error(err);
        def.reject(err);
      });

    return def.promise;
  };

  svc.getId = function(){
    return $http.get('/apic-config/id');
  };

  svc.getByName = function(name){
    return $http.get('/apic-config/get?key='+name);
  };

  svc.getEnableAnalytics = function(){
    return svc.getByName('enable-analytics');
  };

  svc.getAgreementByName = function(name){
    return $http.get('/apic-config/agreements/'+name);
  };

  svc.getAnalyticsAgreement = function(){
    return svc.getAgreementByName('analytics');
  };

  svc.getReminderDate = function(){
    return svc.getByName('analytics-reminder');
  };

  svc.setReminderDate = function(date){
    var global = true;

    return svc.setByName('analytics-reminder', date, global);
  };

  svc.setByName = function(name, value, global){
    global = !!global;

    return $http.post('/apic-config/set', {
      key: name,
      value: value,
      global: global
    });
  };

  svc.deleteByName = function(name, global){
    global = !!global;

    return $http.post('/apic-config/delete', {
      key: name,
      global: global
    });
  };

  svc.getAnalyticsKey = function(){
    return $http.get('/apic-config/keys/analytics');
  };

  svc.setEnableAnalytics = function(enabled){
    var global = true;

    return svc.setByName('enable-analytics', enabled, global);
  };

  return svc;
}];


},{}],8:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$http',
  '$log',
  function FileServices(
  $http,
  $log
){
  'use strict';

  var svc = this;

  svc.getListByPath = function(path) {
    return $http.get('/fs/readdir', { params: path })
      .then(function(data){
        var files = data.data;

        files.files = _.orderBy(files.files, ['type', 'path'], ['asc', 'asc']);

        //handle case where there is no name, we use path for name
        files.parents = files.parents.map(function(item){
          if ( !item.name ) {
            item.name = item.path;
          }

          return item;
        });

        if (files.parents.length) {
          files.parents[0].name = 'root';
        }

        return files;
      })
      .catch(function(err){
        $log.error(err);
        return err;
      });
  };

  return svc;
}];


},{}],9:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  '$log',
  '$rootScope',
  '$state',
  '$window',
  '$localStorage',
  'ProjectsServices',
  'ConfigServices',
  'Workspace',
  '$modalInstance',
  function LoopbackSettingsController(
  $scope,
  $log,
  $rootScope,
  $state,
  $window,
  $localStorage,
  ProjectsServices,
  ConfigServices,
  Workspace,
  $modalInstance
) {
  'use strict';

  $scope.newProject = $rootScope.activeProject;
  $scope.master = angular.copy($scope.newProject);

  $scope.updateLoopbackProject = function(form){
    if (form.$invalid) {
      return;
    }

    ProjectsServices.updateProject($scope.newProject)
      .then(function(result){
        return ProjectsServices.setProjectEnvironment(result.data)
          .then(function(project) {
            $rootScope.activeProject = project;
            $rootScope.workspaceDir = project;
          });
      })
      .then(function(){
        $rootScope.$emit('event:getProjects');
        $modalInstance.close();
      });
  };

  $scope.cancelProjectSettings = function() {
    angular.copy($scope.master, $scope.newProject);
    $modalInstance.close();
  };
}];


},{}],10:[function(require,module,exports){
(function (global){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
'use strict';

var angular = (typeof window !== "undefined" ? window['angular'] : typeof global !== "undefined" ? global['angular'] : null);
require('eventsource-polyfill');
var injectCss = require('inject-css');

angular.module('apic.projects', [
  'pascalprecht.translate',
  'ui.bootstrap',
  'apim.loopback'
])
  .config(function(){
    injectCss(require('./styles/main.styl'));
  })
  .service('ProjectsServices', require('./projects-services'))
  .service('FileServices', require('./file-services'))
  .service('ConfigServices', require('./config-services'))
  .controller('NodeTreeController', require('./node-tree-controller'))
  .controller('NodeItemController', require('./node-item-controller'))
  .controller('AddLoopbackProjectController', require('./add-loopback-project-controller'))
  .controller('AddOpenApiProjectController', require('./add-openapi-project-controller'))
  .controller('AddProjectController', require('./add-project-controller'))
  .controller('LoopbackSettingsController', require('./loopback-settings-controller'))
  .controller('OpenApiSettingsController', require('./openapi-settings-controller'))
  .controller('ProjectNodeItemController', require('./project-node-item-controller'))
  .controller('ProjectNodesController', require('./project-nodes-controller'))
  .controller('ProjectsFilepickerController', require('./projects-filepicker-controller'))
  .directive('apimProjectItem', require('./project-item-directive'))
  .directive('apimProjectsFilepicker', require('./projects-filepicker-directive'))
  .directive('apimNodeTree', require('./node-tree-directive'))
  .directive('apimNodeItem', require('./node-item-directive'))
  .directive('apimProjectNodes', require('./project-nodes-directive'))
  .directive('apimProjectNodeItem', require('./project-node-item-directive'))
  .directive('apimProjectNav', require('./project-nav-directive'));


}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./add-loopback-project-controller":4,"./add-openapi-project-controller":5,"./add-project-controller":6,"./config-services":7,"./file-services":8,"./loopback-settings-controller":9,"./node-item-controller":11,"./node-item-directive":12,"./node-tree-controller":13,"./node-tree-directive":14,"./openapi-settings-controller":15,"./project-item-directive":28,"./project-nav-directive":29,"./project-node-item-controller":30,"./project-node-item-directive":31,"./project-nodes-controller":32,"./project-nodes-directive":33,"./projects-filepicker-controller":34,"./projects-filepicker-directive":35,"./projects-services":36,"./styles/main.styl":37,"eventsource-polyfill":1,"inject-css":3}],11:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  '$log',
  function NodeItemController(
    $scope,
    $log
  ) {
  'use strict';

  $scope.showChildNodes = true;

  $scope.$watch('root.currentNode', checkChildNodes, true);

  $scope.getFilesAndSelectNode = function($event, node){
    if (!$scope.showChildNodes) return;

    if (!node.files || (node.files.files && !node.files.files.isOpen)) {
      $scope.root.getFiles(node);
    }

    $scope.root.selectNode($event, node, true);
  };

  $scope.getFiles = function(node){
    if (!$scope.showChildNodes) return;
    $scope.root.getFiles(node);
  };

  $scope.selectNode = function($event, node){
    // don't allow user to select an existing loopback project path when creating a new project
    if ($scope.root.projectsFilepicker.flow !== 'add-existing' && node.isLoopback ) {
      return;
    }

    $scope.root.selectNode($event, node);
  };

  function checkChildNodes(){
    $scope.showChildNodes = !$scope.node.isLoopback;
  }
}];


},{}],12:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [function NodeItemDirective() {
  'use strict';

  return {
    restrict: 'E',
    replace: true,
    scope: {
      node: '=',
      root: '='
    },
    template: require('./partials/node-item.html'),
    controller: 'NodeItemController'
  }
}];


},{"./partials/node-item.html":20}],13:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  function NodeTreeController($scope) {
  'use strict';

  $scope.getFiles = $scope.root.getFiles;
  $scope.selectNode = $scope.root.selectNode;
}];


},{}],14:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [function NodeTreeDirective() {
  'use strict';

  return {
    restrict: 'E',
    replace: true,
    scope: {
      nodes: '=',
      root: '='
    },
    template: require('./partials/node-tree.html'),
    controller: 'NodeTreeController'
  }
}];


},{"./partials/node-tree.html":21}],15:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  '$log',
  '$rootScope',
  '$state',
  '$window',
  '$localStorage',
  'ProjectsServices',
  'ConfigServices',
  'OpenAPIWorkspace',
  '$modalInstance',
  function OpenApiSettingsController(
  $scope,
  $log,
  $rootScope,
  $state,
  $window,
  $localStorage,
  ProjectsServices,
  ConfigServices,
  OpenAPIWorkspace,
  $modalInstance
) {
  'use strict';

  $scope.newProject = $rootScope.activeProject;
  $scope.master = angular.copy($scope.newProject);

  $scope.updateOpenApiProject = function(form){
    if (form.$invalid) {
      return;
    }

    ProjectsServices.updateProject($scope.newProject)
      .then(function(result){
        return ProjectsServices.setProjectEnvironment(result.data)
          .then(function(project) {
            $rootScope.activeProject = project;
            $rootScope.workspaceDir = project;
          });
      })
      .then(function(){
        $rootScope.$emit('event:getProjects');
        $modalInstance.close();
      });
  };

  $scope.cancelProjectSettings = function(){
    angular.copy($scope.master, $scope.newProject);
    $modalInstance.close();
  }
}];


},{}],16:[function(require,module,exports){
module.exports = '<h2 class="bx--modal-content__heading">{{::\'projectSettings\' | translate}}</h2>\n<button title="Close" class="bx--modal__close" type="button" data-ng-click="cancelProjectSettings()" tabindex="-1">\n  <bx-icon class="bx--modal__close--icon" icon="close"></bx-icon>\n</button>\n<form id="new-project-form" class="bx--form" ng-submit="updateLoopbackProject(form)" name="form" novalidate>\n  <div class="bx--modal-content modal-body">\n    <bx-input-container>\n      <label for="new-project-display-name">{{::\'projects_add_label_display\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.displayName"\n             id="new-project-display-name"\n             name="displayName"\n             unique-project-attrib="displayName"\n             unique-project-attrib-skip-active-project="true"\n             required/>\n      <div ng-messages="form.displayName.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-displayName">{{::\'projects_invalid_displayName\' | translate}}</div>\n      </div>\n    </bx-input-container>\n    <bx-input-container>\n      <label for="new-project-name">{{::\'projects_add_label_name\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.name"\n             id="new-project-name"\n             name="name"\n             required\n             readonly/>\n      <div ng-messages="form.name.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n      </div>\n    </bx-input-container>\n    <bx-input-container>\n      <label for="new-project-path">{{::\'projects_add_label_directory\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.path"\n             id="new-project-path"\n             name="path"\n             required\n             readonly/>\n      <div ng-messages="form.path.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n      </div>\n    </bx-input-container>\n  </div>\n  <div class="bx--modal__buttons">\n    <div class="bx--modal__buttons-container">\n      <button class="bx--btn--secondary" ng-click="cancelProjectSettings()" type="button">{{::\'cancel\' | translate}}</button>\n      <button class="bx--btn" ng-disabled="isSubmittingProject">Save</button>\n    </div>\n  </div>\n</form>\n';
},{}],17:[function(require,module,exports){
module.exports = '<h2 class="bx--modal-content__heading no-animate" ng-show="!projectsFilepicker.show">{{::\'projectNewLoopback\' | translate}}</h2>\n<h2 class="bx--modal-content__heading no-animate" ng-if="projectsFilepicker.flow == \'add-loopback\' || projectsFilepicker.flow == \'add-openapi\'" ng-show="projectsFilepicker.show">{{::\'projectSelectFolder\' | translate}}</h2>\n<button title="Close"\n        class="bx--modal__close no-animate"\n        type="button"\n        ng-disabled="isSubmittingProject"\n        data-ng-click="cancelAddProject(true)"\n        tabindex="-1"\n        ng-show="!projectsFilepicker.show">\n  <bx-icon class="bx--modal__close--icon" icon="close"></bx-icon>\n</button>\n<button title="Close"\n        class="bx--modal__close no-animate"\n        type="button"\n        data-ng-click="cancelAddProject(false)"\n        tabindex="-1"\n        ng-show="projectsFilepicker.show">\n  <bx-icon class="bx--modal__close--icon" icon="close"></bx-icon>\n</button>\n<div class="bx--modal-content bx--new-lb-modal no-animate" ng-show="!isSubmittingProject && !isProjectFinished && !projectsFilepicker.show">\n  <form class="bx--form" id="new-project-form" name="form" novalidate>\n    <div class="bx--select labeledSelect">\n      <label class="bx--form__label" for="new-project-template">{{::\'projectTemplate\' | translate}}</label>\n      <select\n        class="bx--select__input"\n        aria-label="{{::\'api_path_parameter_in\' | translate}}"\n        ng-model="newProject.templateName"\n        id="new-project-template"\n        name="templateName"\n        required>\n        <option class="bx--select__option" ng-value="templateName" ng-repeat="templateName in projectTemplates">{{templateName}}</option>\n      </select>\n      <bx-icon class="bx--select__arrow" icon="caret--down"></bx-icon>\n    </div>\n    <div class="bx--select labeledSelect">\n      <label class="bx--form__label" for="new-project-version">{{::\'loopbackVersion\' | translate}}</label>\n      <select\n        class="bx--select__input"\n        aria-label="{{::\'api_path_parameter_in\' | translate}}"\n        ng-model="newProject.version"\n        id="new-project-version"\n        name="version"\n        required>\n        <option class="bx--select__option"\n                ng-value="version.value"\n                ng-repeat="version in versions">{{version.value}} - {{version.description}}</option>\n      </select>\n      <bx-icon class="bx--select__arrow" icon="caret--down"></bx-icon>\n    </div>\n    <bx-input-container>\n      <label for="new-project-display-name">{{::\'projects_add_label_display\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.displayName"\n             id="new-project-display-name"\n             name="displayName"\n             unique-project-attrib="displayName"\n             required/>\n      <div ng-messages="form.displayName.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-displayName">\n          {{::\'projects_invalid_displayName\' | translate:duplicateProject}}\n        </div>\n      </div>\n    </bx-input-container>\n    <bx-input-container>\n      <label for="new-project-name">{{::\'projects_add_label_name\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.name"\n             id="new-project-name"\n             name="name"\n             unique-project-attrib="name"\n             readonly\n             required/>\n      <div ng-messages="form.name.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-name">\n          {{::\'projects_invalid_name\' | translate:duplicateProject}}\n        </div>\n      </div>\n    </bx-input-container>\n    <label class="bx--form__label-required bx--form__label" for="new-project-path">\n      {{::\'projects_add_label_directory\' | translate}}\n    </label>\n    <div class="displayInline itsAllRelative flex">\n      <input type="text"\n             class="bx--text__input"\n             ng-model="newProject.path"\n             id="new-project-path"\n             name="path"\n             unique-project-attrib="path"\n             placeholder="{{::\'browseFolders\' | translate}}"\n             ng-click="openFilepicker()"\n             readonly\n             required>\n      <button class="bx--btn open-filepicker no-animate"\n              ng-show="!isSubmittingProject"\n              ng-click="openFilepicker()">{{::\'browse\' | translate}}</button>\n    </div>\n    <div ng-messages="form.path.$error">\n      <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n      <div class="bx--form__requirements" ng-message="unique-project-path">\n        {{::\'projects_invalid_path\' | translate:duplicateProject}}\n      </div>\n    </div>\n  </form>\n</div>\n<div class="bx--modal-content no-animate" ng-show="(isSubmittingProject || isProjectFinished) && !projectsFilepicker.show">\n  <apim-log-viewer logs="logs"\n                   status="status"\n                   log-error="projectCreationError"></apim-log-viewer>\n</div>\n<div class="bx--modal-content filepicker no-animate" ng-class="projectsFilepicker.flow" ng-show="projectsFilepicker.show">\n  <apim-projects-filepicker\n    project="newProject"\n    projects-filepicker="projectsFilepicker"\n    update-path="updatePath(path)"\n    cancel-add-project="cancelAddProject()"\n    add-path-to-project="addPathToProject"></apim-projects-filepicker>\n</div>\n<div class="bx--modal__buttons">\n  <div class="bx--modal__buttons-container no-animate" ng-show="!projectsFilepicker.show">\n    <button class="bx--btn--secondary"\n            ng-click="cancelAddProject(true)"\n            ng-hide="isSubmittingProject || isProjectFinished"\n            type="button">{{::\'cancel\' | translate}}</button>\n    <button class="bx--btn"\n            ng-click="addLoopbackProject(form)"\n            ng-show="!isProjectFinished && !isSubmittingProject">{{::\'add\' | translate }}</button>\n    <button class="bx--btn"\n            ng-show="isSubmittingProject || isProjectFinished"\n            ng-disabled="isSubmittingProject"\n            ng-click="closeAddProject()"\n            type="button">{{::\'finished\' | translate }}</button>\n  </div>\n  <div class="bx--modal__buttons-container no-animate" ng-show="projectsFilepicker.show">\n    <button class="bx--btn--secondary"\n            ng-click="cancelAddProject(false)">{{::\'cancel\' | translate}}</button>\n    <button class="bx--btn" ng-click="addPathToProject()">{{::\'ok\' | translate}}</button>\n  </div>\n</div>\n';
},{}],18:[function(require,module,exports){
module.exports = '<h2 class="bx--modal-content__heading no-animate" ng-show="!projectsFilepicker.show">{{::\'projectNewOpenApi\' | translate}}</h2>\n<h2 class="bx--modal-content__heading no-animate" ng-if="projectsFilepicker.flow == \'add-loopback\' || projectsFilepicker.flow == \'add-openapi\'" ng-show="projectsFilepicker.show">{{::\'projectSelectFolder\' | translate}}</h2>\n<button title="Close" class="bx--modal__close" type="button" ng-disabled="isSubmittingProject"         data-ng-click="cancelAddProject(true)" tabindex="-1">\n  <bx-icon class="bx--modal__close--icon" icon="close"></bx-icon>\n</button>\n<div class="bx--modal-content bx--add-openapi-modal no-animate" ng-show="!projectsFilepicker.show">\n  <form id="new-project-form" class="bx--form" name="form" novalidate>\n    <div class="bx--select labeledSelect" ng-if="enableTemplateSelection">\n      <label class="bx--form__label" for="new-project-template">{{::\'projectTemplate\' | translate}}</label>\n      <select\n        class="bx--select__input"\n        aria-label="{{::\'api_path_parameter_in\' | translate}}"\n        ng-model="newProject.templateName"\n        id="new-project-template"\n        name="templateName"\n        required>\n        <option class="bx--select__option" ng-value="templateName" ng-repeat="templateName in projectTemplates">{{templateName}}</option>\n      </select>\n      <bx-icon class="bx--select__arrow" icon="caret--down"></bx-icon>\n    </div>\n    <bx-input-container>\n      <label for="new-project-display-name">{{::\'projects_add_label_display\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.displayName"\n             id="new-project-display-name"\n             name="displayName"\n             unique-project-attrib="displayName"\n             required/>\n      <div ng-messages="form.displayName.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-displayName">{{::\'projects_invalid_displayName\' | translate:duplicateProject}}</div>\n      </div>\n    </bx-input-container>\n    <bx-input-container>\n      <label for="new-project-name">{{::\'projects_add_label_name\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.name"\n             id="new-project-name"\n             name="name"\n             unique-project-attrib="name"\n             readonly\n             required/>\n      <div ng-messages="form.name.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-name">{{::\'projects_invalid_name\' | translate:duplicateProject}}</div>\n      </div>\n    </bx-input-container>\n    <label class="bx--form__label-required bx--form__label" for="new-project-path">{{::\'projects_add_label_directory\' | translate}}</label>\n    <div class="displayInline itsAllRelative flex">\n      <input type="text"\n             class="bx--text__input"\n             ng-model="newProject.path"\n             id="new-project-path"\n             name="path"\n             unique-project-attrib="path"\n             placeholder="{{::\'browseFolders\' | translate}}"\n             ng-click="openFilepicker()"\n             readonly\n             required/>\n      <button class="bx--btn open-filepicker" ng-click="openFilepicker()">{{::\'browse\' | translate}}</button>\n    </div>\n    <div ng-messages="form.path.$error">\n      <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n      <div class="bx--form__requirements" ng-message="unique-project-path">{{::\'projects_invalid_path\' | translate:duplicateProject}}</div>\n    </div>\n  </form>\n</div>\n<div class="bx--modal-content filepicker no-animate" ng-class="projectsFilepicker.flow" ng-show="projectsFilepicker.show">\n  <apim-projects-filepicker\n    project="newProject"\n    projects-filepicker="projectsFilepicker"\n    update-path="updatePath(path)"\n    cancel-add-project="cancelAddProject()"\n    add-path-to-project="addPathToProject"></apim-projects-filepicker>\n</div>\n<div class="bx--modal__buttons">\n  <div class="bx--modal__buttons-container no-animate" ng-show="!projectsFilepicker.show">\n    <button class="bx--btn--secondary"\n            ng-click="cancelAddProject(true)"\n            type="button">{{::\'cancel\' | translate}}</button>\n    <button class="bx--btn" ng-click="addOpenApiProject(form)" ng-disabled="isSubmittingProject">{{::\'add\' | translate}}</button>\n  </div>\n  <div class="bx--modal__buttons-container no-animate" ng-show="projectsFilepicker.show">\n    <button class="bx--btn--secondary"\n            ng-click="cancelAddProject(false)">{{::\'cancel\' | translate}}</button>\n    <button class="bx--btn" ng-click="addPathToProject()">{{::\'ok\' | translate}}</button>\n  </div>\n</div>\n';
},{}],19:[function(require,module,exports){
module.exports = '<h2 class="bx--modal-content__heading no-animate" ng-show="!projectsFilepicker.show">{{::\'projects_list_add_existing\' | translate}}</h2>\n<h2 class="bx--modal-content__heading no-animate" ng-show="projectsFilepicker.show">{{::\'projectSelectProject\' | translate}}</h2>\n<button title="Close" class="bx--modal__close no-animate" type="button" ng-disabled="isSubmittingProject" data-ng-click="cancelAddProject()" tabindex="-1" ng-show="!projectsFilepicker.show">\n  <bx-icon class="bx--modal__close--icon" icon="close"></bx-icon>\n</button>\n<button title="Close" class="bx--modal__close no-animate" type="button" data-ng-click="cancelAddProject(false)" tabindex="-1" ng-show="projectsFilepicker.show">\n  <bx-icon class="bx--modal__close--icon" icon="close"></bx-icon>\n</button>\n<div class="bx--modal-content bx--new-project-modal no-animate" ng-show="!projectsFilepicker.show">\n  <form id="new-project-form" class="bx--form" name="form" novalidate>\n    <bx-input-container>\n      <label for="new-project-display-name">{{::\'projects_add_label_display\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.displayName"\n             id="new-project-display-name"\n             name="displayName"\n             unique-project-attrib="displayName"\n             required/>\n      <div ng-messages="form.displayName.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-displayName">{{::\'projects_invalid_displayName\' | translate:duplicateProject}}</div>\n      </div>\n    </bx-input-container>\n    <bx-input-container>\n      <label for="new-project-name">{{::\'projects_add_label_name\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.name"\n             id="new-project-name"\n             name="name"\n             unique-project-attrib="name"\n             required\n             readonly/>\n      <div ng-messages="form.name.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-name">{{::\'projects_invalid_name\' | translate:duplicateProject}}</div>\n      </div>\n    </bx-input-container>\n    <bx-input-container flex="100" class="has-link">\n      <label for="new-project-path">{{::\'projects_add_label_directory\' | translate}}</label>\n      <div class="displayInline itsAllRelative flex">\n        <input type="text"\n               ng-model="newProject.path"\n               id="new-project-path"\n               name="path"\n               unique-project-attrib="path"\n               placeholder="{{::\'browseFolders\' | translate}}"\n               ng-click="openFilepicker()"\n               required\n               readonly/>\n        <button class="bx--btn open-filepicker" ng-click="openFilepicker()">{{::\'browse\' | translate}}</button>\n      </div>\n      <div ng-messages="form.path.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-path">{{::\'projects_invalid_path\' | translate:duplicateProject}}</div>\n      </div>\n    </bx-input-container>\n  </form>\n</div>\n<div class="bx--modal-content filepicker no-animate" ng-class="projectsFilepicker.flow" ng-show="projectsFilepicker.show">\n  <apim-projects-filepicker\n    project="newProject"\n    projects-filepicker="projectsFilepicker"\n    update-path="updatePath(path)"\n    update-name="updateName(file)"\n    cancel-add-project="cancelAddProject()"\n    add-path-to-project="addPathToProject"></apim-projects-filepicker>\n</div>\n<div class="bx--modal__buttons">\n  <div class="bx--modal__buttons-container no-animate" ng-show="!projectsFilepicker.show">\n    <button class="bx--btn--secondary"\n            ng-click="cancelAddProject()"\n            type="button" class="cancelButton">{{::\'cancel\' | translate}}</button>\n    <button class="bx--btn" ng-click="addProject(form)" ng-disabled="isSubmittingProject">{{::\'projects_add_button_existing\' | translate}}</button>\n  </div>\n  <div class="bx--modal__buttons-container no-animate" ng-show="projectsFilepicker.show">\n    <button class="bx--btn--secondary"\n            ng-click="cancelAddProject(false)">{{::\'cancel\' | translate}}</button>\n    <button class="bx--btn" ng-click="addPathToProject()">{{::\'ok\' | translate}}</button>\n  </div>\n</div>\n';
},{}],20:[function(require,module,exports){
module.exports = '<li class="node-item" ng-class="{ selected: root.selectedFile.path == node.path, \'loopback-app\': node.isLoopback }">\n  <span ng-if="node.type == \'file\' || node.type == \'symlink\'">\n    <i class="material-icons file">insert_drive_file</i>\n    {{node.name}}\n  </span>\n  <a href="#"\n     class="arrow-link"\n     ng-click="getFilesAndSelectNode($event, node)">\n    <i class="material-icons directory" ng-if="!node.files.files.isOpen">keyboard_arrow_right</i>\n    <i class="material-icons directory" ng-if="node.files.files.isOpen">keyboard_arrow_down</i>\n  </a>\n  <a href="#"\n     ng-click="selectNode($event, node)"\n     ng-dblclick="getFiles(node)"\n     ng-if="node.type == \'directory\'">\n    {{ node.name }}\n    <span class="pill" ng-if="node.isLoopback">LB</span>\n  </a>\n  <apim-node-tree nodes="node.files.files"\n                  root="root"\n                  ng-if="showChildNodes"></apim-node-tree>\n</li>\n';
},{}],21:[function(require,module,exports){
module.exports = '<div class="node-tree" ng-class="{\'isOpen\': nodes.isOpen }">\n  <ul>\n    <apim-node-item ng-repeat="node in nodes" node="node" root="root"></apim-node-item>\n  </ul>\n</div>\n';
},{}],22:[function(require,module,exports){
module.exports = '<h2 class="bx--modal-content__heading">{{::\'projectSettings\' | translate}}</h2>\n<button title="Close" class="bx--modal__close" type="button" data-ng-click="cancelProjectSettings()" tabindex="-1">\n  <bx-icon class="bx--modal__close--icon" icon="close"></bx-icon>\n</button>\n<form id="new-project-form" ng-submit="updateOpenApiProject(form)" name="form" novalidate>\n  <div class="bx--modal-content modal-body">\n    <bx-input-container>\n      <label for="new-project-display-name">{{::\'projects_add_label_display\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.displayName"\n             id="new-project-display-name"\n             name="displayName"\n             unique-project-attrib="displayName"\n             unique-project-attrib-skip-active-project="true"\n             required/>\n      <div ng-messages="form.displayName.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n        <div class="bx--form__requirements" ng-message="unique-project-displayName">{{::\'projects_invalid_displayName\' | translate}}</div>\n      </div>\n    </bx-input-container>\n    <bx-input-container>\n      <label for="new-project-name">{{::\'projects_add_label_name\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.name"\n             id="new-project-name"\n             name="name"\n             required\n             readonly/>\n      <div ng-messages="form.name.$error">\n        <div class="bx--form__requirements" ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n      </div>\n    </bx-input-container>\n    <bx-input-container>\n      <label for="new-project-path">{{::\'projects_add_label_directory\' | translate}}</label>\n      <input type="text"\n             ng-model="newProject.path"\n             id="new-project-path"\n             name="path"\n             required\n             readonly/>\n      <div ng-messages="form.path.$error">\n        <div ng-message="required">{{::\'projects_add_field_required\' | translate}}</div>\n      </div>\n    </bx-input-container>\n  </div>\n  <div class="bx--modal__buttons">\n    <div class="bx--modal__buttons-container">\n      <button class="bx--btn--secondary" ng-click="cancelProjectSettings()" type="button">{{::\'cancel\' | translate}}</button>\n      <button class="bx--btn" ng-disabled="isSubmittingProject">{{::\'save\' | translate}}</button>\n    </div>\n  </div>\n</form>\n';
},{}],23:[function(require,module,exports){
module.exports = '<div class="project-item">\n  <p>\n    <span>{{project.displayName}} - {{project.name}} - {{project.path}}</span>\n    <button ng-click="setCurrentProject(project)">Set as current project</button>\n    <button ng-click="deleteProject(project)">Delete</button>\n  </p>\n</div>\n';
},{}],24:[function(require,module,exports){
module.exports = '<div>\n  <div class="navHeader">\n    <a href="" data-ng-click="setVisibleSection(\'projects\')">\n      <h5>{{::\'section-projects\' | translate}}</h5>\n    </a>\n    <span class="dropdown" dropdown data-is-open="projectMenuOpen">\n      <button class="textOnlyButton dropdown-toggle" style="line-height: 49px;" role="button" dropdown-toggle>\n        <i class="material-icons">control_point</i>\n      </button>\n      <ul class="dropdown-menu" role="menu" onkeypress="projectMenuOpen = true;">\n        <li role="menuitem">\n          <a href="" data-ng-click="openAddNewOpenApiProject();"><span class="pill">OA</span> {{::\'projects_nav_add_new_openapi_project\' | translate}}</a>\n        </li>\n        <li role="menuitem">\n          <a href="" data-ng-click="openAddNewLoopbackProject();"><span class="pill">LB</span> {{::\'projects_nav_add_new_loopback_project\' | translate}}</a>\n        </li>\n        <li role="menuitem">\n          <a href="" data-ng-click="openAddExistingProject();">{{::\'projects_nav_add_existing_project\' | translate}}</a>\n        </li>\n      </ul>\n    </span>\n  </div>\n  <div class="clearBoth"></div>\n  <ul>\n    <li class="navItem"\n        data-ng-repeat="project in projects"\n        data-ng-class="{ selected: project.id == $root.activeProject.id }">\n      <a href=""\n         data-ng-click="setCurrentProject($event, project);"\n         tooltip="{{project.displayName}}">\n        <span class="display-name">{{project.displayName}}</span>\n        <span class="pill" ng-if="project.projectType == \'unknown\'">OA</span>\n        <span class="pill" ng-if="project.projectType == \'loopback\'">LB</span>\n      </a>\n      <span class="delete-project" data-ng-click="deleteProject(project)">\n        <i class="material-icons">highlight_off</i>\n      </span>\n    </li>\n  </ul>\n</div>\n';
},{}],25:[function(require,module,exports){
module.exports = '<li class="node-item" ng-class="{ selected: root.selectedFile.path == node.path }">\n  <a href="#"\n     ng-click="selectNode($event, node)"\n     ng-if="node.type == \'directory\'">\n    <span>{{ node.name }}</span>\n    <em ng-if="node.isLoopback">Loopback</em>\n  </a>\n</li>\n';
},{}],26:[function(require,module,exports){
module.exports = '<div class="node-tree">\n  <ul>\n    <apim-project-node-item ng-repeat="node in nodes"\n                            node="node"\n                            root="root"></apim-project-node-item>\n  </ul>\n</div>\n';
},{}],27:[function(require,module,exports){
module.exports = '<div class="tree-container">\n  <section class="primary-tree">\n    <apim-node-tree\n      nodes="files.files.files"\n      select-node="selectNode($event, node)"\n      root="root"></apim-node-tree>\n  </section>\n  <section ng-if="projectsFilepicker.flow == \'add-existing\'"\n           class="secondary-tree">\n    <apim-project-nodes nodes="currentNode.files.files"\n                        ng-if="projectsFilepicker.flow == \'add-existing\'"\n                        class="project-nodes"\n                        root="root">\n    </apim-project-nodes>\n  </section>\n</div>\n';
},{}],28:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$log',
  '$state',
  function ProjectItemDirective(
    $log,
    $state
  ) {
  'use strict';

  return {
    restrict: 'E',
    scope: {
      project: '='
    },
    template: require('./partials/project-item.html'),
    controller: [
      '$scope',
      '$rootScope',
      '$localStorage',
      'ProjectsServices',
      function ProjectItemDirectiveController(
        $scope,
        $rootScope,
        $localStorage,
        ProjectsServices
      ) {
      $scope.deleteProject = function(project) {
        ProjectsServices.deleteProject(project)
          .then(function(result) {
            //todo message UI about successful deletion
            $log.log('project %s deleted', project.displayName);
            $rootScope.$emit('event:getProjects');
          });
      };

      $scope.setCurrentProject = function(project) {
        ProjectsServices.setProjectEnvironment(project)
          .then(function(result) {
            $rootScope.activeProject = result;
            $state.go('apis');
          });
      };
    }]
  }
}];


},{"./partials/project-item.html":23}],29:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  function ProjectNavDirective() {
  'use strict';

  return {
    restrict: 'A',
    scope: {
      projects: '='
    },
    template: require('./partials/project-nav.html'),
    controller: [
      '$scope',
      '$log',
      '$rootScope',
      'ConfigServices',
      'ProjectsServices',
      '$mdSidenav',
      '$state',
      '$modal',
      'translateMultipleFilter',
      function ProjectNavDirectiveController(
      $scope,
      $log,
      $rootScope,
      ConfigServices,
      ProjectsServices,
      $mdSidenav,
      $state,
      $modal,
      translateMultipleFilter
    ){

      $rootScope.$watch('projects', function(newVal){
        if (!newVal) return;
        $scope.projects = newVal;
      });

      $scope.setVisibleSection = $scope.$parent.setVisibleSection;
      $scope.openAddNewOpenApiProject = $scope.$parent.openAddNewOpenApiProject;
      $scope.openAddNewLoopbackProject = $scope.$parent.openAddNewLoopbackProject;
      $scope.openAddExistingProject = $scope.$parent.openAddExistingProject;


      $scope.setCurrentProject = function($event, project){
        $event.preventDefault();
        $rootScope.originalProject = $rootScope.activeProject;

        ConfigServices.inspectPath(project.path)
          .then(function(data){
            return ProjectsServices.setProjectEnvironment(project)
              .then(function(result){
                $rootScope.activeProject = result;

                $mdSidenav('mainNav').close();

                if ($state.current.name === 'apis') {
                  return $state.reload();
                }

                return $state.go('apis');
              });
          })
          .catch(function(err){
            $log.error(err);

            if (err.data.indexOf('ENOENT: no such file or directory')) {
              $log.log('project does not exist, reverting back to previous');
              $rootScope.activeProject = $rootScope.originalProject;
              $rootScope.workspaceDir = $rootScope.originalProject;
              $state.reload();
            }
          });
      };

      $scope.deleteProject = function(project){
        // open modal for confirmation
        $scope.confirmation = {
          titleKey: 'projects_confirm_delete_title',
          message: translateMultipleFilter('projects_confirm_delete', {
            displayName: project.displayName
          }),
          confirmed: function() {
            $scope.isProjectModal = false;
            ProjectsServices.deleteProject(project)
              .then(function(result){
                $log.log('project %s deleted', project.displayName);
                //set workspace to next available project when deleting active project
                if ( $rootScope.activeProject.path === project.path ) {
                  //find next available project that isn't the one we just deleted
                  $rootScope.workspaceDir = $rootScope.projects.filter(function(proj) {
                      return proj.path !== project.path;
                    })[0] || null;

                  if ( $rootScope.workspaceDir ) {
                    // get project object
                    ConfigServices.inspectPath($rootScope.workspaceDir.path)
                      .then(function(pathResult){
                        ProjectsServices.setProjectEnvironment(pathResult);
                      })
                      .catch(function(err){
                        $log.error(err);
                      });
                  }
                }

                $rootScope.$emit('event:getAllProjects');
              });
          },
          rejected: function() {
          }
        };

        // todo: confirm this works as a dropin module
        // $rootScope.$emit('event:openConfirmModal', $scope);

        $modal.open({
          templateUrl: 'apim/partials/confirmation.html',
          windowTemplateUrl: 'apim/partials/main-template.html',
          controller: 'ConfirmationController',
          size: 'sm',
          scope: $scope
        });
      };
    }]
  };
}];


},{"./partials/project-nav.html":24}],30:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  function ProjectNodeItemController(
    $scope
  ) {
  'use strict';

  $scope.selectNode = $scope.root.selectNode;
}];


},{}],31:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [function ProjectNodeItemDirective() {
  'use strict';

  return {
    restrict: 'E',
    replace: true,
    scope: {
      node: '=',
      root: '='
    },
    template: require('./partials/project-node-item.html'),
    controller: 'ProjectNodeItemController'
  }
}];


},{"./partials/project-node-item.html":25}],32:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  function ProjectNodesController(
    $scope
  ) {
  'use strict';

  $scope.selectNode = $scope.root.selectNode;
}];


},{}],33:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [function ProjectNodesDirective() {
  'use strict';

  return {
    restrict: 'E',
    replace: true,
    scope: {
      nodes: '=',
      root: '='
    },
    template: require('./partials/project-nodes.html'),
    controller: 'ProjectNodesController'
  }
}];


},{"./partials/project-nodes.html":26}],34:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [
  '$scope',
  '$rootScope',
  'FileServices',
  'ConfigServices',
  function ProjectsFilepickerController(
  $scope,
  $rootScope,
  FileServices,
  ConfigServices
) {
  'use strict';

  $scope.root = $scope;
  $scope.currentNode = null;
  $scope.selectedFile = null;
  $scope.selectedCrumb = null;
  $scope.files = {};


  getInitialFiles();


  function getInitialFiles(){
    // start at root directory
    FileServices.getListByPath({path: '/'})
      .then(function(items){
        appendNodes(items);
        FileServices.getListByPath({path: $rootScope.workspaceDir.path})
          .then(function(items){
            var parents = items.parents;
            parents = parents.slice(1, parents.length);

            async.eachSeries(parents, function(parent, cb){
              FileServices.getListByPath({path: parent.path})
                .then(function(items){
                  appendNodes(items);
                  cb(null);
                });
            }, function(err){
              $scope.selectNode(null, { path: parents[parents.length-1].path});
            });
          })
      });
  }

  $scope.cancelFilepicker = function() {
    $scope.projectsFilepicker.show = false;
  };

  $scope.addPathToProject = function() {
    $scope.updatePath({path: $scope.selectedFile.path});

    if ($scope.updateName){

      if ($scope.selectedFile.isLoopback){
        // lookup app name for loopback apps
        ConfigServices.inspectPath($scope.selectedFile.path)
          .then(function(result) {
            $scope.selectedFile.name = result.name;
            $scope.updateName({file: $scope.selectedFile});
            $scope.projectsFilepicker.show = false;
          });
      } else {
        $scope.updateName({file: $scope.selectedFile});
        $scope.projectsFilepicker.show = false;
      }
    }
  };

  $scope.selectNode = function($event, node, toggle) {
    if ($event) {
      $event.preventDefault();
    }

    $scope.selectedFile = node;

    // toggle node-tree open/close flag
    if (toggle && node.files && node.files.files){
      node.files.files.isOpen = !node.files.files.isOpen;
    }
  };

  $scope.selectItem = function($event, item) {
    $event.preventDefault();
    $scope.selectedFile = item;
  };

  $scope.getFiles = function(item) {
    FileServices.getListByPath({path: item.path})
      .then(appendNodes);
  };

  function findNode(node, match) {
    if (node.path === match.path) {
      return node;
    } else if (node.files && node.files.files) {
      var result = null;

      for (var i=0, l=node.files.files.length; i<l; i++){
        result = findNode(node.files.files[i], match);

        if (result) {
          break;
        }
      }

      return result;
    }

    return null;
  }

  function appendNodes(items) {
    // only show directories in file picker and skip dirs that start with a dot
    items.files = items.files.filter(function(file){
      return file.type === 'directory' && file.name.indexOf('.') !== 0;
    });

    items.cwd.link = false;
    $scope.currentNode = findNode($scope.files, items.cwd);

    if ($scope.currentNode){
      $scope.currentNode.files = items;
      //set node-tree to open by default
      $scope.currentNode.files.files.isOpen = true;
    }

    if (!$scope.currentNode) {
      $scope.files.files = items;
      $scope.currentNode = items.cwd;
    }
  }
}];


},{}],35:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
module.exports = [function ProjectsFilepickerDirective() {
  'use strict';

  return {
    restrict: 'E',
    replace: true,
    scope: {
      project: '=',
      projectsFilepicker: '=',
      cancelAddProject: '&',
      updatePath: '&',
      updateName: '&',
      addPathToProject: '='
    },
    template: require('./partials/projects-filepicker.html'),
    controller: 'ProjectsFilepickerController'
  }
}];


},{"./partials/projects-filepicker.html":27}],36:[function(require,module,exports){
/********************************************************* {COPYRIGHT-TOP} ***
 * Licensed Materials - Property of IBM
 * 5725-Z22, 5725-Z63, 5725-U33, 5725-Z63
 *
 * (C) Copyright IBM Corporation 2017
 *
 * All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 ********************************************************** {COPYRIGHT-END} **/
'use strict';


module.exports = [
  '$http',
  '$log',
  '$q',
  '$localStorage',
  '$modal',
  '$rootScope',
  'Workspace',
  function ProjectsServices(
  $http,
  $log,
  $q,
  $localStorage,
  $modal,
  $rootScope,
  Workspace
){
  var svc = {};

  svc.openAddNewOpenApiProject = function($event, $scope){
    $scope.isProjectModal = true;
    $modal.open({
      template: require('./partials/new-openapi-project.html'),
      windowTemplateUrl: 'apim/partials/main-template.html',
      controller: 'AddOpenApiProjectController',
      size: 'lg',
      scope: $scope
    });
  };

  svc.openAddNewLoopbackProject = function($event, $scope){
    $scope.isProjectModal = true;
    $modal.open({
      template: require('./partials/new-loopback-project.html'),
      windowTemplateUrl: 'apim/partials/main-template.html',
      controller: 'AddLoopbackProjectController',
      size: 'lg',
      scope: $scope
    });
  };

  svc.openAddExistingProject = function($event, $scope){
    $scope.isProjectModal = true;
    $modal.open({
      template: require('./partials/new-project.html'),
      windowTemplateUrl: 'apim/partials/main-template.html',
      controller: 'AddProjectController',
      size: 'lg',
      scope: $scope
    });
  };

  svc.showProjectSettings = function($event, $scope){
    // defaults
    var controller =  'OpenApiSettingsController';
    var templateOpenApi = require('./partials/openapi-project-settings.html');
    var templateLoopback = require('./partials/loopback-project-settings.html');
    var template = templateOpenApi;

    // override defaults if loopback project
    if ($scope.activeProject.projectType === 'loopback'){
      controller =  'LoopbackSettingsController';
      template = templateLoopback;
    }

    $modal.open({
      template: template,
      windowTemplateUrl: 'apim/partials/main-template.html',
      controller: controller,
      size: 'md',
      scope: $scope
    });
  };

  svc.getProjects = function(){
    return $http.get('/project-list/Projects');
  };

  svc.addProject = function(data){
    var project = data;

    return $http.post('/project-list/Projects', project)
      .then(function(result){
        $localStorage.setItem('activeProject', result.data);
        return result;
      });
  };

  svc.updateProject = function(data){
    var project = data;

    return $http.put('/project-list/Projects/'+project.id, project)
      .then(function(result){
        $localStorage.setItem('activeProject', result.data);

        return result;
      });
  };

  svc.deleteProject = function(project){
    return $http['delete']('/project-list/Projects/'+project.id)
      .then(function(result){
        return $localStorage.removeItem('activeProject');
      });
  };

  svc.setProjectEnvironment = function(project){
    var def = $q.defer();

    if ( !project.path ) {
      def.reject(new Error('no project path defined'));
    } else {
      Workspace.loadWorkspace({ path: project.path }, function(){
        $localStorage.setItem('activeProject', project);
        def.resolve(project);
      });
    }

    return def.promise;
  };

  svc.getWorkspaceEnvironment = function(){
    return Workspace.getWorkspace().$promise
      .then(function(result){
        if ( result.path === 'undefined' ) {
          delete result.path;
        }

        return result;
      });
  };

  svc.getDuplicateProjects = function($scope, newObj){
    if (!Object.keys(newObj).length || !$scope.projects.length) return;

    // get duplicate project if exists
    var duplicateProjects = $scope.projects.filter(function(project) {
      return project.displayName === newObj.displayName ||
        project.path === newObj.path ||
        project.name === newObj.name;
    });

    $scope.duplicateProject = Boolean(duplicateProjects.length) && duplicateProjects.shift();
  };

  // global events
  $rootScope.$on('event:projects:addNewOpenApiProject', svc.openAddNewOpenApiProject.bind(svc));
  $rootScope.$on('event:projects:openAddNewLoopbackProject', svc.openAddNewLoopbackProject.bind(svc));
  $rootScope.$on('event:projects:openAddExistingProject', svc.openAddExistingProject.bind(svc));
  $rootScope.$on('event:projects:showProjectSettings', svc.showProjectSettings.bind(svc));

  return svc;
}];


},{"./partials/loopback-project-settings.html":16,"./partials/new-loopback-project.html":17,"./partials/new-openapi-project.html":18,"./partials/new-project.html":19,"./partials/openapi-project-settings.html":22}],37:[function(require,module,exports){
module.exports = ".apim .add-new-project{padding:2rem;}.apim .add-new-project .spinner-container{display:inline-block;margin-right:1rem;position:relative;width:2rem;height:2rem;}.apim .add-new-project .spinner-container .spinner{position:absolute;top:.5rem;display:inline-block;margin:0;width:2rem;height:2rem}.apim .add-new-project h1{line-height:1.2}.apim .add-new-project md-input-container.has-link{position:relative;}.apim .add-new-project md-input-container.has-link input{width:80%}.apim .add-new-project md-input-container.has-link a.open-filepicker{position:absolute;top:3px;right:0;}.apim .projects-menu .navHeader,.apim .projects-menu .navItem{position:relative;}.apim .projects-menu .navHeader .display-name,.apim .projects-menu .navItem .display-name{display:inline-block;overflow-x:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;width:76%}.apim .projects-menu .navHeader .pill,.apim .projects-menu .navItem .pill{position:absolute;right:2.4rem}.apim .projects-menu .delete-project{position:absolute;top:.8rem;right:.9rem;}.apim .projects-menu .navItem .delete-project{display:none;}.apim .projects-menu .navItem .delete-project i{font-size:1.2rem}.apim .projects-menu .navItem:hover .delete-project{display:block;}.apim .projects-menu .navItem:hover .delete-project:hover{color:$apim-navitem-delete-hover-color}.apim .projects-menu .navItem.selected .delete-project{display:none}.apim .projects-menu .dropdown{position:absolute;top:0;right:.5rem;}.apim .projects-menu .dropdown .dropdown-menu{position:absolute;left:-215px;}.apim .projects-menu .dropdown .dropdown-menu .pill{position:relative;right:auto}.projects-filepicker-deprecated .files{margin-bottom:2rem;max-height:60vh;overflow-y:auto;padding-left:0;}.projects-filepicker-deprecated .files li:nth-child(odd){background-color:$apim-filepicker-odd-bg}.projects-filepicker-deprecated .files .selected a{background:$apim-filepicker-selected-bg;color:$apim-filepicker-selected-color}.projects-filepicker-deprecated .files .selected .material-icons.directory,.projects-filepicker-deprecated .files .selected .material-icons.file,.projects-filepicker-deprecated .files .selected .material-icons.symlink{color:$apim-filepicker-selected-icon-color}.projects-filepicker-deprecated .files li{display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-orient:vertical;-moz-box-orient:vertical;-o-box-orient:vertical;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-moz-box-pack:center;-o-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;resize:vertical}.projects-filepicker-deprecated .files li > span,.projects-filepicker-deprecated .files li > a{color:$apim-filepicker-file-color;padding:.2rem 1rem;resize:vertical;text-decoration:none}.projects-filepicker-deprecated .files .material-icons{font-size:inherit;}.projects-filepicker-deprecated .files .material-icons.directory{color:$apim-filepicker-icon-directory-color}.projects-filepicker-deprecated .files .material-icons.file,.projects-filepicker-deprecated .files .material-icons.symlink{color:$apim-filepicker-icon-file-color}.projects-filepicker-deprecated .cwd{white-space:pre-wrap;word-break:break-all;word-wrap:break-word}#new-project-form footer{display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-pack:justify;-moz-box-pack:justify;-o-box-pack:justify;-ms-flex-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;margin-top:1rem;}#new-project-form footer.no-tertiary{-webkit-box-pack:end;-moz-box-pack:end;-o-box-pack:end;-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.project-settings #new-project-form footer{-webkit-box-pack:end;-moz-box-pack:end;-o-box-pack:end;-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}";
},{}]},{},[10]);
