<commit_before>'use strict';

/**
 * Sequelize provides a host of custom error classes, to allow you to do easier debugging. All of these errors are exposed on the sequelize object and the sequelize constructor.
 * All sequelize errors inherit from the base JS error object.
 *
 * @fileOverview The Error Objects produced by Sequelize.
 * @class Errors
 */

var util = require('util');
var error = module.exports = {};

/**
 * The Base Error all Sequelize Errors inherit from.
 *
 * @constructor
 * @alias Error
 */
error.BaseError = function() {
  var tmp = Error.apply(this, arguments);
  tmp.name = this.name = 'SequelizeBaseError';

  this.message = tmp.message;
  if (Error.captureStackTrace)
    Error.captureStackTrace(this, this.constructor);
};
util.inherits(error.BaseError, Error);

/**
 * Validation Error. Thrown when the sequelize validation has failed. The error contains an `errors` property,
 * which is an array with 1 or more ValidationErrorItems, one for each validation that failed.
 *
 * @param {string} message Error message
 * @param {Array} [errors] Array of ValidationErrorItem objects describing the validation errors
 *
 * @extends BaseError
 * @constructor
 */
error.ValidationError = function(message, errors) {
  error.BaseError.apply(this, arguments);
  this.name = 'SequelizeValidationError';
  this.message = 'Validation Error';
/**
 * An array of ValidationErrorItems
 * @member errors
 */
  this.errors = errors || [];

  // Use provided error message if available...
  if (message) {
    this.message = message;

  // ... otherwise create a concatenated message out of existing errors.
  } else if (this.errors.length > 0 && this.errors[0].message) {
    this.message = this.errors.map(function(err) {
      return err.type + ': ' + err.message;
    }).join(',\n');
  }
};
util.inherits(error.ValidationError, error.BaseError);

/**
 * Gets all validation error items for the path / field specified.
 *
 * @param {string} path The path to be checked for error items
 * @returns {Array} Validation error items for the specified path
 */
error.ValidationError.prototype.get = function(path) {
  return this.errors.reduce(function(reduced, error) {
    if (error.path === path) {
      reduced.push(error);
    }
    return reduced;
  }, []);
};

/**
 * A base class for all database related errors.
 * @extends BaseError
 * @constructor
 */
error.DatabaseError = function (parent) {
  error.BaseError.apply(this, [parent.message]);
  this.name = 'SequelizeDatabaseError';

/**
 * The database specific error which triggered this one
 * @member parent
 */
  this.parent = parent;
  this.original = parent;
/**
 * The SQL that triggered the error
 * @member sql
 */
  this.sql = parent.sql;
/**
 * The message from the DB.
 * @member message
 * @name message
 */
/**
 * The fields of the unique constraint
 * @member fields
 * @name fields
 */
/**
 * The value(s) which triggered the error
 * @member value
 * @name value
 */
/**
 * The name of the index that triggered the error
 * @member index
 * @name index
 */
};
util.inherits(error.DatabaseError, error.BaseError);

/**
 * Thrown when a database query times out because of a deadlock
 * @extends DatabaseError
 * @constructor
 */
error.TimeoutError = function (parent) {
  error.DatabaseError.call(this, parent);
  this.name = 'SequelizeTimeoutError';
};
util.inherits(error.TimeoutError, error.BaseError);

 /**
 * Thrown when a unique constraint is violated in the database
 * @extends DatabaseError
 * @constructor
 */
error.UniqueConstraintError = function (options) {
  options = options || {};
  options.parent = options.parent || { sql: '' };
  options.message = options.message || 'Validation error';
  options.errors = options.errors || {};

  error.ValidationError.call(this, options.message, options.errors);
  this.name = 'SequelizeUniqueConstraintError';
  this.message = options.message;
  this.errors = options.errors;
  this.fields = options.fields;
};
util.inherits(error.UniqueConstraintError, error.ValidationError);

/**
 * Thrown when a foreign key constraint is violated in the database
 * @extends DatabaseError
 * @constructor
 */
error.ForeignKeyConstraintError = function (options) {
  options = options || {};
  options.parent = options.parent || { sql: '' };

  error.DatabaseError.call(this, options.parent);
  this.name = 'SequelizeForeignKeyConstraintError';

  this.message = options.message;
  this.fields = options.fields;
  this.table = options.table;
  this.value = options.value;
  this.index = options.index;
};
util.inherits(error.ForeignKeyConstraintError, error.DatabaseError);

/**
 * Thrown when an exclusion constraint is violated in the database
 * @extends DatabaseError
 * @constructor
 */
error.ExclusionConstraintError = function (options) {
  options = options || {};
  options.parent = options.parent || { sql: '' };

  error.DatabaseError.call(this, options.parent);
  this.name = 'SequelizeExclusionConstraintError';

  this.message = options.message;
  this.constraint = options.constraint;
  this.fields = options.fields;
  this.table = options.table;
};
util.inherits(error.ExclusionConstraintError, error.DatabaseError);

/**
 * Validation Error Item
 * Instances of this class are included in the `ValidationError.errors` property.
 *
 * @param {string} message An error message
 * @param {string} type The type of the validation error
 * @param {string} path The field that triggered the validation error
 * @param {string} value The value that generated the error
 * @constructor
 */
error.ValidationErrorItem = function(message, type, path, value) {
  this.message = message || '';
  this.type = type || null;
  this.path = path || null;
  this.value = value || null;
};

/**
 * A base class for all connection related errors.
 * @extends BaseError
 * @constructor
 */
error.ConnectionError = function (parent) {
  error.BaseError.apply(this, [parent ? parent.message : '']);
  this.name = 'SequelizeConnectionError';
/**
 * The connection specific error which triggered this one
 * @member parent
 */
  this.parent = parent;
  this.original = parent;
};
util.inherits(error.ConnectionError, error.BaseError);

/**
 * Thrown when a connection to a database is refused
 * @extends ConnectionError
 * @constructor
 */
error.ConnectionRefusedError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeConnectionRefusedError';
};
util.inherits(error.ConnectionRefusedError, error.ConnectionError);

/**
 * Thrown when a connection to a database is refused due to insufficient privileges
 * @extends ConnectionError
 * @constructor
 */
error.AccessDeniedError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeAccessDeniedError';
};
util.inherits(error.AccessDeniedError, error.ConnectionError);

/**
 * Thrown when a connection to a database has a hostname that was not found
 * @extends ConnectionError
 * @constructor
 */
error.HostNotFoundError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeHostNotFoundError';
};
util.inherits(error.HostNotFoundError, error.ConnectionError);

/**
 * Thrown when a connection to a database has a hostname that was not reachable
 * @extends ConnectionError
 * @constructor
 */
error.HostNotReachableError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeHostNotReachableError';
};
util.inherits(error.HostNotReachableError, error.ConnectionError);

/**
 * Thrown when a connection to a database has invalid values for any of the connection parameters
 * @extends ConnectionError
 * @constructor
 */
error.InvalidConnectionError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeInvalidConnectionError';
};
util.inherits(error.InvalidConnectionError, error.ConnectionError);

/**
 * Thrown when a connection to a database times out
 * @extends ConnectionError
 * @constructor
 */
error.ConnectionTimedOutError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeConnectionTimedOutError';
};
util.inherits(error.ConnectionTimedOutError, error.ConnectionError);
<commit_msg>Add parent error messages<commit_after>'use strict';

/**
 * Sequelize provides a host of custom error classes, to allow you to do easier debugging. All of these errors are exposed on the sequelize object and the sequelize constructor.
 * All sequelize errors inherit from the base JS error object.
 *
 * @fileOverview The Error Objects produced by Sequelize.
 * @class Errors
 */

var util = require('util');
var error = module.exports = {};

/**
 * The Base Error all Sequelize Errors inherit from.
 *
 * @constructor
 * @alias Error
 */
error.BaseError = function() {
  var tmp = Error.apply(this, arguments);
  tmp.name = this.name = 'SequelizeBaseError';

  this.message = tmp.message;
  if (Error.captureStackTrace)
    Error.captureStackTrace(this, this.constructor);
};
util.inherits(error.BaseError, Error);

/**
 * Validation Error. Thrown when the sequelize validation has failed. The error contains an `errors` property,
 * which is an array with 1 or more ValidationErrorItems, one for each validation that failed.
 *
 * @param {string} message Error message
 * @param {Array} [errors] Array of ValidationErrorItem objects describing the validation errors
 *
 * @extends BaseError
 * @constructor
 */
error.ValidationError = function(message, errors) {
  error.BaseError.apply(this, arguments);
  this.name = 'SequelizeValidationError';
  this.message = 'Validation Error';
/**
 * An array of ValidationErrorItems
 * @member errors
 */
  this.errors = errors || [];

  // Use provided error message if available...
  if (message) {
    this.message = message;

  // ... otherwise create a concatenated message out of existing errors.
  } else if (this.errors.length > 0 && this.errors[0].message) {
    this.message = this.errors.map(function(err) {
      return err.type + ': ' + err.message;
    }).join(',\n');
  }
};
util.inherits(error.ValidationError, error.BaseError);

/**
 * Gets all validation error items for the path / field specified.
 *
 * @param {string} path The path to be checked for error items
 * @returns {Array} Validation error items for the specified path
 */
error.ValidationError.prototype.get = function(path) {
  return this.errors.reduce(function(reduced, error) {
    if (error.path === path) {
      reduced.push(error);
    }
    return reduced;
  }, []);
};

/**
 * A base class for all database related errors.
 * @extends BaseError
 * @constructor
 */
error.DatabaseError = function (parent) {
  error.BaseError.apply(this, [parent.message]);
  this.name = 'SequelizeDatabaseError';

/**
 * The database specific error which triggered this one
 * @member parent
 */
  this.parent = parent;
  this.original = parent;
/**
 * The SQL that triggered the error
 * @member sql
 */
  this.sql = parent.sql;
/**
 * The message from the DB.
 * @member message
 * @name message
 */
/**
 * The fields of the unique constraint
 * @member fields
 * @name fields
 */
/**
 * The value(s) which triggered the error
 * @member value
 * @name value
 */
/**
 * The name of the index that triggered the error
 * @member index
 * @name index
 */
};
util.inherits(error.DatabaseError, error.BaseError);

/**
 * Thrown when a database query times out because of a deadlock
 * @extends DatabaseError
 * @constructor
 */
error.TimeoutError = function (parent) {
  error.DatabaseError.call(this, parent);
  this.name = 'SequelizeTimeoutError';
};
util.inherits(error.TimeoutError, error.BaseError);

 /**
 * Thrown when a unique constraint is violated in the database
 * @extends DatabaseError
 * @constructor
 */
error.UniqueConstraintError = function (options) {
  options = options || {};
  options.parent = options.parent || { sql: '' };
  options.message = options.message || options.parent.message || 'Validation Error';
  options.errors = options.errors || {};

  error.ValidationError.call(this, options.message, options.errors);
  this.name = 'SequelizeUniqueConstraintError';
  this.message = options.message;
  this.errors = options.errors;
  this.fields = options.fields;
};
util.inherits(error.UniqueConstraintError, error.ValidationError);

/**
 * Thrown when a foreign key constraint is violated in the database
 * @extends DatabaseError
 * @constructor
 */
error.ForeignKeyConstraintError = function (options) {
  options = options || {};
  options.parent = options.parent || { sql: '' };

  error.DatabaseError.call(this, options.parent);
  this.name = 'SequelizeForeignKeyConstraintError';

  this.message = options.message || options.parent.message || 'Database Error';
  this.fields = options.fields;
  this.table = options.table;
  this.value = options.value;
  this.index = options.index;
};
util.inherits(error.ForeignKeyConstraintError, error.DatabaseError);

/**
 * Thrown when an exclusion constraint is violated in the database
 * @extends DatabaseError
 * @constructor
 */
error.ExclusionConstraintError = function (options) {
  options = options || {};
  options.parent = options.parent || { sql: '' };

  error.DatabaseError.call(this, options.parent);
  this.name = 'SequelizeExclusionConstraintError';

  this.message = options.message || options.parent.message;
  this.constraint = options.constraint;
  this.fields = options.fields;
  this.table = options.table;
};
util.inherits(error.ExclusionConstraintError, error.DatabaseError);

/**
 * Validation Error Item
 * Instances of this class are included in the `ValidationError.errors` property.
 *
 * @param {string} message An error message
 * @param {string} type The type of the validation error
 * @param {string} path The field that triggered the validation error
 * @param {string} value The value that generated the error
 * @constructor
 */
error.ValidationErrorItem = function(message, type, path, value) {
  this.message = message || '';
  this.type = type || null;
  this.path = path || null;
  this.value = value || null;
};

/**
 * A base class for all connection related errors.
 * @extends BaseError
 * @constructor
 */
error.ConnectionError = function (parent) {
  error.BaseError.apply(this, [parent ? parent.message : '']);
  this.name = 'SequelizeConnectionError';
/**
 * The connection specific error which triggered this one
 * @member parent
 */
  this.parent = parent;
  this.original = parent;
};
util.inherits(error.ConnectionError, error.BaseError);

/**
 * Thrown when a connection to a database is refused
 * @extends ConnectionError
 * @constructor
 */
error.ConnectionRefusedError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeConnectionRefusedError';
};
util.inherits(error.ConnectionRefusedError, error.ConnectionError);

/**
 * Thrown when a connection to a database is refused due to insufficient privileges
 * @extends ConnectionError
 * @constructor
 */
error.AccessDeniedError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeAccessDeniedError';
};
util.inherits(error.AccessDeniedError, error.ConnectionError);

/**
 * Thrown when a connection to a database has a hostname that was not found
 * @extends ConnectionError
 * @constructor
 */
error.HostNotFoundError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeHostNotFoundError';
};
util.inherits(error.HostNotFoundError, error.ConnectionError);

/**
 * Thrown when a connection to a database has a hostname that was not reachable
 * @extends ConnectionError
 * @constructor
 */
error.HostNotReachableError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeHostNotReachableError';
};
util.inherits(error.HostNotReachableError, error.ConnectionError);

/**
 * Thrown when a connection to a database has invalid values for any of the connection parameters
 * @extends ConnectionError
 * @constructor
 */
error.InvalidConnectionError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeInvalidConnectionError';
};
util.inherits(error.InvalidConnectionError, error.ConnectionError);

/**
 * Thrown when a connection to a database times out
 * @extends ConnectionError
 * @constructor
 */
error.ConnectionTimedOutError = function (parent) {
  error.ConnectionError.call(this, parent);
  this.name = 'SequelizeConnectionTimedOutError';
};
util.inherits(error.ConnectionTimedOutError, error.ConnectionError);
<|endoftext|>


<commit_before>Rye.define('Events', function(){

    var util = Rye.require('Util')
      , query = Rye.require('Query')
      , _slice = Array.prototype.slice

    // General-purpose event emitter
    // -----------------------------

    function EventEmitter () {
        this.events = {}
        this.context = null
    }

    // Adds a handler to the events list
    EventEmitter.prototype.addListener = function (event, handler) {
        var handlers = this.events[event] || (this.events[event] = [])
        handlers.push(handler)
        return this
    }

    // Add a handler that can only get called once
    EventEmitter.prototype.once = function (event, handler) {
        var self = this
        function suicide () {
            handler.apply(this, arguments)
            self.removeListener(event, suicide)
        }
        return this.addListener(event, suicide)
    }

    // Removes a handler from the events list
    EventEmitter.prototype.removeListener = function (event, handler) {
        var self = this
          , handlers = this.events[event]
        if (event === '*') {
            if (!handler) {
                this.events = {}
            } else {
                util.each(this.events, function(handlers, event){
                    self.removeListener(event, handler)
                })
            }
        } else if (handler && handlers) {
            handlers.splice(handlers.indexOf(handler), 1)
            if (handlers.length === 0) {
                delete this.events[event]
            }
        } else {
            delete this.events[event]
        }
        return this
    }

    // Calls all handlers that match the event type
    EventEmitter.prototype.emit = function (event) {
        var handlers = this.events[event]
          , args = _slice.call(arguments, 1)
          , context = this.context || this

        if (handlers) {
            util.each(handlers, function(fn) {
                fn.apply(context, args)
            })
        }
        return this
    }

    EventEmitter.prototype.proxy = function (event) {
        return util.applier('left', this.emit, this, [event])
    }

    // Utility methods
    // -----------------------------

    var emitters = {}

    function getEmitter (element) {
        var id = util.getUid(element)
        return emitters[id] || (emitters[id] = new DOMEventEmitter(element))
    }

    function getType (event) {
        var index = event.indexOf(' ')
        return index > 0 ? event.substr(0, index) : event
    }

    function getSelector (event) {
        var index = event.indexOf(' ')
        return index > 0 ? event.substr(index) : ''
    }

    function createEvent (type, properties) {
        if (typeof type != 'string') {
            type = type.type
        }
        var isMouse = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(type) != -1
          , event = document.createEvent(isMouse ? 'MouseEvent' : 'Event')
        if (properties) {
            util.extend(event, properties)
        }
        event.initEvent(type, true, true)
        return event
    }

    // DOM event emitter
    // -----------------------------

    /*
        Creates one event emitter per element, proxies DOM events to it. This way
        we can keep track of the functions so that they can be removed from the
        elements by reference when you call .removeListener() by event name.
    */

    function DOMEventEmitter (element) {
        EventEmitter.call(this)
        this.element = element
        this.proxied = {}
    }

    util.inherits(DOMEventEmitter, EventEmitter)

    DOMEventEmitter.prototype._proxy = function (event) {
        return function (DOMEvent) {
            var selector = getSelector(event)
              , context = this.element
            // delegate behavior
            if (selector) {
                context = DOMEvent.target
                while (context && !query.matches(context, selector)) {
                    context = context !== this.element && context.parentNode
                }
                if (!context || context == this.element) {
                    return
                }
            }
            this.context = context
            this.emit(event, DOMEvent, this.element)
        }.bind(this)
    }

    DOMEventEmitter.prototype.proxy = function (event) {
        return this.proxied[event] || (this.proxied[event] = this._proxy(event))
    }

    DOMEventEmitter.prototype.addListener = function (event, handler) {
        EventEmitter.prototype.addListener.call(this, event, handler)
        if (!this.proxied[event]) {
            this.element.addEventListener(getType(event), this.proxy(event), false)
        }
        return this
    }

    DOMEventEmitter.prototype.removeListener = function (event, handler) {
        if (event.indexOf('*') >= 0) {
            var self = this
              , re = new RegExp('^' + event.replace('*', '\\b'))
            // *      : remove all events
            // type * : remove delegate events
            // type*  : remove delegate and undelegate
            util.each(this.events, function(handlers, event){
                if (re.test(event)) {
                    self.removeListener(event, handler)
                }
            })
        } else {
            var proxy = this.proxied[event]
            EventEmitter.prototype.removeListener.call(this, event, handler)
            if (!this.events[event] && proxy) {
                this.element.removeEventListener(getType(event), proxy, false)
                ;delete this.proxied[event]
            }
        }
        return this
    }

    function acceptMultipleEvents (method) {
        var _method = DOMEventEmitter.prototype[method]
        DOMEventEmitter.prototype[method] = function (event, handler) {
            var self = this
            if (typeof event !== 'string') {
                util.each(event, function(handler, event){
                    _method.call(self, event, handler)
                })
            } else {
                _method.call(self, event, handler)
            }
            return self
        }
    }

    ['addListener', 'once', 'removeListener'].forEach(acceptMultipleEvents)

    DOMEventEmitter.prototype.destroy = function () {
        return this.removeListener('*')
    }

    DOMEventEmitter.prototype.trigger = function (event, data) {
        if (!(event instanceof window.Event)) {
            event = createEvent(event)
        }
        event.data = data
        this.element.dispatchEvent(event)
        return this
    }

    // Exported methods
    // -----------------------------

    var exports = {}

    function emitterProxy (method, element, event, handler) {
        getEmitter(element)[method](event, handler)
    }

    ['addListener', 'removeListener', 'once', 'trigger'].forEach(function(method){
        // Create a function proxy for the method
        var fn = util.curry(emitterProxy, method)
        // Exports module and rye methods
        exports[method] = fn
        this[method] = this.iterate(fn)
    }.bind(this))

    // Aliases
    // -----------------------------

    ;[EventEmitter.prototype, DOMEventEmitter.prototype, this].forEach(function(obj){
        obj.on = obj.addListener
    })

    // Global event bus / pub-sub
    // -----------------------------

    var EE = new EventEmitter

    Rye.subscribe   = EE.addListener.bind(EE)
    Rye.unsubscribe = EE.removeListener.bind(EE)
    Rye.publish     = EE.emit.bind(EE)

    return {
        EventEmitter    : EventEmitter
      , DOMEventEmitter : DOMEventEmitter
      , getEmitter      : getEmitter
      , createEvent     : createEvent
      , addListener     : exports.addListener
      , once            : exports.once
      , removeListener  : exports.removeListener
      , trigger         : exports.trigger
    }
})
<commit_msg>Removing stupid comma<commit_after>Rye.define('Events', function(){

    var util = Rye.require('Util')
      , query = Rye.require('Query')
      , _slice = Array.prototype.slice

    // General-purpose event emitter
    // -----------------------------

    function EventEmitter () {
        this.events = {}
        this.context = null
    }

    // Adds a handler to the events list
    EventEmitter.prototype.addListener = function (event, handler) {
        var handlers = this.events[event] || (this.events[event] = [])
        handlers.push(handler)
        return this
    }

    // Add a handler that can only get called once
    EventEmitter.prototype.once = function (event, handler) {
        var self = this
        function suicide () {
            handler.apply(this, arguments)
            self.removeListener(event, suicide)
        }
        return this.addListener(event, suicide)
    }

    // Removes a handler from the events list
    EventEmitter.prototype.removeListener = function (event, handler) {
        var self = this
          , handlers = this.events[event]
        if (event === '*') {
            if (!handler) {
                this.events = {}
            } else {
                util.each(this.events, function(handlers, event){
                    self.removeListener(event, handler)
                })
            }
        } else if (handler && handlers) {
            handlers.splice(handlers.indexOf(handler), 1)
            if (handlers.length === 0) {
                delete this.events[event]
            }
        } else {
            delete this.events[event]
        }
        return this
    }

    // Calls all handlers that match the event type
    EventEmitter.prototype.emit = function (event) {
        var handlers = this.events[event]
          , args = _slice.call(arguments, 1)
          , context = this.context || this

        if (handlers) {
            util.each(handlers, function(fn) {
                fn.apply(context, args)
            })
        }
        return this
    }

    EventEmitter.prototype.proxy = function (event) {
        return util.applier('left', this.emit, this, [event])
    }

    // Utility methods
    // -----------------------------

    var emitters = {}

    function getEmitter (element) {
        var id = util.getUid(element)
        return emitters[id] || (emitters[id] = new DOMEventEmitter(element))
    }

    function getType (event) {
        var index = event.indexOf(' ')
        return index > 0 ? event.substr(0, index) : event
    }

    function getSelector (event) {
        var index = event.indexOf(' ')
        return index > 0 ? event.substr(index) : ''
    }

    function createEvent (type, properties) {
        if (typeof type != 'string') {
            type = type.type
        }
        var isMouse = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(type) != -1
          , event = document.createEvent(isMouse ? 'MouseEvent' : 'Event')
        if (properties) {
            util.extend(event, properties)
        }
        event.initEvent(type, true, true)
        return event
    }

    // DOM event emitter
    // -----------------------------

    /*
        Creates one event emitter per element, proxies DOM events to it. This way
        we can keep track of the functions so that they can be removed from the
        elements by reference when you call .removeListener() by event name.
    */

    function DOMEventEmitter (element) {
        EventEmitter.call(this)
        this.element = element
        this.proxied = {}
    }

    util.inherits(DOMEventEmitter, EventEmitter)

    DOMEventEmitter.prototype._proxy = function (event) {
        return function (DOMEvent) {
            var selector = getSelector(event)
              , context = this.element
            // delegate behavior
            if (selector) {
                context = DOMEvent.target
                while (context && !query.matches(context, selector)) {
                    context = context !== this.element && context.parentNode
                }
                if (!context || context == this.element) {
                    return
                }
            }
            this.context = context
            this.emit(event, DOMEvent, this.element)
        }.bind(this)
    }

    DOMEventEmitter.prototype.proxy = function (event) {
        return this.proxied[event] || (this.proxied[event] = this._proxy(event))
    }

    DOMEventEmitter.prototype.addListener = function (event, handler) {
        EventEmitter.prototype.addListener.call(this, event, handler)
        if (!this.proxied[event]) {
            this.element.addEventListener(getType(event), this.proxy(event), false)
        }
        return this
    }

    DOMEventEmitter.prototype.removeListener = function (event, handler) {
        if (event.indexOf('*') >= 0) {
            var self = this
              , re = new RegExp('^' + event.replace('*', '\\b'))
            // *      : remove all events
            // type * : remove delegate events
            // type*  : remove delegate and undelegate
            util.each(this.events, function(handlers, event){
                if (re.test(event)) {
                    self.removeListener(event, handler)
                }
            })
        } else {
            var proxy = this.proxied[event]
            EventEmitter.prototype.removeListener.call(this, event, handler)
            if (!this.events[event] && proxy) {
                this.element.removeEventListener(getType(event), proxy, false)
                delete this.proxied[event]
            }
        }
        return this
    }

    function acceptMultipleEvents (method) {
        var _method = DOMEventEmitter.prototype[method]
        DOMEventEmitter.prototype[method] = function (event, handler) {
            var self = this
            if (typeof event !== 'string') {
                util.each(event, function(handler, event){
                    _method.call(self, event, handler)
                })
            } else {
                _method.call(self, event, handler)
            }
            return self
        }
    }

    ['addListener', 'once', 'removeListener'].forEach(acceptMultipleEvents)

    DOMEventEmitter.prototype.destroy = function () {
        return this.removeListener('*')
    }

    DOMEventEmitter.prototype.trigger = function (event, data) {
        if (!(event instanceof window.Event)) {
            event = createEvent(event)
        }
        event.data = data
        this.element.dispatchEvent(event)
        return this
    }

    // Exported methods
    // -----------------------------

    var exports = {}

    function emitterProxy (method, element, event, handler) {
        getEmitter(element)[method](event, handler)
    }

    ['addListener', 'removeListener', 'once', 'trigger'].forEach(function(method){
        // Create a function proxy for the method
        var fn = util.curry(emitterProxy, method)
        // Exports module and rye methods
        exports[method] = fn
        this[method] = this.iterate(fn)
    }.bind(this))

    // Aliases
    // -----------------------------

    ;[EventEmitter.prototype, DOMEventEmitter.prototype, this].forEach(function(obj){
        obj.on = obj.addListener
    })

    // Global event bus / pub-sub
    // -----------------------------

    var EE = new EventEmitter

    Rye.subscribe   = EE.addListener.bind(EE)
    Rye.unsubscribe = EE.removeListener.bind(EE)
    Rye.publish     = EE.emit.bind(EE)

    return {
        EventEmitter    : EventEmitter
      , DOMEventEmitter : DOMEventEmitter
      , getEmitter      : getEmitter
      , createEvent     : createEvent
      , addListener     : exports.addListener
      , once            : exports.once
      , removeListener  : exports.removeListener
      , trigger         : exports.trigger
    }
})
<|endoftext|>


<commit_before>/*!
 * micromatch <https://github.com/jonschlinkert/micromatch>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT license.
 */

'use strict';

var extglob = require('extglob');
var isGlob = require('is-glob');
var braces = require('braces');
var parse = require('./parse');
var utils = require('./utils');
var chars = require('./chars');

/**
 * Expose `expand`
 */

module.exports = expand;

/**
 * Expand a glob pattern to resolve braces and
 * similar patterns before converting to regex.
 *
 * @param  {String|Array} `pattern`
 * @param  {Array} `files`
 * @param  {Options} `opts`
 * @return {Array}
 */

function expand(glob, opts) {
  opts = opts || {};
  opts.dot = opts.dot || opts.dotfiles;

  function replace(re, str) {
    glob = glob.replace(re, esc(str));
  }

  // return early if the glob pattern tests `true`
  if (specialCase(glob) && opts.safemode) {
    return new RegExp(utils.escapeRe(glob), 'g');
  }

  if (opts.nonegate !== true) {
    var negate = glob.charCodeAt(0) === 33; /* '!' */
    if (negate) {
      opts.negated = true;
      glob = glob.slice(1);
    }
  }

  glob = glob.split('(?').join('__QMARK_GROUP__');

  // expand braces, e.g `{1..5}`
  if (glob.indexOf('{') !== -1 && opts.nobraces !== true) {
    glob = expandBraces(glob, opts);
  }

  // parse the glob pattern into tokens
  var tok = parse.glob(glob, opts);
  if (tok.isDotGlob) {
    opts.dot = true;
  }

  if (!isGlob(glob)) {
    return {glob: utils.escapePath(glob), tokens: tok, options: opts};
  }

  if (glob === '**' && opts.globstar !== false) {
    glob = globstar(opts);

  } else {
    if (/^\*\.\w*$/.test(glob)) {
      glob = glob.replace(/\*/, star(opts.dot) + '\\');
      glob = glob.split('__QMARK_GROUP__').join('(?');
      return {glob: glob, tokens: tok, options: opts};
    }

    glob = balance(glob, '[', ']');

    // use heuristics to replace common escape patterns
    glob = escape(glob);

    // if the glob is for one directory deep, we can
    // simplify the parsing and generated regex
    if (tok.dirname === '') {
      return expandFilename(glob, tok, opts);
    }

    // windows drives
    replace(/^(\w):([\\\/]+?)/gi, lookahead + '$1:$2');
    // foo/**
    replace(/(\w+)\*\*(?!\/)/g, '(?=.)$1[^/]*?');
    // **/
    replace(/\*\*\//g, '(.*\\/|^)');
    // **
    replace(/\*\*/g, globstar(opts));
    // *.*
    replace(/\*\.\*/g, '([^/]*?.[^/]*?)');
    // ends with /*
    replace(/\/\*$/g, '\\/' + stardot(opts));
    // ends with *, no slashes
    replace(/(?!\/)\*$/g, boxQ);
    // has '*'
    replace(/\*/g, stardot(opts));

    // has '?.'
    replace(/\?\./g, '?\\.');
    // has '?:'
    replace(/\?:/g, '?:');
    // first of '????'
    replace(/(?!\?)\?/g, '\\/'+ dotstarbase(opts.dot) + box);
    // rest of '????'
    replace(/(?!\()\?/g, box);

    // escape '.abc' => '\\.abc'
    replace(/\.([*\w]+)/g, '\\.$1');
    // fix '[^\\\\\/]'
    replace(/\[\^[\\\/]+\]/g, box);
    // fix '/' => '\/'
    replace(/\/+/g, '\\/');
    // fix double slashes
    replace(/\\+\//g, '\\/');
    glob = unesc(glob);
  }

  glob = glob.split('__QMARK_GROUP__').join('(?');
  glob = unescape(glob);

  return {glob: glob, tokens: tok, options: opts};
}

/**
 * Expand the filename part of the glob into a regex
 * compatible string
 *
 * @param  {String} glob
 * @param  {Object} tok Tokens
 * @param  {Options} opts
 * @return {Object}
 */

function expandFilename(glob, tok, opts) {
  switch (glob) {
    case '.':
      glob = '\\.';
      break;
    case '.*':
      glob = '\\..*';
      break;
    case '*.*':
      glob = star(opts.dot) + '\\.[^/]*?';
      break;
    case '*':
      glob = star(opts.dot);
      break;
    default:
    if (tok.basename === '*') {
      glob = star(opts.dot) + '\\' + tok.extname;
    } else {
      glob = glob.replace(/(?!\()\?/g, '[^/]');
      if (tok.filename.charAt(0) !== '.') {
        opts.dot = true;
      }
      glob = glob.replace(/\*/g, star(opts.dot));
    }
  }

  glob = glob.split('__QMARK_GROUP__').join('(?');
  glob = unescape(glob);
  return {glob: glob, options: opts};
}

/**
 * Special cases
 */

function specialCase(glob) {
  if (glob === '\\') {
    return true;
  }
  return false;
}

/**
 * Escape imbalanced braces/bracket
 */

function balance(str, a, b) {
  var len = str.length;
  var aarr = str.split(a);
  var alen = aarr.join('').length;
  var blen = str.split(b).join('').length;

  if (alen !== blen) {
    str = aarr.join('\\' + a);
    return str.split(b).join('\\' + b);
  }
  return str;
}

/**
 * Escape utils
 */

function esc(str) {
  str = str.split('?').join('%~');
  str = str.split('*').join('%%');
  return str;
}

function unesc(str) {
  str = str.split('%~').join('?');
  str = str.split('%%').join('*');
  return str;
}

function escape(str, ch) {
  var re = ch ? chars.escapeRegex[ch] : /["\\](['"]?[^"'\\]['"]?)/g;
  return str.replace(re, function($0, $1) {
    var o = chars[ch ? 'ESC_TEMP' : 'ESC'];
    var res;

    ch = ch ? $0 : $1;
    if (o && (res = o[ch])) {
      return res;
    }
    if (/[a-z]/i.test($0)) {
      return $0.split('\\').join('');
    }
    return $0;
  });
}

function unescape(str) {
  return str.replace(/__([A-Z]+)_([A-Z]+)__/g, function($0, $1) {
    return chars[$1][$0];
  });
}

/**
 * Special patterns to be converted to regex.
 * Heuristics are used to simplify patterns
 * and speed up processing.
 */

var box         = '[^/]';
var boxQ        = '[^/]*?';
var lookahead   = '(?=.)';
var nodot       = '(?!\\.)(?=.)';

var ex = {};

ex.dotfileGlob = '(?:^|\\/)(?:\\.{1,2})(?:$|\\/)';
ex.stardot     = '(?!' + ex.dotfileGlob + ')(?=.)[^/]*?';
ex.twoStarDot  = '(?:(?!' + ex.dotfileGlob + ').)*?';

/**
 * Create a regex for `*`. If `dot` is true,
 * or the pattern does not begin with a leading
 * star, then return the simple regex.
 */

function star(dotfile) {
  return dotfile ? boxQ : nodot + boxQ;
}

function dotstarbase(dotfile) {
  var re = dotfile ? ex.dotfileGlob : '\\.';
  return '(?!' + re + ')' + lookahead;
}

function globstar(opts) {
  if (opts.dot) { return ex.twoStarDot; }
  return '(?:(?!(?:^|\\/)\\.).)*?';
}

function stardot(opts) {
  return dotstarbase(opts && opts.dot) + '[^/]*?';
}

/**
 * Expand braces in the given glob pattern.
 *
 * We only need to use the [braces] lib when
 * patterns are nested.
 *
 * @param  {String} `glob`
 * @return {String}
 */

function expandBraces(glob, options) {
  options = options || {};
  options.makeRe = options.makeRe || true;

  var a = glob.match(/[\{\(\[]/g);
  var b = glob.match(/[\}\)\]]/g);

  if (a && b && (a.length !== b.length)) {
    options.makeRe = false;
  }

  var res = braces(glob, options);
  return res.join('|');
}
<commit_msg>start moving code to Glob<commit_after>/*!
 * micromatch <https://github.com/jonschlinkert/micromatch>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT license.
 */

'use strict';

var extglob = require('extglob');
var braces = require('braces');
var parse = require('./parse');
var utils = require('./utils');
var chars = require('./chars');
var Glob = require('./glob');

/**
 * Expose `expand`
 */

module.exports = expand;

/**
 * Expand a glob pattern to resolve braces and
 * similar patterns before converting to regex.
 *
 * @param  {String|Array} `pattern`
 * @param  {Array} `files`
 * @param  {Options} `opts`
 * @return {Array}
 */

function expand(pattern, options) {
  var opts = options || {};
  opts.track = true;

  var glob = new Glob(pattern, options);

  function replace(re, str) {
    glob.repl(re, esc(str));
    pattern = glob.pattern;
  }

  // return early if the glob pattern tests `true`
  if (specialCase(pattern) && opts.safemode) {
    return new RegExp(utils.escapeRe(pattern), 'g');
  }

  if (opts.nonegate !== true) {
    opts.negated = glob.negated;
  }

  // expand braces, e.g `{1..5}`
  glob.track('before brackets');
  glob.brackets();
  glob.track('before braces');
  glob.braces();
  glob.track('after braces');
  glob.parse();

  glob.repl('[]', '\\[\\]')
  glob.repl('(?', '__QMARK_GROUP__');

  // parse the glob pattern into tokens
  var tok = glob.tokens;
  if (tok.dotfiles) {
    opts.dot = true;
  }

  if (!tok.isGlob) {
    return {
      pattern: utils.escapePath(glob.pattern),
      tokens: tok,
      options: opts
    };
  }

  if (glob.pattern === '**' && opts.globstar !== false) {
     glob.pattern = globstar(opts);

  } else {
    if (/^\*\.\w*$/.test(glob.pattern)) {
      glob.repl('*', star(opts.dot) + '\\');
      glob.repl('__QMARK_GROUP__', '(?');
      return glob;
    }

    glob.pattern = balance(glob.pattern, '[', ']');

    // use heuristics to replace common escape patterns
    glob.escape(glob.pattern);

    // if the glob is for one directory deep, we can
    // simplify the parsing and generated regex
    if (tok.dirname === '') {
      return expandFilename(glob, opts);
    }

    // windows drives
    replace(/^(\w):([\\\/]+?)/gi, lookahead + '$1:$2');

    // if the pattern has `**`
    if (tok.globstar) {
      glob.repl(/(^|[^\\])\*{2,}([^\\]|$)/g, '$1**$2');
      // foo/**
      replace(/(\w+)\*\*(?!\/)/g, '(?=.)$1[^/]*?');
      // **/
      replace('**/', '(.*\\/|^)');
      // **
      replace('**', globstar(opts));
    }

    // *.*
    replace('*.*', '([^/]*?.[^/]*?)');
    // ends with /*
    replace(/\/\*$/g, '\\/' + stardot(opts));
    // ends with *, no slashes
    replace(/(?!\/)\*$/g, boxQ);
    // has '*'
    replace('*', stardot(opts));

    replace('?.', '?\\.');
    replace('?:', '?:');
    // first of '????'
    replace(/(?!\?)\?/g, '\\/'+ dotstarbase(opts.dot) + box);
    // rest of '????'
    replace(/(?!\()\?/g, box);

    // escape '.abc' => '\\.abc'
    replace(/\.([*\w]+)/g, '\\.$1');
    // fix '[^\\\\\/]'
    replace(/\[\^[\\\/]+\]/g, box);
    // fix '/' => '\/'
    replace(/\/+/g, '\\/');
    // fix double slashes
    replace(/\\+\//g, '\\/');
  }

  glob.repl('__QMARK_GROUP__', '(?');
  glob.unescape(glob.pattern);
  glob.repl('__UNESC_STAR__', '*');
  glob.repl('%~', '?');
  glob.repl('%%', '*');
  return glob;
}

/**
 * Expand the filename part of the glob into a regex
 * compatible string
 *
 * @param  {String} glob
 * @param  {Object} tok Tokens
 * @param  {Options} opts
 * @return {Object}
 */

function expandFilename(glob, opts) {
  var tok = glob.tokens;
  switch (glob.pattern) {
    case '.':
      glob.pattern = '\\.';
      break;
    case '.*':
      glob.pattern = '\\..*';
      break;
    case '*.*':
      glob.pattern = star(opts.dot) + '\\.[^/]*?';
      break;
    case '*':
      glob.pattern = star(opts.dot);
      break;
    default:
    if (tok.basename === '*') {
      glob.pattern = star(opts.dot) + '\\' + tok.extname;
    } else {
      glob.repl(/(?!\()\?/g, '[^/]');
      if (tok.filename.charAt(0) !== '.') {
        opts.dot = true;
      }
      glob.repl('*', star(opts.dot));
    }
  }

  glob.repl('__QMARK_GROUP__', '(?');
  glob.unescape(glob.pattern);
  glob.repl('__UNESC_STAR__', '*');
  return glob;
}

/**
 * Special cases
 */

function specialCase(glob) {
  if (glob === '\\') {
    return true;
  }
  return false;
}

/**
 * Escape imbalanced braces/bracket
 */

function balance(str, a, b) {
  var len = str.length;
  var aarr = str.split(a);
  var alen = aarr.join('').length;
  var blen = str.split(b).join('').length;

  if (alen !== blen) {
    str = aarr.join('\\' + a);
    return str.split(b).join('\\' + b);
  }
  return str;
}

/**
 * Escape utils
 */

function esc(str) {
  str = str.split('?').join('%~');
  str = str.split('*').join('%%');
  return str;
}

/**
 * Special patterns to be converted to regex.
 * Heuristics are used to simplify patterns
 * and speed up processing.
 */

var box         = '[^/]';
var boxQ        = '[^/]*?';
var lookahead   = '(?=.)';
var nodot       = '(?!\\.)(?=.)';

var ex = {};

ex.dotfileGlob = '(?:^|\\/)(?:\\.{1,2})(?:$|\\/)';
ex.stardot     = '(?!' + ex.dotfileGlob + ')(?=.)[^/]*?';
ex.twoStarDot  = '(?:(?!' + ex.dotfileGlob + ').)*?';

/**
 * Create a regex for `*`. If `dot` is true,
 * or the pattern does not begin with a leading
 * star, then return the simple regex.
 */

function star(dotfile) {
  return dotfile ? boxQ : nodot + boxQ;
}

function dotstarbase(dotfile) {
  var re = dotfile ? ex.dotfileGlob : '\\.';
  return '(?!' + re + ')' + lookahead;
}

function globstar(opts) {
  if (opts.dot) { return ex.twoStarDot; }
  return '(?:(?!(?:^|\\/)\\.).)*?';
}

function stardot(opts) {
  return dotstarbase(opts && opts.dot) + '[^/]*?';
}
<|endoftext|>


<commit_before>var clone = require('clone')
  , morph = require('morph');

var aliases = [
  morph.snake,
  morph.snakeCaps,
  morph.dashed,
  morph.camel,
  morph.human,
  morph.title
];

module.exports = Facade;

function Facade (obj) {
  this.obj = obj;
}

Facade.proxy = function (name, field) {
  return function () {
    var obj = field ? this.obj[field] : this.obj;
    if (!obj) return;

    for (var i = 0; i < aliases.length; i++) {
      var aliased = aliases[i](name);
      if (obj.hasOwnProperty(aliased)) return clone(obj[aliased]);
    }
  };
};

Facade.prototype.json = function () {
  return clone(this.obj);
};

Facade.prototype.options = function () {
  return clone(this.obj.options || this.obj.context);
};

Facade.prototype.channel   = Facade.proxy('channel');
Facade.prototype.timestamp = Facade.proxy('timestamp');<commit_msg>Updating<commit_after>var clone = require('clone')
  , morph = require('morph');

var aliases = [
  morph.snake,
  morph.snakeCaps,
  morph.dashed,
  morph.camel,
  morph.human,
  morph.title
];

module.exports = Facade;

function Facade (obj) {
  this.obj = obj;
}

Facade.proxy = function (name, field) {
  return function () {
    var obj = field ? this[field] : this.obj;
    if (!obj) return;
    if (typeof obj === 'function') obj = obj() || {};

    for (var i = 0; i < aliases.length; i++) {
      var aliased = aliases[i](name);
      if (obj.hasOwnProperty(aliased)) return clone(obj[aliased]);
    }
  };
};

Facade.prototype.json = function () {
  return clone(this.obj);
};

Facade.prototype.options = function () {
  return clone(this.obj.options || this.obj.context) || {};
};

Facade.prototype.ip        = Facade.proxy('ip', 'options');
Facade.prototype.channel   = Facade.proxy('channel');
Facade.prototype.timestamp = Facade.proxy('timestamp');<|endoftext|>


<commit_before>var net = require('net');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var _ = require("underscore");
var JsonSocket = require('json-socket');

var clients = [];
var servers = {};

function MeshTcp (tcpPort) {
    var self = this;

    this.tcpPort = tcpPort;

    this.tcp_server = net.createServer(function (socket) {

        // Identify this client
        socket = new JsonSocket(socket);
        socket.name = socket.remoteAddress + ":" + socket.remotePort

        // Put this new client in the list
        clients.push(socket);

        // Handle incoming messages from clients.
        socket.on('message', function (message) {
            console.log(message);
        });

        // Remove the client from the list when it leaves
        socket.on('end', function () {
            clients.splice(clients.indexOf(socket), 1);
        });
    });
    this.tcp_server.listen(tcpPort, '0.0.0.0');
}
util.inherits(MeshTcp, EventEmitter);

MeshTcp.prototype.addConnection = function (info) {
    //connect to remote tcp server
    if(servers[info.name] == undefined) {
        console.log("trying to connect to " + info.address);
        var newServer = new JsonSocket(new net.Socket());
        newServer.connect({"address":info.address, "port":this.tcpPort}, function() {
            newServer.info = info;
            servers[info.name] = newServer;

            console.log("added new server connection");
            console.log(servers);
        });
    }
};

MeshTcp.prototype.publish = function (target, message) {
    for (var key in servers) {
        var server = servers[key];
        if (_.contains(server.info.listensTo, target)) {
            server.sendMessage(JSON.parse(message));
        }
    }
};

module.exports = MeshTcp;<commit_msg>new connect method<commit_after>var net = require('net');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var _ = require("underscore");
var JsonSocket = require('json-socket');

var clients = [];
var servers = {};

function MeshTcp (tcpPort) {
    var self = this;

    this.tcpPort = tcpPort;

    this.tcp_server = net.createServer(function (socket) {

        // Identify this client
        socket = new JsonSocket(socket);
        socket.name = socket.remoteAddress + ":" + socket.remotePort

        // Put this new client in the list
        clients.push(socket);

        // Handle incoming messages from clients.
        socket.on('message', function (message) {
            console.log(message);
        });

        // Remove the client from the list when it leaves
        socket.on('end', function () {
            clients.splice(clients.indexOf(socket), 1);
        });
    });
    this.tcp_server.listen(tcpPort, '0.0.0.0');
}
util.inherits(MeshTcp, EventEmitter);

MeshTcp.prototype.addConnection = function (info) {
    //connect to remote tcp server
    if(servers[info.name] == undefined) {
        console.log("trying to connect to " + info.address);
        var newServer = new JsonSocket(new net.Socket());
        newServer.connect(this.tcpPort, info.address, function() {
            newServer.info = info;
            servers[info.name] = newServer;

            console.log("added new server connection");
            console.log(servers);
        });
    }
};

MeshTcp.prototype.publish = function (target, message) {
    for (var key in servers) {
        var server = servers[key];
        if (_.contains(server.info.listensTo, target)) {
            server.sendMessage(JSON.parse(message));
        }
    }
};

module.exports = MeshTcp;<|endoftext|>


<commit_before>var Logger = require("./logger");
var Config = require("./config");
var spawn = require("child_process").spawn;
var https = require("https");
var http = require("http");
var urlparse = require("url");
require("status-message-polyfill");

var USE_JSON = true;

var acceptedCodecs = {
    "mov/h264": true,
    "flv/h264": true,
    "matroska/vp8": true,
    "matroska/vp9": true,
    "ogg/theora": true
};

var acceptedAudioCodecs = {
    "mp3": true,
    "vorbis": true
};

var audioOnlyContainers = {
    "mp3": true
};

function testUrl(url, cb, redirCount) {
    if (!redirCount) redirCount = 0;
    var data = urlparse.parse(url);
    if (!/https?:/.test(data.protocol)) {
        return cb("Video links must start with http:// or https://");
    }

    if (!data.hostname) {
        return cb("Invalid link");
    }

    var transport = (data.protocol === "https:") ? https : http;
    data.method = "HEAD";
    var req = transport.request(data, function (res) {
        req.abort();

        if (res.statusCode === 301 || res.statusCode === 302) {
            if (redirCount > 2) {
                return cb("Too many redirects.  Please provide a direct link to the " +
                          "file");
            }
            return testUrl(res.headers["location"], cb, redirCount + 1);
        }

        if (res.statusCode !== 200) {
            var message = res.statusMessage;
            if (!message) message = "";
            return cb("HTTP " + res.statusCode + " " + message);
        }

        if (!/^audio|^video/.test(res.headers["content-type"])) {
            return cb("Server did not return an audio or video file, or sent the " +
                      "wrong Content-Type");
        }

        cb();
    });

    req.on("error", function (err) {
        cb(err);
    });

    req.end();
}

function readOldFormat(buf) {
    var lines = buf.split("\n");
    var tmp = { tags: {} };
    var data = {
        streams: []
    };

    lines.forEach(function (line) {
        if (line.match(/\[stream\]|\[format\]/i)) {
            return;
        } else if (line.match(/\[\/stream\]/i)) {
            data.streams.push(tmp);
            tmp = { tags: {} };
        } else if (line.match(/\[\/format\]/i)) {
            data.format = tmp;
            tmp = { tags: {} };
        } else {
            var kv = line.split("=");
            var key = kv[0].toLowerCase();
            if (key.indexOf("tag:") === 0) {
                tmp.tags[key.split(":")[1]] = kv[1];
            } else {
                tmp[key] = kv[1];
            }
        }
    });

    return data;
}

function reformatData(data) {
    var reformatted = {};

    var duration = parseInt(data.format.duration, 10);
    if (isNaN(duration)) duration = "--:--";
    reformatted.duration = Math.ceil(duration);

    var bitrate = parseInt(data.format.bit_rate, 10) / 1000;
    if (isNaN(bitrate)) bitrate = 0;
    reformatted.bitrate = bitrate;

    reformatted.title = data.format.tags ? data.format.tags.title : null;
    var container = data.format.format_name.split(",")[0];

    data.streams.forEach(function (stream) {
        if (stream.codec_type === "video") {
            reformatted.vcodec = stream.codec_name;
            if (!reformatted.title && stream.tags) {
                reformatted.title = stream.tags.title;
            }
        } else if (stream.codec_type === "audio") {
            reformatted.acodec = stream.codec_name;
        }
    });

    if (reformatted.vcodec && !(audioOnlyContainers.hasOwnProperty(container))) {
        reformatted.type = [container, reformatted.vcodec].join("/");
        reformatted.medium = "video";
    } else if (reformatted.acodec) {
        reformatted.type = [container, reformatted.acodec].join("/");
        reformatted.medium = "audio";
    }

    return reformatted;
}

exports.ffprobe = function ffprobe(filename, cb) {
    var childErr;
    var args = ["-show_streams", "-show_format", filename];
    if (USE_JSON) args = ["-of", "json"].concat(args);
    var child = spawn(Config.get("ffmpeg.ffprobe-exec"), args);
    var stdout = "";
    var stderr = "";

    child.on("error", function (err) {
        childErr = err;
    });

    child.stdout.on("data", function (data) {
        stdout += data;
    });

    child.stderr.on("data", function (data) {
        stderr += data;
    });

    child.on("close", function (code) {
        if (code !== 0) {
            if (stderr.match(/unrecognized option|json/i) && USE_JSON) {
                Logger.errlog.log("Warning: ffprobe does not support -of json.  " +
                                  "Assuming it will have old output format.");
                USE_JSON = false;
                return ffprobe(filename, cb);
            }

            if (!childErr) childErr = new Error(stderr);
            return cb(childErr);
        }

        var result;
        if (USE_JSON) {
            try {
                result = JSON.parse(stdout);
            } catch (e) {
                return cb(new Error("Unable to parse ffprobe output: " + e.message));
            }
        } else {
            try {
                result = readOldFormat(stdout);
            } catch (e) {
                return cb(new Error("Unable to parse ffprobe output: " + e.message));
            }
        }

        return cb(null, result);
    });
}

exports.query = function (filename, cb) {
    if (!Config.get("ffmpeg.enabled")) {
        return cb("Raw file playback is not enabled on this server");
    }

    if (!filename.match(/^https?:\/\//)) {
        return cb("Raw file playback is only supported for links accessible via HTTP " +
                  "or HTTPS");
    }

    testUrl(filename, function (err) {
        if (err) {
            return cb(err);
        }

        exports.ffprobe(filename, function (err, data) {
            if (err) {
                if (err.code && err.code === "ENOENT") {
                    return cb("Failed to execute `ffprobe`.  Set ffmpeg.ffprobe-exec " +
                              "to the correct name of the executable in config.yaml.  " +
                              "If you are using Debian or Ubuntu, it is probably " +
                              "avprobe.");
                } else if (err.message) {
                    if (err.message.match(/protocol not found/i))
                        return cb("Link uses a protocol unsupported by this server's " +
                                  "version of ffmpeg");

                    // Ignore ffprobe error messages, they are common and most often
                    // indicate a problem with the remote file, not with this code.
                    if (!/(av|ff)probe/.test(String(err)))
                        Logger.errlog.log(err.stack || err);
                    return cb("Unable to query file data with ffmpeg");
                } else {
                    if (!/(av|ff)probe/.test(String(err)))
                        Logger.errlog.log(err.stack || err);
                    return cb("Unable to query file data with ffmpeg");
                }
            }

            try {
                data = reformatData(data);
            } catch (e) {
                Logger.errlog.log(e.stack || e);
                return cb("Unable to query file data with ffmpeg");
            }

            if (data.medium === "video") {
                if (!acceptedCodecs.hasOwnProperty(data.type)) {
                    return cb("Unsupported video codec " + data.type);
                }

                data = {
                    title: data.title || "Raw Video",
                    duration: data.duration,
                    bitrate: data.bitrate,
                    codec: data.type
                };

                cb(null, data);
            } else if (data.medium === "audio") {
                if (!acceptedAudioCodecs.hasOwnProperty(data.acodec)) {
                    return cb("Unsupported audio codec " + data.acodec);
                }

                data = {
                    title: data.title || "Raw Audio",
                    duration: data.duration,
                    bitrate: data.bitrate,
                    codec: data.acodec
                };

                cb(null, data);
            } else {
                return cb("Parsed metadata did not contain a valid video or audio " +
                          "stream.  Either the file is invalid or it has a format " +
                          "unsupported by this server's version of ffmpeg.");
            }
        });
    });
};
<commit_msg>Kill ffprobe after 30 seconds; add logging<commit_after>var Logger = require("./logger");
var Config = require("./config");
var spawn = require("child_process").spawn;
var https = require("https");
var http = require("http");
var urlparse = require("url");
var path = require("path");
require("status-message-polyfill");

var USE_JSON = true;
var TIMEOUT = 30000;

var acceptedCodecs = {
    "mov/h264": true,
    "flv/h264": true,
    "matroska/vp8": true,
    "matroska/vp9": true,
    "ogg/theora": true
};

var acceptedAudioCodecs = {
    "mp3": true,
    "vorbis": true
};

var audioOnlyContainers = {
    "mp3": true
};

function fflog() { }

function initFFLog() {
    var logger = new Logger.Logger(path.resolve(__dirname, "..", "ffmpeg.log"));
    fflog = function () {
        logger.log.apply(logger, arguments);
    };
}

function testUrl(url, cb, redirCount) {
    if (!redirCount) redirCount = 0;
    var data = urlparse.parse(url);
    if (!/https?:/.test(data.protocol)) {
        return cb("Video links must start with http:// or https://");
    }

    if (!data.hostname) {
        return cb("Invalid link");
    }

    var transport = (data.protocol === "https:") ? https : http;
    data.method = "HEAD";
    var req = transport.request(data, function (res) {
        req.abort();

        if (res.statusCode === 301 || res.statusCode === 302) {
            if (redirCount > 2) {
                return cb("Too many redirects.  Please provide a direct link to the " +
                          "file");
            }
            return testUrl(res.headers["location"], cb, redirCount + 1);
        }

        if (res.statusCode !== 200) {
            var message = res.statusMessage;
            if (!message) message = "";
            return cb("HTTP " + res.statusCode + " " + message);
        }

        if (!/^audio|^video/.test(res.headers["content-type"])) {
            return cb("Server did not return an audio or video file, or sent the " +
                      "wrong Content-Type");
        }

        cb();
    });

    req.on("error", function (err) {
        cb(err);
    });

    req.end();
}

function readOldFormat(buf) {
    var lines = buf.split("\n");
    var tmp = { tags: {} };
    var data = {
        streams: []
    };

    lines.forEach(function (line) {
        if (line.match(/\[stream\]|\[format\]/i)) {
            return;
        } else if (line.match(/\[\/stream\]/i)) {
            data.streams.push(tmp);
            tmp = { tags: {} };
        } else if (line.match(/\[\/format\]/i)) {
            data.format = tmp;
            tmp = { tags: {} };
        } else {
            var kv = line.split("=");
            var key = kv[0].toLowerCase();
            if (key.indexOf("tag:") === 0) {
                tmp.tags[key.split(":")[1]] = kv[1];
            } else {
                tmp[key] = kv[1];
            }
        }
    });

    return data;
}

function reformatData(data) {
    var reformatted = {};

    var duration = parseInt(data.format.duration, 10);
    if (isNaN(duration)) duration = "--:--";
    reformatted.duration = Math.ceil(duration);

    var bitrate = parseInt(data.format.bit_rate, 10) / 1000;
    if (isNaN(bitrate)) bitrate = 0;
    reformatted.bitrate = bitrate;

    reformatted.title = data.format.tags ? data.format.tags.title : null;
    var container = data.format.format_name.split(",")[0];

    data.streams.forEach(function (stream) {
        if (stream.codec_type === "video") {
            reformatted.vcodec = stream.codec_name;
            if (!reformatted.title && stream.tags) {
                reformatted.title = stream.tags.title;
            }
        } else if (stream.codec_type === "audio") {
            reformatted.acodec = stream.codec_name;
        }
    });

    if (reformatted.vcodec && !(audioOnlyContainers.hasOwnProperty(container))) {
        reformatted.type = [container, reformatted.vcodec].join("/");
        reformatted.medium = "video";
    } else if (reformatted.acodec) {
        reformatted.type = [container, reformatted.acodec].join("/");
        reformatted.medium = "audio";
    }

    return reformatted;
}

exports.ffprobe = function ffprobe(filename, cb) {
    fflog("Spawning ffprobe for " + filename);
    var childErr;
    var args = ["-show_streams", "-show_format", filename];
    if (USE_JSON) args = ["-of", "json"].concat(args);
    var child = spawn(Config.get("ffmpeg.ffprobe-exec"), args);
    var stdout = "";
    var stderr = "";
    var timer = setTimeout(function () {
        Logger.errlog.log("Possible runaway ffprobe process for file " + filename);
        fflog("Killing ffprobe for " + filename + " after " + (TIMEOUT/1000) + " seconds");
        childErr = new Error("File query exceeded time limit of 10 seconds");
        child.kill('SIGKILL');
    }, TIMEOUT);

    child.on("error", function (err) {
        childErr = err;
    });

    child.stdout.on("data", function (data) {
        stdout += data;
    });

    child.stderr.on("data", function (data) {
        stderr += data;
    });

    child.on("close", function (code) {
        clearTimeout(timer);
        fflog("ffprobe exited with code " + code + " for file " + filename);
        if (code !== 0) {
            if (stderr.match(/unrecognized option|json/i) && USE_JSON) {
                Logger.errlog.log("Warning: ffprobe does not support -of json.  " +
                                  "Assuming it will have old output format.");
                USE_JSON = false;
                return ffprobe(filename, cb);
            }

            if (!childErr) childErr = new Error(stderr);
            return cb(childErr);
        }

        var result;
        if (USE_JSON) {
            try {
                result = JSON.parse(stdout);
            } catch (e) {
                return cb(new Error("Unable to parse ffprobe output: " + e.message));
            }
        } else {
            try {
                result = readOldFormat(stdout);
            } catch (e) {
                return cb(new Error("Unable to parse ffprobe output: " + e.message));
            }
        }

        return cb(null, result);
    });
}

exports.query = function (filename, cb) {
    if (Config.get("ffmpeg.log")) {
        initFFLog();
    }

    if (!Config.get("ffmpeg.enabled")) {
        return cb("Raw file playback is not enabled on this server");
    }

    if (!filename.match(/^https?:\/\//)) {
        return cb("Raw file playback is only supported for links accessible via HTTP " +
                  "or HTTPS");
    }

    testUrl(filename, function (err) {
        if (err) {
            return cb(err);
        }

        exports.ffprobe(filename, function (err, data) {
            if (err) {
                if (err.code && err.code === "ENOENT") {
                    return cb("Failed to execute `ffprobe`.  Set ffmpeg.ffprobe-exec " +
                              "to the correct name of the executable in config.yaml.  " +
                              "If you are using Debian or Ubuntu, it is probably " +
                              "avprobe.");
                } else if (err.message) {
                    if (err.message.match(/protocol not found/i))
                        return cb("Link uses a protocol unsupported by this server's " +
                                  "version of ffmpeg");

                    if (err.message.match(/exceeded time limit/)) {
                        return cb(err.message);
                    }

                    // Ignore ffprobe error messages, they are common and most often
                    // indicate a problem with the remote file, not with this code.
                    if (!/(av|ff)probe/.test(String(err)))
                        Logger.errlog.log(err.stack || err);
                    return cb("Unable to query file data with ffmpeg");
                } else {
                    if (!/(av|ff)probe/.test(String(err)))
                        Logger.errlog.log(err.stack || err);
                    return cb("Unable to query file data with ffmpeg");
                }
            }

            try {
                data = reformatData(data);
            } catch (e) {
                Logger.errlog.log(e.stack || e);
                return cb("Unable to query file data with ffmpeg");
            }

            if (data.medium === "video") {
                if (!acceptedCodecs.hasOwnProperty(data.type)) {
                    return cb("Unsupported video codec " + data.type);
                }

                data = {
                    title: data.title || "Raw Video",
                    duration: data.duration,
                    bitrate: data.bitrate,
                    codec: data.type
                };

                cb(null, data);
            } else if (data.medium === "audio") {
                if (!acceptedAudioCodecs.hasOwnProperty(data.acodec)) {
                    return cb("Unsupported audio codec " + data.acodec);
                }

                data = {
                    title: data.title || "Raw Audio",
                    duration: data.duration,
                    bitrate: data.bitrate,
                    codec: data.acodec
                };

                cb(null, data);
            } else {
                return cb("Parsed metadata did not contain a valid video or audio " +
                          "stream.  Either the file is invalid or it has a format " +
                          "unsupported by this server's version of ffmpeg.");
            }
        });
    });
};
<|endoftext|>


<commit_before>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'

(function(){

var app = angular.module('notesApp', ['ionic']);

app.config(function($stateProvider, $urlRouterProvider){

  $stateProvider.state('list',{
    url: '/list',
    templateUrl: 'templates/list.html'
  });

  $stateProvider.state('edit',{
    url: '/edit/:noteId',
    templateUrl: 'templates/edit.html'
  });

  $urlRouterProvider.otherwise('/list');

});

var notesText = [
  {
    id: '1',
    title: 'Hey There!',
    description: 'Testing out the notesText array, Hope you guys have a great day'
  },
  {
    id: '2',
    title: 'Hey There! Again',
    description: 'Testing out the notesText array again, Hope you guys have a great day'
  }
];

function getText(noteId){
  for(var i = 0; i < notesText.length; i++){
    if(notesText[i].id == noteId){
      return notesText[i];
    }
  }
  return undefined;
}

function updateText(note){
  for(var i = 0; i < notesText.length; i++){
    if(notesText[i].id == note.id){
      notesText[i] = note;
    }
  }
}

app.controller('ListCtrl', function($scope){
  $scope.notesText = notesText;
});

app.controller('EditCtrl', function($scope, $state){

  $scope.note = angular.copy(getText($state.params.noteId));

  $scope.saveText = function(){
    updateText($scope.note);
    //go back to the list state
    $state.go('list');
  };

});

app.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if(window.cordova && window.cordova.plugins.Keyboard) {
      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
      // for form inputs)
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);

      // Don't remove this line unless you know what you are doing. It stops the viewport
      // from snapping when text inputs are focused. Ionic handles this internally for
      // a much nicer keyboard experience.
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
});

})();
<commit_msg>create comments for easy understanding and debugging<commit_after>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'

//anonymous function
(function(){

var app = angular.module('notesApp', ['ionic']);

app.config(function($stateProvider, $urlRouterProvider){

  //the state for the list view
  $stateProvider.state('list',{
    url: '/list',
    templateUrl: 'templates/list.html'
  });

  //the state for the edit view
  $stateProvider.state('edit',{
    url: '/edit/:noteId',
    templateUrl: 'templates/edit.html'
  });

  //the default state of the application is the list view
  $urlRouterProvider.otherwise('/list');

});

//the object literal which has the details of the notes
var notesText = [
  {
    id: '1',
    title: 'Hey There!',
    description: 'Testing out the notesText array, Hope you guys have a great day'
  },
  {
    id: '2',
    title: 'Hey There! Again',
    description: 'Testing out the notesText array again, Hope you guys have a great day'
  }
];

//function to get text from the notesText array
//takes the note Id as a parameter
function getText(noteId){
  for(var i = 0; i < notesText.length; i++){
    if(notesText[i].id == noteId){
      return notesText[i];
    }
  }
  return undefined;
}

//function to make changes in the notesText array
//takes the note object
function updateText(note){
  for(var i = 0; i < notesText.length; i++){
    if(notesText[i].id == note.id){
      notesText[i] = note;
    }
  }
}

//the controller for the List view
//used to display the data from notesText
app.controller('ListCtrl', function($scope){

  //creates an object notesText for this scope
  $scope.notesText = notesText;

});

//the controller for the Edit view
app.controller('EditCtrl', function($scope, $state){

  //creates an object note for this scope
  //it is created with the help of note id from the url
  $scope.note = angular.copy(getText($state.params.noteId));

  //when the save button is presseds
  $scope.saveText = function(){
    updateText($scope.note);
    //go back to the list state
    $state.go('list');
  };

});

app.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if(window.cordova && window.cordova.plugins.Keyboard) {
      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
      // for form inputs)
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);

      // Don't remove this line unless you know what you are doing. It stops the viewport
      // from snapping when text inputs are focused. Ionic handles this internally for
      // a much nicer keyboard experience.
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
});

})();
<|endoftext|>


<commit_before>var utils = require('cordova/utils'),
    event = require('./event'),
    common = require('./Common'),
    BaseClass = require('./BaseClass');

/*****************************************************************************
 * HTMLInfoWindow Class
 *****************************************************************************/
var HTMLInfoWindow = function() {
    var self = this;
    BaseClass.apply(self);

    var frame = document.createElement("div");
    frame.style.overflow="visible";
    frame.style.position="absolute";
    frame.style.display = "inline-block";
    self.set("frame", frame);

    var contentBox = document.createElement("div");
    contentBox.style.display = "inline-block";
    contentBox.style.padding = "5px";

    var contentFrame = document.createElement("div");
    contentFrame.style.display = "block";
    contentFrame.style.position = "relative";
    contentFrame.style.backgroundColor = "white";
    contentFrame.style.border = "1px solid rgb(204, 204, 204)";
    contentFrame.style.left = "0px";
    contentFrame.style.right = "0px";
    contentFrame.style.zIndex = "1";  // In order to set higher depth than the map div certainly
    frame.appendChild(contentFrame);
    contentFrame.appendChild(contentBox);

    var tailFrame = document.createElement("div");
    tailFrame.style.position = "relative";
    tailFrame.style.marginTop = "-1px";
    frame.appendChild(tailFrame);

    var tailLeft = document.createElement("div");
    tailLeft.style.position = "absolute";
    tailLeft.style.left = "50%";
    tailLeft.style.height = "0px";
    tailLeft.style.width = "0px";
    tailLeft.style.marginLeft = "-15px";
    tailLeft.style.borderWidth = "15px 15px 0px";
    tailLeft.style.borderColor = "rgb(204, 204, 204) transparent transparent";
    tailLeft.style.borderStyle = "solid";
    tailFrame.appendChild(tailLeft);

    var tailRight = document.createElement("div");
    tailRight.style.position = "absolute";
    tailRight.style.left = "50%";
    tailRight.style.height = "0px";
    tailRight.style.width = "0px";
    tailRight.style.marginLeft = "-14px";
    tailRight.style.borderTopWidth = "14px";
    tailRight.style.borderLeftWidth = "14px";
    tailRight.style.borderRightWidth = "14px";
    tailRight.style.borderColor = "rgb(255, 255, 255) transparent transparent";
    tailRight.style.borderStyle = "solid";
    tailFrame.appendChild(tailRight);

    var calculate = function() {

      var marker = self.get("marker");
      var map = marker.getMap();

      var div = map.getDiv();

      var frame = self.get("frame");
      var contentFrame = frame.firstChild;
      var contentBox = contentFrame.firstChild;
      contentBox.style.minWidth = "100px";
      contentBox.style.minHeight = "50px";

      var content = self.get("content");
      if (typeof content === "string") {
          contentBox.style.whiteSpace="pre-wrap";
          contentBox.innerHTML = content;
      } else {
          if (!content) {
            contentBox.innerText = "";
          } else if (content.nodeType === 1) {
            contentBox.innerHTML = "";
            contentBox.appendChild(content);
          } else {
            contentBox.innerText = content;
          }
      }

      // Insert the contents to this HTMLInfoWindow
      if (!frame.parentNode) {
          div.appendChild(frame);
      }

      // Adjust the HTMLInfoWindow size
      var contentsWidth = contentBox.offsetWidth + 10; // padding 5px x 2
      self.set("contentsWidth", contentsWidth);
      var contentsHeight = contentBox.offsetHeight;
      self.set("contentsHeight", contentsHeight );
      contentFrame.style.width = contentsWidth + "px";
      contentFrame.style.height = contentsHeight + "px";
      frame.style.width = contentsWidth  + "px";
      frame.style.height = (contentsHeight+ 15) + "px";

      var infoOffset = {
        y : 0.25,
        x : 0.5
      };

      var iconSize = {
        width: 28,
        height: 60
      };
      var icon = marker.get("icon");
      if (typeof icon === "object") {
          if (typeof icon.size === "object") {
              iconSize.width = icon.size.width;
              iconSize.height = icon.size.height;
          }
          if (typeof icon.url === "string" && icon.url.indexOf("data:image/") === 0) {
              var img = document.createElement("img");
              img.src = icon.url;
              iconSize.width = img.width;
              iconSize.height = img.height;
          }

      }
      var infoWindowAnchor = marker.get("infoWindowAnchor");
      if (utils.isArray(infoWindowAnchor)) {
        infoOffset.x = infoWindowAnchor[0] / icon.size.width;
        infoOffset.x = infoOffset.x > 1 ? 1 : infoOffset.x;
        infoOffset.x = infoOffset.x < 0 ? 0 : infoOffset.x;
        infoOffset.y = infoWindowAnchor[1] / icon.size.height;
        infoOffset.y = infoOffset.y > 1 ? 1 : infoOffset.y;
        infoOffset.y = infoOffset.y < 0 ? 0 : infoOffset.y;
      }
      infoOffset.y *= iconSize.height;
      infoOffset.x = (infoOffset.x - 0.5) * iconSize.width;

      //console.log("contentsSize = " + contentsWidth + ", " + contentsHeight);
      //console.log("iconSize = " + iconSize.width + ", " + iconSize.height);
      //console.log("infoOffset = " + infoOffset.x + ", " + infoOffset.y);

      var offsetX = contentsWidth / 2  - infoOffset.x;
      var offsetY = contentsHeight  - infoOffset.y + iconSize.height;

      self.set("offsetX", offsetX);
      self.set("offsetY", offsetY);

      //console.log("offset = " + self.get("offsetX") + ", " + self.get("offsetY"));
      var infoPosition = map.get("infoPosition");
      self.trigger("infoPosition_changed", "", infoPosition);
    };

    var isInfoOpenFired = false;

    self.on("infoPosition_changed", function(ignore, point) {

        var x = point.x - self.get("offsetX");
        var y = point.y - self.get("offsetY");
        //console.log("offset = " + x + ", " + y);

        frame.style.left = x + "px";
        frame.style.top =  y + "px";

        if (!isInfoOpenFired) {
            isInfoOpenFired = true;
            self.trigger(event.INFO_OPEN);
        }

        cordova.fireDocumentEvent('plugin_touch', {});
    });
    self.on(event.INFO_CLOSE, function() {
        isInfoOpenFired = false;
    });
    self.on("infoWindowAnchor_changed", calculate);
    self.on("icon_changed", calculate);

    self.set("isInfoWindowVisible", false);

};

utils.extend(HTMLInfoWindow, BaseClass);

HTMLInfoWindow.prototype.isInfoWindowShown = function() {
    return this.get("isInfoWindowVisible") === true;
};

HTMLInfoWindow.prototype.close = function() {
    var self = this;

    var marker = self.get("marker");
    if (marker) {
      self.off("isInfoWindowVisible_changed");
    }
    if (!self.isInfoWindowShown() || !marker) {
      return;
    }
    self.set("isInfoWindowVisible", false);
    marker.set("isInfoWindowVisible", false);
    marker.set("infoWindow", undefined);
    this.set('marker', undefined);

    var map = marker.getMap();
    map.off("infoPosition_changed");
    marker.off("icon_changed");
    marker.off("infoWindowAnchor_changed");
    self.trigger(event.INFO_CLOSE);
    marker.off(event.INFO_CLOSE, self.close);  //This event listener is assigned in the open method. So detach it.
    map.set("active_marker_id", null);

    var div = map.getDiv();
    var frame = self.get("frame");
    div.removeChild(frame);

    // Remove the contents from this HTMLInfoWindow
    var contentFrame = frame.firstChild;
    var contentBox = contentFrame.firstChild;
    contentBox.innerHTML = "";
};

HTMLInfoWindow.prototype.setContent = function(content) {
    var self = this;
    var prevContent = self.get("content");
    self.set("content", content);
    var marker = self.get("marker");
    if (content !== prevContent && marker && marker.isInfoWindowShown()) {
      self.trigger("infoWindowAnchor_changed");
    }
};

HTMLInfoWindow.prototype.open = function(marker) {
    if (!marker) {
        return;
    }
    if (marker._objectInstance) {
      // marker is an instance of the ionic-native wrapper plugin.
      marker = marker._objectInstance;
    }

    var map = marker.getMap();
    var self = this,
      markerId = marker.getId();

    marker.set("infoWindow", self);
    marker.set("isInfoWindowVisible", true);
    self.set("isInfoWindowVisible", true);
    marker.one("isInfoWindowVisible_changed", function() {
      self.close.call(self);
    });

    map.fromLatLngToPoint(marker.getPosition(), function(point) {
        map.set("infoPosition", {x: point[0], y: point[1]});

        map.bindTo("infoPosition", self);
        marker.bindTo("infoWindowAnchor", self);
        marker.bindTo("icon", self);
        marker.one(event.INFO_CLOSE, self.close.bind(self));
        self.set("marker", marker);
        map.set("active_marker_id", marker.getId());
        self.trigger.call(self, "infoWindowAnchor_changed");
    });
};

HTMLInfoWindow.prototype.setBackgroundColor = function(backgroundColor) {
  this.get("frame").children[0].style.backgroundColor = backgroundColor;
  this.get("frame").children[1].children[0].style.borderColor = backgroundColor + " rgba(0,0,0,0) rgba(0,0,0,0)";
  this.get("frame").children[1].children[1].style.borderColor = backgroundColor + " rgba(0,0,0,0) rgba(0,0,0,0)";
};

module.exports = HTMLInfoWindow;
<commit_msg>(Add) Accept the idea of pull request #1753. (Update) Change the HTML structor of HtmlInfoWindow<commit_after>var utils = require('cordova/utils'),
    event = require('./event'),
    common = require('./Common'),
    BaseClass = require('./BaseClass');

/*****************************************************************************
 * HTMLInfoWindow Class
 *****************************************************************************/
var HTMLInfoWindow = function() {
    var self = this;
    BaseClass.apply(self);

    var frame = document.createElement("div");
    frame.style.overflow="visible";
    frame.style.position="absolute";
    frame.style.display = "inline-block";
    frame.classList.add('pgm-html-info-frame');
    self.set("frame", frame);

    var contentBox = document.createElement("div");
    contentBox.style.display = "inline-block";
    contentBox.style.padding = "5px";
    contentBox.classList.add('pgm-html-info-content-box');

    var contentFrame = document.createElement("div");
    contentFrame.style.display = "block";
    contentFrame.style.position = "relative";
    contentFrame.style.backgroundColor = "white";
    contentFrame.style.border = "1px solid rgb(204, 204, 204)";
    contentFrame.style.left = "0px";
    contentFrame.style.right = "0px";
    contentFrame.style.zIndex = "1";  // In order to set higher depth than the map div certainly
    contentFrame.classList.add('pgm-html-info-content-frame');
    frame.appendChild(contentFrame);
    contentFrame.appendChild(contentBox);

    var tailFrame = document.createElement("div");
    tailFrame.style.position = "relative";
    tailFrame.style.top = "-1px";
    tailFrame.style.zIndex = 100;
    tailFrame.classList.add('pgm-html-info-tail-frame');
    frame.appendChild(tailFrame);

    var tailLeft = document.createElement("div");
    tailLeft.style.position = "absolute";
    tailLeft.style.marginLeft = "-15px";
    tailLeft.style.left = "50%";
    tailLeft.style.top = "0px";
    tailLeft.style.height = "15px";
    tailLeft.style.width = "16px";
    tailLeft.style.overflow = "hidden";
    tailLeft.style.borderWidth = "0px";
    tailLeft.classList.add('pgm-html-info-tail-left');
    tailFrame.appendChild(tailLeft);

    var tailLeftCover = document.createElement("div");
    tailLeftCover.style.position = "absolute";
    tailLeftCover.style.backgroundColor = "white";
    tailLeftCover.style.transform = "skewX(45deg)";
    tailLeftCover.style.transformOrigin = "0px 0px 0px";
    tailLeftCover.style.left = "0px";
    tailLeftCover.style.height = "15px";
    tailLeftCover.style.width = "15px";
    tailLeftCover.style.top = "0px";
    tailLeftCover.style.zIndex = 1;
    tailLeftCover.style.borderLeft = "1px solid rgb(204, 204, 204)";
    tailLeft.classList.add('pgm-html-info-tail-left-cover');
    tailLeft.appendChild(tailLeftCover);

    var tailRight = document.createElement("div");
    tailRight.style.position = "absolute";
    tailRight.style.left = "50%";
    tailRight.style.top = "0px";
    tailRight.style.height = "15px";
    tailRight.style.width = "16px";
    tailRight.style.overflow = "hidden";
    tailRight.style.borderWidth = "0px";
    tailRight.classList.add('pgm-html-info-tail-right');
    tailFrame.appendChild(tailRight);

    var tailRightCover = document.createElement("div");
    tailRightCover.style.position = "absolute";
    tailRightCover.style.backgroundColor = "white";
    tailRightCover.style.transform = "skewX(-45deg)";
    tailRightCover.style.transformOrigin = "0px 0px 0px";
    tailRightCover.style.left = "0px";
    tailRightCover.style.height = "15px";
    tailRightCover.style.width = "15px";
    tailRightCover.style.top = "0px";
    tailRightCover.style.zIndex = 2;
    tailRightCover.style.borderRight = "1px solid rgb(204, 204, 204)";
    tailRightCover.classList.add('pgm-html-info-tail-right-cover');
    tailRight.appendChild(tailRightCover);

    var eraseBorder = document.createElement("div");
    eraseBorder.style.position = "absolute";
    eraseBorder.style.zIndex = 3;
    eraseBorder.style.backgroundColor = "white";
    eraseBorder.style.width = "27px";
    eraseBorder.style.height = "2px";
    eraseBorder.style.top = "-1px";
    eraseBorder.style.left = "50%";
    eraseBorder.style.marginLeft = "-13px";
    eraseBorder.classList.add('pgm-html-info-tail-erase-border');
    tailFrame.appendChild(eraseBorder);

    var calculate = function() {

      var marker = self.get("marker");
      var map = marker.getMap();

      var div = map.getDiv();

      var frame = self.get("frame");
      var contentFrame = frame.firstChild;
      var contentBox = contentFrame.firstChild;
      contentBox.style.minWidth = "100px";
      contentBox.style.minHeight = "50px";

      var content = self.get("content");
      if (typeof content === "string") {
          contentBox.style.whiteSpace="pre-wrap";
          contentBox.innerHTML = content;
      } else {
          if (!content) {
            contentBox.innerText = "";
          } else if (content.nodeType === 1) {
            contentBox.innerHTML = "";
            contentBox.appendChild(content);
          } else {
            contentBox.innerText = content;
          }
      }

      // Insert the contents to this HTMLInfoWindow
      if (!frame.parentNode) {
          div.appendChild(frame);
      }

      // Adjust the HTMLInfoWindow size
      var contentsWidth = contentBox.offsetWidth + 10; // padding 5px x 2
      self.set("contentsWidth", contentsWidth);
      var contentsHeight = contentBox.offsetHeight;
      self.set("contentsHeight", contentsHeight );
      contentFrame.style.width = contentsWidth + "px";
      contentFrame.style.height = contentsHeight + "px";
      frame.style.width = contentsWidth  + "px";
      frame.style.height = (contentsHeight+ 15) + "px";

      var infoOffset = {
        y : 0.25,
        x : 0.5
      };

      var iconSize = {
        width: 28,
        height: 63
      };

      var icon = marker.get("icon");
      if (typeof icon === "object") {
          if (typeof icon.size === "object") {
              iconSize.width = icon.size.width;
              iconSize.height = icon.size.height;
          }
          if (typeof icon.url === "string" && icon.url.indexOf("data:image/") === 0) {
              var img = document.createElement("img");
              img.src = icon.url;
              iconSize.width = img.width;
              iconSize.height = img.height;
          }

      }
      var infoWindowAnchor = marker.get("infoWindowAnchor");
      if (utils.isArray(infoWindowAnchor)) {
        infoOffset.x = infoWindowAnchor[0] / icon.size.width;
        infoOffset.x = infoOffset.x > 1 ? 1 : infoOffset.x;
        infoOffset.x = infoOffset.x < 0 ? 0 : infoOffset.x;
        infoOffset.y = infoWindowAnchor[1] / icon.size.height;
        infoOffset.y = infoOffset.y > 1 ? 1 : infoOffset.y;
        infoOffset.y = infoOffset.y < 0 ? 0 : infoOffset.y;
      }
      infoOffset.y *= iconSize.height;
      infoOffset.x = (infoOffset.x - 0.5) * iconSize.width;

      //console.log("contentsSize = " + contentsWidth + ", " + contentsHeight);
      //console.log("iconSize = " + iconSize.width + ", " + iconSize.height);
      //console.log("infoOffset = " + infoOffset.x + ", " + infoOffset.y);

      var frameBorder = parseInt(common.getStyle(contentFrame, "border-left-width").replace(/[^\d]/g, ""), 10);
      var offsetX = contentsWidth / 2  - infoOffset.x + frameBorder;
      var offsetY = contentsHeight  - infoOffset.y + iconSize.height;

      self.set("offsetX", offsetX);
      self.set("offsetY", offsetY);

      //console.log("offset = " + self.get("offsetX") + ", " + self.get("offsetY"));
      var infoPosition = map.get("infoPosition");
      self.trigger("infoPosition_changed", "", infoPosition);
    };

    var isInfoOpenFired = false;

    self.on("infoPosition_changed", function(ignore, point) {

        var x = point.x - self.get("offsetX");
        var y = point.y - self.get("offsetY");
        //console.log("offset = " + x + ", " + y);

        frame.style.left = x + "px";
        frame.style.top =  y + "px";

        if (!isInfoOpenFired) {
            isInfoOpenFired = true;
            self.trigger(event.INFO_OPEN);
        }

        cordova.fireDocumentEvent('plugin_touch', {});
    });
    self.on(event.INFO_CLOSE, function() {
        isInfoOpenFired = false;
    });
    self.on("infoWindowAnchor_changed", calculate);
    self.on("icon_changed", calculate);

    self.set("isInfoWindowVisible", false);

};

utils.extend(HTMLInfoWindow, BaseClass);

HTMLInfoWindow.prototype.isInfoWindowShown = function() {
    return this.get("isInfoWindowVisible") === true;
};

HTMLInfoWindow.prototype.close = function() {
    var self = this;

    var marker = self.get("marker");
    if (marker) {
      self.off("isInfoWindowVisible_changed");
    }
    if (!self.isInfoWindowShown() || !marker) {
      return;
    }
    self.set("isInfoWindowVisible", false);
    marker.set("isInfoWindowVisible", false);
    marker.set("infoWindow", undefined);
    this.set('marker', undefined);

    var map = marker.getMap();
    map.off("infoPosition_changed");
    marker.off("icon_changed");
    marker.off("infoWindowAnchor_changed");
    self.trigger(event.INFO_CLOSE);
    marker.off(event.INFO_CLOSE, self.close);  //This event listener is assigned in the open method. So detach it.
    map.set("active_marker_id", null);

    var div = map.getDiv();
    var frame = self.get("frame");
    div.removeChild(frame);

    // Remove the contents from this HTMLInfoWindow
    var contentFrame = frame.firstChild;
    var contentBox = contentFrame.firstChild;
    contentBox.innerHTML = "";
};

HTMLInfoWindow.prototype.setContent = function(content) {
    var self = this;
    var prevContent = self.get("content");
    self.set("content", content);
    var marker = self.get("marker");
    if (content !== prevContent && marker && marker.isInfoWindowShown()) {
      self.trigger("infoWindowAnchor_changed");
    }
};

HTMLInfoWindow.prototype.open = function(marker) {
    if (!marker) {
        return;
    }
    if (marker._objectInstance) {
      // marker is an instance of the ionic-native wrapper plugin.
      marker = marker._objectInstance;
    }

    var map = marker.getMap();
    var self = this,
      markerId = marker.getId();

    marker.set("infoWindow", self);
    marker.set("isInfoWindowVisible", true);
    self.set("isInfoWindowVisible", true);
    marker.one("isInfoWindowVisible_changed", function() {
      self.close.call(self);
    });

    map.fromLatLngToPoint(marker.getPosition(), function(point) {
        map.set("infoPosition", {x: point[0], y: point[1]});

        map.bindTo("infoPosition", self);
        marker.bindTo("infoWindowAnchor", self);
        marker.bindTo("icon", self);
        marker.one(event.INFO_CLOSE, self.close.bind(self));
        self.set("marker", marker);
        map.set("active_marker_id", marker.getId());
        self.trigger.call(self, "infoWindowAnchor_changed");
    });
};

HTMLInfoWindow.prototype.setBackgroundColor = function(backgroundColor) {
  this.get("frame").children[0].style.backgroundColor = backgroundColor;
  this.get("frame").children[1].children[0].children[0].style.backgroundColor = backgroundColor;
  this.get("frame").children[1].children[1].children[0].style.backgroundColor = backgroundColor;
  this.get("frame").children[1].children[2].style.backgroundColor = backgroundColor;
};

module.exports = HTMLInfoWindow;
<|endoftext|>