<commit_before>/*
 * Copyright 2015, Gregg Tavares.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Gregg Tavares. nor the names of his
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

define([
    './attributes',
    './draw',
    './framebuffers',
    './programs',
    './textures',
    './typedarrays',
    './vertex-arrays',
    './utils',
  ], function(
    attributes,
    draw,
    framebuffers,
    programs,
    textures,
    typedArrays,
    vertexArrays,
    utils) {
  "use strict";

  /**
   * The main TWGL module.
   *
   * For most use cases you shouldn't need anything outside this module.
   * Exceptions between the stuff added to twgl-full (v3, m4, primitives)
   *
   * @module twgl
   * @borrows module:twgl/attributes.setAttribInfoBufferFromArray as setAttribInfoBufferFromArray
   * @borrows module:twgl/attributes.createBufferInfoFromArrays as createBufferInfoFromArrays
   * @borrows module:twgl/attributes.createVertexArrayInfo as createVertexArrayInfo
   * @borrows module:twgl/draw.drawBufferInfo as drawBufferInfo
   * @borrows module:twgl/draw.drawObjectList as drawObjectList
   * @borrows module:twgl/framebuffers.createFramebufferInfo as createFramebufferInfo
   * @borrows module:twgl/framebuffers.resizeFramebufferInfo as resizeFramebufferInfo
   * @borrows module:twgl/framebuffers.bindFramebufferInfo as bindFramebufferInfo
   * @borrows module:twgl/programs.createProgramInfo as createProgramInfo
   * @borrows module:twgl/programs.createUniformBlockInfo as createUniformBlockInfo
   * @borrows module:twgl/programs.bindUniformBlock as bindUniformBlock
   * @borrows module:twgl/programs.setUniformBlock as setUniformBlock
   * @borrows module:twgl/programs.setBlockUniforms as setBlockUniforms
   * @borrows module:twgl/programs.setUniforms as setUniforms
   * @borrows module:twgl/programs.setBuffersAndAttributes as setBuffersAndAttributes
   * @borrows module:twgl/textures.setTextureFromArray as setTextureFromArray
   * @borrows module:twgl/textures.createTexture as createTexture
   * @borrows module:twgl/textures.resizeTexture as resizeTexture
   * @borrows module:twgl/textures.createTextures as createTextures
   */

  // make sure we don't see a global gl
  var gl = undefined;  // eslint-disable-line
  var defaults = {
    enableVertexArrayObjects: true,
  };

  /**
   * Various default settings for twgl.
   *
   * Note: You can call this any number of times. Example:
   *
   *     twgl.setDefaults({ textureColor: [1, 0, 0, 1] });
   *     twgl.setDefaults({ attribPrefix: 'a_' });
   *
   * is equivalent to
   *
   *     twgl.setDefaults({
   *       textureColor: [1, 0, 0, 1],
   *       attribPrefix: 'a_',
   *     });
   *
   * @typedef {Object} Defaults
   * @property {string} attribPrefix The prefix to stick on attributes
   *
   *   When writing shaders I prefer to name attributes with `a_`, uniforms with `u_` and varyings with `v_`
   *   as it makes it clear where they came from. But, when building geometry I prefer using unprefixed names.
   *
   *   In otherwords I'll create arrays of geometry like this
   *
   *       var arrays = {
   *         position: ...
   *         normal: ...
   *         texcoord: ...
   *       };
   *
   *   But need those mapped to attributes and my attributes start with `a_`.
   *
   *   Default: `""`
   *
   * @property {number[]} textureColor Array of 4 values in the range 0 to 1
   *
   *   The default texture color is used when loading textures from
   *   urls. Because the URL will be loaded async we'd like to be
   *   able to use the texture immediately. By putting a 1x1 pixel
   *   color in the texture we can start using the texture before
   *   the URL has loaded.
   *
   *   Default: `[0.5, 0.75, 1, 1]`
   *
   * @property {string} crossOrigin
   *
   *   If not undefined sets the crossOrigin attribute on images
   *   that twgl creates when downloading images for textures.
   *
   *   Also see {@link module:twgl.TextureOptions}.
   *
   * @property {bool} enableVertexArrayObjects
   *
   *   If true then in WebGL 1.0 will attempt to get the `OES_vertex_array_object` extension.
   *   If successful it will copy create/bind/delete/isVertexArrayOES from the extension to
   *   the WebGLRenderingContext removing the OES at the end which is the standard entry point
   *   for WebGL 2.
   *
   *   Note: According to webglstats.com 90% of devices support `OES_vertex_array_object`.
   *   In fact AFAICT all devices support them it's just Microsoft Edge does not.
   *   If you just want to count on support I suggest using [this polyfill](https://github.com/KhronosGroup/WebGL/blob/master/sdk/demos/google/resources/OESVertexArrayObject.js)
   *   or ignoring devices that don't support them.
   *
   *   Default: `true`
   *
   * @memberOf module:twgl
   */

  /**
   * Sets various defaults for twgl.
   *
   * In the interest of terseness which is kind of the point
   * of twgl I've integrated a few of the older functions here
   *
   * @param {module:twgl.Defaults} newDefaults The default settings.
   * @memberOf module:twgl
   */
  function setDefaults(newDefaults) {
    utils.copyExistingProperties(newDefaults, defaults);
    attributes.setDefaults_(newDefaults);  // eslint-disable-line
    textures.setDefaults_(newDefaults);  // eslint-disable-line
  }

  /**
   * Adds Vertex Array Objects to WebGL 1 GL contexts if available
   * @param {WebGLRenderingContext} gl A WebGLRenderingContext
   */
  function addVertexArrayObjectSupport(gl) {
    if (!gl || !defaults.enableVertexArrayObjects) {
      return;
    }
    if (utils.isWebGL1(gl)) {
      var ext = gl.getExtension("OES_vertex_array_object");
      if (ext) {
        gl.createVertexArray = function() {
          return ext.createVertexArrayOES();
        };
        gl.deleteVertexArray = function(v) {
          ext.deleteVertexArrayOES(v);
        };
        gl.isVertexArray = function(v) {
          return ext.isVertexArrayOES(v);
        };
        gl.bindVertexArray = function(v) {
          ext.bindVertexArrayOES(v);
        };
        gl.VERTEX_ARRAY_BINDING = ext.VERTEX_ARRAY_BINDING_OES;
      }
    }
  }

  /**
   * Creates a webgl context.
   * @param {HTMLCanvasElement} canvas The canvas tag to get
   *     context from. If one is not passed in one will be
   *     created.
   * @return {WebGLRenderingContext} The created context.
   */
  function create3DContext(canvas, opt_attribs) {
    var names = ["webgl", "experimental-webgl"];
    var context = null;
    for (var ii = 0; ii < names.length; ++ii) {
      context = canvas.getContext(names[ii], opt_attribs);
      if (context) {
        break;
      }
    }
    return context;
  }

  /**
   * Gets a WebGL1 context.
   *
   * Note: Will attempt to enable Vertex Array Objects
   * and add WebGL2 entry points. (unless you first set defaults with
   * `twgl.setDefaults({enableVertexArrayObjects: false})`;
   *
   * @param {HTMLCanvasElement} canvas a canvas element.
   * @param {WebGLContextCreationAttirbutes} [opt_attribs] optional webgl context creation attributes
   * @memberOf module:twgl
   */
  function getWebGLContext(canvas, opt_attribs) {
    var gl = create3DContext(canvas, opt_attribs);
    addVertexArrayObjectSupport(gl);
    return gl;
  }

  /**
   * Creates a webgl context.
   *
   * Will return a WebGL2 context if possible.
   *
   * You can check if it's WebGL2 with
   *
   *     twgl.isWebGL2(gl);
   *
   * @param {HTMLCanvasElement} canvas The canvas tag to get
   *     context from. If one is not passed in one will be
   *     created.
   * @return {WebGLRenderingContext} The created context.
   */
  function createContext(canvas, opt_attribs) {
    var names = ["webgl2", "webgl", "experimental-webgl"];
    var context = null;
    for (var ii = 0; ii < names.length; ++ii) {
      context = canvas.getContext(names[ii], opt_attribs);
      if (context) {
        break;
      }
    }
    return context;
  }

  /**
   * Gets a WebGL context.  Will create a WebGL2 context if possible.
   *
   * You can check if it's WebGL2 with
   *
   *    function isWebGL2(gl) {
   *      return gl.getParameter(gl.VERSION).indexOf("WebGL 2.0 ") == 0;
   *    }
   *
   * Note: For a WebGL1 context will attempt to enable Vertex Array Objects
   * and add WebGL2 entry points. (unless you first set defaults with
   * `twgl.setDefaults({enableVertexArrayObjects: false})`;
   *
   * @param {HTMLCanvasElement} canvas a canvas element.
   * @param {WebGLContextCreationAttirbutes} [opt_attribs] optional webgl context creation attributes
   * @return {WebGLRenderingContext} The created context.
   * @memberOf module:twgl
   */
  function getContext(canvas, opt_attribs) {
    var gl = createContext(canvas, opt_attribs);
    addVertexArrayObjectSupport(gl);
    return gl;
  }

  /**
   * Resize a canvas to match the size it's displayed.
   * @param {HTMLCanvasElement} canvas The canvas to resize.
   * @param {number} [multiplier] So you can pass in `window.devicePixelRatio` if you want to.
   * @return {boolean} true if the canvas was resized.
   * @memberOf module:twgl
   */
  function resizeCanvasToDisplaySize(canvas, multiplier) {
    multiplier = multiplier || 1;
    multiplier = Math.max(1, multiplier);
    var width  = canvas.clientWidth  * multiplier | 0;
    var height = canvas.clientHeight * multiplier | 0;
    if (canvas.width !== width ||
        canvas.height !== height) {
      canvas.width = width;
      canvas.height = height;
      return true;
    }
    return false;
  }

  // Using quotes prevents Uglify from changing the names.
  // No speed diff AFAICT.
  var api = {
    "getContext": getContext,
    "getWebGLContext": getWebGLContext,
    "isWebGL1": utils.isWebGL1,
    "isWebGL2": utils.isWebGL2,
    "resizeCanvasToDisplaySize": resizeCanvasToDisplaySize,
    "setDefaults": setDefaults,
  };

  function notPrivate(name) {
    return name[name.length - 1] !== '_';
  }

  function copyPublicProperties(src, dst) {
    Object.keys(src).filter(notPrivate).forEach(function(key) {
      dst[key] = src[key];
    });
    return dst;
  }

  var apis = {
    attributes: attributes,
    draw: draw,
    framebuffers: framebuffers,
    programs: programs,
    textures: textures,
    typedArrays: typedArrays,
    vertexArrays: vertexArrays,
  };
  Object.keys(apis).forEach(function(name) {
    var srcApi = apis[name];
    copyPublicProperties(srcApi, api);
    api[name] = copyPublicProperties(srcApi, {});
  });

  return api;

});

<commit_msg>use getBoundingClientRect for resizeCanvasToMatchDisplaySize<commit_after>/*
 * Copyright 2015, Gregg Tavares.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Gregg Tavares. nor the names of his
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

define([
    './attributes',
    './draw',
    './framebuffers',
    './programs',
    './textures',
    './typedarrays',
    './vertex-arrays',
    './utils',
  ], function(
    attributes,
    draw,
    framebuffers,
    programs,
    textures,
    typedArrays,
    vertexArrays,
    utils) {
  "use strict";

  /**
   * The main TWGL module.
   *
   * For most use cases you shouldn't need anything outside this module.
   * Exceptions between the stuff added to twgl-full (v3, m4, primitives)
   *
   * @module twgl
   * @borrows module:twgl/attributes.setAttribInfoBufferFromArray as setAttribInfoBufferFromArray
   * @borrows module:twgl/attributes.createBufferInfoFromArrays as createBufferInfoFromArrays
   * @borrows module:twgl/attributes.createVertexArrayInfo as createVertexArrayInfo
   * @borrows module:twgl/draw.drawBufferInfo as drawBufferInfo
   * @borrows module:twgl/draw.drawObjectList as drawObjectList
   * @borrows module:twgl/framebuffers.createFramebufferInfo as createFramebufferInfo
   * @borrows module:twgl/framebuffers.resizeFramebufferInfo as resizeFramebufferInfo
   * @borrows module:twgl/framebuffers.bindFramebufferInfo as bindFramebufferInfo
   * @borrows module:twgl/programs.createProgramInfo as createProgramInfo
   * @borrows module:twgl/programs.createUniformBlockInfo as createUniformBlockInfo
   * @borrows module:twgl/programs.bindUniformBlock as bindUniformBlock
   * @borrows module:twgl/programs.setUniformBlock as setUniformBlock
   * @borrows module:twgl/programs.setBlockUniforms as setBlockUniforms
   * @borrows module:twgl/programs.setUniforms as setUniforms
   * @borrows module:twgl/programs.setBuffersAndAttributes as setBuffersAndAttributes
   * @borrows module:twgl/textures.setTextureFromArray as setTextureFromArray
   * @borrows module:twgl/textures.createTexture as createTexture
   * @borrows module:twgl/textures.resizeTexture as resizeTexture
   * @borrows module:twgl/textures.createTextures as createTextures
   */

  // make sure we don't see a global gl
  var gl = undefined;  // eslint-disable-line
  var defaults = {
    enableVertexArrayObjects: true,
  };

  /**
   * Various default settings for twgl.
   *
   * Note: You can call this any number of times. Example:
   *
   *     twgl.setDefaults({ textureColor: [1, 0, 0, 1] });
   *     twgl.setDefaults({ attribPrefix: 'a_' });
   *
   * is equivalent to
   *
   *     twgl.setDefaults({
   *       textureColor: [1, 0, 0, 1],
   *       attribPrefix: 'a_',
   *     });
   *
   * @typedef {Object} Defaults
   * @property {string} attribPrefix The prefix to stick on attributes
   *
   *   When writing shaders I prefer to name attributes with `a_`, uniforms with `u_` and varyings with `v_`
   *   as it makes it clear where they came from. But, when building geometry I prefer using unprefixed names.
   *
   *   In otherwords I'll create arrays of geometry like this
   *
   *       var arrays = {
   *         position: ...
   *         normal: ...
   *         texcoord: ...
   *       };
   *
   *   But need those mapped to attributes and my attributes start with `a_`.
   *
   *   Default: `""`
   *
   * @property {number[]} textureColor Array of 4 values in the range 0 to 1
   *
   *   The default texture color is used when loading textures from
   *   urls. Because the URL will be loaded async we'd like to be
   *   able to use the texture immediately. By putting a 1x1 pixel
   *   color in the texture we can start using the texture before
   *   the URL has loaded.
   *
   *   Default: `[0.5, 0.75, 1, 1]`
   *
   * @property {string} crossOrigin
   *
   *   If not undefined sets the crossOrigin attribute on images
   *   that twgl creates when downloading images for textures.
   *
   *   Also see {@link module:twgl.TextureOptions}.
   *
   * @property {bool} enableVertexArrayObjects
   *
   *   If true then in WebGL 1.0 will attempt to get the `OES_vertex_array_object` extension.
   *   If successful it will copy create/bind/delete/isVertexArrayOES from the extension to
   *   the WebGLRenderingContext removing the OES at the end which is the standard entry point
   *   for WebGL 2.
   *
   *   Note: According to webglstats.com 90% of devices support `OES_vertex_array_object`.
   *   In fact AFAICT all devices support them it's just Microsoft Edge does not.
   *   If you just want to count on support I suggest using [this polyfill](https://github.com/KhronosGroup/WebGL/blob/master/sdk/demos/google/resources/OESVertexArrayObject.js)
   *   or ignoring devices that don't support them.
   *
   *   Default: `true`
   *
   * @memberOf module:twgl
   */

  /**
   * Sets various defaults for twgl.
   *
   * In the interest of terseness which is kind of the point
   * of twgl I've integrated a few of the older functions here
   *
   * @param {module:twgl.Defaults} newDefaults The default settings.
   * @memberOf module:twgl
   */
  function setDefaults(newDefaults) {
    utils.copyExistingProperties(newDefaults, defaults);
    attributes.setDefaults_(newDefaults);  // eslint-disable-line
    textures.setDefaults_(newDefaults);  // eslint-disable-line
  }

  /**
   * Adds Vertex Array Objects to WebGL 1 GL contexts if available
   * @param {WebGLRenderingContext} gl A WebGLRenderingContext
   */
  function addVertexArrayObjectSupport(gl) {
    if (!gl || !defaults.enableVertexArrayObjects) {
      return;
    }
    if (utils.isWebGL1(gl)) {
      var ext = gl.getExtension("OES_vertex_array_object");
      if (ext) {
        gl.createVertexArray = function() {
          return ext.createVertexArrayOES();
        };
        gl.deleteVertexArray = function(v) {
          ext.deleteVertexArrayOES(v);
        };
        gl.isVertexArray = function(v) {
          return ext.isVertexArrayOES(v);
        };
        gl.bindVertexArray = function(v) {
          ext.bindVertexArrayOES(v);
        };
        gl.VERTEX_ARRAY_BINDING = ext.VERTEX_ARRAY_BINDING_OES;
      }
    }
  }

  /**
   * Creates a webgl context.
   * @param {HTMLCanvasElement} canvas The canvas tag to get
   *     context from. If one is not passed in one will be
   *     created.
   * @return {WebGLRenderingContext} The created context.
   */
  function create3DContext(canvas, opt_attribs) {
    var names = ["webgl", "experimental-webgl"];
    var context = null;
    for (var ii = 0; ii < names.length; ++ii) {
      context = canvas.getContext(names[ii], opt_attribs);
      if (context) {
        break;
      }
    }
    return context;
  }

  /**
   * Gets a WebGL1 context.
   *
   * Note: Will attempt to enable Vertex Array Objects
   * and add WebGL2 entry points. (unless you first set defaults with
   * `twgl.setDefaults({enableVertexArrayObjects: false})`;
   *
   * @param {HTMLCanvasElement} canvas a canvas element.
   * @param {WebGLContextCreationAttirbutes} [opt_attribs] optional webgl context creation attributes
   * @memberOf module:twgl
   */
  function getWebGLContext(canvas, opt_attribs) {
    var gl = create3DContext(canvas, opt_attribs);
    addVertexArrayObjectSupport(gl);
    return gl;
  }

  /**
   * Creates a webgl context.
   *
   * Will return a WebGL2 context if possible.
   *
   * You can check if it's WebGL2 with
   *
   *     twgl.isWebGL2(gl);
   *
   * @param {HTMLCanvasElement} canvas The canvas tag to get
   *     context from. If one is not passed in one will be
   *     created.
   * @return {WebGLRenderingContext} The created context.
   */
  function createContext(canvas, opt_attribs) {
    var names = ["webgl2", "webgl", "experimental-webgl"];
    var context = null;
    for (var ii = 0; ii < names.length; ++ii) {
      context = canvas.getContext(names[ii], opt_attribs);
      if (context) {
        break;
      }
    }
    return context;
  }

  /**
   * Gets a WebGL context.  Will create a WebGL2 context if possible.
   *
   * You can check if it's WebGL2 with
   *
   *    function isWebGL2(gl) {
   *      return gl.getParameter(gl.VERSION).indexOf("WebGL 2.0 ") == 0;
   *    }
   *
   * Note: For a WebGL1 context will attempt to enable Vertex Array Objects
   * and add WebGL2 entry points. (unless you first set defaults with
   * `twgl.setDefaults({enableVertexArrayObjects: false})`;
   *
   * @param {HTMLCanvasElement} canvas a canvas element.
   * @param {WebGLContextCreationAttirbutes} [opt_attribs] optional webgl context creation attributes
   * @return {WebGLRenderingContext} The created context.
   * @memberOf module:twgl
   */
  function getContext(canvas, opt_attribs) {
    var gl = createContext(canvas, opt_attribs);
    addVertexArrayObjectSupport(gl);
    return gl;
  }

  /**
   * Resize a canvas to match the size it's displayed.
   * @param {HTMLCanvasElement} canvas The canvas to resize.
   * @param {number} [multiplier] So you can pass in `window.devicePixelRatio` if you want to.
   * @return {boolean} true if the canvas was resized.
   * @memberOf module:twgl
   */
  function resizeCanvasToDisplaySize(canvas, multiplier) {
    multiplier = multiplier || 1;
    multiplier = Math.max(1, multiplier);
    var bounds = canvas.getBoundingClientRect();
    var width  = Math.round(bounds.width  * multiplier);
    var height = Math.round(bounds.height * multiplier);
    if (canvas.width !== width || canvas.height !== height) {
      canvas.width = width;
      canvas.height = height;
      return true;
    }
    return false;
  }

  // Using quotes prevents Uglify from changing the names.
  // No speed diff AFAICT.
  var api = {
    "getContext": getContext,
    "getWebGLContext": getWebGLContext,
    "isWebGL1": utils.isWebGL1,
    "isWebGL2": utils.isWebGL2,
    "resizeCanvasToDisplaySize": resizeCanvasToDisplaySize,
    "setDefaults": setDefaults,
  };

  function notPrivate(name) {
    return name[name.length - 1] !== '_';
  }

  function copyPublicProperties(src, dst) {
    Object.keys(src).filter(notPrivate).forEach(function(key) {
      dst[key] = src[key];
    });
    return dst;
  }

  var apis = {
    attributes: attributes,
    draw: draw,
    framebuffers: framebuffers,
    programs: programs,
    textures: textures,
    typedArrays: typedArrays,
    vertexArrays: vertexArrays,
  };
  Object.keys(apis).forEach(function(name) {
    var srcApi = apis[name];
    copyPublicProperties(srcApi, api);
    api[name] = copyPublicProperties(srcApi, {});
  });

  return api;

});

<|endoftext|>


<commit_before>'use strict'
var util = require('util')

module.exports = util = Object.create(util)

util.isChar = function isChar(c) {
	return typeof c === 'string' && c.length === 1
}
util.isCharArray = function(a) {
	return util.isArray(a) && a.every(util.isChar)
}
util.string = function (a) {
	if (util.isCharArray(a)) return a.join('')
	if (typeof a === 'string') return a
	throw a
}

util.flattenString = function flatten(a) {
	if (!util.isArray(a)) return a
	if (a.every(util.isChar)) return a.join('')
	else return a.map(flatten)
}
util.flattenArray = function flatten(a) {
	if (!util.isArray(a)) return a
	return [].concat.apply([], a.map(flatten))
}
util.flattenLines = function flattenLines(lines, indent) {
	if (indent === undefined) indent = ''
	return lines.reduce(function(xs, x) {
		if (util.isArray(x)) xs.push.apply(xs, flattenLines(x, indent + ' '))
		else xs.push(indent + x)
		return xs
	}, [])
}

util.indent = function indent(s) {
	return typeof s === 'string' ? '  ' + s : s
}
util.dir = function dir(obj) {
	//console.log(util.inspect(obj, false, 16, true))
	console.log(util.inspect(util.flattenString(obj), false, 32, true))
}

util.toUTF16 = function toUTF16(codePoint) {
	if (codePoint < 0x10000) return String.fromCharCode(codePoint)
	codePoint -= 0x10000
	var lead = (codePoint >> 10) + 0xd800
	var trail = (codePoint & 0x3ff) + 0xdc00
	return String.fromCharCode(lead, trail)
}
<commit_msg>update<commit_after>'use strict'
var util = require('util')

module.exports = util = Object.create(util)

util.isChar = function isChar(c) {
	return typeof c === 'string' && c.length === 1
}
util.isCharArray = function(a) {
	return util.isArray(a) && a.every(util.isChar)
}
util.string = function (a) {
	if (util.isCharArray(a)) return a.join('')
	if (typeof a === 'string') return a
	throw a
}
util.concat = function() {
	return [].concat.apply([], arguments)
}

util.flattenString = function flatten(a) {
	if (!util.isArray(a)) return a
	if (a.every(util.isChar)) return a.join('')
	else return a.map(flatten)
}
util.flattenArray = function flatten(a) {
	if (!util.isArray(a)) return a
	return [].concat.apply([], a.map(flatten))
}
util.flattenLines = function flattenLines(lines, indent) {
	if (indent === undefined) indent = ''
	return lines.reduce(function(xs, x) {
		if (util.isArray(x)) xs.push.apply(xs, flattenLines(x, indent + ' '))
		else xs.push(indent + x)
		return xs
	}, [])
}

util.indent = function indent(s) {
	return typeof s === 'string' ? '  ' + s : s
}
util.dir = function dir(obj) {
	//console.log(util.inspect(obj, false, 16, true))
	console.log(util.inspect(util.flattenString(obj), false, 32, true))
}

util.toUTF16 = function toUTF16(codePoint) {
	if (codePoint < 0x10000) return String.fromCharCode(codePoint)
	codePoint -= 0x10000
	var lead = (codePoint >> 10) + 0xd800
	var trail = (codePoint & 0x3ff) + 0xdc00
	return String.fromCharCode(lead, trail)
}
<|endoftext|>


<commit_before>/**
 * util.js
 *
 * This sets up our util object, which defines a way to export Composer
 * components and also defines a number of helper functions the rest of the
 * system will use.
 * -----------------------------------------------------------------------------
 *
 * Composer.js is an MVC framework for creating and organizing javascript
 * applications. For documentation, please visit:
 *
 *     http://lyonbros.github.com/composer.js/
 *
 * -----------------------------------------------------------------------------
 *
 * Copyright (c) 2011, Lyon Bros Enterprises, LLC. (http://www.lyonbros.com)
 *
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 */
(function() {
	"use strict";

	var global = this;
	if(!global.Composer) global.Composer = {
		// note: this used to be "export" but IE is a whiny little bitch, so now
		// we're sup3r 1337 h4x0r5
		exp0rt: function(obj)
		{
			Object.keys(obj).forEach(function(key) {
				global.Composer[key] = obj[key];
			});
		}
	};

	/**
	 * You must override this function in your app.
	 */
	var sync = function(method, model, options) { return options.success(); };

	// a closure that returns incrementing integers. these will be unique across
	// the entire app since only one counter is instantiated
	var cid = (function() {
		var counter = 1;
		return function(inc) { return 'c'+counter++; };
	})();

	// wraps error callbacks for syncing functions
	var wrap_error = function(callback, model, options)
	{
		return function(resp)
		{
			if(callback)
			{
				callback(model, resp, options);
			}
			else
			{
				this.fire_event('error', options, model, resp, options);
			}
		};
	};

	// Composer equality function. Does deep-inpection and is able to tell the
	// difference between {key: 3} and {key: 3, key2: 4} (_.eq had problems with
	// this back in the day).
	var eq = function(a, b)
	{
		if ( a === b ) return true;
		if(a instanceof Function) return false;
		if(typeof(a) != typeof(b)) return false;
		if((a && a.constructor) && !b || !b.constructor) return false;
		if((b && b.constructor) && !a || !a.constructor) return false;
		if(a && b && a.constructor != b.constructor) return false;
		if(a instanceof Array || Object.prototype.toString.call(a) === '[object Array]')
		{
			if(a.length != b.length) return false;
			// TODO: check if array indexes are always sequential
			for(var i = 0, n = a.length; i < n; i++)
			{
				if(!b.hasOwnProperty(i)) return false;
				if(!eq(a[i], b[i])) return false;
			}
		}
		else if(a instanceof Object)
		{
			for( var p in b )
			{
				if( b.hasOwnProperty(p) && ! a.hasOwnProperty(p) ) return false;
			}
			for( var p in a )
			{
				if ( ! a.hasOwnProperty( p ) ) continue;
				if ( ! b.hasOwnProperty( p ) ) return false;
				if ( a[ p ] === b[ p ] ) continue;
				if ( typeof( a[ p ] ) !== "object" ) return false;
				if ( ! eq( a[ p ],  b[ p ] ) ) return false;
			}
		}
		else if(a != b)
		{
			return false;
		}
		return true;
	};

	// create an extension function that merges specific properties from
	// inherited objects
	var merge_extend = function(cls, properties)
	{
		var _extend = cls.extend;
		cls.extend = function(def, base)
		{
			base || (base = this);
			var attr = base.prototype;

			properties.forEach(function(prop) {
				def[prop] = Composer.object.merge({}, attr[prop], def[prop]);
			});

			var cls = _extend.call(base, def);
			global.Composer.merge_extend(cls, properties);
			return cls;
		}
	};

	// some Mootools-reminiscent object utilities Composer uses
	var array = {
		erase: function(arr, item)
		{
			for(var i = arr.length - 1; i >= 0; i--)
			{
				if(arr[i] === item) arr.splice(i, 1);
			}
		},

		is: (function() {
			return ('isArray' in Array) ?
				Array.isArray :
				function(obj) {
					return obj instanceof Array || Object.prototype.toString.call(obj) === '[object Array]'
				}
		})()
	};
	var object = {
		each: function(obj, fn, bind)
		{
			if(!obj) return;
			bind || (bind = this);
			Object.keys(obj).forEach(function(key) {
				(fn.bind(bind))(obj[key], key)
			});
		},
		clone: function(obj, options)
		{
			options || (options = {});
			if(options.deep) return JSON.parse(JSON.stringify(obj));

			var clone = {};
			Object.keys(obj).forEach(function(key) {
				clone[key] = obj[key];
			});
			return clone;
		},
		merge: function(to, _)
		{
			var args = Array.prototype.slice.call(arguments, 1);
			args.forEach(function(obj) {
				if(!obj) return;
				Object.keys(obj).forEach(function(key) {
					to[key] = obj[key];
				});
			});
			return to;
		},

		// allows recursively setting keys, ie:
		//   Composer.object.set({}, 'user.name', 'andrew')
		// yields
		//   {user: {name: "andrew"}}
		set: function(object, key, value)
		{
			object || (object = {});
			var paths = key.split('.');
			var obj = object;
			for(var i = 0, n = paths.length; i < n; i++)
			{
				var path = paths[i];
				if(i == n - 1)
				{
					obj[path] = value;
					break;
				}

				if(!obj[path])
				{
					obj[path] = {};
				}
				else if(typeof(obj) != 'object' || Composer.array.is(obj))
				{
					obj[path] = {};
				}
				obj = obj[path];
			}
			return object;
		},

		// allows recursively getting keys, ie:
		//   Composer.object.get({user: {name: "andrew"}}, 'user.name')
		// yields
		//   "andrew"
		get: function(object, key)
		{
			object || (object = {});
			var paths = key.split('.');
			var obj = object;
			for(var i = 0, n = paths.length; i < n; i++)
			{
				var path = paths[i];
				var type = typeof(obj[path]);
				if(type == 'undefined')
				{
					return obj[path];
				}
				obj = obj[path];
			}
			return obj;
		}
	};

	var promisify = function()
	{
		var create_converter = function(type)
		{
			return function(key)
			{
				var options = arguments[1] || {};
				var options_idx = options.options_idx || 0;
				var names = options.names || ['success', 'error'];

				var _old = Composer[type].prototype[key];
				global.Composer[type].prototype[key] = function()
				{
					var args = Array.prototype.slice.call(arguments, 0);
					if(args.length < options_idx)
					{
						var _tmp = new Array(options_idx);
						args.forEach(function(item, i) { _tmp[i] = item; });
						args = _tmp;
					}
					if(!args[options_idx]) args[options_idx] = {};
					var _self = this;
					var options = args[options_idx];
					if(options.promisified) return _old.apply(_self, args);
					return new Promise(function(resolve, reject) {
						if(names[0]) options[names[0]] = resolve;
						if(names[1]) options[names[1]] = function(_, err) { reject(err); };
						options.promisified = true;
						_old.apply(_self, args);
					});
				};
			};
		}
		var convert_collection_fn = create_converter('Collection');
		['fetch', 'save', 'destroy'].forEach(create_converter('Model'));
		['fetch'].forEach(convert_collection_fn);
		convert_collection_fn('reset_async', {options_idx: 1, names: ['complete']});
	};

	this.Composer.exp0rt({
		sync: sync,
		cid: cid,
		wrap_error: wrap_error,
		eq: eq,
		merge_extend: merge_extend,
		array: array,
		object: object,
		promisify: promisify
	});
}).apply((typeof exports != 'undefined') ? exports : this);

<commit_msg>a little cleanup<commit_after>/**
 * util.js
 *
 * This sets up our util object, which defines a way to export Composer
 * components and also defines a number of helper functions the rest of the
 * system will use.
 * -----------------------------------------------------------------------------
 *
 * Composer.js is an MVC framework for creating and organizing javascript
 * applications. For documentation, please visit:
 *
 *     http://lyonbros.github.com/composer.js/
 *
 * -----------------------------------------------------------------------------
 *
 * Copyright (c) 2011, Lyon Bros Enterprises, LLC. (http://www.lyonbros.com)
 *
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 */
(function() {
	"use strict";

	var global = this;
	if(!global.Composer) global.Composer = {
		// note: this used to be "export" but IE is a whiny little bitch, so now
		// we're sup3r 1337 h4x0r5
		exp0rt: function(obj)
		{
			Object.keys(obj).forEach(function(key) {
				global.Composer[key] = obj[key];
			});
		}
	};

	/**
	 * You must override this function in your app.
	 */
	var sync = function(method, model, options) { return options.success(); };

	// a closure that returns incrementing integers. these will be unique across
	// the entire app since only one counter is instantiated
	var cid = (function() {
		var counter = 1;
		return function(inc) { return 'c'+counter++; };
	})();

	// wraps error callbacks for syncing functions
	var wrap_error = function(callback, model, options)
	{
		return function(resp)
		{
			if(callback)
			{
				callback(model, resp, options);
			}
			else
			{
				this.fire_event('error', options, model, resp, options);
			}
		};
	};

	// Composer equality function. Does deep-inpection and is able to tell the
	// difference between {key: 3} and {key: 3, key2: 4} (_.eq had problems with
	// this back in the day).
	var eq = function(a, b)
	{
		if ( a === b ) return true;
		if(a instanceof Function) return false;
		if(typeof(a) != typeof(b)) return false;
		if((a && a.constructor) && !b || !b.constructor) return false;
		if((b && b.constructor) && !a || !a.constructor) return false;
		if(a && b && a.constructor != b.constructor) return false;
		if(a instanceof Array || Object.prototype.toString.call(a) === '[object Array]')
		{
			if(a.length != b.length) return false;
			// TODO: check if array indexes are always sequential
			for(var i = 0, n = a.length; i < n; i++)
			{
				if(!b.hasOwnProperty(i)) return false;
				if(!eq(a[i], b[i])) return false;
			}
		}
		else if(a instanceof Object)
		{
			for( var p in b )
			{
				if( b.hasOwnProperty(p) && ! a.hasOwnProperty(p) ) return false;
			}
			for( var p in a )
			{
				if ( ! a.hasOwnProperty( p ) ) continue;
				if ( ! b.hasOwnProperty( p ) ) return false;
				if ( a[ p ] === b[ p ] ) continue;
				if ( typeof( a[ p ] ) !== "object" ) return false;
				if ( ! eq( a[ p ],  b[ p ] ) ) return false;
			}
		}
		else if(a != b)
		{
			return false;
		}
		return true;
	};

	// create an extension function that merges specific properties from
	// inherited objects
	var merge_extend = function(cls, properties)
	{
		var _extend = cls.extend;
		cls.extend = function(def, base)
		{
			base || (base = this);
			var attr = base.prototype;

			properties.forEach(function(prop) {
				def[prop] = Composer.object.merge({}, attr[prop], def[prop]);
			});

			var cls = _extend.call(base, def);
			global.Composer.merge_extend(cls, properties);
			return cls;
		}
	};

	// some Mootools-reminiscent object utilities Composer uses
	var array = {
		erase: function(arr, item)
		{
			for(var i = arr.length - 1; i >= 0; i--)
			{
				if(arr[i] === item) arr.splice(i, 1);
			}
		},

		is: (function() {
			return ('isArray' in Array) ?
				Array.isArray :
				function(obj) {
					return obj instanceof Array || Object.prototype.toString.call(obj) === '[object Array]'
				}
		})()
	};
	var object = {
		each: function(obj, fn, bind)
		{
			if(!obj) return;
			bind || (bind = this);
			Object.keys(obj).forEach(function(key) {
				(fn.bind(bind))(obj[key], key)
			});
		},
		clone: function(obj, options)
		{
			options || (options = {});
			if(options.deep) return JSON.parse(JSON.stringify(obj));

			var clone = {};
			Object.keys(obj).forEach(function(key) {
				clone[key] = obj[key];
			});
			return clone;
		},
		merge: function(to, _)
		{
			var args = Array.prototype.slice.call(arguments, 1);
			args.forEach(function(obj) {
				if(!obj) return;
				Object.keys(obj).forEach(function(key) {
					to[key] = obj[key];
				});
			});
			return to;
		},
		set: function(object, key, value)
		{
			object || (object = {});
			var paths = key.split('.');
			var obj = object;
			for(var i = 0, n = paths.length; i < n; i++)
			{
				var path = paths[i];
				if(i == n - 1)
				{
					obj[path] = value;
					break;
				}

				if(!obj[path])
				{
					obj[path] = {};
				}
				else if(typeof(obj) != 'object' || Composer.array.is(obj))
				{
					obj[path] = {};
				}
				obj = obj[path];
			}
			return object;
		},
		get: function(object, key)
		{
			object || (object = {});
			var paths = key.split('.');
			var obj = object;
			for(var i = 0, n = paths.length; i < n; i++)
			{
				var path = paths[i];
				var type = typeof(obj[path]);
				if(type == 'undefined')
				{
					return obj[path];
				}
				obj = obj[path];
			}
			return obj;
		}
	};

	var promisify = function()
	{
		var create_converter = function(type)
		{
			return function(key)
			{
				var options = arguments[1] || {};
				var options_idx = options.options_idx || 0;
				var names = options.names || ['success', 'error'];

				var _old = Composer[type].prototype[key];
				global.Composer[type].prototype[key] = function()
				{
					var args = Array.prototype.slice.call(arguments, 0);
					if(args.length < options_idx)
					{
						var _tmp = new Array(options_idx);
						args.forEach(function(item, i) { _tmp[i] = item; });
						args = _tmp;
					}
					if(!args[options_idx]) args[options_idx] = {};
					var _self = this;
					var options = args[options_idx];
					if(options.promisified) return _old.apply(_self, args);
					return new Promise(function(resolve, reject) {
						if(names[0]) options[names[0]] = resolve;
						if(names[1]) options[names[1]] = function(_, err) { reject(err); };
						options.promisified = true;
						_old.apply(_self, args);
					});
				};
			};
		}
		var convert_collection_fn = create_converter('Collection');
		['fetch', 'save', 'destroy'].forEach(create_converter('Model'));
		['fetch'].forEach(convert_collection_fn);
		convert_collection_fn('reset_async', {options_idx: 1, names: ['complete']});
	};

	this.Composer.exp0rt({
		sync: sync,
		cid: cid,
		wrap_error: wrap_error,
		eq: eq,
		merge_extend: merge_extend,
		array: array,
		object: object,
		promisify: promisify
	});
}).apply((typeof exports != 'undefined') ? exports : this);

<|endoftext|>


<commit_before>// Gmailの最後に開いたThreadのID
function gmail_last_threadId(threadId) {
    if (threadId) {
        localStorage['gmail_threadId'] = threadId;
    } else {
        return localStorage['gmail_threadId'];
    }
}

function get_data(cb) {
    chrome.storage.sync.get(["laterData"], function(result) {
        if (result.laterData == undefined) { result.laterData = []; }
        if (typeof cb == "function" ) { cb(result); }
    });
}

function add_data(data) {
    get_data(function(result) {
        var laterData = result.laterData;
        var add = false;
        for (var i in laterData) {
            if (laterData[i].id == data.id) {
                laterData[i] = data;
                add = true;
            }
        }
        if (!add) {
            result.laterData.push(data);
        }
        chrome.storage.sync.set({laterData: result.laterData}, function() {
            var message = '';
            message += 'Added threadId: ' + data.id;
            if (message) { message += ' with message ' + data.message; };
            message += ' at ' + data.date;
            notification(message);
        });
    });
}

function set_data(data) {
    chrome.storage.sync.set({laterData: data}, function() {
        console.log('set data:');
        console.log(data);
    });
}

function del_data(id) {
    get_data(function(result) {
        var laterData = result.laterData;
        var data = [];
        for (var i in laterData) {
            if (laterData[i].id != id) {
                data.push(laterData[i]);
            }
        }
        set_data(data);
    });
}

function clear_complete() {
    get_data(function(result) {
        var laterData = result.laterData;
        var data = [];
        for (var i in laterData) {
            if (laterData[i]['isActive'] == 't') {
                data.push(laterData[i]);
            }
        }
        set_data(data);
    });
}

function add_zero(str, length) {
    for (var i=0; i<length; i++) {
        str = '0' + str;
    }
    return str.substr(length * -1, length);
}

function later_check() {
    get_data(function(result) {
        var today = new XDate();
        var t = today.toString('yyyy/MM/dd');
        var data = result.laterData;

        var item = [];
        for (var i in data) {
            var d = data[i];
            if (t >= d["date"] && d["isActive"] == 't') {
                item.push(d);
                resend(d, resended);
            }
        }
        console.log(item);
    });
}

function send_newmail(url, token, _item) {
    var item = _item;
    var mail = "";
    mail += "From: ReSendMeLater\n";
    mail += "\n";
    mail += unescape(encodeURIComponent(item.message)) + "\n";

    var newMail = new XMLHttpRequest();
    newMail.open('POST', url + 'messages');
    newMail.setRequestHeader('Authorization', 'Bearer ' + token);
    newMail.setRequestHeader('Content-Type', 'application/json');
    newMail.send(JSON.stringify(
        {
            threadId: item.id,
            raw: btoa(mail)
        }
    ));
    newMail.onreadystatechange = function() {
        if (newMail.readyState == 4 && newMail.status == 200) {
            console.log(newMail);
        }
    };
}

function unread_message(url, token, _item, thread, cb) {
    var messages = JSON.parse(thread.responseText).messages;
    var messageid = messages[messages.length - 1].id;
    var item = _item;
    console.log(messageid);

    var message = new XMLHttpRequest();
    message.open('POST', url + 'messages/' + messageid + '/modify');
    message.setRequestHeader('Authorization', 'Bearer ' + token);
    message.setRequestHeader('Content-Type', 'application/json');
    message.send(JSON.stringify({"addLabelIds":["UNREAD","INBOX"]}));
    message.onreadystatechange = function() {
        if (message.readyState == 4 && message.status == 200) {
            console.log(message);
            cb(item.id);
        }
    };
}

function get_snippet(threadId, cb) {
    chrome.identity.getAuthToken({ "interactive": true }, function(token) {
        var url = 'https://www.googleapis.com/gmail/v1/users/me/';
        var thread = new XMLHttpRequest();
        thread.open('GET', url + 'threads/' + threadId);
        thread.setRequestHeader('Authorization', 'Bearer ' + token);
        thread.send();
        thread.onreadystatechange = function() {
            if (thread.readyState == 4 && thread.status == 200) {
                console.log(JSON.parse(thread.responseText));
                var mail = JSON.parse(thread.responseText).messages[0];
                var headers = mail.payload.headers;
                var subject, from;
                for (var i in headers) {
                    if (headers[i].name == 'Subject') {
                        subject = headers[i].value;
                    }
                    if (headers[i].name == 'From') {
                        from = headers[i].value;
                    }
                    if (subject && from) {
                        continue;
                    }
                }
                cb(threadId, subject, from);
            }
        };
    });
}

function resend(_item, cb) {
    chrome.identity.getAuthToken({ 'interactive': true }, function(token) {
        var url = 'https://www.googleapis.com/gmail/v1/users/me/';
        var thread = new XMLHttpRequest();
        var item = _item;
        thread.open('GET', url + 'threads/' + item.id);
        thread.setRequestHeader('Authorization', 'Bearer ' + token);
        thread.send();
        thread.onreadystatechange = function() {
            if (thread.readyState == 4 && thread.status == 200) {
                unread_message(url, token, item, thread, cb);
            }
        };
        send_newmail(url, token, item);
    });
}

function resended(id) {
    get_data(function(result) {
        var data = result.laterData;
        for (var i in data) {
            if (id == data[i]["id"]) {
                data[i]["isActive"] = 'f';
                // item.push(data[i]);
            }
        }
        set_data(data);
    });
}

function clear_storage() {
    chrome.storage.sync.clear();
}

function display_storage() {
    chrome.storage.sync.get(["laterData"], function(result) {
        console.log(result);
    });
}

function show_input_dialog(threadId, str) {
    var text = str || "2014/8/5 息子の誕生日プレゼント候補";
    var result = prompt("未読化したい日付とメッセージ(オプション)を入力してください。", text);
    if (result && result.length > 0) {

        var id = (threadId || location.href.replace(/^.*\/([a-z0-9]+)$/, "$1"));

        if (threadId) {
            parseData(result, id);
        } else {
            chrome.extension.sendMessage({text: result, id: id}, function(response) {});
        }
    } else if (result.length == 0) {
        del_data(threadId);
    }
}

function parseData(text, id) {
    var d = text.split(/\s/);
    var date = str2date(d[0]);
    var message = d[1];

    if (date) {
        add_data({date: date, message: message, id: id, isActive: 't'});
    }
}

function str2date(str) {
    var date = undefined;
    var today = new XDate();

    // yyyy/mm/dd
    if (/^(\d{4})\/(\d{1,2})\/(\d{1,2})$/.test(str)) {
        date = RegExp.$1 + "/" + RegExp.$2 + "/" + RegExp.$3;
    }

    // yyyy/mm
    else if (/^(\d{4})\/(\d{1,2})$/.test(str)) {
        date = RegExp.$1 + "/" + RegExp.$2 + '/01'; // TODO: 過去日は弾いた方がいい？
    }

    // dd next mm/dd
    else if (/^(\d{1,2})\/(\d{1,2})$/.test(str)) {
        var m = RegExp.$1;
        var d = RegExp.$2;
        if ((m * 100 + d * 1) > today.toString('MMdd') * 1) {
            date = today.getFullYear() + "/" + m + "/" + d;
        } else {
            date = (today.getFullYear() * 1 + 1) + "/" + m + "/" + d;
        }
    }

    // dd next dd
    else if (/^(\d{1,2})$/.test(str)) {
        var d = RegExp.$1;
        if (d > today.toString('dd') * 1) {
            date = today.getFullYear() + "/" + (today.getMonth() + 1) + "/" + d;
        } else {
            var next = today.addMonths(1);
            date = next.getFullYear() + "/" + (next.getMonth() + 1) + "/" + d;
        }
    }

    // +N N day
    else if (/^\+(\d+)$/.test(str)) {
        date = today.addDays(RegExp.$1).toString('yyyy/MM/dd');
    }

    // +Nw N week
    else if (/^\+(\d+)[wW]$/.test(str)) {
        date = today.addWeeks(RegExp.$1).toString('yyyy/MM/dd');

    }

    // +Nw N month
    else if (/^\+(\d+)[mM]$/.test(str)) {
        date = today.addMonths(RegExp.$1).toString('yyyy/MM/dd');
    }

    if (date != undefined && /^(\d{4})\/(\d{1,2})\/(\d{1,2})$/.test(date)) {
        date = RegExp.$1 + "/" + add_zero(RegExp.$2, 2) + "/" + add_zero(RegExp.$3, 2);
    }

    return date;
}

function create_contextmenus() {
    chrome.contextMenus.create({
        title: "ReSendMeLater",
        id: 'parent',
        enabled: false
    });
    chrome.contextMenus.create({
        title: "Show dialog",
        parentId: 'parent',
        id: 'main'
    });
    chrome.contextMenus.create({
        parentId: 'parent',
        type: 'separator',
        id: 'line1'
    });
    chrome.contextMenus.create({
        title: "Later +1 days",
        parentId: 'parent',
        id: '1days'
    });
    chrome.contextMenus.create({
        title: "Later +1 weeks",
        parentId: 'parent',
        id: '1weeks'
    });
    chrome.contextMenus.create({
        title: "Later +10 days",
        parentId: 'parent',
        id: '10days'
    });
    chrome.contextMenus.create({
        title: "Later +1 months",
        parentId: 'parent',
        id: '1months'
    });
    chrome.contextMenus.create({
        parentId: 'parent',
        type: 'separator',
        id: 'line2'
    });
    chrome.contextMenus.create({
        title: 'Later list',
        parentId: 'parent',
        id: 'list'
    });
}

function notification(message) {
    chrome.notifications.create('ReSendMeLater', {
        type: 'basic',
        title: 'ReSendMeLater',
        iconUrl: chrome.extension.getURL('icons/icon128.png'),
        message: message
    }, function(id) { console.log('notif'); });
}
<commit_msg>エラーの抑制<commit_after>// Gmailの最後に開いたThreadのID
function gmail_last_threadId(threadId) {
    if (threadId) {
        localStorage['gmail_threadId'] = threadId;
    } else {
        return localStorage['gmail_threadId'];
    }
}

function get_data(cb) {
    chrome.storage.sync.get(["laterData"], function(result) {
        if (result.laterData == undefined) { result.laterData = []; }
        if (typeof cb == "function" ) { cb(result); }
    });
}

function add_data(data) {
    get_data(function(result) {
        var laterData = result.laterData;
        var add = false;
        for (var i in laterData) {
            if (laterData[i].id == data.id) {
                laterData[i] = data;
                add = true;
            }
        }
        if (!add) {
            result.laterData.push(data);
        }
        chrome.storage.sync.set({laterData: result.laterData}, function() {
            var message = '';
            message += 'Added threadId: ' + data.id;
            if (message) { message += ' with message ' + data.message; };
            message += ' at ' + data.date;
            notification(message);
        });
    });
}

function set_data(data) {
    chrome.storage.sync.set({laterData: data}, function() {
        console.log('set data:');
        console.log(data);
    });
}

function del_data(id) {
    get_data(function(result) {
        var laterData = result.laterData;
        var data = [];
        for (var i in laterData) {
            if (laterData[i].id != id) {
                data.push(laterData[i]);
            }
        }
        set_data(data);
    });
}

function clear_complete() {
    get_data(function(result) {
        var laterData = result.laterData;
        var data = [];
        for (var i in laterData) {
            if (laterData[i]['isActive'] == 't') {
                data.push(laterData[i]);
            }
        }
        set_data(data);
    });
}

function add_zero(str, length) {
    for (var i=0; i<length; i++) {
        str = '0' + str;
    }
    return str.substr(length * -1, length);
}

function later_check() {
    get_data(function(result) {
        var today = new XDate();
        var t = today.toString('yyyy/MM/dd');
        var data = result.laterData;

        var item = [];
        for (var i in data) {
            var d = data[i];
            if (t >= d["date"] && d["isActive"] == 't') {
                item.push(d);
                resend(d, resended);
            }
        }
        console.log(item);
    });
}

function send_newmail(url, token, _item) {
    var item = _item;
    var mail = "";
    mail += "From: ReSendMeLater\n";
    mail += "\n";
    mail += unescape(encodeURIComponent(item.message)) + "\n";

    var newMail = new XMLHttpRequest();
    newMail.open('POST', url + 'messages');
    newMail.setRequestHeader('Authorization', 'Bearer ' + token);
    newMail.setRequestHeader('Content-Type', 'application/json');
    newMail.send(JSON.stringify(
        {
            threadId: item.id,
            raw: btoa(mail)
        }
    ));
    newMail.onreadystatechange = function() {
        if (newMail.readyState == 4 && newMail.status == 200) {
            console.log(newMail);
        }
    };
}

function unread_message(url, token, _item, thread, cb) {
    var messages = JSON.parse(thread.responseText).messages;
    var messageid = messages[messages.length - 1].id;
    var item = _item;
    console.log(messageid);

    var message = new XMLHttpRequest();
    message.open('POST', url + 'messages/' + messageid + '/modify');
    message.setRequestHeader('Authorization', 'Bearer ' + token);
    message.setRequestHeader('Content-Type', 'application/json');
    message.send(JSON.stringify({"addLabelIds":["UNREAD","INBOX"]}));
    message.onreadystatechange = function() {
        if (message.readyState == 4 && message.status == 200) {
            console.log(message);
            cb(item.id);
        }
    };
}

function get_snippet(threadId, cb) {
    chrome.identity.getAuthToken({ "interactive": true }, function(token) {
        var url = 'https://www.googleapis.com/gmail/v1/users/me/';
        var thread = new XMLHttpRequest();
        thread.open('GET', url + 'threads/' + threadId);
        thread.setRequestHeader('Authorization', 'Bearer ' + token);
        thread.send();
        thread.onreadystatechange = function() {
            if (thread.readyState == 4 && thread.status == 200) {
                console.log(JSON.parse(thread.responseText));
                var mail = JSON.parse(thread.responseText).messages[0];
                var headers = mail.payload.headers;
                var subject, from;
                for (var i in headers) {
                    if (headers[i].name == 'Subject') {
                        subject = headers[i].value;
                    }
                    if (headers[i].name == 'From') {
                        from = headers[i].value;
                    }
                    if (subject && from) {
                        continue;
                    }
                }
                cb(threadId, subject, from);
            }
        };
    });
}

function resend(_item, cb) {
    chrome.identity.getAuthToken({ 'interactive': true }, function(token) {
        var url = 'https://www.googleapis.com/gmail/v1/users/me/';
        var thread = new XMLHttpRequest();
        var item = _item;
        thread.open('GET', url + 'threads/' + item.id);
        thread.setRequestHeader('Authorization', 'Bearer ' + token);
        thread.send();
        thread.onreadystatechange = function() {
            if (thread.readyState == 4 && thread.status == 200) {
                unread_message(url, token, item, thread, cb);
            }
        };
        send_newmail(url, token, item);
    });
}

function resended(id) {
    get_data(function(result) {
        var data = result.laterData;
        for (var i in data) {
            if (id == data[i]["id"]) {
                data[i]["isActive"] = 'f';
                // item.push(data[i]);
            }
        }
        set_data(data);
    });
}

function clear_storage() {
    chrome.storage.sync.clear();
}

function display_storage() {
    chrome.storage.sync.get(["laterData"], function(result) {
        console.log(result);
    });
}

function show_input_dialog(threadId, str) {
    var text = str || "2014/8/5 息子の誕生日プレゼント候補";
    var result = prompt("未読化したい日付とメッセージ(オプション)を入力してください。", text);
    if (result && result.length > 0) {

        var id = (threadId || location.href.replace(/^.*\/([a-z0-9]+)$/, "$1"));

        if (threadId) {
            parseData(result, id);
        } else {
            chrome.extension.sendMessage({text: result, id: id}, function(response) {});
        }
    } else if (result && result.length == 0) {
        del_data(threadId);
    }
}

function parseData(text, id) {
    var d = text.split(/\s/);
    var date = str2date(d[0]);
    var message = d[1];

    if (date) {
        add_data({date: date, message: message, id: id, isActive: 't'});
    }
}

function str2date(str) {
    var date = undefined;
    var today = new XDate();

    // yyyy/mm/dd
    if (/^(\d{4})\/(\d{1,2})\/(\d{1,2})$/.test(str)) {
        date = RegExp.$1 + "/" + RegExp.$2 + "/" + RegExp.$3;
    }

    // yyyy/mm
    else if (/^(\d{4})\/(\d{1,2})$/.test(str)) {
        date = RegExp.$1 + "/" + RegExp.$2 + '/01'; // TODO: 過去日は弾いた方がいい？
    }

    // dd next mm/dd
    else if (/^(\d{1,2})\/(\d{1,2})$/.test(str)) {
        var m = RegExp.$1;
        var d = RegExp.$2;
        if ((m * 100 + d * 1) > today.toString('MMdd') * 1) {
            date = today.getFullYear() + "/" + m + "/" + d;
        } else {
            date = (today.getFullYear() * 1 + 1) + "/" + m + "/" + d;
        }
    }

    // dd next dd
    else if (/^(\d{1,2})$/.test(str)) {
        var d = RegExp.$1;
        if (d > today.toString('dd') * 1) {
            date = today.getFullYear() + "/" + (today.getMonth() + 1) + "/" + d;
        } else {
            var next = today.addMonths(1);
            date = next.getFullYear() + "/" + (next.getMonth() + 1) + "/" + d;
        }
    }

    // +N N day
    else if (/^\+(\d+)$/.test(str)) {
        date = today.addDays(RegExp.$1).toString('yyyy/MM/dd');
    }

    // +Nw N week
    else if (/^\+(\d+)[wW]$/.test(str)) {
        date = today.addWeeks(RegExp.$1).toString('yyyy/MM/dd');

    }

    // +Nw N month
    else if (/^\+(\d+)[mM]$/.test(str)) {
        date = today.addMonths(RegExp.$1).toString('yyyy/MM/dd');
    }

    if (date != undefined && /^(\d{4})\/(\d{1,2})\/(\d{1,2})$/.test(date)) {
        date = RegExp.$1 + "/" + add_zero(RegExp.$2, 2) + "/" + add_zero(RegExp.$3, 2);
    }

    return date;
}

function create_contextmenus() {
    chrome.contextMenus.create({
        title: "ReSendMeLater",
        id: 'parent',
        enabled: false
    });
    chrome.contextMenus.create({
        title: "Show dialog",
        parentId: 'parent',
        id: 'main'
    });
    chrome.contextMenus.create({
        parentId: 'parent',
        type: 'separator',
        id: 'line1'
    });
    chrome.contextMenus.create({
        title: "Later +1 days",
        parentId: 'parent',
        id: '1days'
    });
    chrome.contextMenus.create({
        title: "Later +1 weeks",
        parentId: 'parent',
        id: '1weeks'
    });
    chrome.contextMenus.create({
        title: "Later +10 days",
        parentId: 'parent',
        id: '10days'
    });
    chrome.contextMenus.create({
        title: "Later +1 months",
        parentId: 'parent',
        id: '1months'
    });
    chrome.contextMenus.create({
        parentId: 'parent',
        type: 'separator',
        id: 'line2'
    });
    chrome.contextMenus.create({
        title: 'Later list',
        parentId: 'parent',
        id: 'list'
    });
}

function notification(message) {
    chrome.notifications.create('ReSendMeLater', {
        type: 'basic',
        title: 'ReSendMeLater',
        iconUrl: chrome.extension.getURL('icons/icon128.png'),
        message: message
    }, function(id) { console.log('notif'); });
}
<|endoftext|>


<commit_before>const { hash } = require('crypto-promise')

export const denodeify = require('es6-denodeify')(Promise)

export const err = (message, props) =>
  Object.assign(new Error(message), props)

export const xml = denodeify(require('xml2js').parseString)

export const md5 = async data =>
  (await hash('md5')(data)).toString('hex')
<commit_msg>Flag internal errors<commit_after>const { hash } = require('crypto-promise')

export const denodeify = require('es6-denodeify')(Promise)

export const err = (message, props) =>
  Object.assign(new Error(message), { jvc: true }, props)

export const xml = denodeify(require('xml2js').parseString)

export const md5 = async data =>
  (await hash('md5')(data)).toString('hex')
<|endoftext|>


<commit_before>/** `Object#toString` result shortcuts */
var argsClass = '[object Arguments]',
    arrayClass = '[object Array]',
    boolClass = '[object Boolean]',
    dateClass = '[object Date]',
    errorClass = '[object Error]',
    funcClass = '[object Function]',
    numberClass = '[object Number]',
    objectClass = '[object Object]',
    regexpClass = '[object RegExp]',
    stringClass = '[object String]';
var support = {};
(function() {
  var ctor = function() { this.x = 1; },
      object = { '0': 1, 'length': 1 },
      props = [];

  ctor.prototype = { 'valueOf': 1, 'y': 1 };
  for (var key in new ctor) { props.push(key); }
  for (key in arguments) { }

  /**
   * Detect if an `arguments` object's [[Class]] is resolvable (all but Firefox < 4, IE < 9).
   *
   * @memberOf _.support
   * @type boolean
   */
  support.argsClass = toString.call(arguments) == argsClass;
}(1));
var hasOwnProperty = Object.prototype.hasOwnProperty;
var getOwnPropertyNames = Object.getOwnPropertyNames; //>=ECMAScript5 only

var util = module.exports = {
    objectToString: function(o) {
      return Object.prototype.toString.call(o);
    },

    isArray: Array.isArray,

    isBoolean: function(arg) {
      return typeof arg === 'boolean';
    },

    isNullOrUndefined: function(arg) {
      return arg == null;
    },

    isString: function(arg) {
      return typeof arg === 'string';
    },

    isNumber: function(arg) {
      return typeof arg === 'number';
    },

    isUndefined: function(arg) {
      return arg === void 0;
    },

    isObject: function(arg) {
      return arg != null && typeof arg === 'object';
    },

    isFunction: function(arg) {
      return typeof arg === 'function';
    },

    isDate: function(d) {
      return util.isObject(d) && util.objectToString(d) === '[object Date]';
    },
    isArguments: function(value) {
      return value && typeof value == 'object' && typeof value.length == 'number' &&
        toString.call(value) == argsClass || false;
    },
    isEmpty: function(value) {
      var result = true;
      if (!value) {
        return result;
      }
      var className = toString.call(value),
          length = value.length;

      if ((className == arrayClass || className == stringClass ||
          (support.argsClass ? className == argsClass : util.isArguments(value))) ||
          (className == objectClass && typeof length == 'number' && util.isFunction(value.splice))) {
        return !length;
      }

      if (className == funcClass) {
        return util.isEmptyFunction(value)
      }

      if (getOwnPropertyNames(value).length > 0) return false;
      /*
      for (var key in value) {
        if (hasOwnProperty.call(value, key)) return false;
      }
      */
      return result;
    },

    /**
     * Inherit the prototype methods from one constructor into another.
     *
     *
     * The Function.prototype.inherits from lang.js rewritten as a standalone
     * function (not on Function.prototype). NOTE: If this file is to be loaded
     * during bootstrapping this function needs to be rewritten using some native
     * functions as prototype setup using normal JavaScript does not work as
     * expected during bootstrapping (see mirror.js in r114903).
     *
     * @param {function} ctor Constructor function which needs to inherit the
     *     prototype.
     * @param {function} superCtor Constructor function to inherit prototype from.
     */
    inherits: function(ctor, superCtor) {
      var v  = ctor.super_;
      var result = false;
      if (!util.isInheritedFrom(ctor, superCtor)) {
        ctor.super_ = superCtor;
        ctor.__super__ = superCtor.prototype; //for coffeeScirpt super keyword.
        ctor.prototype = util.newPrototype(superCtor, ctor);
        //result = util.inherits(superCtor, v);
        while (v != null) {
          ctor = superCtor;
          superCtor = v;
          ctor.super_ = superCtor;
          ctor.__super__ = superCtor.prototype; //for coffeeScirpt super keyword.
          ctor.prototype = util.newPrototype(superCtor, ctor);
          v = ctor.super_;
        }
        result = true;
      }
      return result;
    },
    isInheritedFrom: function(ctor, superCtor) {
      var result  = ctor.super_ === superCtor;
      var checkeds = [];
      var lastCtor = ctor;
      checkeds.push(ctor);
      while (!result && ((ctor = ctor.super_) != null)) {
        if (checkeds.indexOf(ctor) >= 0) {
          throw Error("Circular inherits found!");
        }
        checkeds.push(ctor);
        result = ctor.super_ === superCtor;
      }
      return result;
    },
    newPrototype: function(aClass, aConstructor) {
      //Object.create(prototype) only for ES5
      //Object.create(prototype, initProps) only for ES6
      //For Browser not support ES5/6:
      //  var Object = function() { this.constructor = aConstructor; };
      //  Object.prototype = aClass.prototype;
      //  return new Object();
      var ctor = util.isEmptyFunction(aConstructor) ? util.getConstructor(aClass) : aConstructor;
      var result;
      if (Object.create) { //typeof Object.create === 'function'
        result = Object.create(aClass.prototype, {
          constructor: {
            value: ctor,
            enumerable: false,
            writable: true,
            configurable: true
          }
        });
      } else {
        var Obj = function obj() {this.constructor = ctor};
        Obj.prototype = aClass.prototype;
        result = new Obj();
      }
      util._extend(result, aConstructor.prototype);
      return result;
    },
    createObjectWith: function(aClass, aArguments) {
      args = [aClass];
      if (aArguments)
        args = args.concat(Array.prototype.slice.call(aArguments));
      var result = new (Function.prototype.bind.apply(aClass, args));
      if (aClass !== aClass.prototype.constructor)
        aClass.prototype.constructor.apply(result, aArguments);
      return result;
    },
    createObject: function(aClass) {
      var result = new (Function.prototype.bind.apply(aClass, arguments));
      if (aClass !== aClass.prototype.constructor)
        aClass.prototype.constructor.apply(result, Array.prototype.slice.call(arguments, 1));
      return result;
    },
    createObjectOld: function(aClass, aArguments) {
      function F() {
          return aClass.apply(this, aArguments);
      }
      F.prototype = aClass.prototype;
      return new F();
    },
    isEmptyFunction: function(aFunc) {
      var result = /^function\s*\S*\s*\(.*\)\s*{[\s;]*}$/.test(aFunc.toString());
      return result;
    },
    _extend: function(origin, add) {
      // Don't do anything if add isn't an object
      if (!add || !util.isObject(add)) return origin;

      var keys = Object.keys(add);
      var i = keys.length;
      while (i--) {
        origin[keys[i]] = add[keys[i]];
      }
      return origin;
    },
    //make sure the aClass.prototype hook to the aObject instance.
    inheritsObject: function(aObject, aClass) {
      var vOldProto = aObject.__proto__;
      var result = false;
      if ( vOldProto !== aClass.prototype) {
        util.inherits(aClass, vOldProto.constructor);
        aObject.__proto__ = aClass.prototype;
        result = true;
      }
      return result;
    },
    //get latest non-empty constructor function through inherits link:
    getConstructor: function(ctor) {
      var result = ctor;
      var isEmpty = util.isEmptyFunction(result);
      while (isEmpty && (result.super_)) {
        result  = result.super_;
        isEmpty = util.isEmptyFunction(result);
      }
      //if (isEmpty) result = null;
      return result;
    },
    /*
    @desc  inject the function
    @param aOrgFunc     the original function to be injected.
    @param aBeforeExec  this is called before the execution of the aOrgFunc.
                        you must return the arguments(new Arguments(arguments))
                        if you wanna modify the arguments value of the aOrgFunc.
                        it will stop the execution of the aOrgFunc if you return
                        a value not an Arguments object nor a undefined value
    @param aAtferExec   this is called after the execution of the aOrgFunc.
                        you must add a result argument at the last argument of the
                        aAtferExec function if you wanna get the result value of the aOrgFunc.
                        you must add a isDenied argument following the result argument if you
                        wanna know whether the aOrgFunc is executed.
                        you must return the result if you wanna modify the result value of the aOrgFunc .

    @Usage  Obj.prototype.Method = inject(Obj.prototype.Method, aFunctionBeforeExec[, aFunctionAtferExec]);
    @version 1.1
    @author  Aimingoo&Riceball
    @history
      V1.0 -- first released.
      V1.1 --
        Supports to denie the aOrgFunc execution in aBeforeExec.
        Supports around in the aAtferExec, the aAtferExec be always executed even though
        denie the aOrgFunc execution in aBeforeExec.
          + isDenied argument to the aAtferExec function. notice the aAtferExec whether
            the aOrgFunc is executed

    eg:
    var doTest = function (a) {return a};
    function beforeTest(a) {
      alert('before exec: a='+a);
      a += 3;
      return arguments;
    };
    function afterTest(a, result, isDenied) {
      alert('after exec: a='+a+';result='+result+';isDenied='+isDenied);
      return result+5;
    };

    doTest = inject(doTest, beforeTest, afterTest);

    alert (doTest(2));
    the result should be 10.

  */
  inject: function ( aOrgFunc, aBeforeExec, aAtferExec ) {
    return function() {
      var Result, isDenied=false, args=[].slice.call(arguments);
      if (typeof(aBeforeExec) === 'function') {
        //the result
        //  * a return value instead of original function.
        //  * an arguments pass to original function.
        //  * whether deny the original function.
        //    * return the arguments to allow execution
        //    * return undefined to allow execution
        Result = aBeforeExec.apply(this, args);
        if (util.isArguments(Result)) {
          args = [].slice.call(Result)
        }
        else if (isDenied = Result !== undefined)
          args.push(Result)
      }

      !isDenied && args.push(aOrgFunc.apply(this, args)); //if (!isDenied) args.push(aOrgFunc.apply(this, args));

      if (typeof(aAtferExec) === 'function') {
        Result = aAtferExec.apply(this, args.concat(isDenied));
      }
      else
        Result = undefined;

      return (Result !== undefined ? Result : args.pop());
    }
  }
}
<commit_msg>* minor changes.<commit_after>/** `Object#toString` result shortcuts */
var argsClass = '[object Arguments]',
    arrayClass = '[object Array]',
    boolClass = '[object Boolean]',
    dateClass = '[object Date]',
    errorClass = '[object Error]',
    funcClass = '[object Function]',
    numberClass = '[object Number]',
    objectClass = '[object Object]',
    regexpClass = '[object RegExp]',
    stringClass = '[object String]';
var support = {};
(function() {
  var ctor = function() { this.x = 1; },
      object = { '0': 1, 'length': 1 },
      props = [];

  ctor.prototype = { 'valueOf': 1, 'y': 1 };
  for (var key in new ctor) { props.push(key); }
  for (key in arguments) { }

  /**
   * Detect if an `arguments` object's [[Class]] is resolvable (all but Firefox < 4, IE < 9).
   *
   * @memberOf _.support
   * @type boolean
   */
  support.argsClass = toString.call(arguments) == argsClass;
}(1));
var hasOwnProperty = Object.prototype.hasOwnProperty;
var getOwnPropertyNames = Object.getOwnPropertyNames; //>=ECMAScript5 only

var util = module.exports = {
    objectToString: function(o) {
      return Object.prototype.toString.call(o);
    },

    isArray: Array.isArray,

    isBoolean: function(arg) {
      return typeof arg === 'boolean';
    },

    isNullOrUndefined: function(arg) {
      return arg == null;
    },

    isString: function(arg) {
      return typeof arg === 'string';
    },

    isNumber: function(arg) {
      return typeof arg === 'number';
    },

    isUndefined: function(arg) {
      return arg === void 0;
    },

    isObject: function(arg) {
      return arg != null && typeof arg === 'object';
    },

    isFunction: function(arg) {
      return typeof arg === 'function';
    },

    isDate: function(d) {
      return util.isObject(d) && util.objectToString(d) === '[object Date]';
    },
    isArguments: function(value) {
      return value && typeof value == 'object' && typeof value.length == 'number' &&
        toString.call(value) == argsClass || false;
    },
    isEmpty: function(value) {
      var result = true;
      if (!value) {
        return result;
      }
      var className = toString.call(value),
          length = value.length;

      if ((className == arrayClass || className == stringClass ||
          (support.argsClass ? className == argsClass : util.isArguments(value))) ||
          (className == objectClass && typeof length == 'number' && util.isFunction(value.splice))) {
        return !length;
      }

      if (className == funcClass) {
        return util.isEmptyFunction(value)
      }

      if (getOwnPropertyNames(value).length > 0) return false;
      /*
      for (var key in value) {
        if (hasOwnProperty.call(value, key)) return false;
      }
      */
      return result;
    },

    /**
     * Inherit the prototype methods from one constructor into another.
     *
     *
     * The Function.prototype.inherits from lang.js rewritten as a standalone
     * function (not on Function.prototype). NOTE: If this file is to be loaded
     * during bootstrapping this function needs to be rewritten using some native
     * functions as prototype setup using normal JavaScript does not work as
     * expected during bootstrapping (see mirror.js in r114903).
     *
     * @param {function} ctor Constructor function which needs to inherit the
     *     prototype.
     * @param {function} superCtor Constructor function to inherit prototype from.
     */
    inherits: function(ctor, superCtor) {
      var v  = ctor.super_;
      var result = false;
      if (!util.isInheritedFrom(ctor, superCtor)) {
        ctor.super_ = superCtor;
        ctor.__super__ = superCtor.prototype; //for coffeeScirpt super keyword.
        ctor.prototype = util.newPrototype(superCtor, ctor);
        //result = util.inherits(superCtor, v);
        while (v != null) {
          ctor = superCtor;
          superCtor = v;
          ctor.super_ = superCtor;
          ctor.__super__ = superCtor.prototype; //for coffeeScirpt super keyword.
          ctor.prototype = util.newPrototype(superCtor, ctor);
          v = ctor.super_;
        }
        result = true;
      }
      return result;
    },
    isInheritedFrom: function(ctor, superCtor) {
      var result  = ctor.super_ === superCtor;
      var checkeds = [];
      var lastCtor = ctor;
      checkeds.push(ctor);
      while (!result && ((ctor = ctor.super_) != null)) {
        if (checkeds.indexOf(ctor) >= 0) {
          throw Error("Circular inherits found!");
        }
        checkeds.push(ctor);
        result = ctor.super_ === superCtor;
      }
      return result;
    },
    newPrototype: function(aClass, aConstructor) {
      //Object.create(prototype) only for ES5
      //Object.create(prototype, initProps) only for ES6
      //For Browser not support ES5/6:
      //  var Object = function() { this.constructor = aConstructor; };
      //  Object.prototype = aClass.prototype;
      //  return new Object();
      var ctor = util.isEmptyFunction(aConstructor) ? util.getConstructor(aClass) : aConstructor;
      var result;
      if (Object.create) { //typeof Object.create === 'function'
        result = Object.create(aClass.prototype, {
          constructor: {
            value: ctor,
            enumerable: false,
            writable: true,
            configurable: true
          }
        });
      } else {
        var Obj = function obj() {this.constructor = ctor};
        Obj.prototype = aClass.prototype;
        result = new Obj();
      }
      util._extend(result, aConstructor.prototype);
      return result;
    },
    createObjectWith: function(aClass, aArguments) {
      args = [aClass];
      if (aArguments)
        args = args.concat(Array.prototype.slice.call(aArguments));
      var result = new (Function.prototype.bind.apply(aClass, args));
      if (aClass !== aClass.prototype.constructor)
        aClass.prototype.constructor.apply(result, aArguments);
      return result;
    },
    createObject: function(aClass) {
      var result = new (Function.prototype.bind.apply(aClass, arguments));
      if (aClass !== aClass.prototype.constructor)
        aClass.prototype.constructor.apply(result, Array.prototype.slice.call(arguments, 1));
      return result;
    },
    createObjectOld: function(aClass, aArguments) {
      function F() {
          return aClass.apply(this, aArguments);
      }
      F.prototype = aClass.prototype;
      return new F();
    },
    isEmptyFunction: function(aFunc) {
      var result = /^function\s*\S*\s*\(.*\)\s*{[\s;]*}$/.test(aFunc.toString());
      return result;
    },
    _extend: function(origin, add) {
      // Don't do anything if add isn't an object
      if (!add || !util.isObject(add)) return origin;

      var keys = Object.keys(add);
      var i = keys.length;
      while (i--) {
        origin[keys[i]] = add[keys[i]];
      }
      return origin;
    },
    //make sure the aClass.prototype hook to the aObject instance.
    inheritsObject: function(aObject, aClass) {
      var vOldProto = aObject.__proto__;
      var result = false;
      if ( vOldProto !== aClass.prototype) {
        util.inherits(aClass, vOldProto.constructor);
        aObject.__proto__ = aClass.prototype;
        result = true;
      }
      return result;
    },
    //get latest non-empty constructor function through inherits link:
    getConstructor: function(ctor) {
      var result = ctor;
      var isEmpty = util.isEmptyFunction(result);
      while (isEmpty && (result.super_)) {
        result  = result.super_;
        isEmpty = util.isEmptyFunction(result);
      }
      //if (isEmpty) result = null;
      return result;
    },
    /*
    @desc  inject the function
    @param aOrgFunc     the original function to be injected.
    @param aBeforeExec  this is called before the execution of the aOrgFunc.
                        you must return the arguments(new Arguments(arguments))
                        if you wanna modify the arguments value of the aOrgFunc.
                        it will stop the execution of the aOrgFunc if you return
                        a value not an Arguments object nor a undefined value
    @param aAtferExec   this is called after the execution of the aOrgFunc.
                        you must add a result argument at the last argument of the
                        aAtferExec function if you wanna get the result value of the aOrgFunc.
                        you must add a isDenied argument following the result argument if you
                        wanna know whether the aOrgFunc is executed.
                        you must return the result if you wanna modify the result value of the aOrgFunc .

    @Usage  Obj.prototype.Method = inject(Obj.prototype.Method, aFunctionBeforeExec[, aFunctionAtferExec]);
    @version 1.1
    @author  Aimingoo&Riceball
    @history
      V1.0 -- first released.
      V1.1 --
        Supports to denie the aOrgFunc execution in aBeforeExec.
        Supports around in the aAtferExec, the aAtferExec be always executed even though
        denie the aOrgFunc execution in aBeforeExec.
          + isDenied argument to the aAtferExec function. notice the aAtferExec whether
            the aOrgFunc is executed

    eg:
    var doTest = function (a) {return a};
    function beforeTest(a) {
      alert('before exec: a='+a);
      a += 3;
      return arguments;
    };
    function afterTest(a, result, isDenied) {
      alert('after exec: a='+a+';result='+result+';isDenied='+isDenied);
      return result+5;
    };

    doTest = inject(doTest, beforeTest, afterTest);

    alert (doTest(2));
    the result should be 10.

  */
  inject: function ( aOrgFunc, aBeforeExec, aAtferExec ) {
    var arraySlice = Array.prototype.slice;
    return function() {
      var Result, isDenied=false, args=arraySlice.call(arguments);
      if (typeof(aBeforeExec) === 'function') {
        //the result
        //  * a return value instead of original function.
        //  * an arguments pass to original function.
        //  * whether deny the original function.
        //    * return the arguments to allow execution
        //    * return undefined to allow execution
        Result = aBeforeExec.apply(this, args);
        if (util.isArguments(Result)) {
          args = arraySlice.call(Result)
        }
        else if (isDenied = Result !== undefined)
          args.push(Result)
      }

      !isDenied && args.push(aOrgFunc.apply(this, args)); //if (!isDenied) args.push(aOrgFunc.apply(this, args));

      if (typeof(aAtferExec) === 'function') {
        Result = aAtferExec.apply(this, args.concat(isDenied));
      }
      else
        Result = undefined;

      return (Result !== undefined ? Result : args.pop());
    }
  }
}
<|endoftext|>


<commit_before>define([
    'json!langCodes',
    'jquery',
    'jquery.bootstrap-popout'
], function (
    langCodes,
    $
) {
    RegExp.escape = function(s) {
        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    };

    $.fn.stopLink = function() {
        // stops anchor tags from clicking through
        this.click(function (e) {
            e.preventDefault();
        });
        return this;
    };

    $.fn.fdHelp = function () {
        // creates a help popover, requires twitter bootstrap
        this.append($('<i />').addClass('icon-question-sign'))
            .popout({
                trigger: 'hover',
                html: true
            });
        return this;
    };

    var that = {};

    that.langCodeToName = {};
    _.each(langCodes, function (lang) {
        that.langCodeToName[lang.code] = lang.name;
    });

    that.XPATH_REFERENCES = [
        "bindElement/relevantAttr",
        "bindElement/calculateAttr",
        "bindElement/constraintAttr"
    ];

    that.getTemplateObject = function (selector, params) {
        return $(_.template($(selector).text(), params));
    };

    /**
     * Check if value is a valid XML attribute value (additionally disallow all
     * ' and ")
     */
    that.isValidAttributeValue = function (value) {
        return (/^[^<&'"]*$/).test(value);
    };

    /**
     * Grabs the value between the tags of the element passed in
     * and returns a string of everything inside.
     *
     * This method is kindy of hacky, so buyer beware.
     *
     * Motivation: Jquery's selector can't do this.  We need to be able to
     * grab the value of label tags, even if it includes <output> tags inside
     * of it (since the tag may need to be displayed to the user).
     * @param el - jquery selector or string used in the selector pointing to a DOM element.
     */
    that.getXLabelValue = function(el){
        var xmls = new XMLSerializer(),
            resStr, resEl;
        function getEndTag (str) {
            var res, reo, last;
            reo = /<\/(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g;
            res = reo.exec(str);
            last = res;
            while(res !== null) {
                last = res;
                res = reo.exec(str);
            }
            if(last){
                return last[0];
            }else{
                return null;
            }

        }

        function getStartTag (str) {
            var re, res;
            re = /<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/;
            res = re.exec(str);
            return res[0];
        }

        resEl = $(el)[0];
        if(!resEl) { return; }
        resStr = xmls.serializeToString(resEl);
        resStr = resStr.replace(getStartTag(resStr),'').replace(getEndTag(resStr),'');

        return resStr;
    };

    /**
     * Given two lists, creates a new array (and returns it)
     * that contains only unique values
     * based on comparing the two argument arrays.
     * @param arrA
     * @param arrB
     */
    var mergeArray = function (arrA, arrB) {
        var result = [], i;
        for(i in arrA){
            if(arrA.hasOwnProperty(i)){
                if(arrA.slice(0,arrA.indexOf(i)).indexOf(i) === -1){ //check to see if there aren't dupes in arrA
                    result.push(arrA[i]);
                }
            }
        }

        for(i in arrB){
            if(arrB.hasOwnProperty(i)){
                if(result.indexOf(arrB[i]) === -1){
                    result.push(arrB[i]); //grab only anything that hasn't shown up yet
                }
            }
        }

        return result;
    };
    that.mergeArray = mergeArray;

    //Simple Event Framework
    //Just run your object through this function to make it event aware
    //Taken from 'JavaScript: The Good Parts'
    that.eventuality = function (that) {
        var registry = {};
        that.fire = function (event) {
            var array,
                func,
                handler,
                i,
                type = typeof event === 'string' ?
                        event : event.type;
            if (registry.hasOwnProperty(type)) {
                array = registry[type];
                for (i = 0; i < array.length; i += 1) {
                    handler = array[i];
                    func = handler.method;
                    if (typeof func === 'string') {
                        func = this[func];
                    }
                    func.apply(this,
                        handler.parameters || [event]);
                }
            }
            return this;
        };
        that.on = function (type, method, parameters) {
            var handler = {
                method: method,
                parameters: parameters
            };
            if (registry.hasOwnProperty(type)) {
                registry[type].push(handler);
            } else {
                registry[type] = [handler];
            }
            return this;
        };
        return that;
    };

    that.pluralize = function (noun, n) {
        return noun + (n !== 1 ? 's' : '');
    };

    that.get_guid = function() {
        // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
        var S4 = function() {
            return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
        };
        return (S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4());
    };

    that.generate_xmlns_uuid = function () {
        var CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        var uuid = [], r, i;

		// rfc4122 requires these characters
		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
		uuid[14] = '4';

		// Fill in random data.  At i==19 set the high bits of clock sequence as
		// per rfc4122, sec. 4.1.5
		for (i = 0; i < 36; i++) {
			if (!uuid[i]) {
				r = Math.floor((Math.random()*16));
				uuid[i] = CHARS[(i === 19) ? (r & 0x3) | 0x8 : r & 0xf];
			}
		}
		return uuid.toString().replace(/,/g,'');
    };

    that.isValidElementName = function (name) {
        // HT: http://stackoverflow.com/questions/2519845/how-to-check-if-string-is-a-valid-xml-element-name
        var elementNameRegex = /^(?!XML)[a-zA-Z][\w0-9-]*$/;
        return elementNameRegex.test(name);
    };

    /**
     * Turns a list of strings into a single tab separated straing.
     * Replaces newlines with ' ' so they don't affect the spacing.
     * @param list
     */
    that.tabSeparate = function (list) {
        var cleanVal = function (val) {
            return val.replace(/\n/g, ' ');
        };
        return list.map(cleanVal).join("\t");
    };

    /**
     * Converts true to 'true()' and false to 'false()'. Returns null for all else.
     * @param req
     */
    that.createXPathBoolFromJS = function(req) {
        if(req === true || req === 'true') {
            return 'true()';
        }else if (req === false || req === 'false') {
            return 'false()';
        } else {
            return null;
        }
    };

    that.getOneOrFail = function (list, infoMsg) {
        if (list.length === 0) {
            throw ("No match for " + infoMsg + " found!");
        } else if (list.length > 1) {
            throw ("Multiple matches for " + infoMsg + " found!");
        }
        return list[0];
    };

    that.reduceToOne = function (list, func, infoMsg) {
        return that.getOneOrFail(_(list).filter(func), infoMsg);
    };
    return that;
});

<commit_msg>fix language name lookup<commit_after>define([
    'json!langCodes',
    'jquery',
    'jquery.bootstrap-popout'
], function (
    langCodes,
    $
) {
    RegExp.escape = function(s) {
        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    };

    $.fn.stopLink = function() {
        // stops anchor tags from clicking through
        this.click(function (e) {
            e.preventDefault();
        });
        return this;
    };

    $.fn.fdHelp = function () {
        // creates a help popover, requires twitter bootstrap
        this.append($('<i />').addClass('icon-question-sign'))
            .popout({
                trigger: 'hover',
                html: true
            });
        return this;
    };

    var that = {};

    that.langCodeToName = {};
    _.each(langCodes, function (lang) {
        var name = lang.names[0];
        that.langCodeToName[lang.three] = name;
        that.langCodeToName[lang.two] = name;
    });

    that.XPATH_REFERENCES = [
        "bindElement/relevantAttr",
        "bindElement/calculateAttr",
        "bindElement/constraintAttr"
    ];

    that.getTemplateObject = function (selector, params) {
        return $(_.template($(selector).text(), params));
    };

    /**
     * Check if value is a valid XML attribute value (additionally disallow all
     * ' and ")
     */
    that.isValidAttributeValue = function (value) {
        return (/^[^<&'"]*$/).test(value);
    };

    /**
     * Grabs the value between the tags of the element passed in
     * and returns a string of everything inside.
     *
     * This method is kindy of hacky, so buyer beware.
     *
     * Motivation: Jquery's selector can't do this.  We need to be able to
     * grab the value of label tags, even if it includes <output> tags inside
     * of it (since the tag may need to be displayed to the user).
     * @param el - jquery selector or string used in the selector pointing to a DOM element.
     */
    that.getXLabelValue = function(el){
        var xmls = new XMLSerializer(),
            resStr, resEl;
        function getEndTag (str) {
            var res, reo, last;
            reo = /<\/(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g;
            res = reo.exec(str);
            last = res;
            while(res !== null) {
                last = res;
                res = reo.exec(str);
            }
            if(last){
                return last[0];
            }else{
                return null;
            }

        }

        function getStartTag (str) {
            var re, res;
            re = /<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/;
            res = re.exec(str);
            return res[0];
        }

        resEl = $(el)[0];
        if(!resEl) { return; }
        resStr = xmls.serializeToString(resEl);
        resStr = resStr.replace(getStartTag(resStr),'').replace(getEndTag(resStr),'');

        return resStr;
    };

    /**
     * Given two lists, creates a new array (and returns it)
     * that contains only unique values
     * based on comparing the two argument arrays.
     * @param arrA
     * @param arrB
     */
    var mergeArray = function (arrA, arrB) {
        var result = [], i;
        for(i in arrA){
            if(arrA.hasOwnProperty(i)){
                if(arrA.slice(0,arrA.indexOf(i)).indexOf(i) === -1){ //check to see if there aren't dupes in arrA
                    result.push(arrA[i]);
                }
            }
        }

        for(i in arrB){
            if(arrB.hasOwnProperty(i)){
                if(result.indexOf(arrB[i]) === -1){
                    result.push(arrB[i]); //grab only anything that hasn't shown up yet
                }
            }
        }

        return result;
    };
    that.mergeArray = mergeArray;

    //Simple Event Framework
    //Just run your object through this function to make it event aware
    //Taken from 'JavaScript: The Good Parts'
    that.eventuality = function (that) {
        var registry = {};
        that.fire = function (event) {
            var array,
                func,
                handler,
                i,
                type = typeof event === 'string' ?
                        event : event.type;
            if (registry.hasOwnProperty(type)) {
                array = registry[type];
                for (i = 0; i < array.length; i += 1) {
                    handler = array[i];
                    func = handler.method;
                    if (typeof func === 'string') {
                        func = this[func];
                    }
                    func.apply(this,
                        handler.parameters || [event]);
                }
            }
            return this;
        };
        that.on = function (type, method, parameters) {
            var handler = {
                method: method,
                parameters: parameters
            };
            if (registry.hasOwnProperty(type)) {
                registry[type].push(handler);
            } else {
                registry[type] = [handler];
            }
            return this;
        };
        return that;
    };

    that.pluralize = function (noun, n) {
        return noun + (n !== 1 ? 's' : '');
    };

    that.get_guid = function() {
        // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
        var S4 = function() {
            return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
        };
        return (S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4());
    };

    that.generate_xmlns_uuid = function () {
        var CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        var uuid = [], r, i;

		// rfc4122 requires these characters
		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
		uuid[14] = '4';

		// Fill in random data.  At i==19 set the high bits of clock sequence as
		// per rfc4122, sec. 4.1.5
		for (i = 0; i < 36; i++) {
			if (!uuid[i]) {
				r = Math.floor((Math.random()*16));
				uuid[i] = CHARS[(i === 19) ? (r & 0x3) | 0x8 : r & 0xf];
			}
		}
		return uuid.toString().replace(/,/g,'');
    };

    that.isValidElementName = function (name) {
        // HT: http://stackoverflow.com/questions/2519845/how-to-check-if-string-is-a-valid-xml-element-name
        var elementNameRegex = /^(?!XML)[a-zA-Z][\w0-9-]*$/;
        return elementNameRegex.test(name);
    };

    /**
     * Turns a list of strings into a single tab separated straing.
     * Replaces newlines with ' ' so they don't affect the spacing.
     * @param list
     */
    that.tabSeparate = function (list) {
        var cleanVal = function (val) {
            return val.replace(/\n/g, ' ');
        };
        return list.map(cleanVal).join("\t");
    };

    /**
     * Converts true to 'true()' and false to 'false()'. Returns null for all else.
     * @param req
     */
    that.createXPathBoolFromJS = function(req) {
        if(req === true || req === 'true') {
            return 'true()';
        }else if (req === false || req === 'false') {
            return 'false()';
        } else {
            return null;
        }
    };

    that.getOneOrFail = function (list, infoMsg) {
        if (list.length === 0) {
            throw ("No match for " + infoMsg + " found!");
        } else if (list.length > 1) {
            throw ("Multiple matches for " + infoMsg + " found!");
        }
        return list[0];
    };

    that.reduceToOne = function (list, func, infoMsg) {
        return that.getOneOrFail(_(list).filter(func), infoMsg);
    };
    return that;
});

<|endoftext|>