<commit_before>var Utils     = require("../../utils")
  , DataTypes = require("../../data-types")
  , util      = require("util")

module.exports = (function() {
  var QueryGenerator = {
    dialect: 'mysql',

    createSchema: function() {
      var query = "SHOW TABLES"
      return Utils._.template(query)({})
    },

    dropSchema: function(tableName, options) {
      return QueryGenerator.dropTableQuery(tableName, options)
    },

    showSchemasQuery: function() {
      return "SHOW TABLES"
    },

    createTableQuery: function(tableName, attributes, options) {
      options = Utils._.extend({
        engine: 'InnoDB',
        charset: null
      }, options || {})

      var self = this;

      var query   = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>)<%= comment %> ENGINE=<%= engine %> <%= charset %> <%= collation %>"
        , primaryKeys = []
        , foreignKeys = {}
        , attrStr = []

      for (var attr in attributes) {
        if (attributes.hasOwnProperty(attr)) {
          var dataType = this.mysqlDataTypeMapping(tableName, attr, attributes[attr])

          if (Utils._.includes(dataType, 'PRIMARY KEY')) {
            primaryKeys.push(attr)

            if (Utils._.includes(dataType, 'REFERENCES')) {
               // MySQL doesn't support inline REFERENCES declarations: move to the end
              var m = dataType.match(/^(.+) (REFERENCES.*)$/)
              attrStr.push(this.quoteIdentifier(attr) + " " + m[1].replace(/PRIMARY KEY/, ''))
              foreignKeys[attr] = m[2]
            } else {
              attrStr.push(this.quoteIdentifier(attr) + " " + dataType.replace(/PRIMARY KEY/, ''))
            }
          } else if (Utils._.includes(dataType, 'REFERENCES')) {
            // MySQL doesn't support inline REFERENCES declarations: move to the end
            var m = dataType.match(/^(.+) (REFERENCES.*)$/)
            attrStr.push(this.quoteIdentifier(attr) + " " + m[1])
            foreignKeys[attr] = m[2]
          } else {
            attrStr.push(this.quoteIdentifier(attr) + " " + dataType)
          }
        }
      }

      var values = {
        table: this.quoteTable(tableName),
        attributes: attrStr.join(", "),
        comment: options.comment && Utils._.isString(options.comment) ? " COMMENT " + this.escape(options.comment) : "",
        engine: options.engine,
        charset: (options.charset ? "DEFAULT CHARSET=" + options.charset : ""),
        collation: (options.collate ? "COLLATE " + options.collate : "")
      }
      , pkString = primaryKeys.map(function(pk) { return this.quoteIdentifier(pk) }.bind(this)).join(", ")

      if (!!options.uniqueKeys) {
        Utils._.each(options.uniqueKeys, function(columns) {
          values.attributes += ", UNIQUE uniq_" + tableName + '_' + columns.fields.join('_') + " (";
          var i = 0;
          Utils._.each(columns.fields, function(field) {
            if(i++ > 0) values.attributes += ", ";
            values.attributes += self.quoteIdentifier(field);
          });
          values.attributes += ")";
        })
      }

      if (pkString.length > 0) {
        values.attributes += ", PRIMARY KEY (" + pkString + ")"
      }

      for (var fkey in foreignKeys) {
        if(foreignKeys.hasOwnProperty(fkey)) {
          values.attributes += ", FOREIGN KEY (" + this.quoteIdentifier(fkey) + ") " + foreignKeys[fkey]
        }
      }

      return Utils._.template(query)(values).trim() + ";"
    },

    showTablesQuery: function() {
      return 'SHOW TABLES;'
    },

    uniqueConstraintMapping: {
      code: 'ER_DUP_ENTRY',
      map: function(str) {
        // we're manually remvoving uniq_ here for a future capability of defining column names explicitly
        var match = str.replace('uniq_', '').match(/Duplicate entry .* for key '(.*?)'$/)
        if (match === null || match.length < 2) {
          return false
        }

        return match[1].split('_')
      }
    },

    addColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` ADD <%= attributes %>;"
        , attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: this.mysqlDataTypeMapping(tableName, attrName, definition)
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    removeColumnQuery: function(tableName, attributeName) {
      var query = "ALTER TABLE `<%= tableName %>` DROP `<%= attributeName %>`;"
      return Utils._.template(query)({ tableName: tableName, attributeName: attributeName })
    },

    changeColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` `<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    renameColumnQuery: function(tableName, attrBefore, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= before %>` `<%= after %>` <%= definition %>')({
          before: attrBefore,
          after: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    bulkInsertQuery: function(tableName, attrValueHashes, options) {
      var query = "INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %>;"
        , tuples = []
        , allAttributes = []

      Utils._.forEach(attrValueHashes, function(attrValueHash, i) {
        Utils._.forOwn(attrValueHash, function(value, key, hash) {
          if (allAttributes.indexOf(key) === -1) allAttributes.push(key)
        })
      })

      Utils._.forEach(attrValueHashes, function(attrValueHash, i) {
        tuples.push("(" +
          allAttributes.map(function (key) {
            return this.escape(attrValueHash[key])
          }.bind(this)).join(",") +
        ")")
      }.bind(this))

      var replacements  = {
        ignoreDuplicates: options && options.ignoreDuplicates ? ' IGNORE' : '',
        table: this.quoteTable(tableName),
        attributes: allAttributes.map(function(attr){
                      return this.quoteIdentifier(attr)
                    }.bind(this)).join(","),
        tuples: tuples
      }

      return Utils._.template(query)(replacements)
    },

    deleteQuery: function(tableName, where, options) {
      options = options || {}

      var table = this.quoteTable(tableName)
      if (options.truncate === true) {
        // Truncate does not allow LIMIT and WHERE
        return "TRUNCATE " + table
      }

      where = this.getWhereConditions(where)
      var limit = ""

      if(Utils._.isUndefined(options.limit)) {
        options.limit = 1;
      }

      if(!!options.limit) {
        limit = " LIMIT " + this.escape(options.limit)
      }

      return "DELETE FROM " + table + " WHERE " + where + limit
    },

    addIndexQuery: function(tableName, attributes, options) {
      var transformedAttributes = attributes.map(function(attribute) {
        if(typeof attribute === 'string') {
          return this.quoteIdentifier(attribute)
        } else {
          var result = ""

          if (!attribute.attribute) {
            throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute))
          }

          result += this.quoteIdentifier(attribute.attribute)

          if (attribute.length) {
            result += '(' + attribute.length + ')'
          }

          if (attribute.order) {
            result += ' ' + attribute.order
          }

          return result
        }
      }.bind(this))

      var onlyAttributeNames = attributes.map(function(attribute) {
        return (typeof attribute === 'string') ? attribute : attribute.attribute
      }.bind(this))

      options = Utils._.extend({
        indicesType: null,
        indexName: Utils._.underscored(tableName + '_' + onlyAttributeNames.join('_')),
        parser: null
      }, options || {})

      return Utils._.compact([
        "CREATE", options.indicesType, "INDEX", options.indexName,
        (options.indexType ? ('USING ' + options.indexType) : undefined),
        "ON", tableName, '(' + transformedAttributes.join(', ') + ')',
        (options.parser ? "WITH PARSER " + options.parser : undefined)
      ]).join(' ')
    },

    showIndexQuery: function(tableName, options) {
      var sql = "SHOW INDEX FROM `<%= tableName %>`<%= options %>"
      return Utils._.template(sql)({
        tableName: tableName,
        options: (options || {}).database ? ' FROM `' + options.database + '`' : ''
      })
    },

    removeIndexQuery: function(tableName, indexNameOrAttributes) {
      var sql       = "DROP INDEX <%= indexName %> ON <%= tableName %>"
        , indexName = indexNameOrAttributes

      if (typeof indexName !== 'string') {
        indexName = Utils._.underscored(tableName + '_' + indexNameOrAttributes.join('_'))
      }

      return Utils._.template(sql)({ tableName: tableName, indexName: indexName })
    },

    attributesToSQL: function(attributes) {
      var result = {}

      for (var name in attributes) {
        var dataType = attributes[name]

        if (Utils.isHash(dataType)) {
          var template

          if (dataType.type.toString() === DataTypes.ENUM.toString()) {
            if (Array.isArray(dataType.values) && (dataType.values.length > 0)) {
              template = "ENUM(" + Utils._.map(dataType.values, function(value) {
                return this.escape(value)
              }.bind(this)).join(", ") + ")"
            } else {
              throw new Error('Values for ENUM haven\'t been defined.')
            }
          } else {
            template = dataType.type.toString();
          }

          if (dataType.hasOwnProperty('allowNull') && (!dataType.allowNull)) {
            template += " NOT NULL"
          }

          if (dataType.autoIncrement) {
            template += " auto_increment"
          }

          // Blobs/texts cannot have a defaultValue
          if (dataType.type !== "TEXT" && dataType.type._binary !== true && Utils.defaultValueSchemable(dataType.defaultValue)) {
            template += " DEFAULT " + this.escape(dataType.defaultValue)
          }

          if (dataType.unique === true) {
            template += " UNIQUE"
          }

          if (dataType.primaryKey) {
            template += " PRIMARY KEY"
          }

          if (dataType.comment && Utils._.isString(dataType.comment) && dataType.comment.length) {
            template += " COMMENT " + this.escape(dataType.comment)
          }

          if(dataType.references) {
            template += " REFERENCES " + this.quoteTable(dataType.references)

            if(dataType.referencesKey) {
              template += " (" + this.quoteIdentifier(dataType.referencesKey) + ")"
            } else {
              template += " (" + this.quoteIdentifier('id') + ")"
            }

            if(dataType.onDelete) {
              template += " ON DELETE " + dataType.onDelete.toUpperCase()
            }

            if(dataType.onUpdate) {
              template += " ON UPDATE " + dataType.onUpdate.toUpperCase()
            }

          }

          result[name] = template
        } else {
          result[name] = dataType
        }
      }

      return result
    },

    findAutoIncrementField: function(factory) {
      var fields = []

      for (var name in factory.attributes) {
        if (factory.attributes.hasOwnProperty(name)) {
          var definition = factory.attributes[name]

          if (definition && (definition.indexOf('auto_increment') > -1)) {
            fields.push(name)
          }
        }
      }

      return fields
    },

    addLimitAndOffset: function(options, query){
      query = query || ""
      if (options.offset && !options.limit) {
        query += " LIMIT " + options.offset + ", " + 18440000000000000000;
      } else if (options.limit) {
        if (options.offset) {
          query += " LIMIT " + options.offset + ", " + options.limit
        } else {
          query += " LIMIT " + options.limit
        }
      }
      return query;
    },

    quoteIdentifier: function(identifier, force) {
      if (identifier === '*') return identifier
      return Utils.addTicks(identifier, "`")
    },
    /**
     * Generates an SQL query that returns all foreign keys of a table.
     *
     * @param  {String} tableName  The name of the table.
     * @param  {String} schemaName The name of the schema.
     * @return {String}            The generated sql query.
     */
    getForeignKeysQuery: function(tableName, schemaName) {
      return "SELECT CONSTRAINT_NAME as constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = '" + tableName + "' AND CONSTRAINT_NAME!='PRIMARY' AND CONSTRAINT_SCHEMA='" + schemaName + "' AND REFERENCED_TABLE_NAME IS NOT NULL;"
    },

    /**
     * Generates an SQL query that removes a foreign key from a table.
     *
     * @param  {String} tableName  The name of the table.
     * @param  {String} foreignKey The name of the foreign key constraint.
     * @return {String}            The generated sql query.
     */
    dropForeignKeyQuery: function(tableName, foreignKey) {
      return 'ALTER TABLE ' + this.quoteTable(tableName) + ' DROP FOREIGN KEY ' + this.quoteIdentifier(foreignKey) + ';'
    },

    mysqlDataTypeMapping: function(tableName, attr, dataType) {
      if (Utils._.includes(dataType, 'UUID')) {
        dataType = dataType.replace(/UUID/, 'CHAR(36) BINARY')
      }

      return dataType
    }
  }

  return Utils._.extend(Utils._.clone(require("../abstract/query-generator")), QueryGenerator)
})()
<commit_msg>Now using lodash.map(...)<commit_after>var Utils     = require("../../utils")
  , DataTypes = require("../../data-types")
  , util      = require("util")

module.exports = (function() {
  var QueryGenerator = {
    dialect: 'mysql',

    createSchema: function() {
      var query = "SHOW TABLES"
      return Utils._.template(query)({})
    },

    dropSchema: function(tableName, options) {
      return QueryGenerator.dropTableQuery(tableName, options)
    },

    showSchemasQuery: function() {
      return "SHOW TABLES"
    },

    createTableQuery: function(tableName, attributes, options) {
      options = Utils._.extend({
        engine: 'InnoDB',
        charset: null
      }, options || {})

      var self = this;

      var query   = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>)<%= comment %> ENGINE=<%= engine %> <%= charset %> <%= collation %>"
        , primaryKeys = []
        , foreignKeys = {}
        , attrStr = []

      for (var attr in attributes) {
        if (attributes.hasOwnProperty(attr)) {
          var dataType = this.mysqlDataTypeMapping(tableName, attr, attributes[attr])

          if (Utils._.includes(dataType, 'PRIMARY KEY')) {
            primaryKeys.push(attr)

            if (Utils._.includes(dataType, 'REFERENCES')) {
               // MySQL doesn't support inline REFERENCES declarations: move to the end
              var m = dataType.match(/^(.+) (REFERENCES.*)$/)
              attrStr.push(this.quoteIdentifier(attr) + " " + m[1].replace(/PRIMARY KEY/, ''))
              foreignKeys[attr] = m[2]
            } else {
              attrStr.push(this.quoteIdentifier(attr) + " " + dataType.replace(/PRIMARY KEY/, ''))
            }
          } else if (Utils._.includes(dataType, 'REFERENCES')) {
            // MySQL doesn't support inline REFERENCES declarations: move to the end
            var m = dataType.match(/^(.+) (REFERENCES.*)$/)
            attrStr.push(this.quoteIdentifier(attr) + " " + m[1])
            foreignKeys[attr] = m[2]
          } else {
            attrStr.push(this.quoteIdentifier(attr) + " " + dataType)
          }
        }
      }

      var values = {
        table: this.quoteTable(tableName),
        attributes: attrStr.join(", "),
        comment: options.comment && Utils._.isString(options.comment) ? " COMMENT " + this.escape(options.comment) : "",
        engine: options.engine,
        charset: (options.charset ? "DEFAULT CHARSET=" + options.charset : ""),
        collation: (options.collate ? "COLLATE " + options.collate : "")
      }
      , pkString = primaryKeys.map(function(pk) { return this.quoteIdentifier(pk) }.bind(this)).join(", ")

      if (!!options.uniqueKeys) {
        Utils._.each(options.uniqueKeys, function(columns) {
          values.attributes += ", UNIQUE uniq_" + tableName + '_' + columns.fields.join('_') + " (" + Utils._.map(columns.fields, self.quoteIdentifier).join(", ") + ")";
        })
      }

      if (pkString.length > 0) {
        values.attributes += ", PRIMARY KEY (" + pkString + ")"
      }

      for (var fkey in foreignKeys) {
        if(foreignKeys.hasOwnProperty(fkey)) {
          values.attributes += ", FOREIGN KEY (" + this.quoteIdentifier(fkey) + ") " + foreignKeys[fkey]
        }
      }

      return Utils._.template(query)(values).trim() + ";"
    },

    showTablesQuery: function() {
      return 'SHOW TABLES;'
    },

    uniqueConstraintMapping: {
      code: 'ER_DUP_ENTRY',
      map: function(str) {
        // we're manually remvoving uniq_ here for a future capability of defining column names explicitly
        var match = str.replace('uniq_', '').match(/Duplicate entry .* for key '(.*?)'$/)
        if (match === null || match.length < 2) {
          return false
        }

        return match[1].split('_')
      }
    },

    addColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` ADD <%= attributes %>;"
        , attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: this.mysqlDataTypeMapping(tableName, attrName, definition)
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    removeColumnQuery: function(tableName, attributeName) {
      var query = "ALTER TABLE `<%= tableName %>` DROP `<%= attributeName %>`;"
      return Utils._.template(query)({ tableName: tableName, attributeName: attributeName })
    },

    changeColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` `<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    renameColumnQuery: function(tableName, attrBefore, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= before %>` `<%= after %>` <%= definition %>')({
          before: attrBefore,
          after: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    bulkInsertQuery: function(tableName, attrValueHashes, options) {
      var query = "INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %>;"
        , tuples = []
        , allAttributes = []

      Utils._.forEach(attrValueHashes, function(attrValueHash, i) {
        Utils._.forOwn(attrValueHash, function(value, key, hash) {
          if (allAttributes.indexOf(key) === -1) allAttributes.push(key)
        })
      })

      Utils._.forEach(attrValueHashes, function(attrValueHash, i) {
        tuples.push("(" +
          allAttributes.map(function (key) {
            return this.escape(attrValueHash[key])
          }.bind(this)).join(",") +
        ")")
      }.bind(this))

      var replacements  = {
        ignoreDuplicates: options && options.ignoreDuplicates ? ' IGNORE' : '',
        table: this.quoteTable(tableName),
        attributes: allAttributes.map(function(attr){
                      return this.quoteIdentifier(attr)
                    }.bind(this)).join(","),
        tuples: tuples
      }

      return Utils._.template(query)(replacements)
    },

    deleteQuery: function(tableName, where, options) {
      options = options || {}

      var table = this.quoteTable(tableName)
      if (options.truncate === true) {
        // Truncate does not allow LIMIT and WHERE
        return "TRUNCATE " + table
      }

      where = this.getWhereConditions(where)
      var limit = ""

      if(Utils._.isUndefined(options.limit)) {
        options.limit = 1;
      }

      if(!!options.limit) {
        limit = " LIMIT " + this.escape(options.limit)
      }

      return "DELETE FROM " + table + " WHERE " + where + limit
    },

    addIndexQuery: function(tableName, attributes, options) {
      var transformedAttributes = attributes.map(function(attribute) {
        if(typeof attribute === 'string') {
          return this.quoteIdentifier(attribute)
        } else {
          var result = ""

          if (!attribute.attribute) {
            throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute))
          }

          result += this.quoteIdentifier(attribute.attribute)

          if (attribute.length) {
            result += '(' + attribute.length + ')'
          }

          if (attribute.order) {
            result += ' ' + attribute.order
          }

          return result
        }
      }.bind(this))

      var onlyAttributeNames = attributes.map(function(attribute) {
        return (typeof attribute === 'string') ? attribute : attribute.attribute
      }.bind(this))

      options = Utils._.extend({
        indicesType: null,
        indexName: Utils._.underscored(tableName + '_' + onlyAttributeNames.join('_')),
        parser: null
      }, options || {})

      return Utils._.compact([
        "CREATE", options.indicesType, "INDEX", options.indexName,
        (options.indexType ? ('USING ' + options.indexType) : undefined),
        "ON", tableName, '(' + transformedAttributes.join(', ') + ')',
        (options.parser ? "WITH PARSER " + options.parser : undefined)
      ]).join(' ')
    },

    showIndexQuery: function(tableName, options) {
      var sql = "SHOW INDEX FROM `<%= tableName %>`<%= options %>"
      return Utils._.template(sql)({
        tableName: tableName,
        options: (options || {}).database ? ' FROM `' + options.database + '`' : ''
      })
    },

    removeIndexQuery: function(tableName, indexNameOrAttributes) {
      var sql       = "DROP INDEX <%= indexName %> ON <%= tableName %>"
        , indexName = indexNameOrAttributes

      if (typeof indexName !== 'string') {
        indexName = Utils._.underscored(tableName + '_' + indexNameOrAttributes.join('_'))
      }

      return Utils._.template(sql)({ tableName: tableName, indexName: indexName })
    },

    attributesToSQL: function(attributes) {
      var result = {}

      for (var name in attributes) {
        var dataType = attributes[name]

        if (Utils.isHash(dataType)) {
          var template

          if (dataType.type.toString() === DataTypes.ENUM.toString()) {
            if (Array.isArray(dataType.values) && (dataType.values.length > 0)) {
              template = "ENUM(" + Utils._.map(dataType.values, function(value) {
                return this.escape(value)
              }.bind(this)).join(", ") + ")"
            } else {
              throw new Error('Values for ENUM haven\'t been defined.')
            }
          } else {
            template = dataType.type.toString();
          }

          if (dataType.hasOwnProperty('allowNull') && (!dataType.allowNull)) {
            template += " NOT NULL"
          }

          if (dataType.autoIncrement) {
            template += " auto_increment"
          }

          // Blobs/texts cannot have a defaultValue
          if (dataType.type !== "TEXT" && dataType.type._binary !== true && Utils.defaultValueSchemable(dataType.defaultValue)) {
            template += " DEFAULT " + this.escape(dataType.defaultValue)
          }

          if (dataType.unique === true) {
            template += " UNIQUE"
          }

          if (dataType.primaryKey) {
            template += " PRIMARY KEY"
          }

          if (dataType.comment && Utils._.isString(dataType.comment) && dataType.comment.length) {
            template += " COMMENT " + this.escape(dataType.comment)
          }

          if(dataType.references) {
            template += " REFERENCES " + this.quoteTable(dataType.references)

            if(dataType.referencesKey) {
              template += " (" + this.quoteIdentifier(dataType.referencesKey) + ")"
            } else {
              template += " (" + this.quoteIdentifier('id') + ")"
            }

            if(dataType.onDelete) {
              template += " ON DELETE " + dataType.onDelete.toUpperCase()
            }

            if(dataType.onUpdate) {
              template += " ON UPDATE " + dataType.onUpdate.toUpperCase()
            }

          }

          result[name] = template
        } else {
          result[name] = dataType
        }
      }

      return result
    },

    findAutoIncrementField: function(factory) {
      var fields = []

      for (var name in factory.attributes) {
        if (factory.attributes.hasOwnProperty(name)) {
          var definition = factory.attributes[name]

          if (definition && (definition.indexOf('auto_increment') > -1)) {
            fields.push(name)
          }
        }
      }

      return fields
    },

    addLimitAndOffset: function(options, query){
      query = query || ""
      if (options.offset && !options.limit) {
        query += " LIMIT " + options.offset + ", " + 18440000000000000000;
      } else if (options.limit) {
        if (options.offset) {
          query += " LIMIT " + options.offset + ", " + options.limit
        } else {
          query += " LIMIT " + options.limit
        }
      }
      return query;
    },

    quoteIdentifier: function(identifier, force) {
      if (identifier === '*') return identifier
      return Utils.addTicks(identifier, "`")
    },
    /**
     * Generates an SQL query that returns all foreign keys of a table.
     *
     * @param  {String} tableName  The name of the table.
     * @param  {String} schemaName The name of the schema.
     * @return {String}            The generated sql query.
     */
    getForeignKeysQuery: function(tableName, schemaName) {
      return "SELECT CONSTRAINT_NAME as constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = '" + tableName + "' AND CONSTRAINT_NAME!='PRIMARY' AND CONSTRAINT_SCHEMA='" + schemaName + "' AND REFERENCED_TABLE_NAME IS NOT NULL;"
    },

    /**
     * Generates an SQL query that removes a foreign key from a table.
     *
     * @param  {String} tableName  The name of the table.
     * @param  {String} foreignKey The name of the foreign key constraint.
     * @return {String}            The generated sql query.
     */
    dropForeignKeyQuery: function(tableName, foreignKey) {
      return 'ALTER TABLE ' + this.quoteTable(tableName) + ' DROP FOREIGN KEY ' + this.quoteIdentifier(foreignKey) + ';'
    },

    mysqlDataTypeMapping: function(tableName, attr, dataType) {
      if (Utils._.includes(dataType, 'UUID')) {
        dataType = dataType.replace(/UUID/, 'CHAR(36) BINARY')
      }

      return dataType
    }
  }

  return Utils._.extend(Utils._.clone(require("../abstract/query-generator")), QueryGenerator)
})()
<|endoftext|>


<commit_before>// Manage a connection to the Rackspace cloud. Retain and export handles to created resources.

var
  async = require('async'),
  pkgcloud = require('pkgcloud'),
  mongo = require('mongodb'),
  config = require('./config'),
  logger = require('./logging').getLogger();

/**
 * @description Create a function that asynchronously creates a Rackspace container if it
 *   doesn't already exist.
 */
function makeContainerCreator(client, containerName, logicalName, cdn) {
  return function (callback) {
    var reportBack = function (err, container) {
      if (err) return callback(err);

      exports[logicalName] = container;

      logger.debug("Container [" + container.name + "] now exists.");

      callback(null, container);
    };

    var cdnEnable = function (err, container) {
      if (err) return callback(err);

      logger.debug("Enabling CDN on container [" + container.name + "].");

      client.setCdnEnabled(container, { ttl: 31536000, enabled: true }, reportBack);
    };

    var handleCreation = cdn ? cdnEnable : reportBack;

    logger.info("Ensuring that container [" + containerName + "] exists.");

    // Instead of checking if the container exists first, we try to create it, and
    // if it already exists, we get a no-op (202) and move on.
    client.createContainer({ name: containerName }, handleCreation);
  };
}

/**
 * @description Utility function to ensure that the exported Container model includes CDN URIs when
 *   it's supposed to.
 */
function refresh(client, containerName, logicalName, callback) {
  client.getContainer(containerName, function (err, container) {
    if (err) {
      callback(err);
      return;
    }

    exports[logicalName] = container;

    callback(null);
  });
}

/**
 * @description Authenticate to MongoDB, export the active MongoDB connection as "db", and
 *   perform any necessary one-time initialization.
 */
function mongoInit(callback) {
  mongo.MongoClient.connect(config.mongodbURL(), function (err, db) {
    if (err) return callback(err);

    logger.debug("Connected to MongoDB database at [" + config.mongodbURL() + "].");

    exports.db = db;

    var envelopes = db.collection("envelopes");

    // Create indices on collections as necessary.
    async.parallel([
      function (callback) { envelopes.createIndex("tags", { sparse: true }, callback); },
      function (callback) { envelopes.createIndex("categories", { sparse: true }, callback); },
      function (callback) { envelopes.createIndex("contentID", { unique: true }, callback); }
    ], function (err, db) {
      if (err) return callback(err);

      log.debug("All indices created.");

      callback(null);
    });
  });
}

exports.setup = function (callback) {
  var client = pkgcloud.providers.rackspace.storage.createClient({
    username: config.rackspaceUsername(),
    apiKey: config.rackspaceAPIKey(),
    region: config.rackspaceRegion(),
    useInternal: config.rackspaceServiceNet()
  });

  client.on('log::*', function (message, object) {
    if (object) {
      logger.log(this.event.split('::')[1], message, object);
    } else {
      logger.log(this.event.split('::')[1], message);
    }
  });

  client.auth(function (err) {
    if (err) throw err;

    exports.client = client;

    async.parallel([
      makeContainerCreator(client, config.contentContainer(), "contentContainer", false),
      makeContainerCreator(client, config.assetContainer(), "assetContainer", true),
      mongoInit
    ], callback);
  });
};
<commit_msg>Missed a "log" reference.<commit_after>// Manage a connection to the Rackspace cloud. Retain and export handles to created resources.

var
  async = require('async'),
  pkgcloud = require('pkgcloud'),
  mongo = require('mongodb'),
  config = require('./config'),
  logger = require('./logging').getLogger();

/**
 * @description Create a function that asynchronously creates a Rackspace container if it
 *   doesn't already exist.
 */
function makeContainerCreator(client, containerName, logicalName, cdn) {
  return function (callback) {
    var reportBack = function (err, container) {
      if (err) return callback(err);

      exports[logicalName] = container;

      logger.debug("Container [" + container.name + "] now exists.");

      callback(null, container);
    };

    var cdnEnable = function (err, container) {
      if (err) return callback(err);

      logger.debug("Enabling CDN on container [" + container.name + "].");

      client.setCdnEnabled(container, { ttl: 31536000, enabled: true }, reportBack);
    };

    var handleCreation = cdn ? cdnEnable : reportBack;

    logger.info("Ensuring that container [" + containerName + "] exists.");

    // Instead of checking if the container exists first, we try to create it, and
    // if it already exists, we get a no-op (202) and move on.
    client.createContainer({ name: containerName }, handleCreation);
  };
}

/**
 * @description Utility function to ensure that the exported Container model includes CDN URIs when
 *   it's supposed to.
 */
function refresh(client, containerName, logicalName, callback) {
  client.getContainer(containerName, function (err, container) {
    if (err) {
      callback(err);
      return;
    }

    exports[logicalName] = container;

    callback(null);
  });
}

/**
 * @description Authenticate to MongoDB, export the active MongoDB connection as "db", and
 *   perform any necessary one-time initialization.
 */
function mongoInit(callback) {
  mongo.MongoClient.connect(config.mongodbURL(), function (err, db) {
    if (err) return callback(err);

    logger.debug("Connected to MongoDB database at [" + config.mongodbURL() + "].");

    exports.db = db;

    var envelopes = db.collection("envelopes");

    // Create indices on collections as necessary.
    async.parallel([
      function (callback) { envelopes.createIndex("tags", { sparse: true }, callback); },
      function (callback) { envelopes.createIndex("categories", { sparse: true }, callback); },
      function (callback) { envelopes.createIndex("contentID", { unique: true }, callback); }
    ], function (err, db) {
      if (err) return callback(err);

      logger.debug("All indices created.");

      callback(null);
    });
  });
}

exports.setup = function (callback) {
  var client = pkgcloud.providers.rackspace.storage.createClient({
    username: config.rackspaceUsername(),
    apiKey: config.rackspaceAPIKey(),
    region: config.rackspaceRegion(),
    useInternal: config.rackspaceServiceNet()
  });

  client.on('log::*', function (message, object) {
    if (object) {
      logger.log(this.event.split('::')[1], message, object);
    } else {
      logger.log(this.event.split('::')[1], message);
    }
  });

  client.auth(function (err) {
    if (err) throw err;

    exports.client = client;

    async.parallel([
      makeContainerCreator(client, config.contentContainer(), "contentContainer", false),
      makeContainerCreator(client, config.assetContainer(), "assetContainer", true),
      mongoInit
    ], callback);
  });
};
<|endoftext|>


<commit_before>import {sortBy} from 'lodash'
import {isFuture} from '../../shared/utils'

const deals = [
  {
    imgSrc: '/data/deals/dotjs.png',
    organization: 'dotJS',
    tagline: 'The largest JavaScript conference in Europe',
    link: 'http://jsair.io/dotjs-discount',
    deal: 'Use code JSAIR for 20% off your ticket',
    expires: '2016-12-05',
    description: `
      [dotJS](http://dotjs.io) is the largest JavaScript conference in Europe.
      Its 5th edition will happen on December 5th in Paris at the Théâtre Mogador.
      A lot of amazing speakers will be announced soon. Meanwhile you can check the
      dotJS 2015 talks [here](http://www.thedotpost.com/conference/dotjs-2015).
    `,
  },
  {
    imgSrc: '/data/deals/digitalocean.png',
    organization: 'Digital Ocean',
    tagline: 'Simple Cloud Infrastructure for Developers',
    link: 'http://jsair.io/digitalocean',
    deal: '**JSAIR10** - good for $10 credit on a new DigitalOcean account.',
    expires: '',
    description: `
      DigitalOcean is the best place to get your application off the ground quickly,
      and the easiest to scale when you find success.
      Start with the pre-configured NodeJS one-click to get up and running in 55 seconds,
      or build the exact infrastructure you need, with root access to servers running 100%
      SSD's in state-of-the-art datacenters around the world.
    `,
  },
  {
    imgSrc: '/data/deals/dinosaurjs.png',
    organization: 'Dinosaur.js',
    tagline: 'JavaScript Conference in Denver, Colorado on June 24, 2016',
    link: 'http://jsair.io/dinosaurjs',
    deal: 'You can use code "jsonair" for 10% off tickets 10 tickets',
    expires: '2016-04-30',
    description: `
      A non-profit, community-driven JavaScript conference happening in Denver, Colorado on Friday, June 24, 2016.
      One day. One track.
    `,
  },
  {
    imgSrc: '/data/deals/turing.png',
    organization: 'Turing School of Software and Design',
    tagline: 'Seven month developer training program in Denver, Colorado',
    link: 'http://jsair.io/turing',
    deal: 'Refer a student with the code FEE2016. You get $500 cash & the student gets $500 off their tuition.',
    expires: '2016-04-30',
    description: `
      A non-profit, community-driven JavaScript conference happening in Denver, Colorado on Friday, June 24, 2016.
      One day. One track.
    `,
  },
]

const sortedDeals = sortBy(deals, d => d.organization.toLowerCase())
const filteredDeals = sortedDeals.filter(d => d.expires ? isFuture(d.expires) : true)

export default filteredDeals
<commit_msg>fix Turing description<commit_after>import {sortBy} from 'lodash'
import {isFuture} from '../../shared/utils'

const deals = [
  {
    imgSrc: '/data/deals/dotjs.png',
    organization: 'dotJS',
    tagline: 'The largest JavaScript conference in Europe',
    link: 'http://jsair.io/dotjs-discount',
    deal: 'Use code JSAIR for 20% off your ticket',
    expires: '2016-12-05',
    description: `
      [dotJS](http://dotjs.io) is the largest JavaScript conference in Europe.
      Its 5th edition will happen on December 5th in Paris at the Théâtre Mogador.
      A lot of amazing speakers will be announced soon. Meanwhile you can check the
      dotJS 2015 talks [here](http://www.thedotpost.com/conference/dotjs-2015).
    `,
  },
  {
    imgSrc: '/data/deals/digitalocean.png',
    organization: 'Digital Ocean',
    tagline: 'Simple Cloud Infrastructure for Developers',
    link: 'http://jsair.io/digitalocean',
    deal: '**JSAIR10** - good for $10 credit on a new DigitalOcean account.',
    expires: '',
    description: `
      DigitalOcean is the best place to get your application off the ground quickly,
      and the easiest to scale when you find success.
      Start with the pre-configured NodeJS one-click to get up and running in 55 seconds,
      or build the exact infrastructure you need, with root access to servers running 100%
      SSD's in state-of-the-art datacenters around the world.
    `,
  },
  {
    imgSrc: '/data/deals/dinosaurjs.png',
    organization: 'Dinosaur.js',
    tagline: 'JavaScript Conference in Denver, Colorado on June 24, 2016',
    link: 'http://jsair.io/dinosaurjs',
    deal: 'You can use code "jsonair" for 10% off tickets 10 tickets',
    expires: '2016-04-30',
    description: `
      A non-profit, community-driven JavaScript conference happening in Denver, Colorado on Friday, June 24, 2016.
      One day. One track.
    `,
  },
  {
    imgSrc: '/data/deals/turing.png',
    organization: 'Turing School of Software and Design',
    tagline: 'Seven month developer training program in Denver, Colorado',
    link: 'http://jsair.io/turing',
    deal: 'Refer a student with the code FEE2016. You get $500 cash & the student gets $500 off their tuition.',
    expires: '2016-04-30',
    description: `
      We turn great people into outstanding developers. Turing believes in community-driven education. Our community is
      built on three core values which guide our work: love, respect, and curiosity.
      We believe in community-driven education. We're not a co-working space, and we're not a handful of folks in a
      conference room. Turing is a growing, thriving community of over a hundred people helping each other become more
      than what they thought to be possible.
    `,
  },
]

const sortedDeals = sortBy(deals, d => d.organization.toLowerCase())
const filteredDeals = sortedDeals.filter(d => d.expires ? isFuture(d.expires) : true)

export default filteredDeals
<|endoftext|>


<commit_before>var querystring      = require('querystring'),
    util             = require('util'),
    AbstractGeocoder = require('./abstractgeocoder');

/**
 * SmartyStreets Constructor
 * @param <object> httpAdapter Http Adapter
 * @param <object> options     Options
 */
var SmartyStreets = function(httpAdapter, auth_id, auth_token) {
    this.name = "SmartyStreets";
    SmartyStreets.super_.call(this, httpAdapter);

    if(!auth_id && !auth_token){
      throw new Error("You must specify an auth-id and auth-token!");
    }

    this.auth_id = auth_id;
    this.auth_token = auth_token;
};

util.inherits(SmartyStreets, AbstractGeocoder);

SmartyStreets.prototype._endpoint = "https://api.smartystreets.com/street-address";

/**
* Reverse geocoding
* @param <integer>  lat      Latittude
* @param <integer>  lng      Longitude
* @param <function> callback Callback method
*/
SmartyStreets.prototype.reverse = function(lat, lng, callback) {
    if (typeof this._reverse != 'function') {
        throw new Error(this.name + ' doesnt support reverse geocoding!');
    }

    return this._reverse(lat, lng, callback);
};

/**
 * Format Result
 **/
SmartyStreets.prototype._formatResult = function(result) {
    return {
      'latitude' : result.metadata.latitude,
      'longitude' : result.metadata.longitude,
      'country' : null,
      'city' : result.components.city_name,
      'zipcode' : result.components.zipcode,
      'streetName' : result.components.street_name+" "+result.components.street_suffix,
      'streetNumber' : result.components.primary_number,
      'countryCode' : null,
      'type' : result.metadata.record_type,
      'dpv_match' : result.analysis.dpv_match_code,
      'dpv_footnotes' : result.analysis.dpv_footnotes
    };
};

/**
* Geocode
* @param <string>   value    Value to geocode
* @param <function> callback Callback method
*/
SmartyStreets.prototype.geocode = function(value, callback) {
    var _this = this;

    var params = {
      "street": value,
      "auth-id": this.auth_id,
      "auth-token": this.auth_token,
      "format": 'json'
    };

    this.httpAdapter.get(this._endpoint,params,function(err, result){
      if(err) {
        return callback(err);
      } else {
        results = _this._formatResult(result[0]);

        callback(false, results);
      }
    });
};

module.exports = SmartyStreets;
<commit_msg>added checking to make sure result is valid<commit_after>var querystring      = require('querystring'),
    util             = require('util'),
    AbstractGeocoder = require('./abstractgeocoder');

/**
 * SmartyStreets Constructor
 * @param <object> httpAdapter Http Adapter
 * @param <object> options     Options
 */
var SmartyStreets = function(httpAdapter, auth_id, auth_token) {
    this.name = "SmartyStreets";
    SmartyStreets.super_.call(this, httpAdapter);

    if(!auth_id && !auth_token){
      throw new Error("You must specify an auth-id and auth-token!");
    }

    this.auth_id = auth_id;
    this.auth_token = auth_token;
};

util.inherits(SmartyStreets, AbstractGeocoder);

SmartyStreets.prototype._endpoint = "https://api.smartystreets.com/street-address";

/**
* Reverse geocoding
* @param <integer>  lat      Latittude
* @param <integer>  lng      Longitude
* @param <function> callback Callback method
*/
SmartyStreets.prototype.reverse = function(lat, lng, callback) {
    if (typeof this._reverse != 'function') {
        throw new Error(this.name + ' doesnt support reverse geocoding!');
    }

    return this._reverse(lat, lng, callback);
};

/**
 * Format Result
 **/
SmartyStreets.prototype._formatResult = function(result) {
  if(result){
      return {
        'latitude' : result.metadata.latitude,
        'longitude' : result.metadata.longitude,
        'country' : null,
        'city' : result.components.city_name,
        'zipcode' : result.components.zipcode,
        'streetName' : result.components.street_name+" "+result.components.street_suffix,
        'streetNumber' : result.components.primary_number,
        'countryCode' : null,
        'type' : result.metadata.record_type,
        'dpv_match' : result.analysis.dpv_match_code,
        'dpv_footnotes' : result.analysis.dpv_footnotes
      };
  }
};

/**
* Geocode
* @param <string>   value    Value to geocode
* @param <function> callback Callback method
*/
SmartyStreets.prototype.geocode = function(value, callback) {
    var _this = this;

    var params = {
      "street": value,
      "auth-id": this.auth_id,
      "auth-token": this.auth_token,
      "format": 'json'
    };

    this.httpAdapter.get(this._endpoint,params,function(err, result){
      if(err) {
        return callback(err);
      } else {
        results = _this._formatResult(result[0]);

        callback(false, results);
      }
    });
};

module.exports = SmartyStreets;
<|endoftext|>


<commit_before>OV.GetDefaultCamera = function (direction)
{
	if (direction === OV.Direction.X) {
		return new OV.Camera (
			new OV.Coord3D (2.0, -3.0, 1.5),
			new OV.Coord3D (0.0, 0.0, 0.0),
			new OV.Coord3D (1.0, 0.0, 0.0)
		);
	} else if (direction === OV.Direction.Y) {
		return new OV.Camera (
			new OV.Coord3D (-1.5, 2.0, 3.0),
			new OV.Coord3D (0.0, 0.0, 0.0),
			new OV.Coord3D (0.0, 1.0, 0.0)
		);
	} else if (direction === OV.Direction.Z) {
		return new OV.Camera (
			new OV.Coord3D (-1.5, -3.0, 2.0),
			new OV.Coord3D (0.0, 0.0, 0.0),
			new OV.Coord3D (0.0, 0.0, 1.0)
		);
	}
	return null;
};

OV.UpVector = class
{
	constructor ()
	{
		this.direction = OV.Direction.Z;
		this.isFixed = true;
		this.isFlipped = false;
	}

	SetDirection (newDirection, oldCamera)
	{
		this.direction = newDirection;
		this.isFlipped = false;

		let defaultCamera = OV.GetDefaultCamera (this.direction);
		let defaultDir = OV.SubCoord3D (defaultCamera.eye, defaultCamera.center);

		let distance = OV.CoordDistance3D (oldCamera.center, oldCamera.eye);
		let newEye = oldCamera.center.Clone ().Offset (defaultDir, distance);

		let newCamera = oldCamera.Clone ();
		if (this.direction === OV.Direction.Y) {
			newCamera.up = new OV.Coord3D (0.0, 1.0, 0.0);
			newCamera.eye = newEye;
		} else if (this.direction === OV.Direction.Z) {
			newCamera.up = new OV.Coord3D (0.0, 0.0, 1.0);
			newCamera.eye = newEye;
		}
		return newCamera;
	}

	SetFixed (isFixed, oldCamera)
	{
		this.isFixed = isFixed;
		if (this.isFixed) {
			return this.SetDirection (this.direction, oldCamera);
		}
		return null;
	}

	Flip (oldCamera)
	{
		this.isFlipped = !this.isFlipped;
		let newCamera = oldCamera.Clone ();
		newCamera.up.MultiplyScalar (-1.0);
		return newCamera;
	}
};

OV.Viewer = class
{
	constructor ()
	{
		this.canvas = null;
		this.renderer = null;
		this.scene = null;
		this.camera = null;
		this.light = null;
		this.navigation = null;
		this.upVector = null;
		this.settings = {
			animationSteps : 40
		};
	}

	Init (canvas)
	{
		this.canvas = canvas;
		this.canvas.id = 'viewer';
		this.canvas.addEventListener ('contenxtmenu', function (ev) {
			ev.preventDefault ();
		});

		let parameters = {
			canvas : this.canvas,
			antialias : true
		};

		this.renderer = new THREE.WebGLRenderer (parameters);
		this.renderer.setClearColor ('#ffffff', 1);
		this.renderer.setSize (this.canvas.width, this.canvas.height);

		this.scene = new THREE.Scene ();

		this.InitCamera ();
		this.InitLights ();

		this.Render ();
	}

	SetClickHandler (onClick)
	{
		this.navigation.SetClickHandler (onClick);
	}

	GetCamera ()
	{
		return this.navigation.GetCamera ();
	}

	SetCamera (camera)
	{
		this.navigation.SetCamera (camera);
		this.Render ();
	}

	Resize (width, height)
	{
		let innerSize = OV.GetInnerDimensions (this.canvas, width, height);
		this.camera.aspect = innerSize.width / innerSize.height;
		this.camera.updateProjectionMatrix ();
		this.renderer.setSize (innerSize.width, innerSize.height);
		this.Render ();
	}

	FitToWindow (boundingSphere, animation)
	{
		if (boundingSphere === null) {
			return;
		}
		let center = new OV.Coord3D (boundingSphere.center.x, boundingSphere.center.y, boundingSphere.center.z);
		let radius = boundingSphere.radius;
		let fov = this.camera.fov;
		if (animation) {
			let newCamera = this.navigation.GetFitToSphereCamera (center, radius, fov);
			this.navigation.MoveCamera (newCamera, this.settings.animationSteps);
		} else {
			this.navigation.FitToSphere (center, radius, fov);
		}
	}

	AdjustClippingPlanes (boundingSphere)
	{
		if (boundingSphere === null) {
			return;
		}
		if (boundingSphere.radius < 10.0) {
			this.camera.near = 0.01;
			this.camera.far = 100.0;
		} else if (boundingSphere.radius < 100.0) {
			this.camera.near = 0.1;
			this.camera.far = 1000.0;
		} else if (boundingSphere.radius < 1000.0) {
			this.camera.near = 10.0;
			this.camera.far = 10000.0;
		} else {
			this.camera.near = 100.0;
			this.camera.far = 1000000.0;
		}
		this.camera.updateProjectionMatrix ();
		this.Render ();
	}

	IsFixUpVector ()
	{
		return this.navigation.IsFixUpVector ();
	}

	SetFixUpVector (fixUpVector)
	{
		let oldCamera = this.navigation.GetCamera ();
		let newCamera = this.upVector.SetFixed (fixUpVector, oldCamera);
		this.navigation.SetFixUpVector (fixUpVector);
		if (newCamera !== null) {
			this.navigation.MoveCamera (newCamera, this.settings.animationSteps);
		}
		this.Render ();
	}

	SetUpVector (upDirection, animate)
	{
		let oldCamera = this.navigation.GetCamera ();
		let newCamera = this.upVector.SetDirection (upDirection, oldCamera);
		let animationSteps = animate ? this.settings.animationSteps : 0;
		this.navigation.MoveCamera (newCamera, animationSteps);
		this.Render ();
	}

	FlipUpVector ()
	{
		let oldCamera = this.navigation.GetCamera ();
		let newCamera = this.upVector.Flip (oldCamera);
		this.navigation.MoveCamera (newCamera, 0);
		this.Render ();
	}

	Render ()
	{
		let navigationCamera = this.navigation.GetCamera ();
		this.camera.position.set (navigationCamera.eye.x, navigationCamera.eye.y, navigationCamera.eye.z);
		this.camera.up.set (navigationCamera.up.x, navigationCamera.up.y, navigationCamera.up.z);
		this.camera.lookAt (new THREE.Vector3 (navigationCamera.center.x, navigationCamera.center.y, navigationCamera.center.z));

		let lightDir = OV.SubCoord3D (navigationCamera.eye, navigationCamera.center);
		this.light.position.set (lightDir.x, lightDir.y, lightDir.z);
		this.renderer.render (this.scene, this.camera);
	}

	AddMeshes (meshes)
	{
		for (let i = 0; i < meshes.length; i++) {
			let mesh = meshes[i];
			this.scene.add (mesh);
		}
		this.Render ();
	}

	Clear ()
	{
		this.ClearMeshes ();
		this.Render ();
	}

	SetMeshesVisibility (isVisible)
	{
		this.EnumerateMeshes (function (mesh) {
			let visible = isVisible (mesh.userData);
			if (mesh.visible !== visible) {
				mesh.visible = visible;
			}
		});
		this.Render ();
	}

	SetMeshesHighlight (highlightMaterial, isHighlighted)
	{
		function CreateHighlightMaterials (originalMaterials, highlightMaterial)
		{
			let highlightMaterials = [];
			for (let i = 0; i < originalMaterials.length; i++) {
				highlightMaterials.push (highlightMaterial);
			}
			return highlightMaterials;
		}

		this.EnumerateMeshes (function (mesh) {
			let highlighted = isHighlighted (mesh.userData);
			if (highlighted) {
				if (mesh.userData.threeMaterials === null) {
					mesh.userData.threeMaterials = mesh.material;
					mesh.material = CreateHighlightMaterials (mesh.material, highlightMaterial);
				}
			} else {
				if (mesh.userData.threeMaterials !== null) {
					mesh.material = mesh.userData.threeMaterials;
					mesh.userData.threeMaterials = null;
				}
			}
		});
		this.Render ();
	}

	GetMeshUnderMouse (mouseCoords)
	{
		let raycaster = new THREE.Raycaster ();
		let mousePos = new THREE.Vector2 ();
		mousePos.x = (mouseCoords.x / this.canvas.width) * 2 - 1;
		mousePos.y = -(mouseCoords.y / this.canvas.height) * 2 + 1;
		raycaster.setFromCamera (mousePos, this.camera);
		let iSectObjects = raycaster.intersectObjects (this.scene.children);
		for (let i = 0; i < iSectObjects.length; i++) {
			let iSectObject = iSectObjects[i];
			if (iSectObject.object.type === 'Mesh' && iSectObject.object.visible) {
				return iSectObject.object.userData;
			}
		}
		return null;
	}

	GetBoundingBox (needToProcess)
	{
		let hasMesh = false;
		let boundingBox = new THREE.Box3 ();
		this.EnumerateMeshes (function (mesh) {
			if (needToProcess (mesh.userData)) {
				boundingBox.union (new THREE.Box3 ().setFromObject (mesh));
				hasMesh = true;
			}
		});

		if (!hasMesh) {
			return null;
		}
		return boundingBox;
	}

	GetBoundingSphere (needToProcess)
	{
		let boundingBox = this.GetBoundingBox (needToProcess);
		if (boundingBox === null) {
			return null;
		}

		let boundingSphere = new THREE.Sphere ();
		boundingBox.getBoundingSphere (boundingSphere);
		return boundingSphere;
	}

	EnumerateMeshesUserData (enumerator)
	{
		this.EnumerateMeshes (function (mesh) {
			enumerator (mesh.userData);
		});
	}

	EnumerateMeshes (enumerator)
	{
		this.scene.traverse (function (object) {
			if (object.isMesh) {
				enumerator (object);
			}
		});
	}

	ClearMeshes ()
	{
		for (let i = this.scene.children.length - 1; i >= 0; i--) {
			let object = this.scene.children[i];
			if (object.isMesh) {
				object.geometry.dispose ();
				this.scene.remove (object);
			}
		}
	}

	InitCamera ()
	{
		this.camera = new THREE.PerspectiveCamera (45.0, this.canvas.width / this.canvas.height, 0.1, 1000.0);
		this.scene.add (this.camera);

		let canvasElem = this.renderer.domElement;
		let camera = OV.GetDefaultCamera (OV.Direction.Z);

		let obj = this;
		this.navigation = new OV.Navigation (canvasElem, camera);
		this.navigation.SetUpdateHandler (function () {
			obj.Render ();
		});

		this.upVector = new OV.UpVector ();
	}

	InitLights  ()
	{
		let ambientLight = new THREE.AmbientLight (0x888888);
		this.scene.add (ambientLight);

		this.light = new THREE.DirectionalLight (0x888888);
		this.scene.add (this.light);
	}
};
<commit_msg>Get rendered image as data url from the viewer.<commit_after>OV.GetDefaultCamera = function (direction)
{
	if (direction === OV.Direction.X) {
		return new OV.Camera (
			new OV.Coord3D (2.0, -3.0, 1.5),
			new OV.Coord3D (0.0, 0.0, 0.0),
			new OV.Coord3D (1.0, 0.0, 0.0)
		);
	} else if (direction === OV.Direction.Y) {
		return new OV.Camera (
			new OV.Coord3D (-1.5, 2.0, 3.0),
			new OV.Coord3D (0.0, 0.0, 0.0),
			new OV.Coord3D (0.0, 1.0, 0.0)
		);
	} else if (direction === OV.Direction.Z) {
		return new OV.Camera (
			new OV.Coord3D (-1.5, -3.0, 2.0),
			new OV.Coord3D (0.0, 0.0, 0.0),
			new OV.Coord3D (0.0, 0.0, 1.0)
		);
	}
	return null;
};

OV.UpVector = class
{
	constructor ()
	{
		this.direction = OV.Direction.Z;
		this.isFixed = true;
		this.isFlipped = false;
	}

	SetDirection (newDirection, oldCamera)
	{
		this.direction = newDirection;
		this.isFlipped = false;

		let defaultCamera = OV.GetDefaultCamera (this.direction);
		let defaultDir = OV.SubCoord3D (defaultCamera.eye, defaultCamera.center);

		let distance = OV.CoordDistance3D (oldCamera.center, oldCamera.eye);
		let newEye = oldCamera.center.Clone ().Offset (defaultDir, distance);

		let newCamera = oldCamera.Clone ();
		if (this.direction === OV.Direction.Y) {
			newCamera.up = new OV.Coord3D (0.0, 1.0, 0.0);
			newCamera.eye = newEye;
		} else if (this.direction === OV.Direction.Z) {
			newCamera.up = new OV.Coord3D (0.0, 0.0, 1.0);
			newCamera.eye = newEye;
		}
		return newCamera;
	}

	SetFixed (isFixed, oldCamera)
	{
		this.isFixed = isFixed;
		if (this.isFixed) {
			return this.SetDirection (this.direction, oldCamera);
		}
		return null;
	}

	Flip (oldCamera)
	{
		this.isFlipped = !this.isFlipped;
		let newCamera = oldCamera.Clone ();
		newCamera.up.MultiplyScalar (-1.0);
		return newCamera;
	}
};

OV.Viewer = class
{
	constructor ()
	{
		this.canvas = null;
		this.renderer = null;
		this.scene = null;
		this.camera = null;
		this.light = null;
		this.navigation = null;
		this.upVector = null;
		this.settings = {
			animationSteps : 40
		};
	}

	Init (canvas)
	{
		this.canvas = canvas;
		this.canvas.id = 'viewer';
		this.canvas.addEventListener ('contenxtmenu', function (ev) {
			ev.preventDefault ();
		});

		let parameters = {
			canvas : this.canvas,
			antialias : true
		};

		this.renderer = new THREE.WebGLRenderer (parameters);
		this.renderer.setClearColor ('#ffffff', 1.0);
		this.renderer.setSize (this.canvas.width, this.canvas.height);

		this.scene = new THREE.Scene ();

		this.InitCamera ();
		this.InitLights ();

		this.Render ();
	}

	SetClickHandler (onClick)
	{
		this.navigation.SetClickHandler (onClick);
	}

	GetCamera ()
	{
		return this.navigation.GetCamera ();
	}

	SetCamera (camera)
	{
		this.navigation.SetCamera (camera);
		this.Render ();
	}

	Resize (width, height)
	{
		let innerSize = OV.GetInnerDimensions (this.canvas, width, height);
		this.ResizeRenderer (innerSize.width, innerSize.height);
	}

	ResizeRenderer (width, height)
	{
		this.camera.aspect = width / height;
		this.camera.updateProjectionMatrix ();
		this.renderer.setSize (width, height);
		this.Render ();
	}

	FitToWindow (boundingSphere, animation)
	{
		if (boundingSphere === null) {
			return;
		}
		let center = new OV.Coord3D (boundingSphere.center.x, boundingSphere.center.y, boundingSphere.center.z);
		let radius = boundingSphere.radius;
		let fov = this.camera.fov;
		if (animation) {
			let newCamera = this.navigation.GetFitToSphereCamera (center, radius, fov);
			this.navigation.MoveCamera (newCamera, this.settings.animationSteps);
		} else {
			this.navigation.FitToSphere (center, radius, fov);
		}
	}

	AdjustClippingPlanes (boundingSphere)
	{
		if (boundingSphere === null) {
			return;
		}
		if (boundingSphere.radius < 10.0) {
			this.camera.near = 0.01;
			this.camera.far = 100.0;
		} else if (boundingSphere.radius < 100.0) {
			this.camera.near = 0.1;
			this.camera.far = 1000.0;
		} else if (boundingSphere.radius < 1000.0) {
			this.camera.near = 10.0;
			this.camera.far = 10000.0;
		} else {
			this.camera.near = 100.0;
			this.camera.far = 1000000.0;
		}
		this.camera.updateProjectionMatrix ();
		this.Render ();
	}

	IsFixUpVector ()
	{
		return this.navigation.IsFixUpVector ();
	}

	SetFixUpVector (fixUpVector)
	{
		let oldCamera = this.navigation.GetCamera ();
		let newCamera = this.upVector.SetFixed (fixUpVector, oldCamera);
		this.navigation.SetFixUpVector (fixUpVector);
		if (newCamera !== null) {
			this.navigation.MoveCamera (newCamera, this.settings.animationSteps);
		}
		this.Render ();
	}

	SetUpVector (upDirection, animate)
	{
		let oldCamera = this.navigation.GetCamera ();
		let newCamera = this.upVector.SetDirection (upDirection, oldCamera);
		let animationSteps = animate ? this.settings.animationSteps : 0;
		this.navigation.MoveCamera (newCamera, animationSteps);
		this.Render ();
	}

	FlipUpVector ()
	{
		let oldCamera = this.navigation.GetCamera ();
		let newCamera = this.upVector.Flip (oldCamera);
		this.navigation.MoveCamera (newCamera, 0);
		this.Render ();
	}

	Render ()
	{
		let navigationCamera = this.navigation.GetCamera ();
		this.camera.position.set (navigationCamera.eye.x, navigationCamera.eye.y, navigationCamera.eye.z);
		this.camera.up.set (navigationCamera.up.x, navigationCamera.up.y, navigationCamera.up.z);
		this.camera.lookAt (new THREE.Vector3 (navigationCamera.center.x, navigationCamera.center.y, navigationCamera.center.z));

		let lightDir = OV.SubCoord3D (navigationCamera.eye, navigationCamera.center);
		this.light.position.set (lightDir.x, lightDir.y, lightDir.z);
		this.renderer.render (this.scene, this.camera);
	}

	AddMeshes (meshes)
	{
		for (let i = 0; i < meshes.length; i++) {
			let mesh = meshes[i];
			this.scene.add (mesh);
		}
		this.Render ();
	}

	Clear ()
	{
		this.ClearMeshes ();
		this.Render ();
	}

	SetMeshesVisibility (isVisible)
	{
		this.EnumerateMeshes (function (mesh) {
			let visible = isVisible (mesh.userData);
			if (mesh.visible !== visible) {
				mesh.visible = visible;
			}
		});
		this.Render ();
	}

	SetMeshesHighlight (highlightMaterial, isHighlighted)
	{
		function CreateHighlightMaterials (originalMaterials, highlightMaterial)
		{
			let highlightMaterials = [];
			for (let i = 0; i < originalMaterials.length; i++) {
				highlightMaterials.push (highlightMaterial);
			}
			return highlightMaterials;
		}

		this.EnumerateMeshes (function (mesh) {
			let highlighted = isHighlighted (mesh.userData);
			if (highlighted) {
				if (mesh.userData.threeMaterials === null) {
					mesh.userData.threeMaterials = mesh.material;
					mesh.material = CreateHighlightMaterials (mesh.material, highlightMaterial);
				}
			} else {
				if (mesh.userData.threeMaterials !== null) {
					mesh.material = mesh.userData.threeMaterials;
					mesh.userData.threeMaterials = null;
				}
			}
		});
		this.Render ();
	}

	GetMeshUnderMouse (mouseCoords)
	{
		let raycaster = new THREE.Raycaster ();
		let mousePos = new THREE.Vector2 ();
		mousePos.x = (mouseCoords.x / this.canvas.width) * 2 - 1;
		mousePos.y = -(mouseCoords.y / this.canvas.height) * 2 + 1;
		raycaster.setFromCamera (mousePos, this.camera);
		let iSectObjects = raycaster.intersectObjects (this.scene.children);
		for (let i = 0; i < iSectObjects.length; i++) {
			let iSectObject = iSectObjects[i];
			if (iSectObject.object.type === 'Mesh' && iSectObject.object.visible) {
				return iSectObject.object.userData;
			}
		}
		return null;
	}

	GetBoundingBox (needToProcess)
	{
		let hasMesh = false;
		let boundingBox = new THREE.Box3 ();
		this.EnumerateMeshes (function (mesh) {
			if (needToProcess (mesh.userData)) {
				boundingBox.union (new THREE.Box3 ().setFromObject (mesh));
				hasMesh = true;
			}
		});

		if (!hasMesh) {
			return null;
		}
		return boundingBox;
	}

	GetBoundingSphere (needToProcess)
	{
		let boundingBox = this.GetBoundingBox (needToProcess);
		if (boundingBox === null) {
			return null;
		}

		let boundingSphere = new THREE.Sphere ();
		boundingBox.getBoundingSphere (boundingSphere);
		return boundingSphere;
	}

	EnumerateMeshesUserData (enumerator)
	{
		this.EnumerateMeshes (function (mesh) {
			enumerator (mesh.userData);
		});
	}

	EnumerateMeshes (enumerator)
	{
		this.scene.traverse (function (object) {
			if (object.isMesh) {
				enumerator (object);
			}
		});
	}

	ClearMeshes ()
	{
		for (let i = this.scene.children.length - 1; i >= 0; i--) {
			let object = this.scene.children[i];
			if (object.isMesh) {
				object.geometry.dispose ();
				this.scene.remove (object);
			}
		}
	}

	InitCamera ()
	{
		this.camera = new THREE.PerspectiveCamera (45.0, this.canvas.width / this.canvas.height, 0.1, 1000.0);
		this.scene.add (this.camera);

		let canvasElem = this.renderer.domElement;
		let camera = OV.GetDefaultCamera (OV.Direction.Z);

		let obj = this;
		this.navigation = new OV.Navigation (canvasElem, camera);
		this.navigation.SetUpdateHandler (function () {
			obj.Render ();
		});

		this.upVector = new OV.UpVector ();
	}

	InitLights  ()
	{
		let ambientLight = new THREE.AmbientLight (0x888888);
		this.scene.add (ambientLight);

		this.light = new THREE.DirectionalLight (0x888888);
		this.scene.add (this.light);
	}

	GetImageAsDataUrl (width, height)
	{
		let originalSize = null;
		if (width && height) {
			originalSize = new THREE.Vector2 ();
			this.renderer.getSize (originalSize);
			this.ResizeRenderer (width, height);
		}
		this.Render ();
		let url = this.renderer.domElement.toDataURL();
		if (originalSize !== null) {
			this.ResizeRenderer (
				parseInt (originalSize.x, 10),
				parseInt (originalSize.y, 10)
			);
		}
		return url;
	}
};
<|endoftext|>


<commit_before>import {nullCommit} from '../commit';
import BranchSet from '../branch-set';
import RemoteSet from '../remote-set';
import {nullOperationStates} from '../operation-states';
import MultiFilePatch from '../patch/multi-file-patch';

/**
 * Map of registered subclasses to allow states to transition to one another without circular dependencies.
 * Subclasses of State should call `State.register` to add themselves here.
 */
const stateConstructors = new Map();

/**
 * Base class for Repository states. Implements default "null" behavior.
 */
export default class State {
  constructor(repository) {
    this.repository = repository;
  }

  static register(Subclass) {
    stateConstructors.set(Subclass.name, Subclass);
  }

  // This state has just been entered. Perform any asynchronous initialization that needs to occur.
  start() {
    return Promise.resolve();
  }

  // State probe predicates ////////////////////////////////////////////////////////////////////////////////////////////
  // Allow external callers to identify which state a Repository is in if necessary.

  isLoadingGuess() {
    return false;
  }

  isAbsentGuess() {
    return false;
  }

  isAbsent() {
    return false;
  }

  isLoading() {
    return false;
  }

  isEmpty() {
    return false;
  }

  isPresent() {
    return false;
  }

  isTooLarge() {
    return false;
  }

  isDestroyed() {
    return false;
  }

  // Behavior probe predicates /////////////////////////////////////////////////////////////////////////////////////////
  // Determine specific rendering behavior based on the current state.

  isUndetermined() {
    return false;
  }

  showGitTabInit() {
    return false;
  }

  showGitTabInitInProgress() {
    return false;
  }

  showGitTabLoading() {
    return false;
  }

  showStatusBarTiles() {
    return false;
  }

  hasDirectory() {
    return true;
  }

  // Lifecycle actions /////////////////////////////////////////////////////////////////////////////////////////////////
  // These generally default to rejecting a Promise with an error.

  init() {
    return unsupportedOperationPromise(this, 'init');
  }

  clone(remoteUrl) {
    return unsupportedOperationPromise(this, 'clone');
  }

  destroy() {
    return this.transitionTo('Destroyed');
  }

  refresh() {
    // No-op
  }

  observeFilesystemChange(events) {
    this.repository.refresh();
  }

  updateCommitMessageAfterFileSystemChange() {
    // this is only used in unit tests, we don't need no stinkin coverage
    /* istanbul ignore next */
    this.repository.refresh();
  }

  // Git operations ////////////////////////////////////////////////////////////////////////////////////////////////////
  // These default to rejecting a Promise with an error stating that the operation is not supported in the current
  // state.

  // Staging and unstaging

  stageFiles(paths) {
    return unsupportedOperationPromise(this, 'stageFiles');
  }

  unstageFiles(paths) {
    return unsupportedOperationPromise(this, 'unstageFiles');
  }

  stageFilesFromParentCommit(paths) {
    return unsupportedOperationPromise(this, 'stageFilesFromParentCommit');
  }

  applyPatchToIndex(patch) {
    return unsupportedOperationPromise(this, 'applyPatchToIndex');
  }

  applyPatchToWorkdir(patch) {
    return unsupportedOperationPromise(this, 'applyPatchToWorkdir');
  }

  // Committing

  commit(message, options) {
    return unsupportedOperationPromise(this, 'commit');
  }

  // Merging

  merge(branchName) {
    return unsupportedOperationPromise(this, 'merge');
  }

  abortMerge() {
    return unsupportedOperationPromise(this, 'abortMerge');
  }

  checkoutSide(side, paths) {
    return unsupportedOperationPromise(this, 'checkoutSide');
  }

  mergeFile(oursPath, commonBasePath, theirsPath, resultPath) {
    return unsupportedOperationPromise(this, 'mergeFile');
  }

  writeMergeConflictToIndex(filePath, commonBaseSha, oursSha, theirsSha) {
    return unsupportedOperationPromise(this, 'writeMergeConflictToIndex');
  }

  // Checkout

  checkout(revision, options = {}) {
    return unsupportedOperationPromise(this, 'checkout');
  }

  checkoutPathsAtRevision(paths, revision = 'HEAD') {
    return unsupportedOperationPromise(this, 'checkoutPathsAtRevision');
  }

  // Reset

  undoLastCommit() {
    return unsupportedOperationPromise(this, 'undoLastCommit');
  }

  // Remote interactions

  fetch(branchName) {
    return unsupportedOperationPromise(this, 'fetch');
  }

  pull(branchName) {
    return unsupportedOperationPromise(this, 'pull');
  }

  push(branchName) {
    return unsupportedOperationPromise(this, 'push');
  }

  // Configuration

  setConfig(option, value, {replaceAll} = {}) {
    return unsupportedOperationPromise(this, 'setConfig');
  }

  unsetConfig(option) {
    return unsupportedOperationPromise(this, 'unsetConfig');
  }

  // Direct blob interactions

  createBlob({filePath, stdin} = {}) {
    return unsupportedOperationPromise(this, 'createBlob');
  }

  expandBlobToFile(absFilePath, sha) {
    return unsupportedOperationPromise(this, 'expandBlobToFile');
  }

  // Discard history

  createDiscardHistoryBlob() {
    return unsupportedOperationPromise(this, 'createDiscardHistoryBlob');
  }

  updateDiscardHistory() {
    return unsupportedOperationPromise(this, 'updateDiscardHistory');
  }

  storeBeforeAndAfterBlobs(filePaths, isSafe, destructiveAction, partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'storeBeforeAndAfterBlobs');
  }

  restoreLastDiscardInTempFiles(isSafe, partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'restoreLastDiscardInTempFiles');
  }

  popDiscardHistory(partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'popDiscardHistory');
  }

  clearDiscardHistory(partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'clearDiscardHistory');
  }

  discardWorkDirChangesForPaths(paths) {
    return unsupportedOperationPromise(this, 'discardWorkDirChangesForPaths');
  }

  // Accessors /////////////////////////////////////////////////////////////////////////////////////////////////////////
  // When possible, these default to "empty" results when invoked in states that don't have information available, or
  // fail in a way that's consistent with the requested information not being found.

  // Index queries

  getStatusBundle() {
    return Promise.resolve({
      stagedFiles: {},
      unstagedFiles: {},
      mergeConflictFiles: {},
      branch: {
        oid: null,
        head: null,
        upstream: null,
        aheadBehind: {ahead: null, behind: null},
      },
    });
  }

  getStatusesForChangedFiles() {
    return Promise.resolve({
      stagedFiles: [],
      unstagedFiles: [],
      mergeConflictFiles: [],
    });
  }

  getFilePatchForPath(filePath, options = {}) {
    return Promise.resolve(new MultiFilePatch({}));
  }

  getStagedChangesPatch() {
    return Promise.resolve(new MultiFilePatch({}));
  }

  readFileFromIndex(filePath) {
    return Promise.reject(new Error(`fatal: Path ${filePath} does not exist (neither on disk nor in the index).`));
  }

  // Commit access

  getLastCommit() {
    return Promise.resolve(nullCommit);
  }

  getCommit() {
    return Promise.resolve(nullCommit);
  }

  getRecentCommits() {
    return Promise.resolve([]);
  }

  isCommitPushed({sha}) {
    return false;
  }

  // Author information

  getAuthors() {
    return Promise.resolve([]);
  }

  // Branches

  getBranches() {
    return Promise.resolve(new BranchSet());
  }

  getHeadDescription() {
    return Promise.resolve('(no repository)');
  }

  // Merging and rebasing status

  isMerging() {
    return Promise.resolve(false);
  }

  isRebasing() {
    return Promise.resolve(false);
  }

  // Remotes

  getRemotes() {
    return Promise.resolve(new RemoteSet([]));
  }

  addRemote() {
    return unsupportedOperationPromise(this, 'addRemote');
  }

  getAheadCount(branchName) {
    return Promise.resolve(null);
  }

  getBehindCount(branchName) {
    return Promise.resolve(null);
  }

  getConfig(option, {local} = {}) {
    return Promise.resolve(null);
  }

  // Direct blob access

  getBlobContents(sha) {
    return Promise.reject(new Error(`fatal: Not a valid object name ${sha}`));
  }

  // Discard history

  hasDiscardHistory(partialDiscardFilePath = null) {
    return false;
  }

  getDiscardHistory(partialDiscardFilePath = null) {
    return [];
  }

  getLastHistorySnapshots(partialDiscardFilePath = null) {
    return null;
  }

  // Atom repo state

  getOperationStates() {
    return nullOperationStates;
  }

  setCommitMessage(message) {
    return unsupportedOperationPromise(this, 'setCommitMessage');
  }

  getCommitMessage() {
    return '';
  }

  fetchCommitMessageTemplate() {
    return unsupportedOperationPromise(this, 'fetchCommitMessageTemplate');
  }

  // Cache

  getCache() {
    return null;
  }

  // Internal //////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Non-delegated methods that provide subclasses with convenient access to Repository properties.

  git() {
    return this.repository.git;
  }

  workdir() {
    return this.repository.getWorkingDirectoryPath();
  }

  // Call methods on the active Repository state, even if the state has transitioned beneath you.
  // Use this to perform operations within `start()` methods to guard against interrupted state transitions.
  current() {
    return this.repository.state;
  }

  // pipeline
  executePipelineAction(...args) {
    return this.repository.executePipelineAction(...args);
  }

  // Return a Promise that will resolve once the state transitions from Loading.
  getLoadPromise() {
    return this.repository.getLoadPromise();
  }

  getRemoteForBranch(branchName) {
    return this.repository.getRemoteForBranch(branchName);
  }

  saveDiscardHistory() {
    return this.repository.saveDiscardHistory();
  }

  // Initiate a transition to another state.
  transitionTo(stateName, ...payload) {
    const StateConstructor = stateConstructors.get(stateName);
    if (StateConstructor === undefined) {
      throw new Error(`Attempt to transition to unrecognized state ${stateName}`);
    }
    return this.repository.transition(this, StateConstructor, ...payload);
  }

  // Event broadcast

  didDestroy() {
    return this.repository.emitter.emit('did-destroy');
  }

  didUpdate() {
    return this.repository.emitter.emit('did-update');
  }

  // Direct git access
  // Non-delegated git operations for internal use within states.

  directResolveDotGitDir() {
    return Promise.resolve(null);
  }

  directGetConfig(key, options = {}) {
    return Promise.resolve(null);
  }

  directGetBlobContents() {
    return Promise.reject(new Error('Not a valid object name'));
  }

  directInit() {
    return Promise.resolve();
  }

  directClone(remoteUrl, options) {
    return Promise.resolve();
  }

  // Deferred operations
  // Direct raw git operations to the current state, even if the state has been changed. Use these methods within
  // start() methods.

  resolveDotGitDir() {
    return this.current().directResolveDotGitDir();
  }

  doInit(workdir) {
    return this.current().directInit();
  }

  doClone(remoteUrl, options) {
    return this.current().directClone(remoteUrl, options);
  }

  // Parse a DiscardHistory payload from the SHA recorded in config.
  async loadHistoryPayload() {
    const historySha = await this.current().directGetConfig('atomGithub.historySha');
    if (!historySha) {
      return {};
    }

    let blob;
    try {
      blob = await this.current().directGetBlobContents(historySha);
    } catch (e) {
      if (/Not a valid object name/.test(e.stdErr)) {
        return {};
      }

      throw e;
    }

    try {
      return JSON.parse(blob);
    } catch (e) {
      return {};
    }
  }

  // Debugging assistance.

  toString() {
    return this.constructor.name;
  }
}

function unsupportedOperationPromise(self, opName) {
  return Promise.reject(new Error(`${opName} is not available in ${self} state`));
}
<commit_msg>update function name in state<commit_after>import {nullCommit} from '../commit';
import BranchSet from '../branch-set';
import RemoteSet from '../remote-set';
import {nullOperationStates} from '../operation-states';
import MultiFilePatch from '../patch/multi-file-patch';

/**
 * Map of registered subclasses to allow states to transition to one another without circular dependencies.
 * Subclasses of State should call `State.register` to add themselves here.
 */
const stateConstructors = new Map();

/**
 * Base class for Repository states. Implements default "null" behavior.
 */
export default class State {
  constructor(repository) {
    this.repository = repository;
  }

  static register(Subclass) {
    stateConstructors.set(Subclass.name, Subclass);
  }

  // This state has just been entered. Perform any asynchronous initialization that needs to occur.
  start() {
    return Promise.resolve();
  }

  // State probe predicates ////////////////////////////////////////////////////////////////////////////////////////////
  // Allow external callers to identify which state a Repository is in if necessary.

  isLoadingGuess() {
    return false;
  }

  isAbsentGuess() {
    return false;
  }

  isAbsent() {
    return false;
  }

  isLoading() {
    return false;
  }

  isEmpty() {
    return false;
  }

  isPresent() {
    return false;
  }

  isTooLarge() {
    return false;
  }

  isDestroyed() {
    return false;
  }

  // Behavior probe predicates /////////////////////////////////////////////////////////////////////////////////////////
  // Determine specific rendering behavior based on the current state.

  isUndetermined() {
    return false;
  }

  showGitTabInit() {
    return false;
  }

  showGitTabInitInProgress() {
    return false;
  }

  showGitTabLoading() {
    return false;
  }

  showStatusBarTiles() {
    return false;
  }

  hasDirectory() {
    return true;
  }

  // Lifecycle actions /////////////////////////////////////////////////////////////////////////////////////////////////
  // These generally default to rejecting a Promise with an error.

  init() {
    return unsupportedOperationPromise(this, 'init');
  }

  clone(remoteUrl) {
    return unsupportedOperationPromise(this, 'clone');
  }

  destroy() {
    return this.transitionTo('Destroyed');
  }

  refresh() {
    // No-op
  }

  observeFilesystemChange(events) {
    this.repository.refresh();
  }

  updateCommitMessageAfterFileSystemChange() {
    // this is only used in unit tests, we don't need no stinkin coverage
    /* istanbul ignore next */
    this.repository.refresh();
  }

  // Git operations ////////////////////////////////////////////////////////////////////////////////////////////////////
  // These default to rejecting a Promise with an error stating that the operation is not supported in the current
  // state.

  // Staging and unstaging

  stageFiles(paths) {
    return unsupportedOperationPromise(this, 'stageFiles');
  }

  unstageFiles(paths) {
    return unsupportedOperationPromise(this, 'unstageFiles');
  }

  stageFilesFromParentCommit(paths) {
    return unsupportedOperationPromise(this, 'stageFilesFromParentCommit');
  }

  applyPatchToIndex(patch) {
    return unsupportedOperationPromise(this, 'applyPatchToIndex');
  }

  applyPatchToWorkdir(patch) {
    return unsupportedOperationPromise(this, 'applyPatchToWorkdir');
  }

  // Committing

  commit(message, options) {
    return unsupportedOperationPromise(this, 'commit');
  }

  // Merging

  merge(branchName) {
    return unsupportedOperationPromise(this, 'merge');
  }

  abortMerge() {
    return unsupportedOperationPromise(this, 'abortMerge');
  }

  checkoutSide(side, paths) {
    return unsupportedOperationPromise(this, 'checkoutSide');
  }

  mergeFile(oursPath, commonBasePath, theirsPath, resultPath) {
    return unsupportedOperationPromise(this, 'mergeFile');
  }

  writeMergeConflictToIndex(filePath, commonBaseSha, oursSha, theirsSha) {
    return unsupportedOperationPromise(this, 'writeMergeConflictToIndex');
  }

  // Checkout

  checkout(revision, options = {}) {
    return unsupportedOperationPromise(this, 'checkout');
  }

  checkoutPathsAtRevision(paths, revision = 'HEAD') {
    return unsupportedOperationPromise(this, 'checkoutPathsAtRevision');
  }

  // Reset

  undoLastCommit() {
    return unsupportedOperationPromise(this, 'undoLastCommit');
  }

  // Remote interactions

  fetch(branchName) {
    return unsupportedOperationPromise(this, 'fetch');
  }

  pull(branchName) {
    return unsupportedOperationPromise(this, 'pull');
  }

  push(branchName) {
    return unsupportedOperationPromise(this, 'push');
  }

  // Configuration

  setConfig(option, value, {replaceAll} = {}) {
    return unsupportedOperationPromise(this, 'setConfig');
  }

  unsetConfig(option) {
    return unsupportedOperationPromise(this, 'unsetConfig');
  }

  // Direct blob interactions

  createBlob({filePath, stdin} = {}) {
    return unsupportedOperationPromise(this, 'createBlob');
  }

  expandBlobToFile(absFilePath, sha) {
    return unsupportedOperationPromise(this, 'expandBlobToFile');
  }

  // Discard history

  createDiscardHistoryBlob() {
    return unsupportedOperationPromise(this, 'createDiscardHistoryBlob');
  }

  updateDiscardHistory() {
    return unsupportedOperationPromise(this, 'updateDiscardHistory');
  }

  storeBeforeAndAfterBlobs(filePaths, isSafe, destructiveAction, partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'storeBeforeAndAfterBlobs');
  }

  restoreLastDiscardInTempFiles(isSafe, partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'restoreLastDiscardInTempFiles');
  }

  popDiscardHistory(partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'popDiscardHistory');
  }

  clearDiscardHistory(partialDiscardFilePath = null) {
    return unsupportedOperationPromise(this, 'clearDiscardHistory');
  }

  discardWorkDirChangesForPaths(paths) {
    return unsupportedOperationPromise(this, 'discardWorkDirChangesForPaths');
  }

  // Accessors /////////////////////////////////////////////////////////////////////////////////////////////////////////
  // When possible, these default to "empty" results when invoked in states that don't have information available, or
  // fail in a way that's consistent with the requested information not being found.

  // Index queries

  getStatusBundle() {
    return Promise.resolve({
      stagedFiles: {},
      unstagedFiles: {},
      mergeConflictFiles: {},
      branch: {
        oid: null,
        head: null,
        upstream: null,
        aheadBehind: {ahead: null, behind: null},
      },
    });
  }

  getStatusesForChangedFiles() {
    return Promise.resolve({
      stagedFiles: [],
      unstagedFiles: [],
      mergeConflictFiles: [],
    });
  }

  getFilePatchForPath(filePath, options = {}) {
    return Promise.resolve(new MultiFilePatch({}));
  }

  getStagedChangesPatch() {
    return Promise.resolve(new MultiFilePatch({}));
  }

  readFileFromIndex(filePath) {
    return Promise.reject(new Error(`fatal: Path ${filePath} does not exist (neither on disk nor in the index).`));
  }

  // Commit access

  getLastCommit() {
    return Promise.resolve(nullCommit);
  }

  getCommit() {
    return Promise.resolve(nullCommit);
  }

  getRecentCommits() {
    return Promise.resolve([]);
  }

  isCommitPushed(sha) {
    return false;
  }

  // Author information

  getAuthors() {
    return Promise.resolve([]);
  }

  // Branches

  getBranches() {
    return Promise.resolve(new BranchSet());
  }

  getHeadDescription() {
    return Promise.resolve('(no repository)');
  }

  // Merging and rebasing status

  isMerging() {
    return Promise.resolve(false);
  }

  isRebasing() {
    return Promise.resolve(false);
  }

  // Remotes

  getRemotes() {
    return Promise.resolve(new RemoteSet([]));
  }

  addRemote() {
    return unsupportedOperationPromise(this, 'addRemote');
  }

  getAheadCount(branchName) {
    return Promise.resolve(null);
  }

  getBehindCount(branchName) {
    return Promise.resolve(null);
  }

  getConfig(option, {local} = {}) {
    return Promise.resolve(null);
  }

  // Direct blob access

  getBlobContents(sha) {
    return Promise.reject(new Error(`fatal: Not a valid object name ${sha}`));
  }

  // Discard history

  hasDiscardHistory(partialDiscardFilePath = null) {
    return false;
  }

  getDiscardHistory(partialDiscardFilePath = null) {
    return [];
  }

  getLastHistorySnapshots(partialDiscardFilePath = null) {
    return null;
  }

  // Atom repo state

  getOperationStates() {
    return nullOperationStates;
  }

  setCommitMessage(message) {
    return unsupportedOperationPromise(this, 'setCommitMessage');
  }

  getCommitMessage() {
    return '';
  }

  fetchCommitMessageTemplate() {
    return unsupportedOperationPromise(this, 'fetchCommitMessageTemplate');
  }

  // Cache

  getCache() {
    return null;
  }

  // Internal //////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Non-delegated methods that provide subclasses with convenient access to Repository properties.

  git() {
    return this.repository.git;
  }

  workdir() {
    return this.repository.getWorkingDirectoryPath();
  }

  // Call methods on the active Repository state, even if the state has transitioned beneath you.
  // Use this to perform operations within `start()` methods to guard against interrupted state transitions.
  current() {
    return this.repository.state;
  }

  // pipeline
  executePipelineAction(...args) {
    return this.repository.executePipelineAction(...args);
  }

  // Return a Promise that will resolve once the state transitions from Loading.
  getLoadPromise() {
    return this.repository.getLoadPromise();
  }

  getRemoteForBranch(branchName) {
    return this.repository.getRemoteForBranch(branchName);
  }

  saveDiscardHistory() {
    return this.repository.saveDiscardHistory();
  }

  // Initiate a transition to another state.
  transitionTo(stateName, ...payload) {
    const StateConstructor = stateConstructors.get(stateName);
    if (StateConstructor === undefined) {
      throw new Error(`Attempt to transition to unrecognized state ${stateName}`);
    }
    return this.repository.transition(this, StateConstructor, ...payload);
  }

  // Event broadcast

  didDestroy() {
    return this.repository.emitter.emit('did-destroy');
  }

  didUpdate() {
    return this.repository.emitter.emit('did-update');
  }

  // Direct git access
  // Non-delegated git operations for internal use within states.

  directResolveDotGitDir() {
    return Promise.resolve(null);
  }

  directGetConfig(key, options = {}) {
    return Promise.resolve(null);
  }

  directGetBlobContents() {
    return Promise.reject(new Error('Not a valid object name'));
  }

  directInit() {
    return Promise.resolve();
  }

  directClone(remoteUrl, options) {
    return Promise.resolve();
  }

  // Deferred operations
  // Direct raw git operations to the current state, even if the state has been changed. Use these methods within
  // start() methods.

  resolveDotGitDir() {
    return this.current().directResolveDotGitDir();
  }

  doInit(workdir) {
    return this.current().directInit();
  }

  doClone(remoteUrl, options) {
    return this.current().directClone(remoteUrl, options);
  }

  // Parse a DiscardHistory payload from the SHA recorded in config.
  async loadHistoryPayload() {
    const historySha = await this.current().directGetConfig('atomGithub.historySha');
    if (!historySha) {
      return {};
    }

    let blob;
    try {
      blob = await this.current().directGetBlobContents(historySha);
    } catch (e) {
      if (/Not a valid object name/.test(e.stdErr)) {
        return {};
      }

      throw e;
    }

    try {
      return JSON.parse(blob);
    } catch (e) {
      return {};
    }
  }

  // Debugging assistance.

  toString() {
    return this.constructor.name;
  }
}

function unsupportedOperationPromise(self, opName) {
  return Promise.reject(new Error(`${opName} is not available in ${self} state`));
}
<|endoftext|>