<commit_before>
var fs = require('fs');
var util = require('util');
var async = require('async');
var stream = require('stream');
var crypto = require('crypto');
var endpoint = require('endpoint');

function BundleStream(box, from, request, acquired) {
  stream.Transform.call(this);

  var self = this;

  // parent ref
  this.box = box;

  // track query and acquired files
  this._acquired = acquired;
  this._query = [];

  // write wrap flags
  this._first = true;
  this._prepend = false;
  this._append = false;

  // state write content
  // some writes methods require some extra data, that is stored here
  this._initError = null;
  this._startpath = null;
  this._filepath = null;
  this._resolved = {};

  // resolve startpath
  this.box._localizer(from, request, function (err, resolved) {
    // A localizer errors is treaded as a warning, since the client
    // will be able to deal with it. Note that an init error is a special
    // case, since it can't be asociated with a filepath
    if (err) {
      self.emit('warning', err);
      self._initError = err;
      return self._next();
    }

    // Store resolved filepath
    self._startpath = resolved;

    // create a map between request and resolved filepath and add it
    // to the query list
    if (self._acquired.indexOf(resolved) === -1) {
      self._query.push(resolved);
    }

    // start file streaming
    self._getMeta(function (err, meta) {
      if (err) {
        self.emit('warning', err);
        self._initError = err;
        return self._next();
      }

      self.emit('meta', meta);
      self._next();
    });
  });
}
util.inherits(BundleStream, stream.Transform);
module.exports = BundleStream;

BundleStream.prototype._getMeta = function (callback) {
  if (!this._startpath) return callback(this._initError, null);

  this.box._getMeta(this._startpath, this._acquired, callback);
};

BundleStream.prototype._transform = function (chunk, send, callback) {
  this._writeHeader(send);
  this._writeFileEnd(send);
  this._writeFileStart(send);

  callback(null, chunk);
};

BundleStream.prototype._flush = function (send, callback) {
  // In rare cases, nothing has been writen and the header will need to be
  // send in the flush
  this._writeHeader(send);

  this._writeFileEnd(send);
  this._writeFooter(send);

  callback(null);
};

// Predefine some XML datachunks
var DATA_CHUNK = {
  xml: new Buffer('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n'),
  modules: {
    start: new Buffer('<modules>\n'),
    end: new Buffer('</modules>')
  },
  file: {
    startLeft: new Buffer('<file path="'),
    startRight: new Buffer('"><![CDATA['),
    end: new Buffer(']]></file>\n')
  },
  resolve: {
    start: new Buffer('<resolve>'),
    end: '</resolve>\n'
  },
  map: {
    start: new Buffer('<map>'),
    end: '</map>\n'
  },
  error: {
    start: new Buffer('<error>'),
    end: '</error>\n'
  }
};

BundleStream.prototype._writeHeader = function (send) {
  if (!this._first) return;
  this._first = false;

  // writes:
  // <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  // <modules>
  send(DATA_CHUNK.xml);
  send(DATA_CHUNK.modules.start);

  // writes init error as an <error> element, if such init error exists
  if (this._initError) {
    var errorObject = {
      message: this._initError.message,
      code: this._initError.code,
      name: this._initError.name
    };

    send(DATA_CHUNK.error.start);
    send(new Buffer(JSON.stringify(errorObject)));
    send(DATA_CHUNK.error.end);

    return;
  }

  // write resolved path for input
  send(DATA_CHUNK.resolve.start);
  send(new Buffer(this._startpath));
  send(DATA_CHUNK.resolve.end);
};

BundleStream.prototype._writeFooter = function (send) {
  // writes: <map>{{resolved}}</map>
  send(DATA_CHUNK.map.start);
  send(new Buffer( JSON.stringify(this._resolved) ));
  send(DATA_CHUNK.map.end);

  // writes: </modules>
  send(DATA_CHUNK.modules.end);
};

BundleStream.prototype._writeFileStart = function (send) {
  if (!this._prepend) return;
  this._prepend = false;

  // writes: <file path="{{filepath}}"><![CDATA[
  send(DATA_CHUNK.file.startLeft);
  send(new Buffer( this._filepath ));
  send(DATA_CHUNK.file.startRight);
};

BundleStream.prototype._writeFileEnd = function (send) {
  if (!this._append) return;
  this._append = false;

  // writes: ]]></file>
  send(DATA_CHUNK.file.end);
};

// add dependencies to query
BundleStream.prototype._push = function (filepath, dependencies) {
  // The dependencies format is `input:require.resolve(input)`
  var keys = Object.keys(dependencies);

  // Don't do anything, if there are no dependencies. This also prevents
  // superfluous data from being send. Otherwice `"/longfilename.ext": {}`
  // would be stored in the resolved map object.
  if (keys.length === 0) return;

  // Add dependencies map to the bottom of the stream, by adding them
  // to a temporary object here.
  this._resolved[filepath] = dependencies;

  // Add dependencies to query.
  for (var i = 0; i < keys.length; i++) {
    var resolved = dependencies[ keys[i] ];

    // Input could not be translated to a filepath
    if (typeof resolved !== 'string') continue;

    if (this._acquired.indexOf(resolved) === -1 &&
        this._query.indexOf(resolved) === -1) {
      this._query.push(resolved);
    }
  }
};

// start next file stream
BundleStream.prototype._next = function () {
  var self = this;

  // first flag, set to false when the first chunk is writen
  var first = this._first;

  // prepear for read, by setting flags
  if (!first) this._append = true;
  this._prepend = true;

  // this._flush will be called if there are no more files in the query
  if (this._query.length === 0) return this.end();

  // get the next filepath
  var filepath = this._query.shift();
  var realpath = this.box._realpath(filepath);

  // update stored filepath and make sure it won't be send again
  this._filepath = filepath;
  this._acquired.push(filepath);

  // create a new file read stream
  var file = fs.createReadStream(realpath);

  // if dependencies for this file hasn't been resolved before, buffer the
  // result and resolve/save them.
  if (this.box._getCache(filepath) === null) {
    async.parallel({
      stat: function (callback) {
        fs.stat(realpath, function (err, stat) {
          if (err) {
            self.emit('error', err);
            return callback(null);
          }

          callback(null, stat);
        });
      },

      hash: function (callback) {
        file.pipe(crypto.createHash('md5')).pipe(endpoint(function (err, hash) {
          // this error will be emitted by the other pipe, so just ignore here.
          // Note, this is a real error not a warning, since it is completly
          // unknown what the error is.
          // However the next file will be opended, in case the user decides to
          // continue.
          callback(null, hash);
        }));
      },

      resolved: function (callback) {
        file.pipe(endpoint(function (err, content) {
          // Again error is ignored here too to prevent double emit
          if (err) return callback(null);

          // construct resolve map from filepath and file content
          self.box._scanFile(filepath, content, function (errors, resolveMap) {
            // Error is either null or an array of errors
            // Note that scan errors don't stop the module bundle to be build and
            // are therefor emitted as a warning
            if (errors) errors.forEach(self.emit.bind(self, 'warning'));

            // save resolved dependencies in cache
            callback(null, resolveMap);
          });
        }));
      }
    }, function (err, data) {
      // Error is handled in each parallel method, so they are ignored here

      // Check that all types of cache data could be fetched
      if (data.stat && data.hash && data.resolved) {
        self.box._setCache(filepath, {
          resolved: data.resolved,
          hash: data.hash,
          mtime: data.stat.mtime.getTime()
        });
      }

      nextFile();
    });
  } else {
    file.once('end', nextFile);
  }

  // pipe the file to this stream, thereby calling this._transform
  // since it is unknown if there are more dependencies, the end event is not
  // relayed.
  file.pipe(this, {end: false});

  // once the file read is done, dependencies should be added to the query
  // and the next file should be read
  function nextFile() {
    self._push(filepath, self.box._getCache(filepath).resolved);
    self._next();
  }
};
<commit_msg>[fix] error handling in bad mtime fetching<commit_after>
var fs = require('fs');
var util = require('util');
var async = require('async');
var stream = require('stream');
var crypto = require('crypto');
var endpoint = require('endpoint');

function BundleStream(box, from, request, acquired) {
  stream.Transform.call(this);

  var self = this;

  // parent ref
  this.box = box;

  // track query and acquired files
  this._acquired = acquired;
  this._query = [];

  // write wrap flags
  this._first = true;
  this._prepend = false;
  this._append = false;

  // state write content
  // some writes methods require some extra data, that is stored here
  this._initError = null;
  this._startpath = null;
  this._filepath = null;
  this._resolved = {};

  // resolve startpath
  this.box._localizer(from, request, function (err, resolved) {
    // A localizer errors is treaded as a warning, since the client
    // will be able to deal with it. Note that an init error is a special
    // case, since it can't be asociated with a filepath
    if (err) {
      self.emit('warning', err);
      self._initError = err;
      return self._next();
    }

    // Store resolved filepath
    self._startpath = resolved;

    // create a map between request and resolved filepath and add it
    // to the query list
    if (self._acquired.indexOf(resolved) === -1) {
      self._query.push(resolved);
    }

    // start file streaming
    self._getMeta(function (err, meta) {
      if (err) {
        self.emit('warning', err);
        self._initError = err;
        return self._next();
      }

      self.emit('meta', meta);
      self._next();
    });
  });
}
util.inherits(BundleStream, stream.Transform);
module.exports = BundleStream;

BundleStream.prototype._getMeta = function (callback) {
  if (!this._startpath) return callback(this._initError, null);

  this.box._getMeta(this._startpath, this._acquired, callback);
};

BundleStream.prototype._transform = function (chunk, send, callback) {
  this._writeHeader(send);
  this._writeFileEnd(send);
  this._writeFileStart(send);

  callback(null, chunk);
};

BundleStream.prototype._flush = function (send, callback) {
  // In rare cases, nothing has been writen and the header will need to be
  // send in the flush
  this._writeHeader(send);

  this._writeFileEnd(send);
  this._writeFooter(send);

  callback(null);
};

// Predefine some XML datachunks
var DATA_CHUNK = {
  xml: new Buffer('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n'),
  modules: {
    start: new Buffer('<modules>\n'),
    end: new Buffer('</modules>')
  },
  file: {
    startLeft: new Buffer('<file path="'),
    startRight: new Buffer('"><![CDATA['),
    end: new Buffer(']]></file>\n')
  },
  resolve: {
    start: new Buffer('<resolve>'),
    end: '</resolve>\n'
  },
  map: {
    start: new Buffer('<map>'),
    end: '</map>\n'
  },
  error: {
    start: new Buffer('<error>'),
    end: '</error>\n'
  }
};

BundleStream.prototype._writeHeader = function (send) {
  if (!this._first) return;
  this._first = false;

  // writes:
  // <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  // <modules>
  send(DATA_CHUNK.xml);
  send(DATA_CHUNK.modules.start);

  // writes init error as an <error> element, if such init error exists
  if (this._initError) {
    var errorObject = {
      message: this._initError.message,
      code: this._initError.code,
      name: this._initError.name
    };

    send(DATA_CHUNK.error.start);
    send(new Buffer(JSON.stringify(errorObject)));
    send(DATA_CHUNK.error.end);

    return;
  }

  // write resolved path for input
  send(DATA_CHUNK.resolve.start);
  send(new Buffer(this._startpath));
  send(DATA_CHUNK.resolve.end);
};

BundleStream.prototype._writeFooter = function (send) {
  // writes: <map>{{resolved}}</map>
  send(DATA_CHUNK.map.start);
  send(new Buffer( JSON.stringify(this._resolved) ));
  send(DATA_CHUNK.map.end);

  // writes: </modules>
  send(DATA_CHUNK.modules.end);
};

BundleStream.prototype._writeFileStart = function (send) {
  if (!this._prepend) return;
  this._prepend = false;

  // writes: <file path="{{filepath}}"><![CDATA[
  send(DATA_CHUNK.file.startLeft);
  send(new Buffer( this._filepath ));
  send(DATA_CHUNK.file.startRight);
};

BundleStream.prototype._writeFileEnd = function (send) {
  if (!this._append) return;
  this._append = false;

  // writes: ]]></file>
  send(DATA_CHUNK.file.end);
};

// add dependencies to query
BundleStream.prototype._push = function (filepath, dependencies) {
  // The dependencies format is `input:require.resolve(input)`
  var keys = Object.keys(dependencies);

  // Don't do anything, if there are no dependencies. This also prevents
  // superfluous data from being send. Otherwice `"/longfilename.ext": {}`
  // would be stored in the resolved map object.
  if (keys.length === 0) return;

  // Add dependencies map to the bottom of the stream, by adding them
  // to a temporary object here.
  this._resolved[filepath] = dependencies;

  // Add dependencies to query.
  for (var i = 0; i < keys.length; i++) {
    var resolved = dependencies[ keys[i] ];

    // Input could not be translated to a filepath
    if (typeof resolved !== 'string') continue;

    if (this._acquired.indexOf(resolved) === -1 &&
        this._query.indexOf(resolved) === -1) {
      this._query.push(resolved);
    }
  }
};

// start next file stream
BundleStream.prototype._next = function () {
  var self = this;

  // first flag, set to false when the first chunk is writen
  var first = this._first;

  // prepear for read, by setting flags
  if (!first) this._append = true;
  this._prepend = true;

  // this._flush will be called if there are no more files in the query
  if (this._query.length === 0) return this.end();

  // get the next filepath
  var filepath = this._query.shift();
  var realpath = this.box._realpath(filepath);

  // update stored filepath and make sure it won't be send again
  this._filepath = filepath;
  this._acquired.push(filepath);

  // create a new file read stream
  var file = fs.createReadStream(realpath);

  // if dependencies for this file hasn't been resolved before, buffer the
  // result and resolve/save them.
  if (this.box._getCache(filepath) === null) {
    async.parallel({
      stat: function (callback) {
        fs.stat(realpath, function (err, stat) {
          if (err) {
            self.emit('error', err);
            return callback(null);
          }

          callback(null, stat);
        });
      },

      hash: function (callback) {
        file.pipe(crypto.createHash('md5')).pipe(endpoint(function (err, hash) {
          // this error will be emitted by the other pipe, so just ignore here.
          // Note, this is a real error not a warning, since it is completly
          // unknown what the error is.
          // However the next file will be opended, in case the user decides to
          // continue.
          callback(null, hash);
        }));
      },

      resolved: function (callback) {
        file.pipe(endpoint(function (err, content) {
          // Again error is ignored here too to prevent double emit
          if (err) return callback(null);

          // construct resolve map from filepath and file content
          self.box._scanFile(filepath, content, function (errors, resolveMap) {
            // Error is either null or an array of errors
            // Note that scan errors don't stop the module bundle to be build and
            // are therefor emitted as a warning
            if (errors) errors.forEach(self.emit.bind(self, 'warning'));

            // save resolved dependencies in cache
            callback(null, resolveMap);
          });
        }));
      }
    }, function (err, data) {
      // Error is handled in each parallel method, so they are ignored here

      // Check that all types of cache data could be fetched
      if (data.stat && data.hash && data.resolved) {
        self.box._setCache(filepath, {
          resolved: data.resolved,
          hash: data.hash,
          mtime: data.stat.mtime.getTime()
        });
      }

      nextFile(data.resolved);
    });
  } else {
    file.once('end', nextFile.bind(file, self.box._getCache(filepath).resolved));
  }

  // pipe the file to this stream, thereby calling this._transform
  // since it is unknown if there are more dependencies, the end event is not
  // relayed.
  file.pipe(this, {end: false});

  // once the file read is done, dependencies should be added to the query
  // and the next file should be read
  function nextFile(resolved) {
    self._push(filepath, resolved);
    self._next();
  }
};
<|endoftext|>


<commit_before>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org/
 *
 */
(function (api) {
    /*
     * PRIVATE STUFF
     */

    // Match vendor and product codes for Firefox
    var vendorProductRE = /^([0-9a-f]{1,4})-([0-9a-f]{1,4})-/i;

    // Match leading zeros
    var leadingZeroRE = /^0+/;

    /**
     * Firefox reports different ids for gamepads depending on the platform:
     * - Windows: vendor and product codes contain leading zeroes
     * - Mac: vendor and product codes are sparse (no leading zeroes)
     *
     * This function normalizes the id to support both formats
     * @ignore
     */
    function addMapping(id, mapping) {
        var expanded_id = id.replace(vendorProductRE, function (_, a, b) {
            return (
                "000".substr(a.length - 1) + a + "-" +
                "000".substr(b.length - 1) + b + "-"
            );
        });
        var sparse_id = id.replace(vendorProductRE, function (_, a, b) {
            return (
                a.replace(leadingZeroRE, "") + "-" +
                b.replace(leadingZeroRE, "") + "-"
            );
        });

        remap.set(expanded_id, mapping);
        remap.set(sparse_id, mapping);
    }

    // binding list
    var bindings = {};

    // mapping list
    var remap = new Map();

    /**
     * Default gamepad mappings
     * @ignore
     */
    [
        // Firefox mappings
        [
            "45e-28e-Xbox 360 Wired Controller",
            {
                "axes" : [ 0, 1, 3, 4, 2, 5 ],
                "buttons" : [ 11, 12, 13, 14, 8, 9, -1, -1, 5, 4, 6, 7, 0, 1, 2, 3, 10 ]
            }
        ],
        [
            "54c-268-PLAYSTATION(R)3 Controller",
            {
                "axes" : [ 0, 1, 2, 3, -1, -1 ],
                "buttons" : [ 14, 13, 15, 12, 10, 11, 8, 9, 0, 3, 1, 2, 4, 6, 7, 5, 16 ]
            }
        ],
        [
            "54c-5c4-Wireless Controller", // PS4 Controller
            {
                "axes" : [ 0, 1, 2, 3, -1, -1 ],
                "buttons" : [ 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 12, 13]
            }
        ],
        [
            "2836-1-OUYA Game Controller",
            {
                "axes" : [ 0, 3, 7, 9, 5, 11 ],
                "buttons" : [ 3, 6, 4, 5, 7, 8, 15, 16, -1, -1, 9, 10, 11, 12, 13, 14, -1 ]
            }
        ],

        // Chrome mappings
        [
            "OUYA Game Controller (Vendor: 2836 Product: 0001)",
            {
                "axes" : [ 0, 1, 3, 4, 2, 5 ],
                "buttons" : [ 0, 3, 1, 2, 4, 5, 12, 13, -1, -1, 6, 7, 8, 9, 10, 11, -1 ]
            }
        ]
    ].forEach(function (value) {
        addMapping(value[0], value[1]);
    });

    /**
     * gamepad connected callback
     * @ignore
     */
     api._onGamepadConnected = function (event) {
        me.event.publish(me.event.GAMEPAD_CONNECTED, [ event.gamepad ]);
     };

    /**
     * gamepad disconnected callback
     * @ignore
     */
     api._onGamepadDisconnected = function (event) {
        me.event.publish(me.event.GAMEPAD_DISCONNECTED, [ event.gamepad ]);
     };

    window.addEventListener("gamepadconnected", api._onGamepadConnected.bind(api), false);
    window.addEventListener("gamepaddisconnected", api._onGamepadDisconnected.bind(api), false);

    /**
     * Update gamepad status
     * @ignore
     */
    api._updateGamepads = navigator.getGamepads ? function () {
        var gamepads = navigator.getGamepads();
        var mapping;
        var e = {};

        // Trigger button bindings
        Object.keys(bindings).forEach(function (index) {
            if (!gamepads[index]) {
                return;
            }

            if (gamepads[index].mapping !== "standard") {
                mapping = remap.get(gamepads[index].id);
            }

            Object.keys(bindings[index].buttons).forEach(function (button) {
                var last = bindings[index].buttons[button];

                // Remap buttons if necessary
                if (mapping) {
                    button = mapping.buttons[button];
                    if (button < 0) {
                        return;
                    }
                }

                // Get mapped button
                var current = gamepads[index].buttons[button];

                // Edge detection
                if (!last.pressed && current.pressed) {
                    last.pressed = true;
                    api._keydown(e, last.keyCode, button + 256);
                }
                else if (last.pressed && !current.pressed) {
                    last.pressed = false;
                    api._keyup(e, last.keyCode, button + 256);
                }
            });
        });
    } : function () {};

    /*
     * PUBLIC STUFF
     */

    /**
     * Standard gamepad mapping information

     * Axes:

     *

     *
Left control stick: LX, LY

     *
Right control stick: RX, RY

     *
Left trigger: LT

     *
Right trigger: RT

     *

     * Buttons:

     *

     *
Face buttons: FACE_1, FACE_2, FACE_3, FACE_4

     *
D-Pad: UP, DOWN, LEFT, RIGHT

     *
Shoulder buttons: L1, L2, R1, R2

     *
Analog stick (clicks): L3, R3

     *
Navigation: SELECT (BACK), START (FORWARD), HOME

     *
Extras: EXTRA_1, EXTRA_2, EXTRA_3, EXTRA_4

     *

     * @public
     * @name GAMEPAD
     * @enum {Number}
     * @memberOf me.input
     * @see https://w3c.github.io/gamepad/#remapping
     */
    api.GAMEPAD = {
        // Axes
        "LX"        : 0,
        "LY"        : 1,
        "RX"        : 2,
        "RY"        : 3,
        "LT"        : 4,
        "RT"        : 5,

        // Buttons
        "FACE_1"    : 0,
        "FACE_2"    : 1,
        "FACE_3"    : 2,
        "FACE_4"    : 3,
        "L1"        : 4,
        "L2"        : 5,
        "R1"        : 6,
        "R2"        : 7,
        "SELECT"    : 8,
        "BACK"      : 8,
        "START"     : 9,
        "FORWARD"   : 9,
        "L3"        : 10,
        "R3"        : 11,
        "UP"        : 12,
        "DOWN"      : 13,
        "LEFT"      : 14,
        "RIGHT"     : 15,
        "HOME"      : 16,
        "EXTRA_1"   : 17,
        "EXTRA_2"   : 18,
        "EXTRA_3"   : 19,
        "EXTRA_4"   : 20
    };

    /**
     * Associate a gamepad event to a keycode
     * @name bindGamepad
     * @memberOf me.input
     * @public
     * @function
     * @param {Number} index Gamepad index
     * @param {me.input.GAMEPAD} button
     * @param {me.input.KEY} keyCode
     * @example
     * // enable the keyboard
     * me.input.bindKey(me.input.KEY.X, "shoot");
     * // map the lower face button on the first gamepad to the X key
     * me.input.bindGamepad(0, me.input.GAMEPAD.FACE_1, me.input.KEY.X);
     */
    api.bindGamepad = function (index, button, keyCode) {
        // Throw an exception if no action is defined for the specified keycode
        if (!api._KeyBinding[keyCode]) {
            throw new me.Error("no action defined for keycode " + keyCode);
        }

        // Allocate bindings if not defined
        if (!bindings[index]) {
            bindings[index] = {
                "axes" : {},
                "buttons" : {}
            };
        }

        // Map the gamepad button to the keycode
        bindings[index].buttons[button] = {
            "keyCode" : keyCode,
            "pressed" : false
        };
    };

    /**
     * unbind the defined keycode
     * @name unbindGamepad
     * @memberOf me.input
     * @public
     * @function
     * @param {Number} index Gamepad index
     * @param {me.input.GAMEPAD} button
     * @example
     * me.input.unbindGamepad(0, me.input.GAMEPAD.FACE_1);
     */
    api.unbindGamepad = function (index, button) {
        if (!bindings[index]) {
            throw new me.Error("no bindings for gamepad " + index);
        }
        bindings[index].buttons[button] = {};
    };

    /**
     * specify a custom mapping for a specific gamepad id

     * see below for the default mapping :

     *

     * @name setGamepadMapping
     * @memberOf me.input
     * @public
     * @function
     * @param {String} id gamepad id string
     * @param {Number[]} axes an array of mapping
     * @param {Number[]} buttons an array of mapping
     * @param {Function} normalize_fn (RFU)
     */
    api.setGamepadMapping = function (id, axes, buttons, normalize_fn) {
        addMapping(id, {
            axes : axes,
            buttons : buttons,
            normalize_fn : normalize_fn //?
            }
        );
    };

})(me.input);
<commit_msg>[#724] updated the `setGamepadMapping` function signature to match with the ticket "specifications"<commit_after>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org/
 *
 */
(function (api) {
    /*
     * PRIVATE STUFF
     */

    // Match vendor and product codes for Firefox
    var vendorProductRE = /^([0-9a-f]{1,4})-([0-9a-f]{1,4})-/i;

    // Match leading zeros
    var leadingZeroRE = /^0+/;

    /**
     * Firefox reports different ids for gamepads depending on the platform:
     * - Windows: vendor and product codes contain leading zeroes
     * - Mac: vendor and product codes are sparse (no leading zeroes)
     *
     * This function normalizes the id to support both formats
     * @ignore
     */
    function addMapping(id, mapping) {
        var expanded_id = id.replace(vendorProductRE, function (_, a, b) {
            return (
                "000".substr(a.length - 1) + a + "-" +
                "000".substr(b.length - 1) + b + "-"
            );
        });
        var sparse_id = id.replace(vendorProductRE, function (_, a, b) {
            return (
                a.replace(leadingZeroRE, "") + "-" +
                b.replace(leadingZeroRE, "") + "-"
            );
        });

        remap.set(expanded_id, mapping);
        remap.set(sparse_id, mapping);
    }

    // binding list
    var bindings = {};

    // mapping list
    var remap = new Map();

    /**
     * Default gamepad mappings
     * @ignore
     */
    [
        // Firefox mappings
        [
            "45e-28e-Xbox 360 Wired Controller",
            {
                "axes" : [ 0, 1, 3, 4, 2, 5 ],
                "buttons" : [ 11, 12, 13, 14, 8, 9, -1, -1, 5, 4, 6, 7, 0, 1, 2, 3, 10 ]
            }
        ],
        [
            "54c-268-PLAYSTATION(R)3 Controller",
            {
                "axes" : [ 0, 1, 2, 3, -1, -1 ],
                "buttons" : [ 14, 13, 15, 12, 10, 11, 8, 9, 0, 3, 1, 2, 4, 6, 7, 5, 16 ]
            }
        ],
        [
            "54c-5c4-Wireless Controller", // PS4 Controller
            {
                "axes" : [ 0, 1, 2, 3, -1, -1 ],
                "buttons" : [ 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 12, 13]
            }
        ],
        [
            "2836-1-OUYA Game Controller",
            {
                "axes" : [ 0, 3, 7, 9, 5, 11 ],
                "buttons" : [ 3, 6, 4, 5, 7, 8, 15, 16, -1, -1, 9, 10, 11, 12, 13, 14, -1 ]
            }
        ],

        // Chrome mappings
        [
            "OUYA Game Controller (Vendor: 2836 Product: 0001)",
            {
                "axes" : [ 0, 1, 3, 4, 2, 5 ],
                "buttons" : [ 0, 3, 1, 2, 4, 5, 12, 13, -1, -1, 6, 7, 8, 9, 10, 11, -1 ]
            }
        ]
    ].forEach(function (value) {
        addMapping(value[0], value[1]);
    });

    /**
     * gamepad connected callback
     * @ignore
     */
     api._onGamepadConnected = function (event) {
        me.event.publish(me.event.GAMEPAD_CONNECTED, [ event.gamepad ]);
     };

    /**
     * gamepad disconnected callback
     * @ignore
     */
     api._onGamepadDisconnected = function (event) {
        me.event.publish(me.event.GAMEPAD_DISCONNECTED, [ event.gamepad ]);
     };

    window.addEventListener("gamepadconnected", api._onGamepadConnected.bind(api), false);
    window.addEventListener("gamepaddisconnected", api._onGamepadDisconnected.bind(api), false);

    /**
     * Update gamepad status
     * @ignore
     */
    api._updateGamepads = navigator.getGamepads ? function () {
        var gamepads = navigator.getGamepads();
        var mapping;
        var e = {};

        // Trigger button bindings
        Object.keys(bindings).forEach(function (index) {
            if (!gamepads[index]) {
                return;
            }

            if (gamepads[index].mapping !== "standard") {
                mapping = remap.get(gamepads[index].id);
            }

            Object.keys(bindings[index].buttons).forEach(function (button) {
                var last = bindings[index].buttons[button];

                // Remap buttons if necessary
                if (mapping) {
                    button = mapping.buttons[button];
                    if (button < 0) {
                        return;
                    }
                }

                // Get mapped button
                var current = gamepads[index].buttons[button];

                // Edge detection
                if (!last.pressed && current.pressed) {
                    last.pressed = true;
                    api._keydown(e, last.keyCode, button + 256);
                }
                else if (last.pressed && !current.pressed) {
                    last.pressed = false;
                    api._keyup(e, last.keyCode, button + 256);
                }
            });
        });
    } : function () {};

    /*
     * PUBLIC STUFF
     */

    /**
     * Standard gamepad mapping information

     * Axes:

     *

     *
Left control stick: LX, LY

     *
Right control stick: RX, RY

     *
Left trigger: LT

     *
Right trigger: RT

     *

     * Buttons:

     *

     *
Face buttons: FACE_1, FACE_2, FACE_3, FACE_4

     *
D-Pad: UP, DOWN, LEFT, RIGHT

     *
Shoulder buttons: L1, L2, R1, R2

     *
Analog stick (clicks): L3, R3

     *
Navigation: SELECT (BACK), START (FORWARD), HOME

     *
Extras: EXTRA_1, EXTRA_2, EXTRA_3, EXTRA_4

     *

     * @public
     * @name GAMEPAD
     * @enum {Number}
     * @memberOf me.input
     * @see https://w3c.github.io/gamepad/#remapping
     */
    api.GAMEPAD = {
        // Axes
        "LX"        : 0,
        "LY"        : 1,
        "RX"        : 2,
        "RY"        : 3,
        "LT"        : 4,
        "RT"        : 5,

        // Buttons
        "FACE_1"    : 0,
        "FACE_2"    : 1,
        "FACE_3"    : 2,
        "FACE_4"    : 3,
        "L1"        : 4,
        "L2"        : 5,
        "R1"        : 6,
        "R2"        : 7,
        "SELECT"    : 8,
        "BACK"      : 8,
        "START"     : 9,
        "FORWARD"   : 9,
        "L3"        : 10,
        "R3"        : 11,
        "UP"        : 12,
        "DOWN"      : 13,
        "LEFT"      : 14,
        "RIGHT"     : 15,
        "HOME"      : 16,
        "EXTRA_1"   : 17,
        "EXTRA_2"   : 18,
        "EXTRA_3"   : 19,
        "EXTRA_4"   : 20
    };

    /**
     * Associate a gamepad event to a keycode
     * @name bindGamepad
     * @memberOf me.input
     * @public
     * @function
     * @param {Number} index Gamepad index
     * @param {me.input.GAMEPAD} button
     * @param {me.input.KEY} keyCode
     * @example
     * // enable the keyboard
     * me.input.bindKey(me.input.KEY.X, "shoot");
     * // map the lower face button on the first gamepad to the X key
     * me.input.bindGamepad(0, me.input.GAMEPAD.FACE_1, me.input.KEY.X);
     */
    api.bindGamepad = function (index, button, keyCode) {
        // Throw an exception if no action is defined for the specified keycode
        if (!api._KeyBinding[keyCode]) {
            throw new me.Error("no action defined for keycode " + keyCode);
        }

        // Allocate bindings if not defined
        if (!bindings[index]) {
            bindings[index] = {
                "axes" : {},
                "buttons" : {}
            };
        }

        // Map the gamepad button to the keycode
        bindings[index].buttons[button] = {
            "keyCode" : keyCode,
            "pressed" : false
        };
    };

    /**
     * unbind the defined keycode
     * @name unbindGamepad
     * @memberOf me.input
     * @public
     * @function
     * @param {Number} index Gamepad index
     * @param {me.input.GAMEPAD} button
     * @example
     * me.input.unbindGamepad(0, me.input.GAMEPAD.FACE_1);
     */
    api.unbindGamepad = function (index, button) {
        if (!bindings[index]) {
            throw new me.Error("no bindings for gamepad " + index);
        }
        bindings[index].buttons[button] = {};
    };

    /**
     * specify a custom mapping for a specific gamepad id

     * see below for the default mapping :

     *

     * @name setGamepadMapping
     * @memberOf me.input
     * @public
     * @function
     * @param {String} id gamepad id string
     * @param {Object} mapping a hash table
     * @param {Number[]} mapping.axes standard analog control stick axis locations
     * @param {Number[]} mapping.buttons standard digital button locations
     * @param {Number[]} mapping.analog analog axis locations for buttons
     * @param {Function} normalize_fn a function that return a normalized value in range [-1.0..1.0], or 0.0 if the button or axis is unknown.
     */
    api.setGamepadMapping = function (id, mapping, normalize_fn) {
        addMapping(id, {
            axes : mapping.axes,
            buttons : mapping.buttons,
            normalize_fn : normalize_fn //?
            }
        );
    };

})(me.input);
<|endoftext|>


<commit_before>TC.control = TC.control || {};
TC.Control = function () {
    var self = this;

    //TC.Object.apply(self, arguments);
    self.$events = $(self);

    self.map = null;
    self.isActive = false;
    self.isDisabled = false;
    self._firstRender = $.Deferred();

    var len = arguments.length;

    self.options = $.extend({}, len > 1 ? arguments[1] : arguments[0]);
    self.div = TC.Util.getDiv(self.options.div ? self.options.div : arguments[0]);
    self._$div = $(self.div);
    self._$div.addClass(TC.Control.prototype.CLASS).addClass(self.CLASS);
    self.template = self.options.template || self.template;

    //self.render();
};

//TC.inherit(TC.Control, TC.Object);
TC.Control.prototype.on = function (events, callback) {
    var obj = this;
    obj.$events.on(events, callback);
    return obj;
};

TC.Control.prototype.one = function (events, callback) {
    var obj = this;
    obj.$events.one(events, callback);
    return obj;
};

TC.Control.prototype.off = function (events, callback) {
    var obj = this;
    obj.$events.off(events, callback);
    return obj;
};

TC.Control.prototype.CLASS = 'tc-ctl';

TC.Control.prototype.template = '';

TC.Control.prototype.show = function () {
    this._$div.show();
};

TC.Control.prototype.hide = function () {
    this._$div.hide();
};

TC.Control.prototype.render = function (callback) {
    var self = this;
    self.renderData(null, callback);
};

TC.Control.prototype.renderData = function (data, callback) {
    var self = this;
    if (self.map) {
        var e = $.Event(TC.Consts.event.BEFORECONTROLRENDER, { dataObject: data });
        self.$events.trigger(e);
    }
    self._$div.toggleClass(TC.Consts.classes.DISABLED, self.isDisabled);

    TC.loadJSInOrder(
        !window.dust,
        TC.url.templating,
        function () {
            var processTemplates = function (templates)
            {
                var ret = $.Deferred();
                var htmDefs = [];
                for (var key in templates)
                {
                    var template = templates[key];
                    if (typeof template === 'string')
                    {
                        if (dust.cache[self.CLASS]) {
                            dust.render(self.CLASS, data, function (err, out) {
                                self._$div.html(out);
                                if (err) {
                                    TC.error(err);
                                }
                            });
                        } else {
                            var def = $.ajax({
                                url: template,
                                type: "get",
                                dataType: "html"
                            });
                            def.templateKey = key;

                            htmDefs.push(def);
                        }
                    }
                    else if ($.isFunction(template))
                    {
                        template();
                    }
                }

                //si defs está vacío, resolver inmediatamente
                if (htmDefs.length == 0) ret.resolve();
                else
                {
                    $.when.apply($, htmDefs).then(function ()   //args tiene los htms
                    {
                        //si sólo había un deferred, args es arguments
                        if (arguments.length==3 && !$.isArray(arguments[0]))
                        {
                            var htm = arguments[0];
                            var key = arguments[2].templateKey;
                            var tpl = dust.compile(htm, key);
                            dust.loadSource(tpl);
                        }
                        else
                        {
                            for (var i = 0; i < arguments.length; i++)
                            {
                                var args = arguments[i];
                                var htm = args[0];
                                var key = args[2].templateKey;
                                var tpl = dust.compile(htm, key);
                                dust.loadSource(tpl);
                            }
                        }

                        ret.resolve();
                    },
                    function (a,b,c)
                    {
                        console.error("Deferred fallido");
                    });
                }

                return ret;
            };

            var tplDef;

            if (typeof self.template === 'object') {
                tplDef = processTemplates(self.template);
            }
            else {
                var templates = {};

                if(self.template) templates[self.CLASS] = self.template;

                tplDef = processTemplates(templates);
            }

            tplDef.then(function ()
            {
                if (dust.cache[self.CLASS])
                {
                    dust.render(self.CLASS, data, function (err, out)
                    {
                        self._$div.html(out);
                        if (err)
                        {
                            TC.error(err);
                        }
                    });
                }

                self._firstRender.resolve();
                self.$events.trigger($.Event(TC.Consts.event.CONTROLRENDER));
                if ($.isFunction(callback))
                {
                    callback();
                }
            });
        }
    );
};

TC.Control.prototype.getRenderedHtml = function (templateId, data, callback) {
    var self = this;
    var result = $.Deferred();
    var render = function () {
        if (dust.cache[templateId]) {
            dust.render(templateId, data, function (err, out) {
                if (err) {
                    TC.error(err);
                    result.reject();
                }
                else {
                    if ($.isFunction(callback)) {
                        callback(out);
                    }
                    result.resolve(out);
                }
            });
        }
    };
    TC.loadJSInOrder(
        !window.dust,
        TC.url.templating,
        function () {
            if (!dust.cache[templateId]) {
                var template = self.template[templateId];
                if (typeof template === 'string') {
                    $.ajax({
                        url: template,
                        type: "get",
                        dataType: "html"
                    }).done(function () {
                        var html = arguments[0];
                        var tpl = dust.compile(html, templateId);
                        dust.loadSource(tpl);
                        render();
                    });
                }
                else if ($.isFunction(template)) {
                    template();
                    render();
                }
            }
            else {
                render();
            }
        }
    );
    return result;
};

TC.Control.prototype.register = function (map) {
    var self = this;
    self.map = map;
    self.render();
    if (self.options.active) {
        self.activate();
    }
};

TC.Control.prototype.activate = function () {
    var self = this;
    if (self.map && self.map.activeControl && self.map.activeControl != self)
    {
        self.map.previousActiveControl = self.map.activeControl;
        self.map.activeControl.deactivate();
    }
    self.isActive = true;
    if (self.map) {
        self.map.activeControl = self;
        self.map.$events.trigger($.Event(TC.Consts.event.CONTROLACTIVATE, { control: self }));
        self.$events.trigger($.Event(TC.Consts.event.CONTROLACTIVATE, { control: self }));
    }
};

TC.Control.prototype.deactivate = function (stopChain)
{
    if (arguments.length == 0) stopChain = false;

    var self = this;
    self.isActive = false;
    if (self.map)
    {
        self.map.activeControl = null;

        if (!stopChain)
        {
            //determinar cuál es el control predeterminado para reactivarlo
            //salvo que sea yo mismo, claro
            var nextControl = self.map.getDefaultControl();
            if (nextControl == self) nextControl = null;
            else if(self.map.previousActiveControl == self) // GLS: Validamos antes de activar que el control activo anterior sea distinto al control actual
                nextControl = null;
            else if (!nextControl) {
                nextControl = self.map.previousActiveControl;
            }

            if (nextControl)
                nextControl.activate();
        }
        self.map.$events.trigger($.Event(TC.Consts.event.CONTROLDEACTIVATE, { control: self }));
        self.$events.trigger($.Event(TC.Consts.event.CONTROLDEACTIVATE, { control: self }));
    }
};

TC.Control.prototype.enable = function () {
    var self = this;
    self.isDisabled = false;
    if (self._$div) {
        self._$div.removeClass(TC.Consts.classes.DISABLED);
    }
};

TC.Control.prototype.disable = function () {
    var self = this;
    self.isDisabled = true;
    if (self._$div) {
        self._$div.addClass(TC.Consts.classes.DISABLED);
    }
};

TC.Control.prototype.renderPromise = function ()
{
    return this._firstRender;
};

TC.Control.prototype.isExclusive = function () {
    return false;
};

TC.Control.prototype.getLocaleString = function (key, texts) {
    var self = this;
    var locale = self.map ? self.map.options.locale : TC.Cfg.locale;
    return TC.Util.getLocaleString(locale, key, texts);
};<commit_msg>Add provisional exception to ThreeD control deactivation<commit_after>TC.control = TC.control || {};
TC.Control = function () {
    var self = this;

    //TC.Object.apply(self, arguments);
    self.$events = $(self);

    self.map = null;
    self.isActive = false;
    self.isDisabled = false;
    self._firstRender = $.Deferred();

    var len = arguments.length;

    self.options = $.extend({}, len > 1 ? arguments[1] : arguments[0]);
    self.div = TC.Util.getDiv(self.options.div ? self.options.div : arguments[0]);
    self._$div = $(self.div);
    self._$div.addClass(TC.Control.prototype.CLASS).addClass(self.CLASS);
    self.template = self.options.template || self.template;

    //self.render();
};

//TC.inherit(TC.Control, TC.Object);
TC.Control.prototype.on = function (events, callback) {
    var obj = this;
    obj.$events.on(events, callback);
    return obj;
};

TC.Control.prototype.one = function (events, callback) {
    var obj = this;
    obj.$events.one(events, callback);
    return obj;
};

TC.Control.prototype.off = function (events, callback) {
    var obj = this;
    obj.$events.off(events, callback);
    return obj;
};

TC.Control.prototype.CLASS = 'tc-ctl';

TC.Control.prototype.template = '';

TC.Control.prototype.show = function () {
    this._$div.show();
};

TC.Control.prototype.hide = function () {
    this._$div.hide();
};

TC.Control.prototype.render = function (callback) {
    var self = this;
    self.renderData(null, callback);
};

TC.Control.prototype.renderData = function (data, callback) {
    var self = this;
    if (self.map) {
        var e = $.Event(TC.Consts.event.BEFORECONTROLRENDER, { dataObject: data });
        self.$events.trigger(e);
    }
    self._$div.toggleClass(TC.Consts.classes.DISABLED, self.isDisabled);

    TC.loadJSInOrder(
        !window.dust,
        TC.url.templating,
        function () {
            var processTemplates = function (templates)
            {
                var ret = $.Deferred();
                var htmDefs = [];
                for (var key in templates)
                {
                    var template = templates[key];
                    if (typeof template === 'string')
                    {
                        if (dust.cache[self.CLASS]) {
                            dust.render(self.CLASS, data, function (err, out) {
                                self._$div.html(out);
                                if (err) {
                                    TC.error(err);
                                }
                            });
                        } else {
                            var def = $.ajax({
                                url: template,
                                type: "get",
                                dataType: "html"
                            });
                            def.templateKey = key;

                            htmDefs.push(def);
                        }
                    }
                    else if ($.isFunction(template))
                    {
                        template();
                    }
                }

                //si defs está vacío, resolver inmediatamente
                if (htmDefs.length == 0) ret.resolve();
                else
                {
                    $.when.apply($, htmDefs).then(function ()   //args tiene los htms
                    {
                        //si sólo había un deferred, args es arguments
                        if (arguments.length==3 && !$.isArray(arguments[0]))
                        {
                            var htm = arguments[0];
                            var key = arguments[2].templateKey;
                            var tpl = dust.compile(htm, key);
                            dust.loadSource(tpl);
                        }
                        else
                        {
                            for (var i = 0; i < arguments.length; i++)
                            {
                                var args = arguments[i];
                                var htm = args[0];
                                var key = args[2].templateKey;
                                var tpl = dust.compile(htm, key);
                                dust.loadSource(tpl);
                            }
                        }

                        ret.resolve();
                    },
                    function (a,b,c)
                    {
                        console.error("Deferred fallido");
                    });
                }

                return ret;
            };

            var tplDef;

            if (typeof self.template === 'object') {
                tplDef = processTemplates(self.template);
            }
            else {
                var templates = {};

                if(self.template) templates[self.CLASS] = self.template;

                tplDef = processTemplates(templates);
            }

            tplDef.then(function ()
            {
                if (dust.cache[self.CLASS])
                {
                    dust.render(self.CLASS, data, function (err, out)
                    {
                        self._$div.html(out);
                        if (err)
                        {
                            TC.error(err);
                        }
                    });
                }

                self._firstRender.resolve();
                self.$events.trigger($.Event(TC.Consts.event.CONTROLRENDER));
                if ($.isFunction(callback))
                {
                    callback();
                }
            });
        }
    );
};

TC.Control.prototype.getRenderedHtml = function (templateId, data, callback) {
    var self = this;
    var result = $.Deferred();
    var render = function () {
        if (dust.cache[templateId]) {
            dust.render(templateId, data, function (err, out) {
                if (err) {
                    TC.error(err);
                    result.reject();
                }
                else {
                    if ($.isFunction(callback)) {
                        callback(out);
                    }
                    result.resolve(out);
                }
            });
        }
    };
    TC.loadJSInOrder(
        !window.dust,
        TC.url.templating,
        function () {
            if (!dust.cache[templateId]) {
                var template = self.template[templateId];
                if (typeof template === 'string') {
                    $.ajax({
                        url: template,
                        type: "get",
                        dataType: "html"
                    }).done(function () {
                        var html = arguments[0];
                        var tpl = dust.compile(html, templateId);
                        dust.loadSource(tpl);
                        render();
                    });
                }
                else if ($.isFunction(template)) {
                    template();
                    render();
                }
            }
            else {
                render();
            }
        }
    );
    return result;
};

TC.Control.prototype.register = function (map) {
    var self = this;
    self.map = map;
    self.render();
    if (self.options.active) {
        self.activate();
    }
};

TC.Control.prototype.activate = function () {
    var self = this;
    if (self.map && self.map.activeControl && self.map.activeControl != self)
    {
        self.map.previousActiveControl = self.map.activeControl;

        /* provisional hasta que el 3D deje de ser un control */
        if (!(self instanceof TC.control.ThreeD)) {
            self.map.activeControl.deactivate();
        }
    }
    self.isActive = true;
    if (self.map) {
        self.map.activeControl = self;
        self.map.$events.trigger($.Event(TC.Consts.event.CONTROLACTIVATE, { control: self }));
        self.$events.trigger($.Event(TC.Consts.event.CONTROLACTIVATE, { control: self }));
    }
};

TC.Control.prototype.deactivate = function (stopChain)
{
    if (arguments.length == 0) stopChain = false;

    var self = this;
    self.isActive = false;
    if (self.map)
    {
        self.map.activeControl = null;

        if (!stopChain)
        {
            //determinar cuál es el control predeterminado para reactivarlo
            //salvo que sea yo mismo, claro
            var nextControl = self.map.getDefaultControl();
            if (nextControl == self) nextControl = null;
            else if(self.map.previousActiveControl == self) // GLS: Validamos antes de activar que el control activo anterior sea distinto al control actual
                nextControl = null;
            else if (!nextControl) {
                nextControl = self.map.previousActiveControl;
            }

            if (nextControl)
                nextControl.activate();
        }
        self.map.$events.trigger($.Event(TC.Consts.event.CONTROLDEACTIVATE, { control: self }));
        self.$events.trigger($.Event(TC.Consts.event.CONTROLDEACTIVATE, { control: self }));
    }
};

TC.Control.prototype.enable = function () {
    var self = this;
    self.isDisabled = false;
    if (self._$div) {
        self._$div.removeClass(TC.Consts.classes.DISABLED);
    }
};

TC.Control.prototype.disable = function () {
    var self = this;
    self.isDisabled = true;
    if (self._$div) {
        self._$div.addClass(TC.Consts.classes.DISABLED);
    }
};

TC.Control.prototype.renderPromise = function ()
{
    return this._firstRender;
};

TC.Control.prototype.isExclusive = function () {
    return false;
};

TC.Control.prototype.getLocaleString = function (key, texts) {
    var self = this;
    var locale = self.map ? self.map.options.locale : TC.Cfg.locale;
    return TC.Util.getLocaleString(locale, key, texts);
};<|endoftext|>


<commit_before>var Board = require("../lib/board.js");
var Pins = Board.Pins;
var __ = require("../lib/fn.js");
var events = require("events");
var util = require("util");

// Button instance private data
var priv = new Map(),
  aliases = {
    down: ["down", "press", "tap", "impact", "hit"],
    up: ["up", "release"]
  },
  // Create a 5 ms debounce boundary on event triggers
  // this avoids button events firing on
  // press noise and false positives
  trigger = __.debounce(function(key) {
    aliases[key].forEach(function(type) {
      this.emit(type, null);
    }, this);
  }, 7);

/**
 * Button
 * @constructor
 *
 * five.Button();
 *
 * five.Button({
 *   pin: 10
 * });
 *
 *
 * @param {Object} opts [description]
 *
 */

function Button(opts) {
  var timeout;
  var pinValue;
  var isFirmata;

  if (!(this instanceof Button)) {
    return new Button(opts);
  }

  pinValue = typeof opts === "object" ? opts.pin : opts;

  Board.Component.call(
    this, opts = Board.Options(opts)
  );

  isFirmata = Pins.isFirmata(this);

  if (isFirmata && typeof pinValue === "string" && pinValue[0] === "A") {
    pinValue = this.io.analogPins[+pinValue.slice(1)];
  }

  pinValue = +pinValue;

  // Set the pin to INPUT mode
  this.mode = this.io.MODES.INPUT;

  // Option to enable the built-in pullup resistor
  this.isPullup = opts.isPullup || false;

  if (isFirmata && !Number.isNaN(pinValue)) {
    this.pin = pinValue;
  }

  this.io.pinMode(this.pin, this.mode);

  // Enable the pullup resistor after setting pin mode
  if (this.isPullup) {
    this.io.digitalWrite(this.pin, this.io.HIGH);
  }

  // Turns out some button circuits will send
  // 0 for up and 1 for down, and some the inverse,
  // so we can invert our function with this option.
  // Default to invert in pullup mode, but use opts.invert
  // if explicitly defined (even if false)
  this.invert = typeof opts.invert !== "undefined" ?
    opts.invert : (this.isPullup || false);

  this.downValue = this.invert ? 0 : 1;
  this.upValue = this.invert ? 1 : 0;

  // Button instance properties
  this.holdtime = opts && opts.holdtime || 500;

  // Create a "state" entry for privately
  // storing the state of the button
  priv.set(this, {
    isDown: false
  });

  // Analog Read event loop
  this.io.digitalRead(this.pin, function(data) {
    var err = null;

    // data = upValue, this.isDown = true
    // indicates that the button has been released
    // after previously being pressed
    if (data === this.upValue && this.isDown) {
      if (timeout) {
        clearTimeout(timeout);
      }
      priv.get(this).isDown = false;

      trigger.call(this, "up");
    }

    // data = downValue, this.isDown = false
    // indicates that the button has been pressed
    // after previously being released
    if (data === this.downValue && !this.isDown) {

      // Update private data
      priv.get(this).isDown = true;

      // Call debounced event trigger for given "key"
      // This will trigger all event aliases assigned
      // to "key"
      trigger.call(this, "down" /* key */ );

      timeout = setTimeout(function() {
        if (this.isDown) {
          this.emit("hold", err);
        }
      }.bind(this), this.holdtime);
    }
  }.bind(this));

  Object.defineProperties(this, {
    isDown: {
      get: function() {
        return priv.get(this).isDown;
      }
    }
  });
}

util.inherits(Button, events.EventEmitter);

/**
 * Fired when the button is pressed down
 *
 * @event
 * @name down
 * @memberOf Button
 */

/**
 * Fired when the button is held
 *
 * @event
 * @name hold
 * @memberOf Button
 */

/**
 * Fired when the button is released
 *
 * @event
 * @name up
 * @memberOf Button
 */

module.exports = Button;
<commit_msg>Move debounce function to constructor<commit_after>var Board = require("../lib/board.js");
var Pins = Board.Pins;
var __ = require("../lib/fn.js");
var events = require("events");
var util = require("util");

// Button instance private data
var priv = new Map(),
  aliases = {
    down: ["down", "press", "tap", "impact", "hit"],
    up: ["up", "release"]
  };

/**
 * Button
 * @constructor
 *
 * five.Button();
 *
 * five.Button({
 *   pin: 10
 * });
 *
 *
 * @param {Object} opts [description]
 *
 */

function Button(opts) {
  var timeout;
  var pinValue;
  var isFirmata;

  // Create a 5 ms debounce boundary on event triggers
  // this avoids button events firing on
  // press noise and false positives
  var trigger = __.debounce(function(key) {
    aliases[key].forEach(function(type) {
      this.emit(type, null);
    }, this);
  }, 7);

  if (!(this instanceof Button)) {
    return new Button(opts);
  }

  pinValue = typeof opts === "object" ? opts.pin : opts;

  Board.Component.call(
    this, opts = Board.Options(opts)
  );

  isFirmata = Pins.isFirmata(this);

  if (isFirmata && typeof pinValue === "string" && pinValue[0] === "A") {
    pinValue = this.io.analogPins[+pinValue.slice(1)];
  }

  pinValue = +pinValue;

  // Set the pin to INPUT mode
  this.mode = this.io.MODES.INPUT;

  // Option to enable the built-in pullup resistor
  this.isPullup = opts.isPullup || false;

  if (isFirmata && !Number.isNaN(pinValue)) {
    this.pin = pinValue;
  }

  this.io.pinMode(this.pin, this.mode);

  // Enable the pullup resistor after setting pin mode
  if (this.isPullup) {
    this.io.digitalWrite(this.pin, this.io.HIGH);
  }

  // Turns out some button circuits will send
  // 0 for up and 1 for down, and some the inverse,
  // so we can invert our function with this option.
  // Default to invert in pullup mode, but use opts.invert
  // if explicitly defined (even if false)
  this.invert = typeof opts.invert !== "undefined" ?
    opts.invert : (this.isPullup || false);

  this.downValue = this.invert ? 0 : 1;
  this.upValue = this.invert ? 1 : 0;

  // Button instance properties
  this.holdtime = opts && opts.holdtime || 500;

  // Create a "state" entry for privately
  // storing the state of the button
  priv.set(this, {
    isDown: false
  });

  // Analog Read event loop
  this.io.digitalRead(this.pin, function(data) {
    var err = null;

    // data = upValue, this.isDown = true
    // indicates that the button has been released
    // after previously being pressed
    if (data === this.upValue && this.isDown) {
      if (timeout) {
        clearTimeout(timeout);
      }
      priv.get(this).isDown = false;

      trigger.call(this, "up");
    }

    // data = downValue, this.isDown = false
    // indicates that the button has been pressed
    // after previously being released
    if (data === this.downValue && !this.isDown) {

      // Update private data
      priv.get(this).isDown = true;

      // Call debounced event trigger for given "key"
      // This will trigger all event aliases assigned
      // to "key"
      trigger.call(this, "down" /* key */ );

      timeout = setTimeout(function() {
        if (this.isDown) {
          this.emit("hold", err);
        }
      }.bind(this), this.holdtime);
    }
  }.bind(this));

  Object.defineProperties(this, {
    isDown: {
      get: function() {
        return priv.get(this).isDown;
      }
    }
  });
}

util.inherits(Button, events.EventEmitter);

/**
 * Fired when the button is pressed down
 *
 * @event
 * @name down
 * @memberOf Button
 */

/**
 * Fired when the button is held
 *
 * @event
 * @name hold
 * @memberOf Button
 */

/**
 * Fired when the button is released
 *
 * @event
 * @name up
 * @memberOf Button
 */

module.exports = Button;
<|endoftext|>


<commit_before>module.exports = {
	package: {
		src: [ '<%= paths.tmp %>' ]
	},
	wpcom: {
		src: [
			'<%= paths.wpcom %>/*',
			'!<%= paths.wpcom %>/.svn',
			'!<%= paths.wpcom %>/includes',
			'<%= paths.wpcom %>/includes/*',
			'!<%= paths.wpcom %>/includes/wpcom',
			'!<%= paths.wpcom %>/languages'
		]
	}
};
<commit_msg>Don't remove the /inc directory during the WP.com build.<commit_after>module.exports = {
	package: {
		src: [ '<%= paths.tmp %>' ]
	},
	wpcom: {
		src: [
			'<%= paths.wpcom %>/*',
			'!<%= paths.wpcom %>/.svn',
			'!<%= paths.wpcom %>/inc',
			'!<%= paths.wpcom %>/includes',
			'<%= paths.wpcom %>/includes/*',
			'!<%= paths.wpcom %>/includes/wpcom',
			'!<%= paths.wpcom %>/languages'
		]
	}
};
<|endoftext|>


<commit_before>var
    _ = require('lodash'),

    src         = './src',
    build       = './build',
    dist        = './dist',
    src_preview = './src_preview'
;

var config = {
    $: (require('gulp-load-plugins'))(),

    clean: [build],

    banner: {
        src: [
            build+'/**/*.js',
            build+'/**/*.css'
        ],
        dest: build
    },

    dist: {
        src: build+'/**/*',
        dest: dist
    },

    script: {
        watch: src+'/js/**/*.js',
        entry: [
            src+'/js/quasar.js'
        ],
        dest: build+'/js',
        depsName: 'quasar-dependencies',
        deps: [
            'jquery/dist/jquery',
            'lodash/index',
            'vue/dist/vue',
            'fastclick/lib/fastclick',
            'quasar-semantic/dist/semantic'
            //'touchswipe/index.js',
            //gsap
        ],
        webpack: {
            dev: {
                devtool: '#inline-source-map'
                //devtool: '#cheap-module-eval-source-map'
            },
            prod: {}
        }
    },

    style: {
        watch: src+'/style/**/*.scss',
        entry: [
            src+'/style/quasar.scss'
        ],
        dest: build+'/style',
        depsName: 'quasar-dependencies',
        deps: [
            'quasar-semantic/dist/semantic'
        ],
        autoprefixer: {browsers: ['last 3 versions']}
    },

    preview: {
        server: {
            port: 3000,
            ui: { port: 3001 },
            open: false,
            reloadOnRestart: true,
            server: {
                baseDir: preview
            }
        },
        html: {
            src: src_preview+'/**/*.html',
            dest: preview
        },
        image: {
            src: src_preview+'/images/**/*',
            dest: preview
        },
        style: {
            watch: src_preview+'/style/**/*.scss',
            entry: [
                src_preview+'/style/project.scss'
            ],
            dest: preview+'/style',
        },
        script: {
            watch: src_preview+'/js/**/*.js',
            entry: [
                src_preview+'/js/project.js'
            ],
            dest: preview+'/js',
        },
        deps: {
            src: build+'/**/*',
            dest: preview+'/quasar'
        }
    }
};

config.script.deps = _.map(config.script.deps, function(item) {
    if (item.indexOf('!') === 0) {
        return item.substr(1)+'.js';
    }
    return 'node_modules/'+item+'.js';
});
config.style.deps = _.map(config.style.deps, function(item) {
    if (item.indexOf('!') === 0) {
        return item.substr(1)+'.css';
    }
    return 'node_modules/'+item+'.css';
});

module.exports = config;<commit_msg>fix: build<commit_after>var
    _ = require('lodash'),

    src         = './src',
    build       = './build',
    dist        = './dist',

    src_preview = './src_preview',
    preview = './preview'
;

var config = {
    $: (require('gulp-load-plugins'))(),

    clean: [build],

    banner: {
        src: [
            build+'/**/*.js',
            build+'/**/*.css'
        ],
        dest: build
    },

    dist: {
        src: build+'/**/*',
        dest: dist
    },

    script: {
        watch: src+'/js/**/*.js',
        entry: [
            src+'/js/quasar.js'
        ],
        dest: build+'/js',
        depsName: 'quasar-dependencies',
        deps: [
            'jquery/dist/jquery',
            'lodash/index',
            'vue/dist/vue',
            'fastclick/lib/fastclick',
            'quasar-semantic/dist/semantic'
            //'touchswipe/index.js',
            //gsap
        ],
        webpack: {
            dev: {
                devtool: '#inline-source-map'
                //devtool: '#cheap-module-eval-source-map'
            },
            prod: {}
        }
    },

    style: {
        watch: src+'/style/**/*.scss',
        entry: [
            src+'/style/quasar.scss'
        ],
        dest: build+'/style',
        depsName: 'quasar-dependencies',
        deps: [
            'quasar-semantic/dist/semantic'
        ],
        autoprefixer: {browsers: ['last 3 versions']}
    },

    preview: {
        server: {
            port: 3000,
            ui: { port: 3001 },
            open: false,
            reloadOnRestart: true,
            server: {
                baseDir: preview
            }
        },
        html: {
            src: src_preview+'/**/*.html',
            dest: preview
        },
        image: {
            src: src_preview+'/images/**/*',
            dest: preview
        },
        style: {
            watch: src_preview+'/style/**/*.scss',
            entry: [
                src_preview+'/style/project.scss'
            ],
            dest: preview+'/style',
        },
        script: {
            watch: src_preview+'/js/**/*.js',
            entry: [
                src_preview+'/js/project.js'
            ],
            dest: preview+'/js',
        },
        deps: {
            src: build+'/**/*',
            dest: preview+'/quasar'
        }
    }
};

config.script.deps = _.map(config.script.deps, function(item) {
    if (item.indexOf('!') === 0) {
        return item.substr(1)+'.js';
    }
    return 'node_modules/'+item+'.js';
});
config.style.deps = _.map(config.style.deps, function(item) {
    if (item.indexOf('!') === 0) {
        return item.substr(1)+'.css';
    }
    return 'node_modules/'+item+'.css';
});

module.exports = config;<|endoftext|>


<commit_before>// jsCarton 0.1.0

// (c) 2013 Mathias Prinz
// cartonFactory.js is distributed under the MIT license.
// For more details, see http: http://github.com/cartonmarkup/jsCarton

  var domo = domo || {};
  var help = help || {};

  ! function  ( domo, help ) {

    // Determine the global object.

    var global = Function( 'return this' )();

    // globalQuery

    var globalQuery = [];

    // store factory obj

    var factory;

    // csscarton "tags"

    var cartonTags = [ 'CELL', 'STRETCH', 'SLIM','CHOPPED', 'STICKER', 'FIXED', 'FIT' ];

    // html tags

    var tags = [
      'A', 'ABBR', 'ACRONYM', 'ADDRESS', 'AREA', 'ARTICLE', 'ASIDE', 'AUDIO',
      'B', 'BDI', 'BDO', 'BIG', 'BLOCKQUOTE', 'BODY', 'BR', 'BUTTON',
      'CANVAS', 'CAPTION', 'CITE', 'CODE', 'COL', 'COLGROUP', 'COMMAND',
      'DATALIST', 'DD', 'DEL', 'DETAILS', 'DFN', 'DIV', 'DL', 'DT', 'EM',
      'EMBED', 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 'FRAME',
      'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HEADER',
      'HGROUP', 'HR', 'HTML', 'I', 'IFRAME', 'IMG', 'INPUT', 'INS', 'KBD',
      'KEYGEN', 'LABEL', 'LEGEND', 'LI', 'LINK', 'MAP', 'MARK', 'META',
      'METER', 'NAV', 'NOSCRIPT', 'OBJECT', 'OL', 'OPTGROUP', 'OPTION',
      'OUTPUT', 'P', 'PARAM', 'PRE', 'PROGRESS', 'Q', 'RP', 'RT', 'RUBY',
      'SAMP', 'SCRIPT', 'SECTION', 'SELECT', 'SMALL', 'SOURCE', 'SPAN',
      'SPLIT', 'STRONG', 'STYLE', 'SUB', 'SUMMARY', 'SUP', 'TABLE', 'TBODY',
      'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TIME', 'TITLE', 'TR',
      'TRACK', 'TT', 'UL', 'VAR', 'VIDEO', 'WBR'
    ];

    typeof module == 'object'
    ? module.exports = function ( Domo, Factory, Query, Shim, Help ) {

        if ( ! Domo ) throw new Error( 'No domo provided.' );
        if ( ! Factory ) throw new Error( 'No cartonFactory provided.' );
        if ( ! Shim ) throw new Error( 'No document provided.' );
        if ( ! Help ) throw new Error( 'No help provided.' );

        domo = Domo;
        factory = Factory;
        document = Shim;
        help = Help;
        globalQuery = Query || [];
        return Carton.call( this, document );
    }
    : window.carton = function () {
        var i = arguments.length;

        while ( i-- ) {

          if ( help.isObject( arguments[ i ] ) ) factory = arguments[ i ];
          else if ( help.isArray( arguments[ i ] ) ) globalQuery = arguments[ i ];
        }

        if ( ! domo ) throw new Error( 'No domo provided.' );
        if ( ! factory ) throw new Error( 'No cartonFactory provided.' );
        if ( ! help ) throw new Error( 'No help provided.' );

        factory = initFactory( factory );

        domo.global( false );

        return new Carton( global.document ).global( true );
      };

    ///////////////////////////

    var shift = Array.prototype.shift;
    var concat = Array.prototype.concat;

    ///////////////////////////

    // create factory if nessesary

    function initFactory ( Factory ) {
      var Factory = Factory || {}
      var settings = { selector: '#', showGrid: false };
      var key;

      if ( ! Factory || ! Factory.index ){
        if ( ! cartonFactory ) throw new Error( 'No cartonFactory provided.' )
        if ( Factory ) help.mix( settings, Factory );
        Factory = cartonFactory( settings )
      }

      if ( settings.extend ) {
        for ( key in settings.extend ) if ( cartonTags.indexOf( key ) === -1 ) cartonTags.push( key.toUpperCase() );
      }

      return Factory;
    }

    ///////////////////////////

    function shortcut ( type, list, attr ) {
      var args = []
      var settings = { styles: {}, align: ' ', show: factory.setup.showGrid  }
      var l = list.length
      var i = 0;

      this.cell = function () {
        var args   = concat.apply( [], arguments );
        var keys = [ 'width', 'height', 'max-width', 'max-height', 'min-width', 'min-height' ];

        return transformToSettings( keys, args );
      }

      this.sticker = function () {
        var l = arguments.length;
        var keys = ( l === 2 ) ? [ 'top', 'left' ] : [ 'top', 'right', 'bottom', 'left' ];

        return transformToSettings( keys, args );
      }

      this.fixed = this.sticker;

      function transformToSettings ( loop, specials ) {
        var l = loop.length;
        var i = 0;

        for ( i; i < l; i = i + 1 ) {

          if ( specials[ i ] !== undefined ) {
            if ( ! settings.styles ) settings.styles = {};
            settings.styles[ loop[ i ] ] = specials[ i ];
          }
        }

        for ( i in settings ) {

          if ( attr[ i ] !== undefined && help.isArray( attr[ i ] ) ) {

            settings[ i ] = attr[ i ].concat( settings[ i ] );

          }
          else if ( attr[ i ] !== undefined ) {

            settings[ i ] = [ attr[ i ], settings[ i ] ];
          }

        }

        return help.mix( attr, settings );
      }

      for ( ; i < l; i = i + 1 ) {

        if ( help.isObject( list[ i ] ) ) {

          if ( ! settings.styles ) settings.styles = {};
          help.mix( settings.styles, list[ i ] );
        }

        else if ( help.isBoolean( list[ i ] ) ) {

          settings.show = list[ i ];
        }

        else if ( help.isString( list[ i ] ) && help.has( tags, list[ i ].toUpperCase() ) ) {

          settings.nodeName = list[ i ];
        }

        else if ( help.isString( list[ i ] ) && help.has( 'left,right,center', list[ i ]  ) ) {

          settings.align = list[ i ];
        }

        else {

          args.push( list[ i ] );
        }
      }

      if ( ! this[ type ] ) return transformToSettings( [], args );
      return this[ type ].apply( null, args );
    }

    ///////////////////////////

    function factorify ( obj ) {

      function filter() {
        var filterObj = { length: 1, keys:{}, attr: {}, nodeName: '' }
        var pseudos
        var i;

        for ( i in obj ) {

          if ( i === 'nodeName' ) filterObj.nodeName = obj[ i ];

          else if ( help.has( 'styles,query,type,align,show', i ) ) {

            // add globalQuery if needed

            if ( help.isArray( obj[ i ] ) && !filterObj.keys.query ) {

              filterObj.keys.query = globalQuery;
            }

            filterObj.keys[ i ] = obj[ i ];
            filterObj.length = ( obj[ i ].length > filterObj.length ) && help.isArray( obj[ i ] ) ? obj[ i ].length : filterObj.length;

          }
          else {

            filterObj.attr[ i ] = obj[ i ];
          }
        }

        return filterObj;
      }

      function transformToFactoryOptions () {
        var filtered = filter();
        var keys = filtered.keys;
        var l = filtered.length;
        var args = [];
        var i = 0;
        var k;

        for ( i; i < l; i = i + 1 ) {

          args[ i ] = {};

          for ( k in keys ) {

            if ( ! help.isArray( keys[ k ] ) ) {

              args[ i ][ k ] = keys[ k ];
            }
            else {

              if ( ! keys[ k ][ i ] || help.isObject( keys[ k ][ i ]) && help.isEmpty( keys[ k ][ i ] ) || help.isString( keys[ k ][ i ] ) && ! keys[ k ][ i ].length ) continue
              args[ i ][ k ] =  keys[ k ][ i ];
            }
          }
        }

        return { factory: args, attributes: filtered.attr, nodeName: filtered.nodeName };

      }

      return transformToFactoryOptions();
    }

    ///////////////////////////

    function hasPseudoClass ( factories ) {
      var l = factories.length;
      var list = [];
      var i = 0;

      function lookForPseudo ( styles, query, p ) {
        var p = p || '';
        var pseudoList = [];
        var pseudoSelectors = {};
        var selector;
        var i;

        for ( i in styles ) {

          if ( i[ 0 ] === '_' ) {

            selector = i.slice( 1 );
            if ( selector[ 0 ] !== ':' ) selector = ' ' + selector;
            pseudoSelectors[ selector ] = help.mix( {}, styles[ i ] );
            delete styles[ i ];
          }
        }

        for ( i in pseudoSelectors ) {

          pseudoList.push( { pseudo: p + i, styles: pseudoSelectors[ i ], query: query } );
          lookForPseudo( pseudoSelectors[ i ], query,  p + i + ' ' );
        }

        if ( pseudoList.length ) factories = factories.concat( pseudoList )
      }

      for ( i; i < l; i = i + 1 ) {

         lookForPseudo( factories[ i ].styles, factories[ i ].query );
      }

      return factories;
    }

    ///////////////////////////

    function makeFactory ( carton, type ) {
      carton[ type ] =
        carton[ type.toLowerCase() ] = function () {
          var l = arguments.length;
          var childNodes = [];
          var attr = {};
          var i = 0;

          for ( i; i < l; i = i + 1 ) {

            if ( help.isArray( arguments[ i ] ) ) {

              help.mix( attr, shortcut( type.toLowerCase(), arguments[ i ], attr ) );
            }
            else if ( help.isObject( arguments[ i ] ) && ! arguments[ i ].nodeType ) {

              help.mix( attr, arguments[ i ] );
            }
            else {

              childNodes.push( arguments[ i ] );
            }
          }

          if ( ! attr.type && tags.indexOf( type ) === -1 ) {

            attr.type = type.toLowerCase();
          }

          if ( ! attr.nodeName ) {

            attr.nodeName = tags.indexOf( type ) > -1 ? type : 'div';
          }

          childNodes.unshift( attr.nodeName, attr );

          return carton.FACTORY.apply( carton, childNodes );
        }
    }

    ///////////////////////////

    function Carton ( document ) {
      if ( ! document ) throw new Error( 'No document provided.' )

      var extendedTags = cartonTags.concat( tags );
      var i = extendedTags.length;
      var styleTag;

      help.mix( this, factory );
      this.carton = this;

      this.FACTORY = function () {
        var childNodes = concat.apply( [], arguments );

        var nodeName = childNodes.shift();
        var attributes = childNodes[ 0 ];
        var element;
        var sorted;

        if ( attributes ) {

          if ( typeof attributes == "object" && ! attributes.nodeType ) {

            attributes = shift.apply( childNodes )
            sorted = factorify( attributes );

            if ( sorted.nodeName ) {

              nodeName = sorted.nodeName;
            }
          }
        }

        element = domo.ELEMENT.apply( domo, [ nodeName, sorted.attributes ].concat( childNodes ) );
        factory.add.apply( null, [ element ].concat( hasPseudoClass( sorted.factory ) ) );

        if ( nodeName === 'STYLE' ) {

          styleTag = element;
        }

        switch ( nodeName ) {
          case "HTML":
          case "HEAD":
          case "BODY":
            if ( styleTag ) {

              factory.parse( styleTag )
            }
          }

          return element;
      }

      this.EACH = function () {
        var frag = domo.FRAGMENT();
        var list = arguments[ 0 ];
        var item = arguments[ 1 ];
        var i;
        var l;

        if ( typeof list !== 'object' ) return ''
        if ( typeof item !== 'function' ) throw new Error( 'No function' )

        if ( typeof list === 'object' && list instanceof Array === false  ) {

          for ( i in list ) {
            frag.appendChild( item.call( null,  list[i], i, list.length ) );
          }

          return frag;
        }

        i = 0;
        l = list.length;

        for ( i; i < l; i = i + 1 ) {

          frag.appendChild( item.call( null, list[i], i, list.length ) );
        }

        return frag;
      }

      while ( i-- ) {

         if ( ! help.has( cartonTags,  extendedTags[ i ] ) ) {

           this[ extendedTags[ i ] + '_' ] = domo[ extendedTags[ i ] ];
         }

         makeFactory( this, extendedTags[ i ] );
      }

      this.ELEMENT = domo.ELEMENT;
      this.FRAGMENT = domo.FRAGMENT;
      this.TEXT = domo.TEXT;
      this.COMMENT = domo.COMMENT;
      this.STYLE.on = domo.STYLE.on;

      this.global = function ( on ) {
        var values = this.global.values;
        var key;
        var code;

        if ( on !== false ) {

          global.carton = this;

          for ( key in this ) {
            code = key.charCodeAt( 0 );
            if ( code < 65 || code > 90 ) continue;
            if ( this[ key ] == global[ key ] ) continue;
            if ( key in global ) values[ key ] = global[ key ];

            global[ key ] = this[ key ];
          }
        }
        else {

          try {

            delete global.carton;
          }
          catch ( e ) {

            global.carton = undefined;
          }

          for ( key in this ) {

            if ( key in values ) {

              if ( global[ key ] == this[ key ] ) global[ key ] = values[ key ];
            }
            else {

              try {

                delete global[ key ];
              }
              catch ( e ) {

                global[ key ] = undefined;
              }
            }
          }
        }

        return this;
      }

      this.global.values = {};
    }
}( domo, help )
;<commit_msg>Added .update method to carton namspace<commit_after>// jsCarton 0.1.1

// (c) 2013 Mathias Prinz
// cartonFactory.js is distributed under the MIT license.
// For more details, see http: http://github.com/cartonmarkup/jsCarton

  var domo = domo || {};
  var help = help || {};

  ! function  ( domo, help ) {

    // Determine the global object.

    var global = Function( 'return this' )();

    // globalQuery

    var globalQuery = [];

    // store factory obj

    var factory;

    // csscarton "tags"

    var cartonTags = [ 'CELL', 'STRETCH', 'SLIM','CHOPPED', 'STICKER', 'FIXED', 'FIT' ];

    // html tags

    var tags = [
      'A', 'ABBR', 'ACRONYM', 'ADDRESS', 'AREA', 'ARTICLE', 'ASIDE', 'AUDIO',
      'B', 'BDI', 'BDO', 'BIG', 'BLOCKQUOTE', 'BODY', 'BR', 'BUTTON',
      'CANVAS', 'CAPTION', 'CITE', 'CODE', 'COL', 'COLGROUP', 'COMMAND',
      'DATALIST', 'DD', 'DEL', 'DETAILS', 'DFN', 'DIV', 'DL', 'DT', 'EM',
      'EMBED', 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 'FRAME',
      'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HEADER',
      'HGROUP', 'HR', 'HTML', 'I', 'IFRAME', 'IMG', 'INPUT', 'INS', 'KBD',
      'KEYGEN', 'LABEL', 'LEGEND', 'LI', 'LINK', 'MAP', 'MARK', 'META',
      'METER', 'NAV', 'NOSCRIPT', 'OBJECT', 'OL', 'OPTGROUP', 'OPTION',
      'OUTPUT', 'P', 'PARAM', 'PRE', 'PROGRESS', 'Q', 'RP', 'RT', 'RUBY',
      'SAMP', 'SCRIPT', 'SECTION', 'SELECT', 'SMALL', 'SOURCE', 'SPAN',
      'SPLIT', 'STRONG', 'STYLE', 'SUB', 'SUMMARY', 'SUP', 'TABLE', 'TBODY',
      'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TIME', 'TITLE', 'TR',
      'TRACK', 'TT', 'UL', 'VAR', 'VIDEO', 'WBR'
    ];

    typeof module == 'object'
    ? module.exports = function ( Domo, Factory, Query, Shim, Help ) {

        if ( ! Domo ) throw new Error( 'No domo provided.' );
        if ( ! Factory ) throw new Error( 'No cartonFactory provided.' );
        if ( ! Shim ) throw new Error( 'No document provided.' );
        if ( ! Help ) throw new Error( 'No help provided.' );

        domo = Domo;
        factory = Factory;
        document = Shim;
        help = Help;
        globalQuery = Query || [];
        return Carton.call( this, document );
    }
    : window.carton = function () {
        var i = arguments.length;

        while ( i-- ) {

          if ( help.isObject( arguments[ i ] ) ) factory = arguments[ i ];
          else if ( help.isArray( arguments[ i ] ) ) globalQuery = arguments[ i ];
        }

        if ( ! domo ) throw new Error( 'No domo provided.' );
        if ( ! factory ) throw new Error( 'No cartonFactory provided.' );
        if ( ! help ) throw new Error( 'No help provided.' );

        factory = initFactory( factory );

        domo.global( false );

        return new Carton( global.document ).global( true );
      };

    ///////////////////////////

    var shift = Array.prototype.shift;
    var concat = Array.prototype.concat;

    ///////////////////////////

    // create factory if nessesary

    function initFactory ( Factory ) {
      var Factory = Factory || {}
      var settings = { selector: '#', showGrid: false };
      var key;

      if ( ! Factory || ! Factory.index ){
        if ( ! cartonFactory ) throw new Error( 'No cartonFactory provided.' )
        if ( Factory ) help.mix( settings, Factory );
        Factory = cartonFactory( settings )
      }

      if ( settings.extend ) {
        for ( key in settings.extend ) if ( cartonTags.indexOf( key ) === -1 ) cartonTags.push( key.toUpperCase() );
      }

      return Factory;
    }

    ///////////////////////////

    function shortcut ( type, list, attr ) {
      var args = []
      var settings = { styles: {}, align: ' ', show: factory.setup.showGrid  }
      var l = list.length
      var i = 0;

      this.cell = function () {
        var args   = concat.apply( [], arguments );
        var keys = [ 'width', 'height', 'max-width', 'max-height', 'min-width', 'min-height' ];

        return transformToSettings( keys, args );
      }

      this.sticker = function () {
        var l = arguments.length;
        var keys = ( l === 2 ) ? [ 'top', 'left' ] : [ 'top', 'right', 'bottom', 'left' ];

        return transformToSettings( keys, args );
      }

      this.fixed = this.sticker;

      function transformToSettings ( loop, specials ) {
        var l = loop.length;
        var i = 0;

        for ( i; i < l; i = i + 1 ) {

          if ( specials[ i ] !== undefined ) {
            if ( ! settings.styles ) settings.styles = {};
            settings.styles[ loop[ i ] ] = specials[ i ];
          }
        }

        for ( i in settings ) {

          if ( attr[ i ] !== undefined && help.isArray( attr[ i ] ) ) {

            settings[ i ] = attr[ i ].concat( settings[ i ] );

          }
          else if ( attr[ i ] !== undefined ) {

            settings[ i ] = [ attr[ i ], settings[ i ] ];
          }

        }

        return help.mix( attr, settings );
      }

      for ( ; i < l; i = i + 1 ) {

        if ( help.isObject( list[ i ] ) ) {

          if ( ! settings.styles ) settings.styles = {};
          help.mix( settings.styles, list[ i ] );
        }

        else if ( help.isBoolean( list[ i ] ) ) {

          settings.show = list[ i ];
        }

        else if ( help.isString( list[ i ] ) && help.has( tags, list[ i ].toUpperCase() ) ) {

          settings.nodeName = list[ i ];
        }

        else if ( help.isString( list[ i ] ) && help.has( 'left,right,center', list[ i ]  ) ) {

          settings.align = list[ i ];
        }

        else {

          args.push( list[ i ] );
        }
      }

      if ( ! this[ type ] ) return transformToSettings( [], args );
      return this[ type ].apply( null, args );
    }

    ///////////////////////////

    function factorify ( obj ) {

      function filter() {
        var filterObj = { length: 1, keys:{}, attr: {}, nodeName: '' }
        var pseudos
        var i;

        for ( i in obj ) {

          if ( i === 'nodeName' ) filterObj.nodeName = obj[ i ];

          else if ( help.has( 'styles,query,type,align,show', i ) ) {

            // add globalQuery if needed

            if ( help.isArray( obj[ i ] ) && !filterObj.keys.query ) {

              filterObj.keys.query = globalQuery;
            }

            filterObj.keys[ i ] = obj[ i ];
            filterObj.length = ( obj[ i ].length > filterObj.length ) && help.isArray( obj[ i ] ) ? obj[ i ].length : filterObj.length;

          }
          else {

            filterObj.attr[ i ] = obj[ i ];
          }
        }

        return filterObj;
      }

      function transformToFactoryOptions () {
        var filtered = filter();
        var keys = filtered.keys;
        var l = filtered.length;
        var args = [];
        var i = 0;
        var k;

        for ( i; i < l; i = i + 1 ) {

          args[ i ] = {};

          for ( k in keys ) {

            if ( ! help.isArray( keys[ k ] ) ) {

              args[ i ][ k ] = keys[ k ];
            }
            else {

              if ( ! keys[ k ][ i ] || help.isObject( keys[ k ][ i ]) && help.isEmpty( keys[ k ][ i ] ) || help.isString( keys[ k ][ i ] ) && ! keys[ k ][ i ].length ) continue
              args[ i ][ k ] =  keys[ k ][ i ];
            }
          }
        }

        return { factory: args, attributes: filtered.attr, nodeName: filtered.nodeName };

      }

      return transformToFactoryOptions();
    }

    ///////////////////////////

    function hasPseudoClass ( factories ) {
      var l = factories.length;
      var list = [];
      var i = 0;

      function lookForPseudo ( styles, query, p ) {
        var p = p || '';
        var pseudoList = [];
        var pseudoSelectors = {};
        var selector;
        var i;

        for ( i in styles ) {

          if ( i[ 0 ] === '_' ) {

            selector = i.slice( 1 );
            if ( selector[ 0 ] !== ':' ) selector = ' ' + selector;
            pseudoSelectors[ selector ] = help.mix( {}, styles[ i ] );
            delete styles[ i ];
          }
        }

        for ( i in pseudoSelectors ) {

          pseudoList.push( { pseudo: p + i, styles: pseudoSelectors[ i ], query: query } );
          lookForPseudo( pseudoSelectors[ i ], query,  p + i + ' ' );
        }

        if ( pseudoList.length ) factories = factories.concat( pseudoList )
      }

      for ( i; i < l; i = i + 1 ) {

         lookForPseudo( factories[ i ].styles, factories[ i ].query );
      }

      return factories;
    }

    ///////////////////////////

    function makeFactory ( carton, type ) {
      carton[ type ] =
        carton[ type.toLowerCase() ] = function () {
          var l = arguments.length;
          var childNodes = [];
          var attr = {};
          var i = 0;

          for ( i; i < l; i = i + 1 ) {

            if ( help.isArray( arguments[ i ] ) ) {

              help.mix( attr, shortcut( type.toLowerCase(), arguments[ i ], attr ) );
            }
            else if ( help.isObject( arguments[ i ] ) && ! arguments[ i ].nodeType ) {

              help.mix( attr, arguments[ i ] );
            }
            else {

              childNodes.push( arguments[ i ] );
            }
          }

          if ( ! attr.type && tags.indexOf( type ) === -1 ) {

            attr.type = type.toLowerCase();
          }

          if ( ! attr.nodeName ) {

            attr.nodeName = tags.indexOf( type ) > -1 ? type : 'div';
          }

          childNodes.unshift( attr.nodeName, attr );

          return carton.FACTORY.apply( carton, childNodes );
        }
    }

    ///////////////////////////

    function Carton ( document ) {
      if ( ! document ) throw new Error( 'No document provided.' )

      var extendedTags = cartonTags.concat( tags );
      var i = extendedTags.length;
      var styleTag;

      help.mix( this, factory );
      this.carton = this;

      this.FACTORY = function () {
        var childNodes = concat.apply( [], arguments );

        var nodeName = childNodes.shift();
        var attributes = childNodes[ 0 ];
        var element;
        var sorted;

        if ( attributes ) {

          if ( typeof attributes == "object" && ! attributes.nodeType ) {

            attributes = shift.apply( childNodes )
            sorted = factorify( attributes );

            if ( sorted.nodeName ) {

              nodeName = sorted.nodeName;
            }
          }
        }

        element = domo.ELEMENT.apply( domo, [ nodeName, sorted.attributes ].concat( childNodes ) );
        factory.add.apply( null, [ element ].concat( hasPseudoClass( sorted.factory ) ) );

        if ( nodeName === 'STYLE' ) {

          styleTag = element;
        }

        switch ( nodeName ) {
          case "HTML":
          case "HEAD":
          case "BODY":
            if ( styleTag ) {

              factory.parse( styleTag )
            }
          }

          return element;
      }

      this.EACH = function () {
        var frag = domo.FRAGMENT();
        var list = arguments[ 0 ];
        var item = arguments[ 1 ];
        var i;
        var l;

        if ( typeof list !== 'object' ) return ''
        if ( typeof item !== 'function' ) throw new Error( 'No function' )

        if ( typeof list === 'object' && list instanceof Array === false  ) {

          for ( i in list ) {
            frag.appendChild( item.call( null,  list[i], i, list.length ) );
          }

          return frag;
        }

        i = 0;
        l = list.length;

        for ( i; i < l; i = i + 1 ) {

          frag.appendChild( item.call( null, list[i], i, list.length ) );
        }

        return frag;
      }

      while ( i-- ) {

         if ( ! help.has( cartonTags,  extendedTags[ i ] ) ) {

           this[ extendedTags[ i ] + '_' ] = domo[ extendedTags[ i ] ];
         }

         makeFactory( this, extendedTags[ i ] );
      }

      this.ELEMENT = domo.ELEMENT;
      this.FRAGMENT = domo.FRAGMENT;
      this.TEXT = domo.TEXT;
      this.COMMENT = domo.COMMENT;
      this.STYLE.on = domo.STYLE.on;

      this.update = function ( node, settings, hard ) {
        var filterPseudos = hasPseudoClass( [ help.mix( {}, settings ) ] );
        var l = filterPseudos.length;
        var criteria;
        var i = 0;

        for ( i ;i < l; i = i + 1 ) {
          criteria = { dom: node, pseudo: false }

          if ( ! help.isEmpty( filterPseudos[ i ].query ) ) {

            criteria.query = filterPseudos[ i ].query;
          }

          if ( filterPseudos[ i ].pseudo ) {

            criteria.pseudo = filterPseudos[ i ].pseudo;
          }

          carton.set( criteria, filterPseudos[ i ], hard ? { deep: false } : {} );
        }
      }

      this.global = function ( on ) {
        var values = this.global.values;
        var key;
        var code;

        if ( on !== false ) {

          global.carton = this;

          for ( key in this ) {
            code = key.charCodeAt( 0 );
            if ( code < 65 || code > 90 ) continue;
            if ( this[ key ] == global[ key ] ) continue;
            if ( key in global ) values[ key ] = global[ key ];

            global[ key ] = this[ key ];
          }
        }
        else {

          try {

            delete global.carton;
          }
          catch ( e ) {

            global.carton = undefined;
          }

          for ( key in this ) {

            if ( key in values ) {

              if ( global[ key ] == this[ key ] ) global[ key ] = values[ key ];
            }
            else {

              try {

                delete global[ key ];
              }
              catch ( e ) {

                global[ key ] = undefined;
              }
            }
          }
        }

        return this;
      }

      this.global.values = {};
    }
}( domo, help )
;<|endoftext|>