<commit_before>'use strict'

import newCounter from './counter.js'

let subscriptions
const matcher = /{{([^}]*)}}/

function subscribe (obj, prop, action) {
  let stack = subscriptions.get(obj)
  let pile = stack.get(prop) || stack.set(prop, new Set()).get(prop)
  pile.add(action)
}

function getScopedLoop (scope, schema) {
  let scopeAtt = schema.scope
  if (scopeAtt) {
    return scope[scopeAtt][schema.repeat]
  } else {
    return scope[schema.repeat]
  }
}

function parseStr (str) {
  if (!str) {
    return []
  }
  let st = str.match(matcher)
  if (st.index) {
    let out = str.substr(0, st.index)
    let fns = parseStr(str.substring(st.index))
    return [() => out].concat(fns)
  } else {
    let model = st[1].trim()
    let fns = parseStr(str.substring(st[0].length))
    return [scope => scope[model] || ''].concat(fns)
  }
}

function compileStr (str) {
  let fns = parseStr(str)
  let reduce
  if (fns.length === 1) {
    reduce = scope => fns[0](scope)
  } else {
    reduce = scope => fns.reduce((str, fn) => str + fn(scope), '')
  }
  let models = new Set()
  str.replace(/{{(.*?)}}/g, (g0, g1) => models.add(g1.trim()))
  return { reduce, models }
}

function compileAttributes (atts) { // compile attributes
  let fns = Object.keys(atts).map(name => {
    let value = atts[name]
    if (name.endsWith('-')) {
      let att = name.slice(0, -1)
      let model = value.match(matcher)[1].trim()
      return function (nut) {
        let updateFn = () => {
          if (nut.scope[model]) {
            nut.el.setAttribute(att, '')
          } else {
            nut.el.removeAttribute(att)
          }
        }
        subscribe(nut.scope, model, updateFn)
        updateFn()
      }
    } else {
      if (!value.match(matcher)) {
        return nut => nut.el.setAttribute(name, value)
      }
      let { reduce, models } = compileStr(value)
      return function (nut) {
        let updateFn = () => nut.el.setAttribute(name, reduce(nut.scope))
        models.forEach(model => subscribe(nut.scope, model, updateFn))
        updateFn()
      }
    }
  })
  return (nut) => fns.forEach(fn => fn(nut))
}

function compileText (schema, callback) {
  let data = schema.data
  if (data.match(matcher)) {
    let { reduce, models } = compileStr(data)
    schema.render = function (scope) {
      let el = document.createTextNode(reduce(scope))
      let updateFn = () => el.textContent = reduce(scope)
      models.forEach(model => subscribe(scope, model, updateFn))
      return el
    }
  } else {
    schema.render = () => document.createTextNode(data)
  }
  callback()
}

function createStack () {
  let pile = []
  return {
    add: fn => pile.push(fn),
    exec: nut => pile.forEach(fn => fn(nut))
  }
}

function compileTag (schema, callback) {
  let { events, children, attribs } = schema
  let stack = createStack()
  if (attribs) stack.add(compileAttributes(attribs))
  if (events) {
    stack.add(nut => {
      Object.keys(events).forEach(type => {
        nut.el.addEventListener(type, e => events[type](e, nut))
      })
    })
  }
  if (children) {
    stack.add(nut => children.forEach(c => nut.el.appendChild(c.render(nut.scope))))
  }

  schema.render = (outerScope) => {
    if (schema.scope && !outerScope[schema.scope]) return document.createDocumentFragment()
    let scope = schema.scope ? outerScope[schema.scope] : outerScope,
        el = document.createElement(schema.localName),
        nut = { el, scope }
    stack.exec(nut)
    return el
  }

  // compile children
  if (children && children.length) {
    let count = newCounter(children.length, callback)
    children.forEach(c => compile(c, count))
  } else {
    callback()
  }
}

function compileLoop (schema, callback) {
  let { events, children, attribs } = schema
  let renderAttributes
  if (attribs) {
    renderAttributes = compileAttributes(attribs)
  }
  schema.render = (outerScope) => {
    let scope = getScopedLoop(outerScope, schema),
        fragment = document.createDocumentFragment()

    scope.forEach(item => {
      let el = document.createElement(schema.localName),
          nut = { el, scope: item }
      // render attributes
      if (attribs) renderAttributes(el, item)
      // add events
      if (events) {
        Object.keys(events).forEach(type => el.addEventListener(type, e => events[type](e, nut)))
      }
      // render children
      if (schema.children) {
        schema.children.forEach(c => el.appendChild(c.render(item)))
      }
      fragment.appendChild(el)
    })
    return fragment
  }
  // compile children
  if (children && children.length) {
    let count = newCounter(children.length, callback)
    children.forEach(c => compile(c, count))
  } else {
    callback()
  }
}

function compile (schema, callback) {
  if (schema.type === 1) {
    if ('repeat' in schema) {
      compileLoop(schema, callback)
    } else {
      compileTag(schema, callback)
    }
  } else if (schema.type === 3) {
    compileText(schema, callback)
  }
}

export default function (inLinks) {
  subscriptions = inLinks
  return compile
}
<commit_msg>remove getScope and getScopedLoop methods from compiler<commit_after>'use strict'

import newCounter from './counter.js'

let subscriptions
const matcher = /{{([^}]*)}}/

function subscribe (obj, prop, action) {
  let stack = subscriptions.get(obj)
  let pile = stack.get(prop) || stack.set(prop, new Set()).get(prop)
  pile.add(action)
}

function parseStr (str) {
  if (!str) return []
  let st = str.match(matcher)
  if (st.index) {
    let out = str.substr(0, st.index)
    let fns = parseStr(str.substring(st.index))
    return [() => out].concat(fns)
  } else {
    let model = st[1].trim()
    let fns = parseStr(str.substring(st[0].length))
    return [scope => scope[model] || ''].concat(fns)
  }
}

function compileStr (str) {
  let fns = parseStr(str)
  let reduce
  if (fns.length === 1) {
    reduce = scope => fns[0](scope)
  } else {
    reduce = scope => fns.reduce((str, fn) => str + fn(scope), '')
  }
  let models = new Set()
  str.replace(/{{(.*?)}}/g, (g0, g1) => models.add(g1.trim()))
  return { reduce, models }
}

function compileAttributes (atts) { // compile attributes
  let fns = Object.keys(atts).map(name => {
    let value = atts[name]
    if (name.endsWith('-')) {
      let att = name.slice(0, -1)
      let model = value.match(matcher)[1].trim()
      return function (nut) {
        let updateFn = () => {
          if (nut.scope[model]) {
            nut.el.setAttribute(att, '')
          } else {
            nut.el.removeAttribute(att)
          }
        }
        subscribe(nut.scope, model, updateFn)
        updateFn()
      }
    } else {
      if (!value.match(matcher)) {
        return nut => nut.el.setAttribute(name, value)
      }
      let { reduce, models } = compileStr(value)
      return function (nut) {
        let updateFn = () => nut.el.setAttribute(name, reduce(nut.scope))
        models.forEach(model => subscribe(nut.scope, model, updateFn))
        updateFn()
      }
    }
  })
  return (nut) => fns.forEach(fn => fn(nut))
}

function compileText (schema, callback) {
  let data = schema.data
  if (data.match(matcher)) {
    let { reduce, models } = compileStr(data)
    schema.render = function (scope) {
      let el = document.createTextNode(reduce(scope))
      let updateFn = () => el.textContent = reduce(scope)
      models.forEach(model => subscribe(scope, model, updateFn))
      return el
    }
  } else {
    schema.render = () => document.createTextNode(data)
  }
  callback()
}

function createStack () {
  let pile = []
  return {
    add: fn => pile.push(fn),
    exec: nut => pile.forEach(fn => fn(nut))
  }
}

function compileTag (schema, callback) {
  let { events, children, attribs } = schema
  let stack = createStack()
  if (attribs) stack.add(compileAttributes(attribs))
  if (events) {
    stack.add(nut => {
      Object.keys(events).forEach(type => {
        nut.el.addEventListener(type, e => events[type](e, nut))
      })
    })
  }
  if (children) {
    stack.add(nut => children.forEach(c => nut.el.appendChild(c.render(nut.scope))))
  }

  schema.render = (outerScope) => {
    if (schema.scope && !outerScope[schema.scope]) return document.createDocumentFragment()
    let scope = schema.scope ? outerScope[schema.scope] : outerScope,
        el = document.createElement(schema.localName),
        nut = { el, scope }
    stack.exec(nut)
    return el
  }

  // compile children
  if (children && children.length) {
    let count = newCounter(children.length, callback)
    children.forEach(c => compile(c, count))
  } else {
    callback()
  }
}

function compileLoop (schema, callback) {
  let { events, children, attribs } = schema
  let scopeAtt = schema.scope
  let renderAttributes
  if (attribs) {
    renderAttributes = compileAttributes(attribs)
  }
  schema.render = (outerScope) => {
    let fragment = document.createDocumentFragment()
    let scope = scopeAtt ? outerScope[scopeAtt][schema.repeat] : outerScope[schema.repeat]

    scope.forEach(item => {
      let el = document.createElement(schema.localName),
          nut = { el, scope: item }
      // render attributes
      if (attribs) renderAttributes(el, item)
      // add events
      if (events) {
        Object.keys(events).forEach(type => el.addEventListener(type, e => events[type](e, nut)))
      }
      // render children
      if (schema.children) {
        schema.children.forEach(c => el.appendChild(c.render(item)))
      }
      fragment.appendChild(el)
    })
    return fragment
  }
  // compile children
  if (children && children.length) {
    let count = newCounter(children.length, callback)
    children.forEach(c => compile(c, count))
  } else {
    callback()
  }
}

function compile (schema, callback) {
  if (schema.type === 1) {
    if ('repeat' in schema) {
      compileLoop(schema, callback)
    } else {
      compileTag(schema, callback)
    }
  } else if (schema.type === 3) {
    compileText(schema, callback)
  }
}

export default function (inLinks) {
  subscriptions = inLinks
  return compile
}
<|endoftext|>


<commit_before>'use strict';

var async = require('async'),
    Bluebird = require('bluebird');

module.exports = {
    description: 'Adicionando campo type ao tipo a tabela de tarefas',

    up: function(transaction, migrator, sequelize) {
        var queries = [
            "ALTER TABLE `tasks` CHANGE `type` `type` ENUM('TASK','KNOWLEDGEBASE')  CHARACTER SET utf8  NOT NULL  DEFAULT 'task';"
        ];

        return new Bluebird(function(resolve, reject) {
            async.eachSeries(queries, function(query, callback) {
                sequelize.query(query, null, {
                    transaction: transaction
                }).complete(callback);
            }, function(err) {
                if(err) {
                    return reject(err);
                }

                resolve();
            });
        });
    },

    down: function(transaction, migrator, sequelize) {
        var queries = [
            "SELECT 1;"
        ];

        return new Bluebird(function(resolve, reject) {
            async.eachSeries(queries, function(query, callback) {
                sequelize.query(query, null, {
                    transaction: transaction
                }).complete(callback);
            }, function(err) {
                if(err) {
                    return reject(err);
                }

                resolve();
            });
        });
    }
}<commit_msg>bugfix<commit_after>'use strict';

var async = require('async'),
    Bluebird = require('bluebird');

module.exports = {
    description: 'Adicionando campo type ao tipo a tabela de tarefas',

    up: function(transaction, migrator, sequelize) {
        var queries = [
            "ALTER TABLE `tasks` ADD `type` ENUM('task','knowledgebase')  NOT NULL  DEFAULT 'task'  AFTER `description`;"
        ];

        return new Bluebird(function(resolve, reject) {
            async.eachSeries(queries, function(query, callback) {
                sequelize.query(query, null, {
                    transaction: transaction
                }).complete(callback);
            }, function(err) {
                if(err) {
                    return reject(err);
                }

                resolve();
            });
        });
    },

    down: function(transaction, migrator, sequelize) {
        var queries = [
            "SELECT 1;"
        ];

        return new Bluebird(function(resolve, reject) {
            async.eachSeries(queries, function(query, callback) {
                sequelize.query(query, null, {
                    transaction: transaction
                }).complete(callback);
            }, function(err) {
                if(err) {
                    return reject(err);
                }

                resolve();
            });
        });
    }
}<|endoftext|>


<commit_before>import AWS from 'aws-sdk-promise'
import awsLambda from 'node-aws-lambda'
import crypto from 'crypto'
import fs from 'fs'
import glob from 'glob'
import yazl from 'yazl'
import { EventEmitter } from 'events'

const DEFAULT_STAGE_NAME = 'production';

/**
 * @class
 */
export default class Composer extends EventEmitter {
  /**
   * @param {String} accessKeyId
   * @param {Application} application
   * @param {Client=} client
   * @param {String} region
   * @param {String} secretAccessKey
   */
  constructor({ accessKeyId, application, client, secretAccessKey }) {
    super();
    this.accessKeyId = accessKeyId;
    this.secretAccessKey = secretAccessKey;
    this.application = application;
    this.client = client;
  }

  /**
   * @param {Stirng} restApiId
   * @return {Promise}
   */
  createDeployment({ restApiId }) {
    return this.getClient().createDeployment({
      restApiId: restApiId,
      stageName: DEFAULT_STAGE_NAME
    }).promise().then((value) => {
      this.emit(
        'deploymentCreated',
        {
          restApiId: restApiId,
          region: this.application.getRegion(),
          stageName: DEFAULT_STAGE_NAME
        }
      );
      return value.data;
    });
  }

  /**
   * @param {Array.<Object>} resources
   * @return {Promise}
   */
  _sortResourceByPathHierarchy(resources) {
    return new Promise((resolve, reject) => {
      resolve(resources.sort((a, b) => {
        /* sort descending */
        let aPathDepth = a.path.split('/').filter((dir) => { return dir !== '' }).length;
        let bPathDepth = b.path.split('/').filter((dir) => { return dir !== '' }).length;
        if (aPathDepth < bPathDepth) {
          return 1;
        } else if (aPathDepth > bPathDepth) {
          return -1;
        } else {
          return 0;
        }
      }));
    });
  }

  /**
   * @param {Array.<Object>} existingResources
   * @param {String} path
   * @return {Promise}
   */
  _findParentResourceByPath({ existingResources, path }) {
    return this._sortResourceByPathHierarchy(existingResources).then((resources) => {
      for (var i = 0; i < resources.length; i++) {
        if (path.indexOf(resources[i].path) == 0) {
          return resources[i];
        }
      }
      throw new Error("path '" + path + "' does not have any parent resources");
    });
  }

  /**
   * @param {Array.<Object>} existingResources
   * @param {String} restApiId
   * @param {String} path
   * @return {Promise}
   */
  createResourceWithRecursivePath({ existingResources, restApiId, path }) {
    return this._findParentResourceByPath({
      existingResources: existingResources,
      path: path
    }).then((existingParentResource) => {
      let restPaths = path.slice(existingParentResource.path.length).split('/').filter((dir) => { return dir !== '' });
      return restPaths.map((pathPart) => {
        return (parentResource) => {
          return this.getClient().createResource({
            parentId: parentResource.id,
            pathPart: pathPart,
            restApiId: restApiId
          }).promise();
        };
      }).reduce((promise, task) => {
        return promise.then(task).then((resource) => {
          existingResources.push(resource.data);
          return resource.data;
        });
      }, Promise.resolve(existingParentResource));
    });
  }

  /**
   * @param {String} existingResources
   * @param {Object} action
   * @param {String} restApiId
   * @return {Promise}
   */
  buildResource({ existingResources, action, restApiId }) {
    return this.createResourceWithRecursivePath({
      existingResources: existingResources,
      restApiId: restApiId,
      path: action.getPath()
    }).then((resource) => {
      return this.updateMethodSet({
        region: this.application.getRegion(),
        restApiId: restApiId,
        resource: resource,
        action: action
      });
    });
  }

  /**
   * @param {String} restApiId
   * @return {Promise}
   */
  createResourceSets({ restApiId }) {
    return this.getClient().getResources({
      restApiId: restApiId
    }).promise().then((resources) => {
      resources = resources.data.items;
      return this.application.getActions().map((action) => {
        return () => {
          return this.buildResource({
            existingResources: resources,
            restApiId: restApiId,
            action: action
          });
        };
      }).reduce((promise, task) => {
        return promise.then(task);
      }, Promise.resolve());
    });
  }

  /**
   * @return {Promise}
   */
  createRestApi() {
    return this.getClient().createRestApi({
      name: this.application.getName()
    }).promise().then((restApi) => {
      this.application.writeRestApiId(restApi.data.id);
      return restApi;
    }).then((restApi) => {
      this.emit('restApiCreated', { restApiId: restApi.data.id });
      return restApi;
    });
  }

  /**
   * @param {Action} action
   * @return {Promise}
   */
  createZipFile({ action }) {
    return new Promise((resolve, reject) => {
      const actionPath = action.getDirectoryPath();
      const zipFile = new yazl.ZipFile();
      const zipPath = action.getZipPath();
      if (fs.existsSync(zipPath)) {
        fs.unlinkSync(zipPath);
      }
      glob.sync(`${actionPath}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(
            path,
            path.substr(`${actionPath}/`.length)
          );
        }
      });
      glob.sync(`./node_modules/{${this.application.getProductionPackageNames().join(',')}}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      glob.sync(`./config/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      zipFile.outputStream.pipe(
        fs.createWriteStream(zipPath)
      ).on('close', () => {
        resolve();
      });
      zipFile.end();
    }).then((value) => {
      this.emit('zipFileCreated', { zipPath: action.getZipPath() });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  createZipFiles() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.createZipFile({ action: action });
      })
    );
  }

  /**
   * Set up Amazon Lambda functions and API Gateway endpoints.
   * @return {Promise}
   */
  deploy() {
    return this.createZipFiles().then(() => {
      return this.uploadActions();
    }).then(() => {
      return this.findOrCreateRestApi();
    }).then((restApi) => {
      return this.createResourceSets({
        restApiId: restApi.data.id
      }).then(() => {
        return restApi.data;
      });
    }).then((restApi) => {
      this.createDeployment({
        restApiId: restApi.id
      });
    });
  }

  /**
   * @return {Promise}
   */
  findOrCreateRestApi() {
    const restApiId = this.application.getRestApiId();
    if (restApiId) {
      return this.getClient().getRestApi({
        restApiId: restApiId
      }).promise().then((restApi) => {
        return restApi;
      }).catch((reason) => {
        if (reason.code === 'NotFoundException') {
          return this.createRestApi();
        }
      });
    } else {
      return this.createRestApi();
    }
  }

  /**
   * @return {Client}
   */
  getClient() {
    if (!this.client) {
      this.client = new AWS.APIGateway({
        accessKeyId: this.accessKeyId,
        secretAccessKey: this.secretAccessKey,
        region: this.application.getRegion()
      });
    }
    return this.client;
  }

  /**
   * @param {String} region
   * @param {String} restApiId
   * @param {Object} action
   * @param {Object} resource
   * @return {Promise}
   */
  updateMethodSet({ region, restApiId, action, resource }) {
    return (() => {
      let foundMethod;
      if (resource.resourceMethods) {
        foundMethod = Object.keys(resource.resourceMethods).find((method) => {
          return method === action.getHttpMethod();
        });
      } else {
        foundMethod = false;
      }
      if (foundMethod) {
        return Promise.resolve(resource.resourceMethods[foundMethod]);
      } else {
        return this.getClient().putMethod({
          authorizationType: 'NONE',
          httpMethod: action.getHttpMethod(),
          resourceId: resource.id,
          restApiId: restApiId
        }).promise()
      }
    })().then((method) => {
      return this.getClient().putIntegration({
        httpMethod: action.getHttpMethod(),
        integrationHttpMethod: 'POST',
        requestTemplates: action.getRequestTemplates(),
        resourceId: resource.id,
        restApiId: restApiId,
        type: 'AWS',
        uri: action.getUri()
      }).promise();
    }).then((integration) => {
      return this.getClient().putMethodResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseModels: action.getResponseModels(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return this.getClient().putIntegrationResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseTemplates: action.getResponseTemplates(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return new AWS.Lambda({
        region: region
      }).addPermission({
        Action: 'lambda:InvokeFunction',
        FunctionName: action.getName(),
        Principal: 'apigateway.amazonaws.com',
        StatementId: crypto.randomBytes(20).toString('hex')
      }).promise();
    }).then((value) => {
      this.emit(
        'methodSetUpdated',
        {
          httpMethod: action.getHttpMethod(),
          path: action.getPath()
        }
      );
      return value.data;
    });
  }

  /**
   * @param {String} functionName
   * @param {String} handlerId
   * @param {String} region
   * @param {String} roleArn
   * @param {Integer} timeout
   * @param {Integer} memorySize
   * @param {String} zipPath
   * @return {Promise}
   */
  uploadAction({ functionName, handlerId, region, roleArn, timeout, memorySize, zipPath, }) {
    return new Promise((resolve, reject) => {
      awsLambda.deploy(
        zipPath,
        {
          functionName: functionName,
          handler: handlerId,
          region: region,
          role: roleArn,
          timeout: timeout,
          memorySize: memorySize
        },
        (error) => {
          if (error) {
            reject(error);
          } else {
            resolve();
          }
        }
      );
    }).then((value) => {
      this.emit('functionUploaded', { functionName: functionName });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  uploadActions() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.uploadAction({
          zipPath: `${action.getDirectoryPath()}/lambda.zip`,
          region: this.application.getRegion(),
          roleArn: this.application.getRoleArn(),
          functionName: action.getName(),
          handlerId: action.getHandlerId(),
          timeout: action.getTimeout(),
          memorySize: action.getMemorySize()
        });
      })
    );
  }

  /**
   * @param {Function} middleware
   * @param {Object=} options
   * @return {Composer}
   */
  use(middleware, options) {
    return new this.constructor({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      application: this.application,
      client: this.getClient().use(middleware, options)
    });
  }
}
<commit_msg>Get method data with individual getting resource because this bug: https://github.com/aws/aws-sdk-js/issues/764<commit_after>import AWS from 'aws-sdk-promise'
import awsLambda from 'node-aws-lambda'
import crypto from 'crypto'
import fs from 'fs'
import glob from 'glob'
import yazl from 'yazl'
import { EventEmitter } from 'events'

const DEFAULT_STAGE_NAME = 'production';

/**
 * @class
 */
export default class Composer extends EventEmitter {
  /**
   * @param {String} accessKeyId
   * @param {Application} application
   * @param {Client=} client
   * @param {String} region
   * @param {String} secretAccessKey
   */
  constructor({ accessKeyId, application, client, secretAccessKey }) {
    super();
    this.accessKeyId = accessKeyId;
    this.secretAccessKey = secretAccessKey;
    this.application = application;
    this.client = client;
  }

  /**
   * @param {Stirng} restApiId
   * @return {Promise}
   */
  createDeployment({ restApiId }) {
    return this.getClient().createDeployment({
      restApiId: restApiId,
      stageName: DEFAULT_STAGE_NAME
    }).promise().then((value) => {
      this.emit(
        'deploymentCreated',
        {
          restApiId: restApiId,
          region: this.application.getRegion(),
          stageName: DEFAULT_STAGE_NAME
        }
      );
      return value.data;
    });
  }

  /**
   * @param {Array.<Object>} resources
   * @return {Promise}
   */
  _sortResourceByPathHierarchy(resources) {
    return new Promise((resolve, reject) => {
      resolve(resources.sort((a, b) => {
        /* sort descending */
        let aPathDepth = a.path.split('/').filter((dir) => { return dir !== '' }).length;
        let bPathDepth = b.path.split('/').filter((dir) => { return dir !== '' }).length;
        if (aPathDepth < bPathDepth) {
          return 1;
        } else if (aPathDepth > bPathDepth) {
          return -1;
        } else {
          return 0;
        }
      }));
    });
  }

  /**
   * @param {Array.<Object>} existingResources
   * @param {String} path
   * @return {Promise}
   */
  _findParentResourceByPath({ existingResources, path }) {
    return this._sortResourceByPathHierarchy(existingResources).then((resources) => {
      for (var i = 0; i < resources.length; i++) {
        if (path.indexOf(resources[i].path) == 0) {
          return resources[i];
        }
      }
      throw new Error("path '" + path + "' does not have any parent resources");
    });
  }

  /**
   * @param {Array.<Object>} existingResources
   * @param {String} restApiId
   * @param {String} path
   * @return {Promise}
   */
  createResourceWithRecursivePath({ existingResources, restApiId, path }) {
    return this._findParentResourceByPath({
      existingResources: existingResources,
      path: path
    }).then((existingParentResource) => {
      let restPaths = path.slice(existingParentResource.path.length).split('/').filter((dir) => { return dir !== '' });
      return restPaths.map((pathPart) => {
        return (parentResource) => {
          return this.getClient().createResource({
            parentId: parentResource.id,
            pathPart: pathPart,
            restApiId: restApiId
          }).promise();
        };
      }).reduce((promise, task) => {
        return promise.then(task).then((resource) => {
          existingResources.push(resource.data);
          return resource.data;
        });
      }, Promise.resolve(existingParentResource));
    });
  }

  /**
   * @param {String} existingResources
   * @param {Object} action
   * @param {String} restApiId
   * @return {Promise}
   */
  buildResource({ existingResources, action, restApiId }) {
    return this.createResourceWithRecursivePath({
      existingResources: existingResources,
      restApiId: restApiId,
      path: action.getPath()
    }).then((resource) => {
      return this.updateMethodSet({
        region: this.application.getRegion(),
        restApiId: restApiId,
        resource: resource,
        action: action
      });
    });
  }

  /**
   * @param {String} restApiId
   * @return {Promise}
   */
  createResourceSets({ restApiId }) {
    return this.getClient().getResources({
      restApiId: restApiId
    }).promise().then((resources) => {
      resources = resources.data.items;
      return this.application.getActions().map((action) => {
        return () => {
          return this.buildResource({
            existingResources: resources,
            restApiId: restApiId,
            action: action
          });
        };
      }).reduce((promise, task) => {
        return promise.then(task);
      }, Promise.resolve());
    });
  }

  /**
   * @return {Promise}
   */
  createRestApi() {
    return this.getClient().createRestApi({
      name: this.application.getName()
    }).promise().then((restApi) => {
      this.application.writeRestApiId(restApi.data.id);
      return restApi;
    }).then((restApi) => {
      this.emit('restApiCreated', { restApiId: restApi.data.id });
      return restApi;
    });
  }

  /**
   * @param {Action} action
   * @return {Promise}
   */
  createZipFile({ action }) {
    return new Promise((resolve, reject) => {
      const actionPath = action.getDirectoryPath();
      const zipFile = new yazl.ZipFile();
      const zipPath = action.getZipPath();
      if (fs.existsSync(zipPath)) {
        fs.unlinkSync(zipPath);
      }
      glob.sync(`${actionPath}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(
            path,
            path.substr(`${actionPath}/`.length)
          );
        }
      });
      glob.sync(`./node_modules/{${this.application.getProductionPackageNames().join(',')}}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      glob.sync(`./config/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      zipFile.outputStream.pipe(
        fs.createWriteStream(zipPath)
      ).on('close', () => {
        resolve();
      });
      zipFile.end();
    }).then((value) => {
      this.emit('zipFileCreated', { zipPath: action.getZipPath() });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  createZipFiles() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.createZipFile({ action: action });
      })
    );
  }

  /**
   * Set up Amazon Lambda functions and API Gateway endpoints.
   * @return {Promise}
   */
  deploy() {
    return this.createZipFiles().then(() => {
      return this.uploadActions();
    }).then(() => {
      return this.findOrCreateRestApi();
    }).then((restApi) => {
      return this.createResourceSets({
        restApiId: restApi.data.id
      }).then(() => {
        return restApi.data;
      });
    }).then((restApi) => {
      this.createDeployment({
        restApiId: restApi.id
      });
    });
  }

  /**
   * @return {Promise}
   */
  findOrCreateRestApi() {
    const restApiId = this.application.getRestApiId();
    if (restApiId) {
      return this.getClient().getRestApi({
        restApiId: restApiId
      }).promise().then((restApi) => {
        return restApi;
      }).catch((reason) => {
        if (reason.code === 'NotFoundException') {
          return this.createRestApi();
        }
      });
    } else {
      return this.createRestApi();
    }
  }

  /**
   * @return {Client}
   */
  getClient() {
    if (!this.client) {
      this.client = new AWS.APIGateway({
        accessKeyId: this.accessKeyId,
        secretAccessKey: this.secretAccessKey,
        region: this.application.getRegion()
      });
    }
    return this.client;
  }

  /**
   * @param {String} region
   * @param {String} restApiId
   * @param {Object} action
   * @param {Object} resource
   * @return {Promise}
   */
  updateMethodSet({ region, restApiId, action, resource }) {
    return (() => {
      let foundMethod;
      if (resource.resourceMethods) {
        foundMethod = Object.keys(resource.resourceMethods).find((method) => {
          return method === action.getHttpMethod();
        });
      } else {
        foundMethod = false;
      }
      if (foundMethod) {
        return this.getClient().getMethod({
          httpMethod: action.getHttpMethod(),
          resourceId: resource.id,
          restApiId: restApiId
        }).promise()
      } else {
        return this.getClient().putMethod({
          authorizationType: 'NONE',
          httpMethod: action.getHttpMethod(),
          resourceId: resource.id,
          restApiId: restApiId
        }).promise()
      }
    })().then((method) => {
      return this.getClient().putIntegration({
        httpMethod: action.getHttpMethod(),
        integrationHttpMethod: 'POST',
        requestTemplates: action.getRequestTemplates(),
        resourceId: resource.id,
        restApiId: restApiId,
        type: 'AWS',
        uri: action.getUri()
      }).promise();
    }).then((integration) => {
      return this.getClient().putMethodResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseModels: action.getResponseModels(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return this.getClient().putIntegrationResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseTemplates: action.getResponseTemplates(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return new AWS.Lambda({
        region: region
      }).addPermission({
        Action: 'lambda:InvokeFunction',
        FunctionName: action.getName(),
        Principal: 'apigateway.amazonaws.com',
        StatementId: crypto.randomBytes(20).toString('hex')
      }).promise();
    }).then((value) => {
      this.emit(
        'methodSetUpdated',
        {
          httpMethod: action.getHttpMethod(),
          path: action.getPath()
        }
      );
      return value.data;
    });
  }

  /**
   * @param {String} functionName
   * @param {String} handlerId
   * @param {String} region
   * @param {String} roleArn
   * @param {Integer} timeout
   * @param {Integer} memorySize
   * @param {String} zipPath
   * @return {Promise}
   */
  uploadAction({ functionName, handlerId, region, roleArn, timeout, memorySize, zipPath, }) {
    return new Promise((resolve, reject) => {
      awsLambda.deploy(
        zipPath,
        {
          functionName: functionName,
          handler: handlerId,
          region: region,
          role: roleArn,
          timeout: timeout,
          memorySize: memorySize
        },
        (error) => {
          if (error) {
            reject(error);
          } else {
            resolve();
          }
        }
      );
    }).then((value) => {
      this.emit('functionUploaded', { functionName: functionName });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  uploadActions() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.uploadAction({
          zipPath: `${action.getDirectoryPath()}/lambda.zip`,
          region: this.application.getRegion(),
          roleArn: this.application.getRoleArn(),
          functionName: action.getName(),
          handlerId: action.getHandlerId(),
          timeout: action.getTimeout(),
          memorySize: action.getMemorySize()
        });
      })
    );
  }

  /**
   * @param {Function} middleware
   * @param {Object=} options
   * @return {Composer}
   */
  use(middleware, options) {
    return new this.constructor({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      application: this.application,
      client: this.getClient().use(middleware, options)
    });
  }
}
<|endoftext|>


<commit_before>import AWS from 'aws-sdk-promise'
import awsLambda from 'node-aws-lambda'
import crypto from 'crypto'
import fs from 'fs'
import glob from 'glob'
import yazl from 'yazl'
import { EventEmitter } from 'events'

const DEFAULT_STAGE_NAME = 'production';

/**
 * @class
 */
export default class Composer extends EventEmitter {
  /**
   * @param {String} accessKeyId
   * @param {Application} application
   * @param {Client=} client
   * @param {String} region
   * @param {String} secretAccessKey
   */
  constructor({ accessKeyId, application, client, secretAccessKey }) {
    super();
    this.accessKeyId = accessKeyId;
    this.secretAccessKey = secretAccessKey;
    this.application = application;
    this.client = client;
  }

  /**
   * @param {Stirng} restApiId
   * @return {Promise}
   */
  createDeployment({ restApiId }) {
    return this.getClient().createDeployment({
      restApiId: restApiId,
      stageName: DEFAULT_STAGE_NAME
    }).promise().then((value) => {
      this.emit(
        'deploymentCreated',
        {
          restApiId: restApiId,
          region: this.application.getRegion(),
          stageName: DEFAULT_STAGE_NAME
        }
      );
      return value.data;
    });
  }

  /**
   * @param {Array.<Object>} resources
   * @return {Promise}
   */
  _sortResourceByPathHierarchy(resources) {
    return new Promise((resolve, reject) => {
      resolve(resources.sort((a, b) => {
        /* sort descending */
        let aPathDepth = a.path.split('/').filter((dir) => { return dir !== '' }).length;
        let bPathDepth = a.path.split('/').filter((dir) => { return dir !== '' }).length;
        if (aPathDepth < bPathDepth) {
          return 1;
        } else if (aPathDepth > bPathDepth) {
          return -1;
        } else {
          return 0;
        }
      }));
    });
  }

  /**
   * @param {Array.<Object>} resources
   * @param {String} path
   * @return {Promise}
   */
  _findParentResourceByPath({ existingResources, path }) {
    return this._sortResourceByPathHierarchy(existingResources).then((resources) => {
      for (var i = 0; i < resources.length; i++) {
        if (path.indexOf(resources[i].path) == 0) {
          return resources[i];
        }
      }
      throw new Error("path '" + path + "' does not have any parent resources");
    });
  }

  /**
   * @param {String} restApiId
   * @return {Promise}
   */
  createResourceWithRecursivePath({ existingResources, restApiId, path }) {
    return this._findParentResourceByPath({
      existingResources: existingResources,
      path: path
    }).then((existingParentResource) => {
      let restPaths = path.slice(existingParentResource.path.length).split('/').filter((dir) => { return dir !== '' });
      return restPaths.map((pathPart) => {
        return (parentResource) => {
          return this.getClient().createResource({
            parentId: parentResource.id,
            pathPart: pathPart,
            restApiId: restApiId
          }).promise();
        };
      }).reduce((promise, task) => {
        return promise.then(task).then((resource) => {
          return resource.data;
        });
      }, Promise.resolve(existingParentResource));
    });
  }

  /**
   * @param {String} restApiId
   * @return {Promise}
   */
  createResourceSets({ restApiId }) {
    return this.getClient().getResources({
      restApiId: restApiId
    }).promise().then((resources) => {
      resources = resources.data.items;
      return this.application.getActions().map((action) => {
        return () => {
          return this.createResourceWithRecursivePath({
            existingResources: resources,
            restApiId: restApiId,
            path: action.getPath()
          }).then((resource) => {
            resources.push(resource);
            return {
              action: action,
              resource: resource
            };
          });
        };
      }).reduce((promise, task) => {
        return promise.then(task).then((results, value) => {
          results.push(value);
          return results;
        }.bind(null, []));
      }, Promise.resolve());
    }).then((result) => {
      return Promise.all(
        result.map((item) => {
          return this.updateMethodSet({
            region: this.application.getRegion(),
            restApiId: restApiId,
            resource: item.resource,
            action: item.action
          });
        })
      ).then(() => {
        return restApiId;
      });
    });
  }

  /**
   * @return {Promise}
   */
  createRestApi() {
    return this.getClient().createRestApi({
      name: this.application.getName()
    }).promise().then((restApi) => {
      this.application.writeRestApiId(restApi.data.id);
      return restApi;
    }).then((restApi) => {
      this.emit('restApiCreated', { restApiId: restApi.data.id });
      return restApi;
    });
  }

  /**
   * @param {Action} action
   * @return {Promise}
   */
  createZipFile({ action }) {
    return new Promise((resolve, reject) => {
      const actionPath = action.getDirectoryPath();
      const zipFile = new yazl.ZipFile();
      const zipPath = action.getZipPath();
      if (fs.existsSync(zipPath)) {
        fs.unlinkSync(zipPath);
      }
      glob.sync(`${actionPath}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(
            path,
            path.substr(`${actionPath}/`.length)
          );
        }
      });
      glob.sync(`./node_modules/{${this.application.getProductionPackageNames().join(',')}}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      glob.sync(`./config/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      zipFile.outputStream.pipe(
        fs.createWriteStream(zipPath)
      ).on('close', () => {
        resolve();
      });
      zipFile.end();
    }).then((value) => {
      this.emit('zipFileCreated', { zipPath: action.getZipPath() });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  createZipFiles() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.createZipFile({ action: action });
      })
    );
  }

  /**
   * Set up Amazon Lambda functions and API Gateway endpoints.
   * @return {Promise}
   */
  deploy() {
    return this.createZipFiles().then(() => {
      return this.uploadActions();
    }).then(() => {
      return this.findOrCreateRestApi();
    }).then((restApi) => {
      return this.createResourceSets({
        restApiId: restApi.data.id
      }).then(() => {
        return restApi;
      });
    }).then((restApi) => {
      this.createDeployment({
        restApiId: restApi.id
      });
    });
  }

  /**
   * @return {Promise}
   */
  findOrCreateRestApi() {
    const restApiId = this.application.getRestApiId();
    if (restApiId) {
      return this.getClient().getRestApi({
        restApiId: restApiId
      }).promise().then((restApi) => {
        return restApi;
      }).catch((reason) => {
        if (reason.code === 'NotFoundException') {
          return this.createRestApi();
        }
      });
    } else {
      return this.createRestApi();
    }
  }

  /**
   * @return {Client}
   */
  getClient() {
    if (!this.client) {
      this.client = new AWS.APIGateway({
        accessKeyId: this.accessKeyId,
        secretAccessKey: this.secretAccessKey,
        region: this.application.getRegion()
      });
    }
    return this.client;
  }

  /**
   * @param {String} region
   * @param {String} restApiId
   * @param {Object} action
   * @param {Object} resource
   * @return {Promise}
   */
  updateMethodSet({ region, restApiId, action, resource }) {
    (() => {
      let foundMethod = Object.keys(resource.resourceMethods).find((method) => {
        return method === action.getHttpMethod();
      });
      if (foundMethod) {
        return Promise.resolve(resource.resourceMethods[foundMethod]);
      } else {
        return this.getClient().putMethod({
          authorizationType: 'NONE',
          httpMethod: action.getHttpMethod(),
          resourceId: resource.id,
          restApiId: restApiId
        }).promise()
      }
    })().then((method) => {
      return this.getClient().putIntegration({
        httpMethod: action.getHttpMethod(),
        integrationHttpMethod: 'POST',
        requestTemplates: action.getRequestTemplates(),
        resourceId: resource.id,
        restApiId: restApiId,
        type: 'AWS',
        uri: action.getUri()
      }).promise();
    }).then((integration) => {
      return this.getClient().putMethodResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseModels: action.getResponseModels(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return this.getClient().putIntegrationResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseTemplates: action.getResponseTemplates(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return new Promise((resolve, reject) => {
        new AWS.Lambda({
          region: region
        }).addPermission({
          Action: 'lambda:InvokeFunction',
          FunctionName: action.getName(),
          Principal: 'apigateway.amazonaws.com',
          StatementId: crypto.randomBytes(20).toString('hex')
        }).promise();
      })
    }).then((value) => {
      this.emit(
        'methodSetUpdated',
        {
          httpMethod: action.getHttpMethod(),
          path: action.getPath()
        }
      );
      return value.data;
    });
  }

  /**
   * @param {String} functionName
   * @param {String} handlerId
   * @param {String} region
   * @param {String} roleArn
   * @param {Integer} timeout
   * @param {Integer} memorySize
   * @param {String} zipPath
   * @return {Promise}
   */
  uploadAction({ functionName, handlerId, region, roleArn, timeout, memorySize, zipPath, }) {
    return new Promise((resolve, reject) => {
      awsLambda.deploy(
        zipPath,
        {
          functionName: functionName,
          handler: handlerId,
          region: region,
          role: roleArn,
          timeout: timeout,
          memorySize: memorySize
        },
        (error) => {
          if (error) {
            reject(error);
          } else {
            resolve();
          }
        }
      );
    }).then((value) => {
      this.emit('functionUploaded', { functionName: functionName });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  uploadActions() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.uploadAction({
          zipPath: `${action.getDirectoryPath()}/lambda.zip`,
          region: this.application.getRegion(),
          roleArn: this.application.getRoleArn(),
          functionName: action.getName(),
          handlerId: action.getHandlerId(),
          timeout: action.getTimeout(),
          memorySize: action.getMemorySize()
        });
      })
    );
  }

  /**
   * @param {Function} middleware
   * @param {Object=} options
   * @return {Composer}
   */
  use(middleware, options) {
    return new this.constructor({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      application: this.application,
      client: this.getClient().use(middleware, options)
    });
  }
}
<commit_msg>Process that a resource has no resourceMethods<commit_after>import AWS from 'aws-sdk-promise'
import awsLambda from 'node-aws-lambda'
import crypto from 'crypto'
import fs from 'fs'
import glob from 'glob'
import yazl from 'yazl'
import { EventEmitter } from 'events'

const DEFAULT_STAGE_NAME = 'production';

/**
 * @class
 */
export default class Composer extends EventEmitter {
  /**
   * @param {String} accessKeyId
   * @param {Application} application
   * @param {Client=} client
   * @param {String} region
   * @param {String} secretAccessKey
   */
  constructor({ accessKeyId, application, client, secretAccessKey }) {
    super();
    this.accessKeyId = accessKeyId;
    this.secretAccessKey = secretAccessKey;
    this.application = application;
    this.client = client;
  }

  /**
   * @param {Stirng} restApiId
   * @return {Promise}
   */
  createDeployment({ restApiId }) {
    return this.getClient().createDeployment({
      restApiId: restApiId,
      stageName: DEFAULT_STAGE_NAME
    }).promise().then((value) => {
      this.emit(
        'deploymentCreated',
        {
          restApiId: restApiId,
          region: this.application.getRegion(),
          stageName: DEFAULT_STAGE_NAME
        }
      );
      return value.data;
    });
  }

  /**
   * @param {Array.<Object>} resources
   * @return {Promise}
   */
  _sortResourceByPathHierarchy(resources) {
    return new Promise((resolve, reject) => {
      resolve(resources.sort((a, b) => {
        /* sort descending */
        let aPathDepth = a.path.split('/').filter((dir) => { return dir !== '' }).length;
        let bPathDepth = a.path.split('/').filter((dir) => { return dir !== '' }).length;
        if (aPathDepth < bPathDepth) {
          return 1;
        } else if (aPathDepth > bPathDepth) {
          return -1;
        } else {
          return 0;
        }
      }));
    });
  }

  /**
   * @param {Array.<Object>} resources
   * @param {String} path
   * @return {Promise}
   */
  _findParentResourceByPath({ existingResources, path }) {
    return this._sortResourceByPathHierarchy(existingResources).then((resources) => {
      for (var i = 0; i < resources.length; i++) {
        if (path.indexOf(resources[i].path) == 0) {
          return resources[i];
        }
      }
      throw new Error("path '" + path + "' does not have any parent resources");
    });
  }

  /**
   * @param {String} restApiId
   * @return {Promise}
   */
  createResourceWithRecursivePath({ existingResources, restApiId, path }) {
    return this._findParentResourceByPath({
      existingResources: existingResources,
      path: path
    }).then((existingParentResource) => {
      let restPaths = path.slice(existingParentResource.path.length).split('/').filter((dir) => { return dir !== '' });
      return restPaths.map((pathPart) => {
        return (parentResource) => {
          return this.getClient().createResource({
            parentId: parentResource.id,
            pathPart: pathPart,
            restApiId: restApiId
          }).promise();
        };
      }).reduce((promise, task) => {
        return promise.then(task).then((resource) => {
          return resource.data;
        });
      }, Promise.resolve(existingParentResource));
    });
  }

  /**
   * @param {String} restApiId
   * @return {Promise}
   */
  createResourceSets({ restApiId }) {
    return this.getClient().getResources({
      restApiId: restApiId
    }).promise().then((resources) => {
      resources = resources.data.items;
      return this.application.getActions().map((action) => {
        return () => {
          return this.createResourceWithRecursivePath({
            existingResources: resources,
            restApiId: restApiId,
            path: action.getPath()
          }).then((resource) => {
            resources.push(resource);
            return {
              action: action,
              resource: resource
            };
          });
        };
      }).reduce((promise, task) => {
        return promise.then(task).then((results, value) => {
          results.push(value);
          return results;
        }.bind(null, []));
      }, Promise.resolve());
    }).then((result) => {
      return Promise.all(
        result.map((item) => {
          return this.updateMethodSet({
            region: this.application.getRegion(),
            restApiId: restApiId,
            resource: item.resource,
            action: item.action
          });
        })
      ).then(() => {
        return restApiId;
      });
    });
  }

  /**
   * @return {Promise}
   */
  createRestApi() {
    return this.getClient().createRestApi({
      name: this.application.getName()
    }).promise().then((restApi) => {
      this.application.writeRestApiId(restApi.data.id);
      return restApi;
    }).then((restApi) => {
      this.emit('restApiCreated', { restApiId: restApi.data.id });
      return restApi;
    });
  }

  /**
   * @param {Action} action
   * @return {Promise}
   */
  createZipFile({ action }) {
    return new Promise((resolve, reject) => {
      const actionPath = action.getDirectoryPath();
      const zipFile = new yazl.ZipFile();
      const zipPath = action.getZipPath();
      if (fs.existsSync(zipPath)) {
        fs.unlinkSync(zipPath);
      }
      glob.sync(`${actionPath}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(
            path,
            path.substr(`${actionPath}/`.length)
          );
        }
      });
      glob.sync(`./node_modules/{${this.application.getProductionPackageNames().join(',')}}/**/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      glob.sync(`./config/*`).forEach((path) => {
        if (!fs.lstatSync(path).isDirectory()) {
          zipFile.addFile(path, path);
        }
      });
      zipFile.outputStream.pipe(
        fs.createWriteStream(zipPath)
      ).on('close', () => {
        resolve();
      });
      zipFile.end();
    }).then((value) => {
      this.emit('zipFileCreated', { zipPath: action.getZipPath() });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  createZipFiles() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.createZipFile({ action: action });
      })
    );
  }

  /**
   * Set up Amazon Lambda functions and API Gateway endpoints.
   * @return {Promise}
   */
  deploy() {
    return this.createZipFiles().then(() => {
      return this.uploadActions();
    }).then(() => {
      return this.findOrCreateRestApi();
    }).then((restApi) => {
      return this.createResourceSets({
        restApiId: restApi.data.id
      }).then(() => {
        return restApi;
      });
    }).then((restApi) => {
      this.createDeployment({
        restApiId: restApi.id
      });
    });
  }

  /**
   * @return {Promise}
   */
  findOrCreateRestApi() {
    const restApiId = this.application.getRestApiId();
    if (restApiId) {
      return this.getClient().getRestApi({
        restApiId: restApiId
      }).promise().then((restApi) => {
        return restApi;
      }).catch((reason) => {
        if (reason.code === 'NotFoundException') {
          return this.createRestApi();
        }
      });
    } else {
      return this.createRestApi();
    }
  }

  /**
   * @return {Client}
   */
  getClient() {
    if (!this.client) {
      this.client = new AWS.APIGateway({
        accessKeyId: this.accessKeyId,
        secretAccessKey: this.secretAccessKey,
        region: this.application.getRegion()
      });
    }
    return this.client;
  }

  /**
   * @param {String} region
   * @param {String} restApiId
   * @param {Object} action
   * @param {Object} resource
   * @return {Promise}
   */
  updateMethodSet({ region, restApiId, action, resource }) {
    (() => {
      let foundMethod;
      if (resource.resourceMethods) {
        foundMethod = Object.keys(resource.resourceMethods).find((method) => {
          return method === action.getHttpMethod();
        });
      } else {
        foundMethod = false;
      }
      if (foundMethod) {
        return Promise.resolve(resource.resourceMethods[foundMethod]);
      } else {
        return this.getClient().putMethod({
          authorizationType: 'NONE',
          httpMethod: action.getHttpMethod(),
          resourceId: resource.id,
          restApiId: restApiId
        }).promise()
      }
    })().then((method) => {
      return this.getClient().putIntegration({
        httpMethod: action.getHttpMethod(),
        integrationHttpMethod: 'POST',
        requestTemplates: action.getRequestTemplates(),
        resourceId: resource.id,
        restApiId: restApiId,
        type: 'AWS',
        uri: action.getUri()
      }).promise();
    }).then((integration) => {
      return this.getClient().putMethodResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseModels: action.getResponseModels(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return this.getClient().putIntegrationResponse({
        httpMethod: action.getHttpMethod(),
        resourceId: resource.id,
        responseTemplates: action.getResponseTemplates(),
        restApiId: restApiId,
        statusCode: action.getStatusCode().toString()
      }).promise();
    }).then(() => {
      return new Promise((resolve, reject) => {
        new AWS.Lambda({
          region: region
        }).addPermission({
          Action: 'lambda:InvokeFunction',
          FunctionName: action.getName(),
          Principal: 'apigateway.amazonaws.com',
          StatementId: crypto.randomBytes(20).toString('hex')
        }).promise();
      })
    }).then((value) => {
      this.emit(
        'methodSetUpdated',
        {
          httpMethod: action.getHttpMethod(),
          path: action.getPath()
        }
      );
      return value.data;
    });
  }

  /**
   * @param {String} functionName
   * @param {String} handlerId
   * @param {String} region
   * @param {String} roleArn
   * @param {Integer} timeout
   * @param {Integer} memorySize
   * @param {String} zipPath
   * @return {Promise}
   */
  uploadAction({ functionName, handlerId, region, roleArn, timeout, memorySize, zipPath, }) {
    return new Promise((resolve, reject) => {
      awsLambda.deploy(
        zipPath,
        {
          functionName: functionName,
          handler: handlerId,
          region: region,
          role: roleArn,
          timeout: timeout,
          memorySize: memorySize
        },
        (error) => {
          if (error) {
            reject(error);
          } else {
            resolve();
          }
        }
      );
    }).then((value) => {
      this.emit('functionUploaded', { functionName: functionName });
      return value;
    });
  }

  /**
   * @return {Promise}
   */
  uploadActions() {
    return Promise.all(
      this.application.getActions().map((action) => {
        return this.uploadAction({
          zipPath: `${action.getDirectoryPath()}/lambda.zip`,
          region: this.application.getRegion(),
          roleArn: this.application.getRoleArn(),
          functionName: action.getName(),
          handlerId: action.getHandlerId(),
          timeout: action.getTimeout(),
          memorySize: action.getMemorySize()
        });
      })
    );
  }

  /**
   * @param {Function} middleware
   * @param {Object=} options
   * @return {Composer}
   */
  use(middleware, options) {
    return new this.constructor({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      application: this.application,
      client: this.getClient().use(middleware, options)
    });
  }
}
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------- \\
// File: ToolbarView.js                                                       \\
// Module: CollectionViews                                                    \\
// Requires: Core, Foundation, View, ControlViews                             \\
// Author: Neil Jenkins                                                       \\
// License: © 2010-2015 FastMail Pty Ltd. MIT Licensed.                       \\
// -------------------------------------------------------------------------- \\

"use strict";

( function ( NS ) {

var toView = function ( name ) {
    return ( name === '-' ) ?
        NS.Element.create( 'span.v-Toolbar-divider' ) :
        this._views[ name ];
};

var OverflowMenuView = NS.Class({

    Extends: NS.MenuButtonView,

    didEnterDocument: function () {
        OverflowMenuView.parent.didEnterDocument.call( this );
        this.setShortcuts( null, '', {}, this.get( 'shortcuts' ) );
        return this;
    },

    willLeaveDocument: function () {
        this.setShortcuts( null, '', this.get( 'shortcuts' ), {} );
        return OverflowMenuView.parent.willLeaveDocument.call( this );
    },

    shortcuts: function () {
        var views = this.getFromPath( 'menuView.options' );
        return views ? views.reduce( function ( acc, view ) {
            var shortcut = view.get( 'shortcut' );
            if ( shortcut ) {
                shortcut.split( ' ' ).forEach( function ( key ) {
                    acc[ key ] = view;
                });
            }
            return acc;
        }, {} ) : {};
    }.property( 'menuView' ),

    setShortcuts: function ( _, __, oldShortcuts, shortcuts ) {
        if ( this.get( 'isInDocument' ) ) {
            var kbShortcuts = NS.ViewEventsController.kbShortcuts,
                key;
            if ( !shortcuts ) { shortcuts = this.get( 'shortcuts' ); }
            for ( key in oldShortcuts ) {
                kbShortcuts.deregister( key, this, 'activateButton' );
            }
            for ( key in shortcuts ) {
                kbShortcuts.register( key, this, 'activateButton' );
            }
        }
    }.observes( 'shortcuts' ),

    activateButton: function ( event ) {
        var key = NS.DOMEvent.lookupKey( event ),
            button = this.get( 'shortcuts' )[ key ];
        if ( button instanceof NS.MenuButtonView ) {
            this.activate();
        }
        button.activate();
    }
});

var ToolbarView = NS.Class({

    Extends: NS.View,

    className: 'v-Toolbar',

    config: 'standard',
    minimumGap: 20,
    preventOverlap: false,

    init: function ( mixin ) {
        ToolbarView.parent.init.call( this, mixin );
        this._views = {
            overflow: new OverflowMenuView({
                label: NS.loc( 'More' ),
                popOverView: mixin.popOverView || new NS.PopOverView()
            })
        };
        this._configs = {
            standard: {
                left: [],
                right: []
            }
        };
        this._measureView = null;
        this._widths = {};
    },

    registerView: function ( name, view, _dontMeasure ) {
        this._views[ name ] = view;
        if ( !_dontMeasure && this.get( 'isInDocument' ) &&
                this.get( 'preventOverlap' ) ) {
            this.preMeasure().postMeasure();
        }
        return this;
    },

    registerViews: function ( views ) {
        for ( var name in views ) {
            this.registerView( name, views[ name ], true );
        }
        if ( this.get( 'isInDocument' ) && this.get( 'preventOverlap' ) ) {
            this.preMeasure().postMeasure();
        }
        return this;
    },

    registerConfig: function ( name, config ) {
        this._configs[ name ] = config;
        if ( this.get( 'config' ) === name ) {
            this.computedPropertyDidChange( 'config' );
        }
        return this;
    },

    registerConfigs: function ( configs ) {
        for ( var name in configs ) {
            this.registerConfig( name, configs[ name ] );
        }
        return this;
    },

    getView: function ( name ) {
        return this._views[ name ];
    },

    // ---

    leftConfig: function () {
        var configs = this._configs,
            config = configs[ this.get( 'config' ) ];
        return ( config && config.left ) || configs.standard.left;
    }.property( 'config' ),

    rightConfig: function () {
        var configs = this._configs,
            config = configs[ this.get( 'config' ) ];
        return ( config && config.right ) || configs.standard.right;
    }.property( 'config' ),

    left: function () {
        var leftConfig = this.get( 'leftConfig' ),
            rightConfig = this.get( 'rightConfig' ),
            pxWidth = this.get( 'pxWidth' ),
            widths = this._widths,
            i, l;

        if ( widths && pxWidth && this.get( 'preventOverlap' ) ) {
            pxWidth -= this.get( 'minimumGap' );
            for ( i = 0, l = rightConfig.length; i < l; i += 1 ) {
                pxWidth -= widths[ rightConfig[i] ];
            }
            for ( i = 0, l = leftConfig.length; i < l; i += 1 ) {
                pxWidth -= widths[ leftConfig[i] ];
            }
            if ( pxWidth < 0 ) {
                pxWidth -= widths[ '-' ];
                pxWidth -= widths.overflow;

                while ( pxWidth < 0 && l-- ) {
                    pxWidth += widths[ leftConfig[l] ];
                }
                if ( l < 0 ) { l = 0; }

                this._views.overflow.set( 'menuView', new NS.MenuView({
                    showFilter: false,
                    options: leftConfig.slice( l )
                        .map( toView, this )
                        .filter( function ( view ) {
                            return view instanceof NS.View;
                        })
                }) );

                if ( l > 0 ) {
                    if ( leftConfig[ l - 1 ] === '-' ) {
                        l -= 1;
                    }
                    leftConfig = leftConfig.slice( 0, l );
                    leftConfig.push( '-' );
                    leftConfig.push( 'overflow' );
                } else {
                    leftConfig = [ 'overflow' ];
                    l = 0;
                }
            }
        }
        return leftConfig.map( toView, this );
    }.property( 'leftConfig', 'rightConfig', 'pxWidth' ),

    right: function () {
        return this.get( 'rightConfig' ).map( toView, this );
    }.property( 'rightConfig' ),

    preMeasure: function () {
        this.insertView( this._measureView =
            new NS.View({
                className: 'v-Toolbar-section v-Toolbar-section--measure',
                layerStyles: {},
                childViews: Object.values( this._views )
                                  .filter( function ( view ) {
                    return !view.get( 'parentView' );
                }),
                draw: function ( layer, Element, el ) {
                    return [
                        el( 'span.v-Toolbar-divider' ),
                        NS.View.prototype.draw.call( this, layer, Element, el )
                    ];
                }
            }),
            this.get( 'layer' ).lastChild,
            'before'
        );
        return this;
    },

    postMeasure: function () {
        var widths = this._widths,
            views = this._views,
            measureView = this._measureView,
            unused = measureView.get( 'childViews' ),
            container = measureView.get( 'layer' ),
            containerBoundingClientRect = container.getBoundingClientRect(),
            firstButton = unused.length ? unused[0].get( 'layer' ) : null,
            name, l;

        for ( name in views ) {
            widths[ name ] = views[ name ].get( 'pxWidth' ) || widths[ name ];
        }

        // Want to include any left/right margin, so get difference between
        // edge of first button and start of container
        widths[ '-' ] = ( firstButton ?
            firstButton.getBoundingClientRect().left :
            containerBoundingClientRect.right
        ) - containerBoundingClientRect.left;

        this.removeView( measureView );
        l = unused.length;
        while ( l-- ) {
            measureView.removeView( unused[l] );
        }
        measureView.destroy();
        this._measureView = null;

        return this;
    },

    willEnterDocument: function () {
        if ( this.get( 'preventOverlap' ) ) {
            this.preMeasure();
        }
        return ToolbarView.parent.willEnterDocument.call( this );
    },

    didEnterDocument: function () {
        this.beginPropertyChanges();
        ToolbarView.parent.didEnterDocument.call( this );
        if ( this.get( 'preventOverlap' ) ) {
            this.postMeasure();
        }
        this.endPropertyChanges();
        return this;
    },

    draw: function ( layer, Element, el ) {
        return [
            el( 'div.v-Toolbar-section.v-Toolbar-section--left',
                this.get( 'left' )
            ),
            el( 'div.v-Toolbar-section.v-Toolbar-section--right',
                this.get( 'right' )
            )
        ];
    },

    toolbarNeedsRedraw: function ( self, property, oldValue ) {
       return this.propertyNeedsRedraw( self, property, oldValue );
    }.observes( 'left', 'right' ),

    redrawLeft: function ( layer, oldViews ) {
        this.redrawSide( layer.firstChild, oldViews, this.get( 'left' ) );
    },
    redrawRight: function ( layer, oldViews ) {
        this.redrawSide( layer.lastChild, oldViews, this.get( 'right' ) );
    },

    redrawSide: function ( container, oldViews, newViews ) {
        var View = NS.View,
            start = 0,
            isEqual = true,
            i, l, view, parent;

        for ( i = start, l = oldViews.length; i < l; i += 1 ) {
            view = oldViews[i];
            if ( view instanceof View ) {
                if ( isEqual && view === newViews[i] ) {
                    start += 1;
                } else {
                    isEqual = false;
                    // Check it hasn't already swapped sides!
                    if ( view.get( 'layer' ).parentNode === container ) {
                        this.removeView( view );
                    }
                }
            } else {
                if ( isEqual && !( newViews[i] instanceof View ) ) {
                    start += 1;
                    newViews[i] = view;
                } else {
                    container.removeChild( view );
                }
            }
        }
        for ( i = start, l = newViews.length; i < l; i += 1 ) {
            view = newViews[i];
            if ( view instanceof View ) {
                if ( parent = view.get( 'parentView' ) ) {
                    parent.removeView( view );
                }
                this.insertView( view, container );
            } else {
                container.appendChild( view );
            }
        }
    }
});

NS.ToolbarView = ToolbarView;

}( O ) );
<commit_msg>Only redraw ToolbarView side if there's an old value.<commit_after>// -------------------------------------------------------------------------- \\
// File: ToolbarView.js                                                       \\
// Module: CollectionViews                                                    \\
// Requires: Core, Foundation, View, ControlViews                             \\
// Author: Neil Jenkins                                                       \\
// License: © 2010-2015 FastMail Pty Ltd. MIT Licensed.                       \\
// -------------------------------------------------------------------------- \\

"use strict";

( function ( NS ) {

var toView = function ( name ) {
    return ( name === '-' ) ?
        NS.Element.create( 'span.v-Toolbar-divider' ) :
        this._views[ name ];
};

var OverflowMenuView = NS.Class({

    Extends: NS.MenuButtonView,

    didEnterDocument: function () {
        OverflowMenuView.parent.didEnterDocument.call( this );
        this.setShortcuts( null, '', {}, this.get( 'shortcuts' ) );
        return this;
    },

    willLeaveDocument: function () {
        this.setShortcuts( null, '', this.get( 'shortcuts' ), {} );
        return OverflowMenuView.parent.willLeaveDocument.call( this );
    },

    shortcuts: function () {
        var views = this.getFromPath( 'menuView.options' );
        return views ? views.reduce( function ( acc, view ) {
            var shortcut = view.get( 'shortcut' );
            if ( shortcut ) {
                shortcut.split( ' ' ).forEach( function ( key ) {
                    acc[ key ] = view;
                });
            }
            return acc;
        }, {} ) : {};
    }.property( 'menuView' ),

    setShortcuts: function ( _, __, oldShortcuts, shortcuts ) {
        if ( this.get( 'isInDocument' ) ) {
            var kbShortcuts = NS.ViewEventsController.kbShortcuts,
                key;
            if ( !shortcuts ) { shortcuts = this.get( 'shortcuts' ); }
            for ( key in oldShortcuts ) {
                kbShortcuts.deregister( key, this, 'activateButton' );
            }
            for ( key in shortcuts ) {
                kbShortcuts.register( key, this, 'activateButton' );
            }
        }
    }.observes( 'shortcuts' ),

    activateButton: function ( event ) {
        var key = NS.DOMEvent.lookupKey( event ),
            button = this.get( 'shortcuts' )[ key ];
        if ( button instanceof NS.MenuButtonView ) {
            this.activate();
        }
        button.activate();
    }
});

var ToolbarView = NS.Class({

    Extends: NS.View,

    className: 'v-Toolbar',

    config: 'standard',
    minimumGap: 20,
    preventOverlap: false,

    init: function ( mixin ) {
        ToolbarView.parent.init.call( this, mixin );
        this._views = {
            overflow: new OverflowMenuView({
                label: NS.loc( 'More' ),
                popOverView: mixin.popOverView || new NS.PopOverView()
            })
        };
        this._configs = {
            standard: {
                left: [],
                right: []
            }
        };
        this._measureView = null;
        this._widths = {};
    },

    registerView: function ( name, view, _dontMeasure ) {
        this._views[ name ] = view;
        if ( !_dontMeasure && this.get( 'isInDocument' ) &&
                this.get( 'preventOverlap' ) ) {
            this.preMeasure().postMeasure();
        }
        return this;
    },

    registerViews: function ( views ) {
        for ( var name in views ) {
            this.registerView( name, views[ name ], true );
        }
        if ( this.get( 'isInDocument' ) && this.get( 'preventOverlap' ) ) {
            this.preMeasure().postMeasure();
        }
        return this;
    },

    registerConfig: function ( name, config ) {
        this._configs[ name ] = config;
        if ( this.get( 'config' ) === name ) {
            this.computedPropertyDidChange( 'config' );
        }
        return this;
    },

    registerConfigs: function ( configs ) {
        for ( var name in configs ) {
            this.registerConfig( name, configs[ name ] );
        }
        return this;
    },

    getView: function ( name ) {
        return this._views[ name ];
    },

    // ---

    leftConfig: function () {
        var configs = this._configs,
            config = configs[ this.get( 'config' ) ];
        return ( config && config.left ) || configs.standard.left;
    }.property( 'config' ),

    rightConfig: function () {
        var configs = this._configs,
            config = configs[ this.get( 'config' ) ];
        return ( config && config.right ) || configs.standard.right;
    }.property( 'config' ),

    left: function () {
        var leftConfig = this.get( 'leftConfig' ),
            rightConfig = this.get( 'rightConfig' ),
            pxWidth = this.get( 'pxWidth' ),
            widths = this._widths,
            i, l;

        if ( widths && pxWidth && this.get( 'preventOverlap' ) ) {
            pxWidth -= this.get( 'minimumGap' );
            for ( i = 0, l = rightConfig.length; i < l; i += 1 ) {
                pxWidth -= widths[ rightConfig[i] ];
            }
            for ( i = 0, l = leftConfig.length; i < l; i += 1 ) {
                pxWidth -= widths[ leftConfig[i] ];
            }
            if ( pxWidth < 0 ) {
                pxWidth -= widths[ '-' ];
                pxWidth -= widths.overflow;

                while ( pxWidth < 0 && l-- ) {
                    pxWidth += widths[ leftConfig[l] ];
                }
                if ( l < 0 ) { l = 0; }

                this._views.overflow.set( 'menuView', new NS.MenuView({
                    showFilter: false,
                    options: leftConfig.slice( l )
                        .map( toView, this )
                        .filter( function ( view ) {
                            return view instanceof NS.View;
                        })
                }) );

                if ( l > 0 ) {
                    if ( leftConfig[ l - 1 ] === '-' ) {
                        l -= 1;
                    }
                    leftConfig = leftConfig.slice( 0, l );
                    leftConfig.push( '-' );
                    leftConfig.push( 'overflow' );
                } else {
                    leftConfig = [ 'overflow' ];
                    l = 0;
                }
            }
        }
        return leftConfig.map( toView, this );
    }.property( 'leftConfig', 'rightConfig', 'pxWidth' ),

    right: function () {
        return this.get( 'rightConfig' ).map( toView, this );
    }.property( 'rightConfig' ),

    preMeasure: function () {
        this.insertView( this._measureView =
            new NS.View({
                className: 'v-Toolbar-section v-Toolbar-section--measure',
                layerStyles: {},
                childViews: Object.values( this._views )
                                  .filter( function ( view ) {
                    return !view.get( 'parentView' );
                }),
                draw: function ( layer, Element, el ) {
                    return [
                        el( 'span.v-Toolbar-divider' ),
                        NS.View.prototype.draw.call( this, layer, Element, el )
                    ];
                }
            }),
            this.get( 'layer' ).lastChild,
            'before'
        );
        return this;
    },

    postMeasure: function () {
        var widths = this._widths,
            views = this._views,
            measureView = this._measureView,
            unused = measureView.get( 'childViews' ),
            container = measureView.get( 'layer' ),
            containerBoundingClientRect = container.getBoundingClientRect(),
            firstButton = unused.length ? unused[0].get( 'layer' ) : null,
            name, l;

        for ( name in views ) {
            widths[ name ] = views[ name ].get( 'pxWidth' ) || widths[ name ];
        }

        // Want to include any left/right margin, so get difference between
        // edge of first button and start of container
        widths[ '-' ] = ( firstButton ?
            firstButton.getBoundingClientRect().left :
            containerBoundingClientRect.right
        ) - containerBoundingClientRect.left;

        this.removeView( measureView );
        l = unused.length;
        while ( l-- ) {
            measureView.removeView( unused[l] );
        }
        measureView.destroy();
        this._measureView = null;

        return this;
    },

    willEnterDocument: function () {
        if ( this.get( 'preventOverlap' ) ) {
            this.preMeasure();
        }
        return ToolbarView.parent.willEnterDocument.call( this );
    },

    didEnterDocument: function () {
        this.beginPropertyChanges();
        ToolbarView.parent.didEnterDocument.call( this );
        if ( this.get( 'preventOverlap' ) ) {
            this.postMeasure();
        }
        this.endPropertyChanges();
        return this;
    },

    draw: function ( layer, Element, el ) {
        return [
            el( 'div.v-Toolbar-section.v-Toolbar-section--left',
                this.get( 'left' )
            ),
            el( 'div.v-Toolbar-section.v-Toolbar-section--right',
                this.get( 'right' )
            )
        ];
    },

    toolbarNeedsRedraw: function ( self, property, oldValue ) {
        if ( oldValue ) {
            this.propertyNeedsRedraw( self, property, oldValue );
        }
    }.observes( 'left', 'right' ),

    redrawLeft: function ( layer, oldViews ) {
        this.redrawSide( layer.firstChild, oldViews, this.get( 'left' ) );
    },
    redrawRight: function ( layer, oldViews ) {
        this.redrawSide( layer.lastChild, oldViews, this.get( 'right' ) );
    },

    redrawSide: function ( container, oldViews, newViews ) {
        var View = NS.View,
            start = 0,
            isEqual = true,
            i, l, view, parent;

        for ( i = start, l = oldViews.length; i < l; i += 1 ) {
            view = oldViews[i];
            if ( view instanceof View ) {
                if ( isEqual && view === newViews[i] ) {
                    start += 1;
                } else {
                    isEqual = false;
                    // Check it hasn't already swapped sides!
                    if ( view.get( 'layer' ).parentNode === container ) {
                        this.removeView( view );
                    }
                }
            } else {
                if ( isEqual && !( newViews[i] instanceof View ) ) {
                    start += 1;
                    newViews[i] = view;
                } else {
                    container.removeChild( view );
                }
            }
        }
        for ( i = start, l = newViews.length; i < l; i += 1 ) {
            view = newViews[i];
            if ( view instanceof View ) {
                if ( parent = view.get( 'parentView' ) ) {
                    parent.removeView( view );
                }
                this.insertView( view, container );
            } else {
                container.appendChild( view );
            }
        }
    }
});

NS.ToolbarView = ToolbarView;

}( O ) );
<|endoftext|>


<commit_before>define(function (require, exports, module) {
    'use strict';

    var ExtensionUtils      = brackets.getModule("utils/ExtensionUtils"),
        Dialogs             = brackets.getModule("widgets/Dialogs"),
        DefaultDialogs      = brackets.getModule("widgets/DefaultDialogs");

    ExtensionUtils.loadStyleSheet(module, "./css/showLatest.css");

    var getLatest = function(current_version, showIfLatest){   //if showIfLatest is true, will show a message like, 'Your version is up to date'
        $.ajax({
            url: "http://download.arduino.org/revision",
            method: "GET",
            data: {"version": parseInt(current_version)},
            success: function(data, status, xhr){
                if(status == 'success')
                    if(data.version > current_version )
                        showLatest(data);
                    //else
                        //if(showIfLatest)
                        //TODO SHOW UP TO DATE MESSAGE
            },
            error: function(err){alert(JSON.stringify(err));},
            dataType: "json"
        });
    }

    var showLatest = function(latest){
        var template = require("text!./html/showLatest.html");

        var info = $.extend({}, latest, brakets.arduino.strings);

        var html = Mustache.render(template, info);

        Dialogs.showModalDialog(DefaultDialogs.DIALOG_ID_INFO, /*TODO LOCALIZE THIS*/"Get latest version", html);
    }

    module.exports.checkLatest = getLatest;
    //module.exports.showLatest = showLatest;
});<commit_msg>update dialog title, use locale strigns<commit_after>define(function (require, exports, module) {
    'use strict';

    var ExtensionUtils      = brackets.getModule("utils/ExtensionUtils"),
        Dialogs             = brackets.getModule("widgets/Dialogs"),
        DefaultDialogs      = brackets.getModule("widgets/DefaultDialogs");

    ExtensionUtils.loadStyleSheet(module, "./css/showLatest.css");

    var getLatest = function(current_version, showIfLatest){   //if showIfLatest is true, will show a message like, 'Your version is up to date'
        $.ajax({
            url: "http://download.arduino.org/revision",
            method: "GET",
            data: {"version": parseInt(current_version)},
            success: function(data, status, xhr){
                if(status == 'success')
                    if(data.version > current_version )
                        showLatest(data);
                    //else
                        //if(showIfLatest)
                        //TODO SHOW UP TO DATE MESSAGE
            },
            error: function(err){alert(JSON.stringify(err));},
            dataType: "json"
        });
    }

    var showLatest = function(latest){
        var template = require("text!./html/showLatest.html");
        var info = $.extend({}, latest, brakets.arduino.strings);
        var html = Mustache.render(template, info);

        Dialogs.showModalDialog(DefaultDialogs.DIALOG_ID_INFO, brakets.arduino.strings.ARDUINO.DIALOG.LATEST.TITLE, html);
    }

    module.exports.checkLatest = getLatest;
    //module.exports.showLatest = showLatest;
});<|endoftext|>