<commit_before>var WebGL = require('./webgl');

/* A calculator object for the Float texture based GEMM

	Generalized Matrix Multiply (GEMM):

	C = alpha * A * B + beta * C

	where A * B is matrix multiplication

	webgl - a weblas.WebGL object
	standalone - whether or not to automatically run the floating point encode
		step for rendering to an UNSIGNED_BYTE texture (this is required for
		mobile, circa 2015) but can't be used as part of a pipeline.

	* uploads and downloads data
	* executes calculation
 */
function SGEMMCalculator(webgl, standalone){
	this.webgl = webgl,
	this.standalone = standalone || true; // default to standalone mode

	// create the webgl shader program for this calculation
	// based on the specific fragment shader for this calculation
	// and the generic pass through shader
	if(this.standalone){
		this.program = this.webgl.createProgram(SGEMMCalculator.STANDALONE_FRAGMENT_SHADER);
	} else {
		this.program = this.webgl.createProgram(SGEMMCalculator.PIPELINE_FRAGMENT_SHADER);
	}

}

module.exports = SGEMMCalculator;

/* Names of the uniforms (variables) used in the shader program passed in on
   each calculation.
 */
SGEMMCalculator.TEXTURE_UNIFORM_NAME_0 = "A";
SGEMMCalculator.TEXTURE_UNIFORM_NAME_1 = "B_t";
SGEMMCalculator.SHARED_LENGTH_UNIFORM_NAME = "K";
SGEMMCalculator.ALPHA_UNIFORM_NAME = "alpha";

SGEMMCalculator.DOT_FUNCTION = "\n\
 uniform sampler2D A;		// texture with data from padded A           \n\
 uniform sampler2D B_t;		// texture with data from padded transpose of B \n\
 uniform int       K;		// number of elements in shared dimension    \n\
 uniform float alpha; 		// coefficient to multiplication             \n\
 float delta_t = 1./float(K);// space (on texture) between elements     \n\
 \n\
// sum of products between elements in row i (from A) x col j (from B)   \n\
//																		 \n\
// Calculate the dot product between the row (from A) and column (from B)\n\
// identified by the passed indeces (output texture coordinate space).   \n\
// We loop over elements in the row and column and sum the product       \n\
// using the glsl `dot` function to process four elements at a time.     \n\
// This four element optimization requires that the matrix B be          \n\
// transposed before texel packing and that both matrices be padded      \n\
// (with zeros) to a multiple of four (4) in their shared dimension.     \n\
float dot_rowcol(float x, float y) {                                     \n\
	float sum = 0.;			// sum for this row/column pair              \n\
	float z = 0.5 * (4.0 * delta_t);// position for shared dimension on source textures \n\
			 															\n\
	for (int l=0 ; l<4096 ; ++l) {                                       \n\
		if(l >= K / 4) break;    // stop when we finish the row/column   \n\
		// l is in pixel space, so we divide by four                     \n\
				 															\n\
		// retrieve next four elements from each texture                 \n\
		vec4 a_ik = texture2D(  A, vec2(z, x));                          \n\
		vec4 b_kj = texture2D(B_t, vec2(z, y));                          \n\
				 															\n\
		// use `dot` to process four elements at a time                  \n\
		sum += alpha * dot(a_ik, b_kj);                                  \n\
		z += (4.0 * delta_t);      // (z + 0.5)*delta                              \n\
	}                                                                    \n\
	return sum;                                                          \n\
}";

/* The GLSL fragment shader that carries out the calculation.

   the `outTex` variable is named and defined in the pass-through vertex shader
 */
SGEMMCalculator.STANDALONE_FRAGMENT_SHADER = "                                  \n\
// fragment shader that calculates the matrix product and renders each   \n\
// element to the bytes representing a 32-bit IEEE754 floating point in  \n\
// the output RGBA canvas.                                               \n\
// readPixel is used to read the bytes.                                  \n\
																		 \n\
precision highp float;                                                   \n\
varying vec2      outTex;	// texture coords of row/column to calculate \n\
	                                                              		\n" +
SGEMMCalculator.DOT_FUNCTION +
WebGL.ENCODE_FLOAT_FUNCTION +
"																		 \n\
																		 \n\
void main(void) {                                                        \n\
																		 \n\
	// get the implied row and column from .y and .x of passed (output)  \n\
	// texture coordinate. These map directly to input texture space when\n\
	// the relevant dimensions are the same.                             \n\
 	float row_t = outTex.y;                                                \n\
	float col_t = outTex.x;                                                \n\
																		 \n\
	// sum row x col for the passed pixel                                \n\
	float sum = dot_rowcol(row_t, col_t);                                    \n\
																		 \n\
	if (sum == 0.) {                                                     \n\
		gl_FragColor = vec4(0.,0.,0.,0.);                                \n\
		return;                                                          \n\
	}                                                                    \n\
																		 \n\
 	// output vec4 with bytes for an IEEE754 32-bit floating point number\n\
	gl_FragColor = encodeFloat(sum);									 \n\
}                                                                        \n\
";

/* Calculate the GEMM, with the given data.

	M - number of rows in A
	N - number of columns in B
	K - number of elements in shared dimension (including padding)
	alpha - scalar for A
	A - left hand matrix (as padded texture)
	B - transpose of right hand matrix (as padded texture)
	beta - scalar for C
	C - additive matrix (texture)
	out - output (texture)

  How this works:

  1. Activate our shader program
  2. Bind input textures
  3. Set shader program parameters
  4. Bind output texture
  5. Activate calculation with `drawElements`

 TODO: signature should look like this:
 ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC )
 http://www.math.utah.edu/software/lapack/lapack-blas/dgemm.html
 */
SGEMMCalculator.prototype.calculate = function(M, N, K, alpha, A, B, beta, C, out){

	var gl = this.webgl.context;

	/*
	var h1 = M, w1 = K,
		h2 = K, w2 = N;
	*/

	// set this calculator program as the active program
	this.webgl.selectProgram(this.program);

	//  bind our input textures containing matrix data
	this.bindInputTexture(A, gl.TEXTURE0, SGEMMCalculator.TEXTURE_UNIFORM_NAME_0);
	this.bindInputTexture(B, gl.TEXTURE1, SGEMMCalculator.TEXTURE_UNIFORM_NAME_1);

	// set the data specific variables in our shader program
	this.bindUniforms(K, alpha);

	// bind our destination texture
	this.webgl.bindOutputTexture(M, N, out);

	// initiate calculation
	gl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);

	this.webgl.unbindInputTexture(gl.TEXTURE0);
	this.webgl.unbindInputTexture(gl.TEXTURE1);

	// result can now be read with gl.readResult, or more operations can be
	// performed on destination texture (in pipeline mode)
};

/* Create a texture from the given texel data and bind it to our shader program.

	h - number of rows in input matrix
	w - number of cols in input matrix
	texels - packed data
	textureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)
	name - the uniform name to associate with (must match shader program)

	must compile program (with createProgram) first
*/
SGEMMCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){
	var gl = this.webgl.context,
		program = this.program;

	gl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc
	gl.bindTexture(	  gl.TEXTURE_2D, texture);

	var sampler = gl.getUniformLocation(program, name);
	gl.uniform1i(sampler, textureUnit - gl.TEXTURE0);

};

/* Set up inputs for the texture shader

	K - size of shared dimension for multiplied matrices
 */
SGEMMCalculator.prototype.bindUniforms = function(K, alpha) {
	var gl = this.webgl.context;

	// get var locations
	var K_gl	 = gl.getUniformLocation(this.program, SGEMMCalculator.SHARED_LENGTH_UNIFORM_NAME),
		alpha_gl = gl.getUniformLocation(this.program, SGEMMCalculator.ALPHA_UNIFORM_NAME);

	// bind length of shared dimension
	gl.uniform1i(K_gl, K);
	// bind alpha
	gl.uniform1f(alpha_gl, alpha);

};
<commit_msg>cleanup shader code<commit_after>var WebGL = require('./webgl');

/* A calculator object for the Float texture based GEMM

	Generalized Matrix Multiply (GEMM):

	C = alpha * A * B + beta * C

	where A * B is matrix multiplication

	webgl - a weblas.WebGL object
	standalone - whether or not to automatically run the floating point encode
		step for rendering to an UNSIGNED_BYTE texture (this is required for
		mobile, circa 2015) but can't be used as part of a pipeline.

	* uploads and downloads data
	* executes calculation
 */
function SGEMMCalculator(webgl, standalone){
	this.webgl = webgl,
	this.standalone = standalone || true; // default to standalone mode

	// create the webgl shader program for this calculation
	// based on the specific fragment shader for this calculation
	// and the generic pass through shader
	if(this.standalone){
		this.program = this.webgl.createProgram(SGEMMCalculator.STANDALONE_FRAGMENT_SHADER);
	} else {
		this.program = this.webgl.createProgram(SGEMMCalculator.PIPELINE_FRAGMENT_SHADER);
	}

}

module.exports = SGEMMCalculator;

/* Names of the uniforms (variables) used in the shader program passed in on
   each calculation.
 */
SGEMMCalculator.TEXTURE_UNIFORM_NAME_0 = "A";
SGEMMCalculator.TEXTURE_UNIFORM_NAME_1 = "B_t";
SGEMMCalculator.SHARED_LENGTH_UNIFORM_NAME = "K";
SGEMMCalculator.ALPHA_UNIFORM_NAME = "alpha";

SGEMMCalculator.DOT_FUNCTION = "\n\
 float delta_t = 1./float(K);// space (on texture) between elements     \n\
 																		 \n\
// sum of products between elements in row i (from A) x col j (from B)   \n\
//																		 \n\
// Calculate the dot product between the row (from A) and column (from B)\n\
// identified by the passed indeces (output texture coordinate space).   \n\
// We loop over elements in the row and column and sum the product       \n\
// using the glsl `dot` function to process four elements at a time.     \n\
// This four element optimization requires that the matrix B be          \n\
// transposed before texel packing and that both matrices be padded      \n\
// (with zeros) to a multiple of four (4) in their shared dimension.     \n\
float dot_rowcol(float x, float y) {                                     \n\
	float sum = 0.;			// sum for this row/column pair              \n\
	float z = 0.5 * (4.0 * delta_t);// position for shared dimension on source textures \n\
			 															\n\
	for (int l=0 ; l<4096 ; ++l) {                                       \n\
		if(l >= K / 4) break;    // stop when we finish the row/column   \n\
		// l is in pixel space, so we divide by four                     \n\
				 														\n\
		// retrieve next four elements from each texture                 \n\
		vec4 a_ik = texture2D(  A, vec2(z, x));                          \n\
		vec4 b_kj = texture2D(B_t, vec2(z, y));                          \n\
				 															\n\
		// use `dot` to process four elements at a time                  \n\
		sum += alpha * dot(a_ik, b_kj);                                  \n\
		z += (4.0 * delta_t);      // (z + 0.5)*delta                              \n\
	}                                                                    \n\
	return sum;                                                          \n\
}";

/* The GLSL fragment shader that carries out the calculation.

   the `outTex` variable is named and defined in the pass-through vertex shader
 */
SGEMMCalculator.STANDALONE_FRAGMENT_SHADER = "                                  \n\
// fragment shader that calculates the matrix product and renders each   \n\
// element to the bytes representing a 32-bit IEEE754 floating point in  \n\
// the output RGBA canvas.                                               \n\
// readPixel is used to read the bytes.                                  \n\
																		 \n\
precision highp float;                                                   \n\
																		 \n\
varying vec2      outTex;	// texture coords of row/column to calculate \n\
uniform sampler2D A;		// texture with data from padded A           \n\
uniform sampler2D B_t;		// texture with data from padded transpose of B \n\
uniform int       K;		// number of elements in shared dimension    \n\
uniform float     alpha; 	// coefficient to multiplication             \n\
	                                                              		\n" +
SGEMMCalculator.DOT_FUNCTION +
WebGL.ENCODE_FLOAT_FUNCTION +
"																		 \n\
																		 \n\
void main(void) {                                                        \n\
																		 \n\
	// get the implied row and column from .y and .x of passed (output)  \n\
	// texture coordinate. These map directly to input texture space when\n\
	// the relevant dimensions are the same.                             \n\
 	float row_t = outTex.y;                                                \n\
	float col_t = outTex.x;                                                \n\
																		 \n\
	// sum row x col for the passed pixel                                \n\
	float sum = dot_rowcol(row_t, col_t);                                    \n\
																		 \n\
	if (sum == 0.) {                                                     \n\
		gl_FragColor = vec4(0.,0.,0.,0.);                                \n\
		return;                                                          \n\
	}                                                                    \n\
																		 \n\
 	// output vec4 with bytes for an IEEE754 32-bit floating point number\n\
	gl_FragColor = encodeFloat(sum);									 \n\
}                                                                        \n\
";

/* Calculate the GEMM, with the given data.

	M - number of rows in A
	N - number of columns in B
	K - number of elements in shared dimension (including padding)
	alpha - scalar for A
	A - left hand matrix (as padded texture)
	B - transpose of right hand matrix (as padded texture)
	beta - scalar for C
	C - additive matrix (texture)
	out - output (texture)

  How this works:

  1. Activate our shader program
  2. Bind input textures
  3. Set shader program parameters
  4. Bind output texture
  5. Activate calculation with `drawElements`

 TODO: signature should look like this:
 ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC )
 http://www.math.utah.edu/software/lapack/lapack-blas/dgemm.html
 */
SGEMMCalculator.prototype.calculate = function(M, N, K, alpha, A, B, beta, C, out){

	var gl = this.webgl.context;

	/*
	var h1 = M, w1 = K,
		h2 = K, w2 = N;
	*/

	// set this calculator program as the active program
	this.webgl.selectProgram(this.program);

	//  bind our input textures containing matrix data
	this.bindInputTexture(A, gl.TEXTURE0, SGEMMCalculator.TEXTURE_UNIFORM_NAME_0);
	this.bindInputTexture(B, gl.TEXTURE1, SGEMMCalculator.TEXTURE_UNIFORM_NAME_1);

	// set the data specific variables in our shader program
	this.bindUniforms(K, alpha);

	// bind our destination texture
	this.webgl.bindOutputTexture(M, N, out);

	// initiate calculation
	gl.drawElements(gl.TRIANGLES, /*num items*/6, gl.UNSIGNED_SHORT, 0);

	this.webgl.unbindInputTexture(gl.TEXTURE0);
	this.webgl.unbindInputTexture(gl.TEXTURE1);

	// result can now be read with gl.readResult, or more operations can be
	// performed on destination texture (in pipeline mode)
};

/* Create a texture from the given texel data and bind it to our shader program.

	h - number of rows in input matrix
	w - number of cols in input matrix
	texels - packed data
	textureUnit - the texture unit to bind to (gl.TEXTURE0, gl.TEXTURE1, etc)
	name - the uniform name to associate with (must match shader program)

	must compile program (with createProgram) first
*/
SGEMMCalculator.prototype.bindInputTexture = function(texture, textureUnit, name){
	var gl = this.webgl.context,
		program = this.program;

	gl.activeTexture(textureUnit); // gl.TEXTURE0, gl.TEXTURE1, etc
	gl.bindTexture(	  gl.TEXTURE_2D, texture);

	var sampler = gl.getUniformLocation(program, name);
	gl.uniform1i(sampler, textureUnit - gl.TEXTURE0);

};

/* Set up inputs for the texture shader

	K - size of shared dimension for multiplied matrices
 */
SGEMMCalculator.prototype.bindUniforms = function(K, alpha) {
	var gl = this.webgl.context;

	// get var locations
	var K_gl	 = gl.getUniformLocation(this.program, SGEMMCalculator.SHARED_LENGTH_UNIFORM_NAME),
		alpha_gl = gl.getUniformLocation(this.program, SGEMMCalculator.ALPHA_UNIFORM_NAME);

	// bind length of shared dimension
	gl.uniform1i(K_gl, K);
	// bind alpha
	gl.uniform1f(alpha_gl, alpha);

};
<|endoftext|>


<commit_before>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

"use strict";

function fillIn(wnd)
{
  let fields = wnd.document.querySelectorAll("input[type=password]");
  let result = false;
  fields = Array.filter(fields, element => element.offsetHeight && element.offsetWidth);
  if (fields.length > 0)
  {
    result = true;
    for (let field of fields)
    {
      field.value = password;
      field.dispatchEvent(new Event("change", {bubbles: true}));
    }
    fields[0].focus();
  }

  for (let i = 0; i < wnd.frames.length; i++)
  {
    try
    {
      wnd.frames[i].document;
    }
    catch (e)
    {
      // Forbidden by same-origin policy, ignore
      continue;
    }
    result = result || fillIn(wnd.frames[i]);
  }

  return result;
}

let {host, password} = self.options;
if (window.location.hostname != host)
  throw new Error("Password is meant for a different website, not filling in.");

if (fillIn(window))
  self.port.emit("success");
else
  self.port.emit("failure");
<commit_msg>Fixes #16 - If a password field is focused, fill in this field only<commit_after>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

"use strict";

function getActiveElement(doc)
{
  let result = doc.activeElement;
  if (result && result.contentDocument)
    return getActiveElement(result.contentDocument);
  else
    return result;
}

function fillIn(wnd)
{
  if (wnd == wnd.top)
  {
    let field = getActiveElement(wnd.document);
    if (field instanceof HTMLInputElement && field.type == "password")
    {
      field.value = password;
      return true;
    }
  }

  let fields = wnd.document.querySelectorAll("input[type=password]");
  let result = false;
  fields = Array.filter(fields, element => element.offsetHeight && element.offsetWidth);
  if (fields.length > 0)
  {
    result = true;
    for (let field of fields)
    {
      field.value = password;
      field.dispatchEvent(new Event("change", {bubbles: true}));
    }
    fields[0].focus();
  }

  for (let i = 0; i < wnd.frames.length; i++)
  {
    try
    {
      wnd.frames[i].document;
    }
    catch (e)
    {
      // Forbidden by same-origin policy, ignore
      continue;
    }
    result = result || fillIn(wnd.frames[i]);
  }

  return result;
}

let {host, password} = self.options;
if (window.location.hostname != host)
  throw new Error("Password is meant for a different website, not filling in.");

if (fillIn(window))
  self.port.emit("success");
else
  self.port.emit("failure");
<|endoftext|>


<commit_before>'use babel'

export default class StatusBarItem {
  constructor () {
    this.element = document.createElement('a')
    this.element.className = 'line-ending-tile inline-block'
    this.setLineEndings(new Set())
  }

  setLineEndings (lineEndings) {
    this.lineEndings = lineEndings
    this.element.textContent = lineEndingName(lineEndings)
  }

  hasLineEnding (lineEnding) {
    return this.lineEndings.has(lineEnding)
  }

  onClick (callback) {
    this.element.addEventListener('click', callback)
  }
}

function lineEndingName (lineEndings) {
  if (lineEndings.size > 1) {
    return 'Mixed'
  } else if (lineEndings.has('\n')) {
    return 'LF'
  } else if (lineEndings.has('\r\n')) {
    return 'CRLF'
  } else {
    return ''
  }
}
<commit_msg>Display CR line endings<commit_after>'use babel'

export default class StatusBarItem {
  constructor () {
    this.element = document.createElement('a')
    this.element.className = 'line-ending-tile inline-block'
    this.setLineEndings(new Set())
  }

  setLineEndings (lineEndings) {
    this.lineEndings = lineEndings
    this.element.textContent = lineEndingName(lineEndings)
  }

  hasLineEnding (lineEnding) {
    return this.lineEndings.has(lineEnding)
  }

  onClick (callback) {
    this.element.addEventListener('click', callback)
  }
}

function lineEndingName (lineEndings) {
  if (lineEndings.size > 1) {
    return 'Mixed'
  } else if (lineEndings.has('\n')) {
    return 'LF'
  } else if (lineEndings.has('\r\n')) {
    return 'CRLF'
  } else if (lineEndings.has('\r')) {
    return 'CR'
  } else {
    return ''
  }
}
<|endoftext|>


<commit_before>'use strict';

const RSVP = require('rsvp');
const ember = require('../helpers/ember');
const path = require('path');
let remove = RSVP.denodeify(require('fs-extra').remove);
let root = process.cwd();
let tmproot = path.join(root, 'tmp');
const mkTmpDirIn = require('../../lib/utilities/mk-tmp-dir-in');

const chai = require('../chai');
let expect = chai.expect;
let file = chai.file;

describe('Acceptance: ember install', function() {
  this.timeout(60000);

  beforeEach(function() {
    return mkTmpDirIn(tmproot).then(function(tmpdir) {
      process.chdir(tmpdir);
    });
  });

  afterEach(function() {
    process.chdir(root);
    return remove(tmproot);
  });

  function initApp() {
    return ember([
      'init',
      '--name=my-app',
      '--skip-npm',
      '--skip-bower',
    ]);
  }

  function installAddon(args) {
    let generateArgs = ['install'].concat(args);

    return initApp().then(function() {
      return ember(generateArgs);
    });
  }

  it('installs addons via npm and runs generators', function() {
    return installAddon(['ember-cli-fastclick', 'ember-cli-photoswipe']).then(function(result) {
      expect(file('package.json'))
        .to.match(/"ember-cli-fastclick": ".*"/)
        .to.match(/"ember-cli-photoswipe": ".*"/);

      expect(file('bower.json'))
        .to.match(/"photoswipe": ".*"/);

      expect(result.outputStream.join()).not.to.include('The `ember generate` command ' +
                                              'requires an entity name to be specified. For more details, use `ember help`.');
    });
  });
});
<commit_msg>tests/acceptance/install: Convert promise chains to coroutines<commit_after>'use strict';

const co = require('co');
const RSVP = require('rsvp');
const ember = require('../helpers/ember');
const path = require('path');
let remove = RSVP.denodeify(require('fs-extra').remove);
let root = process.cwd();
let tmproot = path.join(root, 'tmp');
const mkTmpDirIn = require('../../lib/utilities/mk-tmp-dir-in');

const chai = require('../chai');
let expect = chai.expect;
let file = chai.file;

describe('Acceptance: ember install', function() {
  this.timeout(60000);

  beforeEach(co.wrap(function *() {
    let tmpdir = yield mkTmpDirIn(tmproot);
    process.chdir(tmpdir);
  }));

  afterEach(function() {
    process.chdir(root);
    return remove(tmproot);
  });

  function initApp() {
    return ember([
      'init',
      '--name=my-app',
      '--skip-npm',
      '--skip-bower',
    ]);
  }

  function installAddon(args) {
    let generateArgs = ['install'].concat(args);

    return initApp().then(function() {
      return ember(generateArgs);
    });
  }

  it('installs addons via npm and runs generators', co.wrap(function *() {
    let result = yield installAddon(['ember-cli-fastclick', 'ember-cli-photoswipe']);

    expect(file('package.json'))
      .to.match(/"ember-cli-fastclick": ".*"/)
      .to.match(/"ember-cli-photoswipe": ".*"/);

    expect(file('bower.json'))
      .to.match(/"photoswipe": ".*"/);

    expect(result.outputStream.join())
      .not.to.include('The `ember generate` command requires an entity name to be specified. For more details, use `ember help`.');
  }));
});
<|endoftext|>


<commit_before>/*jshint laxcomma: true, smarttabs: true, node:true, esnext:true*/
'use strict';
/**
 * The Http transport backend
 * @module skyring/lib/transports/http
 * @author Eric Satterwhite
 * @since 1.0.0
 * @requires http
 * @requires request
 * @requires debug
 * @requires skyring/lib/timer
 */

const STATUS_CODES = require('http').STATUS_CODES
    , request = require('request')
    , debug   = require('debug')('skyring:transport:http')
    ;

/**
 * Dispatches an http request
 * @function
 * @alias module:skyring/lib/transports/http
 * @param {String} method The http method to use when dispatching the request
 * @param {String} url the url to target when dispatching
 * @param {String} payload The data payload to include in the request
 * @param {String} id The id of the timer being executed
 **/
module.exports = function makeRequest( method, url, payload, id, cache) {
  const isJSON = typeof payload === 'object'
  const options = {
    body: payload || ""
  , json: isJSON
  };
  debug('executing http transport %s', id);
  request[method](url, options, (err, res, body) => {
    if(err){
      debug('timer fail');
      return cache.remove(id);
    }
    if(res.statusCode > 299 ){
      debug('timer fail');
      const err = new Error(STATUS_CODES[res.statusCode])
      err.code = res.statusCode = res.statusCode;
      console.error(err, body)
      return cache.remove(id);
    }

    debug('timer sucess');
    return cache.remove(id);
  });
};
<commit_msg>lower case the http method<commit_after>/*jshint laxcomma: true, smarttabs: true, node:true, esnext:true*/
'use strict';
/**
 * The Http transport backend
 * @module skyring/lib/transports/http
 * @author Eric Satterwhite
 * @since 1.0.0
 * @requires http
 * @requires request
 * @requires debug
 * @requires skyring/lib/timer
 */

const STATUS_CODES = require('http').STATUS_CODES
    , request = require('request')
    , debug   = require('debug')('skyring:transport:http')
    ;

/**
 * Dispatches an http request
 * @function
 * @alias module:skyring/lib/transports/http
 * @param {String} method The http method to use when dispatching the request
 * @param {String} url the url to target when dispatching
 * @param {String} payload The data payload to include in the request
 * @param {String} id The id of the timer being executed
 **/
module.exports = function makeRequest( method, url, payload, id, cache) {
  const isJSON = typeof payload === 'object'
  const options = {
    body: payload || ""
  , json: isJSON
  };
  debug('executing http transport %s', id, method);
  request[method.toLowerCase()](url, options, (err, res, body) => {
    if(err){
      debug('timer fail');
      return cache.remove(id);
    }
    if(res.statusCode > 299 ){
      debug('timer fail');
      const err = new Error(STATUS_CODES[res.statusCode])
      err.code = res.statusCode = res.statusCode;
      console.error(err, body)
      return cache.remove(id);
    }

    debug('timer sucess');
    return cache.remove(id);
  });
};
<|endoftext|>


<commit_before>'use strict';

var adapters = ['http', 'local'];

adapters.forEach(function (adapter) {
  describe('test.design_docs.js-' + adapter, function () {

    var dbs = {};

    beforeEach(function () {
      dbs.name = testUtils.adapterUrl(adapter, 'testdb');
    });

    afterEach(function (done) {
      testUtils.cleanup([dbs.name], done);
    });

    var doc = {
      _id: '_design/foo',
      views: {
        scores: {
          map: 'function (doc) { if (doc.score) { emit(null, doc.score); } }',
          reduce: 'function (keys, values, rereduce) { return sum(values); }'
        }
      },
      filters: { even: 'function (doc) { return doc.integer % 2 === 0; }' }
    };

    it('Test writing design doc', function (done) {
      var db = new PouchDB(dbs.name);
      db.post(doc, function (err) {
        should.not.exist(err, 'Wrote design doc');
        db.get('_design/foo', function (err) {
          done(err);
        });
      });
    });

    it('Changes filter', function (done) {
      var docs1 = [
        doc,
        {_id: '0', integer: 0},
        {_id: '1', integer: 1},
        {_id: '2', integer: 2},
        {_id: '3', integer: 3}
      ];
      var docs2 = [
        {_id: '4', integer: 4},
        {_id: '5', integer: 5},
        {_id: '6', integer: 6},
        {_id: '7', integer: 7}
      ];

      var db = new PouchDB(dbs.name);
      var count = 0;
      db.bulkDocs({ docs: docs1 }, function () {
        var changes = db.changes({
          live: true,
          filter: 'foo/even'
        }).on('change', function () {
          count += 1;
          if (count === 4) {
            changes.cancel();
          }
        }).on('complete', function (result) {
          result.status.should.equal('cancelled');
          done();
        }).on('error', done);
        db.bulkDocs({ docs: docs2 }, {});
      });
    });

    it('Basic views', function (done) {

      var docs1 = [
        doc,
        {_id: 'dale', score: 3},
        {_id: 'mikeal', score: 5},
        {_id: 'max', score: 4},
        {_id: 'nuno', score: 3}
      ];
      var db = new PouchDB(dbs.name);
      // Test invalid if adapter doesnt support mapreduce
      if (!db.query) {
        return done();
      }

      db.bulkDocs({ docs: docs1 }, function () {
        db.query('foo/scores', { reduce: false }, function (err, result) {
          result.rows.should.have.length(4, 'Correct # of results');
          db.query('foo/scores', function (err, result) {
            result.rows[0].value.should.equal(15, 'Reduce gave correct result');
            done();
          });
        });
      });
    });

    it('Indexing event', function (done) {
      var docs1 = [
        doc,
        {_id: 'dale', score: 3},
        {_id: 'mikeal', score: 5},
        {_id: 'max', score: 4},
        {_id: 'nuno', score: 3},
      ];
      var db = new PouchDB(dbs.name);
      // Test invalid if adapter doesnt support mapreduce
      if (!db.query || adapter !== 'local') {
        return done();
      }

      let indexingEvents = [];

      db.on('indexing', function (result) {
        indexingEvents.push(result);
      });

      db.bulkDocs({ docs: docs1 }, function () {
        db.query('foo/scores', { reduce: false }, function () {
          indexingEvents.length.should.equal(2);
          indexingEvents[0]['indexed_docs'].should.equal(0);
          indexingEvents[1]['last_seq'].should.equal(5);
          indexingEvents[1]['results_count'].should.equal(5);
          indexingEvents[1]['indexed_docs'].should.equal(5);

          done();
        });
      });
    });

    it('Concurrent queries', function (done) {
      var db = new PouchDB(dbs.name);
      // Test invalid if adapter doesnt support mapreduce
      if (!db.query) {
        return done();
      }

      db.bulkDocs({
        docs: [
          doc,
          {_id: 'dale', score: 3}
        ]
      }, function () {
        var cnt = 0;
        db.query('foo/scores', { reduce: false }, function (err, result) {
          result.rows.should.have.length(1, 'Correct # of results');
          if (++cnt === 2) {
            done();
          }
        });
        db.query('foo/scores', { reduce: false }, function (err, result) {
          result.rows.should.have.length(1, 'Correct # of results');
          if (++cnt === 2) {
            done();
          }
        });
      });
    });

  });
});
<commit_msg>Update indexing event test to use async/await instead of callbacks<commit_after>'use strict';

var adapters = ['http', 'local'];

adapters.forEach(function (adapter) {
  describe('test.design_docs.js-' + adapter, function () {

    var dbs = {};

    beforeEach(function () {
      dbs.name = testUtils.adapterUrl(adapter, 'testdb');
    });

    afterEach(function (done) {
      testUtils.cleanup([dbs.name], done);
    });

    var doc = {
      _id: '_design/foo',
      views: {
        scores: {
          map: 'function (doc) { if (doc.score) { emit(null, doc.score); } }',
          reduce: 'function (keys, values, rereduce) { return sum(values); }'
        }
      },
      filters: { even: 'function (doc) { return doc.integer % 2 === 0; }' }
    };

    it('Test writing design doc', function (done) {
      var db = new PouchDB(dbs.name);
      db.post(doc, function (err) {
        should.not.exist(err, 'Wrote design doc');
        db.get('_design/foo', function (err) {
          done(err);
        });
      });
    });

    it('Changes filter', function (done) {
      var docs1 = [
        doc,
        {_id: '0', integer: 0},
        {_id: '1', integer: 1},
        {_id: '2', integer: 2},
        {_id: '3', integer: 3}
      ];
      var docs2 = [
        {_id: '4', integer: 4},
        {_id: '5', integer: 5},
        {_id: '6', integer: 6},
        {_id: '7', integer: 7}
      ];

      var db = new PouchDB(dbs.name);
      var count = 0;
      db.bulkDocs({ docs: docs1 }, function () {
        var changes = db.changes({
          live: true,
          filter: 'foo/even'
        }).on('change', function () {
          count += 1;
          if (count === 4) {
            changes.cancel();
          }
        }).on('complete', function (result) {
          result.status.should.equal('cancelled');
          done();
        }).on('error', done);
        db.bulkDocs({ docs: docs2 }, {});
      });
    });

    it('Basic views', function (done) {

      var docs1 = [
        doc,
        {_id: 'dale', score: 3},
        {_id: 'mikeal', score: 5},
        {_id: 'max', score: 4},
        {_id: 'nuno', score: 3}
      ];
      var db = new PouchDB(dbs.name);
      // Test invalid if adapter doesnt support mapreduce
      if (!db.query) {
        return done();
      }

      db.bulkDocs({ docs: docs1 }, function () {
        db.query('foo/scores', { reduce: false }, function (err, result) {
          result.rows.should.have.length(4, 'Correct # of results');
          db.query('foo/scores', function (err, result) {
            result.rows[0].value.should.equal(15, 'Reduce gave correct result');
            done();
          });
        });
      });
    });

    it('Indexing event', async () => {
      const docs1 = [
        doc,
        {_id: 'dale', score: 3},
        {_id: 'mikeal', score: 5},
        {_id: 'max', score: 4},
        {_id: 'nuno', score: 3},
      ];
      let db = new PouchDB(dbs.name);
      // Test invalid if adapter doesnt support mapreduce
      if (!db.query || adapter !== 'local') {
        return;
      }

      let indexingEvents = [];

      db.on('indexing', (result) => {
        indexingEvents.push(result);
      });

      await db.bulkDocs({ docs: docs1 });
      await db.query('foo/scores', { reduce: false });

      indexingEvents.length.should.equal(2);
      indexingEvents[0]['indexed_docs'].should.equal(0);
      indexingEvents[1]['last_seq'].should.equal(5);
      indexingEvents[1]['results_count'].should.equal(5);
      indexingEvents[1]['indexed_docs'].should.equal(5);
    });

    it('Concurrent queries', function (done) {
      var db = new PouchDB(dbs.name);
      // Test invalid if adapter doesnt support mapreduce
      if (!db.query) {
        return done();
      }

      db.bulkDocs({
        docs: [
          doc,
          {_id: 'dale', score: 3}
        ]
      }, function () {
        var cnt = 0;
        db.query('foo/scores', { reduce: false }, function (err, result) {
          result.rows.should.have.length(1, 'Correct # of results');
          if (++cnt === 2) {
            done();
          }
        });
        db.query('foo/scores', { reduce: false }, function (err, result) {
          result.rows.should.have.length(1, 'Correct # of results');
          if (++cnt === 2) {
            done();
          }
        });
      });
    });

  });
});
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { SyncHook, AsyncSeriesHook } = require("tapable");

const QUEUED_STATE = 0;
const PROCESSING_STATE = 1;
const DONE_STATE = 2;

/**
 * @template T
 * @callback Callback<T>
 * @param {Error=} err
 * @param {T=} result
 */

/**
 * @template T
 * @template K
 * @template R
 */
class AsyncQueueEntry {
	/**
	 * @param {T} item the item
	 * @param {Callback<R>} callback the callback
	 */
	constructor(item, callback) {
		this.item = item;
		/** @type {typeof QUEUED_STATE | typeof PROCESSING_STATE | typeof DONE_STATE} */
		this.state = QUEUED_STATE;
		this.callback = callback;
		/** @type {Callback<R>[] | undefined} */
		this.callbacks = undefined;
		this.result = undefined;
		this.error = undefined;
	}
}

/**
 * @template T
 * @template K
 * @template R
 */
class AsyncQueue {
	/**
	 * @param {Object} options options object
	 * @param {string=} options.name name of the queue
	 * @param {number} options.parallelism how many items should be processed at once
	 * @param {function(T): K=} options.getKey extract key from item
	 * @param {function(T, Callback<R>): void} options.processor async function to process items
	 */
	constructor({ name, parallelism, processor, getKey }) {
		this._name = name;
		this._parallelism = parallelism;
		this._processor = processor;
		this._getKey =
			getKey || /** @type {(T) => K} */ (item => /** @type {any} */ (item));
		/** @type {Map<K, AsyncQueueEntry<T, K, R>>} */
		this._entries = new Map();
		/** @type {Set<AsyncQueueEntry<T, K, R>>} */
		this._queued = new Set();
		this._activeTasks = 0;
		this._willEnsureProcessing = false;
		this._stopped = false;

		this.hooks = {
			beforeAdd: new AsyncSeriesHook(["item"]),
			added: new SyncHook(["item"]),
			beforeStart: new AsyncSeriesHook(["item"]),
			started: new SyncHook(["item"]),
			result: new SyncHook(["item", "error", "result"])
		};

		this._ensureProcessing = this._ensureProcessing.bind(this);
	}

	/**
	 * @param {T} item a item
	 * @param {Callback<R>} callback callback function
	 * @returns {void}
	 */
	add(item, callback) {
		if (this._stopped) return callback(new Error("Queue was stopped"));
		this.hooks.beforeAdd.callAsync(item, err => {
			if (err) {
				callback(err);
				return;
			}
			const key = this._getKey(item);
			const entry = this._entries.get(key);
			if (entry !== undefined) {
				if (entry.state === DONE_STATE) {
					process.nextTick(() => callback(entry.error, entry.result));
				} else if (entry.callbacks === undefined) {
					entry.callbacks = [callback];
				} else {
					entry.callbacks.push(callback);
				}
				return;
			}
			const newEntry = new AsyncQueueEntry(item, callback);
			if (this._stopped) {
				this.hooks.added.call(item);
				this._activeTasks++;
				this._handleResult(newEntry, new Error("Queue was stopped"));
			} else {
				this._entries.set(key, newEntry);
				this._queued.add(newEntry);
				if (this._willEnsureProcessing === false) {
					this._willEnsureProcessing = true;
					process.nextTick(this._ensureProcessing);
				}
				this.hooks.added.call(item);
			}
		});
	}

	/**
	 * @param {T} item a item
	 * @returns {void}
	 */
	invalidate(item) {
		const key = this._getKey(item);
		this._entries.delete(key);
	}

	/**
	 * @returns {void}
	 */
	stop() {
		this._stopped = true;
		for (const entry of this._queued) {
			this._queued.delete(entry);
			this._entries.delete(this._getKey(entry.item));
			this._activeTasks++;
			this._handleResult(entry, new Error("Queue was stopped"));
		}
	}

	/**
	 * @returns {void}
	 */
	increaseParallelism() {
		this._parallelism++;
		if (this._willEnsureProcessing === false && this._queued.size > 0) {
			this._willEnsureProcessing = true;
			process.nextTick(this._ensureProcessing);
		}
	}

	/**
	 * @returns {void}
	 */
	decreaseParallelism() {
		this._parallelism--;
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, if the item is currently being processed
	 */
	isProcessing(item) {
		const key = this._getKey(item);
		const entry = this._entries.get(key);
		return entry !== undefined && entry.state === PROCESSING_STATE;
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, if the item is currently queued
	 */
	isQueued(item) {
		const key = this._getKey(item);
		const entry = this._entries.get(key);
		return entry !== undefined && entry.state === QUEUED_STATE;
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, if the item is currently queued
	 */
	isDone(item) {
		const key = this._getKey(item);
		const entry = this._entries.get(key);
		return entry !== undefined && entry.state === DONE_STATE;
	}

	/**
	 * @returns {void}
	 */
	_ensureProcessing() {
		if (this._activeTasks >= this._parallelism) {
			this._willEnsureProcessing = false;
			return;
		}
		for (const entry of this._queued) {
			this._activeTasks++;
			this._queued.delete(entry);
			entry.state = PROCESSING_STATE;
			this._startProcessing(entry);
			if (this._activeTasks >= this._parallelism) {
				this._willEnsureProcessing = false;
				return;
			}
		}
		this._willEnsureProcessing = false;
	}

	/**
	 * @param {AsyncQueueEntry<T, K, R>} entry the entry
	 * @returns {void}
	 */
	_startProcessing(entry) {
		this.hooks.beforeStart.callAsync(entry.item, err => {
			if (err) {
				this._handleResult(entry, err);
				return;
			}
			try {
				this._processor(entry.item, (e, r) => {
					process.nextTick(() => {
						this._handleResult(entry, e, r);
					});
				});
			} catch (err) {
				this._handleResult(entry, err, null);
			}
			this.hooks.started.call(entry.item);
		});
	}

	/**
	 * @param {AsyncQueueEntry<T, K, R>} entry the entry
	 * @param {Error=} err error, if any
	 * @param {R=} result result, if any
	 * @returns {void}
	 */
	_handleResult(entry, err, result) {
		this.hooks.result.callAsync(entry.item, err, result, hookError => {
			const error = hookError || err;

			const callback = entry.callback;
			const callbacks = entry.callbacks;
			entry.state = DONE_STATE;
			entry.callback = undefined;
			entry.callbacks = undefined;
			entry.result = result;
			entry.error = error;
			this._activeTasks--;

			if (this._willEnsureProcessing === false && this._queued.size > 0) {
				this._willEnsureProcessing = true;
				process.nextTick(this._ensureProcessing);
			}

			callback(error, result);
			if (callbacks !== undefined) {
				for (const callback of callbacks) {
					callback(error, result);
				}
			}
		});
	}
}

module.exports = AsyncQueue;
<commit_msg>AsyncQueue._queued to array, remove nextTick<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { SyncHook, AsyncSeriesHook } = require("tapable");

const QUEUED_STATE = 0;
const PROCESSING_STATE = 1;
const DONE_STATE = 2;

/**
 * @template T
 * @callback Callback<T>
 * @param {Error=} err
 * @param {T=} result
 */

/**
 * @template T
 * @template K
 * @template R
 */
class AsyncQueueEntry {
	/**
	 * @param {T} item the item
	 * @param {Callback<R>} callback the callback
	 */
	constructor(item, callback) {
		this.item = item;
		/** @type {typeof QUEUED_STATE | typeof PROCESSING_STATE | typeof DONE_STATE} */
		this.state = QUEUED_STATE;
		this.callback = callback;
		/** @type {Callback<R>[] | undefined} */
		this.callbacks = undefined;
		this.result = undefined;
		this.error = undefined;
	}
}

/**
 * @template T
 * @template K
 * @template R
 */
class AsyncQueue {
	/**
	 * @param {Object} options options object
	 * @param {string=} options.name name of the queue
	 * @param {number} options.parallelism how many items should be processed at once
	 * @param {function(T): K=} options.getKey extract key from item
	 * @param {function(T, Callback<R>): void} options.processor async function to process items
	 */
	constructor({ name, parallelism, processor, getKey }) {
		this._name = name;
		this._parallelism = parallelism;
		this._processor = processor;
		this._getKey =
			getKey || /** @type {(T) => K} */ (item => /** @type {any} */ (item));
		/** @type {Map<K, AsyncQueueEntry<T, K, R>>} */
		this._entries = new Map();
		/** @type {AsyncQueueEntry<T, K, R>[]} */
		this._queued = [];
		this._activeTasks = 0;
		this._willEnsureProcessing = false;
		this._stopped = false;

		this.hooks = {
			beforeAdd: new AsyncSeriesHook(["item"]),
			added: new SyncHook(["item"]),
			beforeStart: new AsyncSeriesHook(["item"]),
			started: new SyncHook(["item"]),
			result: new SyncHook(["item", "error", "result"])
		};

		this._ensureProcessing = this._ensureProcessing.bind(this);
	}

	/**
	 * @param {T} item a item
	 * @param {Callback<R>} callback callback function
	 * @returns {void}
	 */
	add(item, callback) {
		if (this._stopped) return callback(new Error("Queue was stopped"));
		this.hooks.beforeAdd.callAsync(item, err => {
			if (err) {
				callback(err);
				return;
			}
			const key = this._getKey(item);
			const entry = this._entries.get(key);
			if (entry !== undefined) {
				if (entry.state === DONE_STATE) {
					process.nextTick(() => callback(entry.error, entry.result));
				} else if (entry.callbacks === undefined) {
					entry.callbacks = [callback];
				} else {
					entry.callbacks.push(callback);
				}
				return;
			}
			const newEntry = new AsyncQueueEntry(item, callback);
			if (this._stopped) {
				this.hooks.added.call(item);
				this._activeTasks++;
				this._handleResult(newEntry, new Error("Queue was stopped"));
			} else {
				this._entries.set(key, newEntry);
				this._queued.push(newEntry);
				if (this._willEnsureProcessing === false) {
					this._willEnsureProcessing = true;
					process.nextTick(this._ensureProcessing);
				}
				this.hooks.added.call(item);
			}
		});
	}

	/**
	 * @param {T} item a item
	 * @returns {void}
	 */
	invalidate(item) {
		const key = this._getKey(item);
		this._entries.delete(key);
	}

	/**
	 * @returns {void}
	 */
	stop() {
		this._stopped = true;
		const queue = this._queued;
		this._queued = [];
		for (const entry of queue) {
			this._entries.delete(this._getKey(entry.item));
			this._activeTasks++;
			this._handleResult(entry, new Error("Queue was stopped"));
		}
	}

	/**
	 * @returns {void}
	 */
	increaseParallelism() {
		this._parallelism++;
		if (this._willEnsureProcessing === false && this._queued.length > 0) {
			this._willEnsureProcessing = true;
			process.nextTick(this._ensureProcessing);
		}
	}

	/**
	 * @returns {void}
	 */
	decreaseParallelism() {
		this._parallelism--;
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, if the item is currently being processed
	 */
	isProcessing(item) {
		const key = this._getKey(item);
		const entry = this._entries.get(key);
		return entry !== undefined && entry.state === PROCESSING_STATE;
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, if the item is currently queued
	 */
	isQueued(item) {
		const key = this._getKey(item);
		const entry = this._entries.get(key);
		return entry !== undefined && entry.state === QUEUED_STATE;
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, if the item is currently queued
	 */
	isDone(item) {
		const key = this._getKey(item);
		const entry = this._entries.get(key);
		return entry !== undefined && entry.state === DONE_STATE;
	}

	/**
	 * @returns {void}
	 */
	_ensureProcessing() {
		while (this._activeTasks < this._parallelism && this._queued.length > 0) {
			const entry = this._queued.pop();
			this._activeTasks++;
			entry.state = PROCESSING_STATE;
			this._startProcessing(entry);
		}
		this._willEnsureProcessing = false;
	}

	/**
	 * @param {AsyncQueueEntry<T, K, R>} entry the entry
	 * @returns {void}
	 */
	_startProcessing(entry) {
		this.hooks.beforeStart.callAsync(entry.item, err => {
			if (err) {
				this._handleResult(entry, err);
				return;
			}
			try {
				this._processor(entry.item, (e, r) => {
					this._handleResult(entry, e, r);
				});
			} catch (err) {
				this._handleResult(entry, err, null);
			}
			this.hooks.started.call(entry.item);
		});
	}

	/**
	 * @param {AsyncQueueEntry<T, K, R>} entry the entry
	 * @param {Error=} err error, if any
	 * @param {R=} result result, if any
	 * @returns {void}
	 */
	_handleResult(entry, err, result) {
		this.hooks.result.callAsync(entry.item, err, result, hookError => {
			const error = hookError || err;

			const callback = entry.callback;
			const callbacks = entry.callbacks;
			entry.state = DONE_STATE;
			entry.callback = undefined;
			entry.callbacks = undefined;
			entry.result = result;
			entry.error = error;
			this._activeTasks--;

			if (this._willEnsureProcessing === false && this._queued.length > 0) {
				this._willEnsureProcessing = true;
				process.nextTick(this._ensureProcessing);
			}

			callback(error, result);
			if (callbacks !== undefined) {
				for (const callback of callbacks) {
					callback(error, result);
				}
			}
		});
	}
}

module.exports = AsyncQueue;
<|endoftext|>


<commit_before>if (typeof (fetch) === 'undefined') require('isomorphic-fetch')

const API_USER_PATH = '/api/secure/user'

export async function secureFetch (url, accessToken, apiKey, method = 'get', options = {}) {
  const res = await fetch(url, {
    method,
    mode: 'cors', // Middleware is at a different URL.
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
      'x-api-key': apiKey
    },
    ...options
  })
  if ((res.status && res.status >= 400) || (res.code && res.code >= 400)) {
    const result = await res.json()
    let message = `Error ${method}-ing user: ${result.message}`
    if (result.detail) message += `  (${result.detail})`

    console.log(message)
    return {
      status: 'error',
      message
    }
  }
  return {
    status: 'success',
    data: await res.json()
  }
}

export async function fetchUser (middlewareConfig, token) {
  const API_AUTH0USER_PATH = '/api/secure/user/fromtoken'
  const { apiBaseUrl, apiKey } = middlewareConfig
  const requestUrl = `${apiBaseUrl}${API_AUTH0USER_PATH}`

  return secureFetch(requestUrl, token, apiKey)
}

export async function addUser (middlewareConfig, token, data) {
  const { apiBaseUrl, apiKey } = middlewareConfig
  const requestUrl = `${apiBaseUrl}${API_USER_PATH}`

  return secureFetch(requestUrl, token, apiKey, 'POST', {
    body: JSON.stringify(data)
  })
}

export async function updateUser (middlewareConfig, token, data) {
  const { apiBaseUrl, apiKey } = middlewareConfig
  const { id } = data // Middleware ID, NOT auth0 (or similar) id.
  const requestUrl = `${apiBaseUrl}${API_USER_PATH}/${id}`

  if (id) {
    return secureFetch(requestUrl, token, apiKey, 'PUT', {
      body: JSON.stringify(data)
    })
  } else {
    return {
      status: 'error',
      message: 'Corrupted state: User ID not available for exiting user.'
    }
  }
}
<commit_msg>refactor(middleware): Use API_USER_PATH/fromtoken instead of API_AUTH0USER_PATH<commit_after>if (typeof (fetch) === 'undefined') require('isomorphic-fetch')

const API_USER_PATH = '/api/secure/user'

export async function secureFetch (url, accessToken, apiKey, method = 'get', options = {}) {
  const res = await fetch(url, {
    method,
    mode: 'cors', // Middleware is at a different URL.
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
      'x-api-key': apiKey
    },
    ...options
  })
  if ((res.status && res.status >= 400) || (res.code && res.code >= 400)) {
    const result = await res.json()
    let message = `Error ${method}-ing user: ${result.message}`
    if (result.detail) message += `  (${result.detail})`

    console.log(message)
    return {
      status: 'error',
      message
    }
  }
  return {
    status: 'success',
    data: await res.json()
  }
}

export async function fetchUser (middlewareConfig, token) {
  const { apiBaseUrl, apiKey } = middlewareConfig
  const requestUrl = `${apiBaseUrl}${API_USER_PATH}/fromtoken`

  return secureFetch(requestUrl, token, apiKey)
}

export async function addUser (middlewareConfig, token, data) {
  const { apiBaseUrl, apiKey } = middlewareConfig
  const requestUrl = `${apiBaseUrl}${API_USER_PATH}`

  return secureFetch(requestUrl, token, apiKey, 'POST', {
    body: JSON.stringify(data)
  })
}

export async function updateUser (middlewareConfig, token, data) {
  const { apiBaseUrl, apiKey } = middlewareConfig
  const { id } = data // Middleware ID, NOT auth0 (or similar) id.
  const requestUrl = `${apiBaseUrl}${API_USER_PATH}/${id}`

  if (id) {
    return secureFetch(requestUrl, token, apiKey, 'PUT', {
      body: JSON.stringify(data)
    })
  } else {
    return {
      status: 'error',
      message: 'Corrupted state: User ID not available for exiting user.'
    }
  }
}
<|endoftext|>


<commit_before>describe("Entity", function(){
    before(function(){
        enchant();
        var game = new Core(320, 320);
        game.preload('start.png');
        // working around of error "game.assets['start.png'] is undefined"
        game.assets['start.png'] = new Surface();
    });

    /**
     * @see https://github.com/wise9/enchant.js/issues/14
     */
    describe("issue #14", function(){
        it("should not throw error when Sprite.frame set before Sprite.image set.", function(){
            var sprite = new enchant.Sprite(32, 32);
            var error;
            try {
                sprite.frame = 0;
                sprite.image = enchant.Core.instance.assets['start.png'];
            } catch(e) {
                error = e;
            }
            expect(error).to.be.undefined;
        });
    });

    /**
     * @see https://github.com/wise9/enchant.js/issues/18
     */
    describe("issue #18", function(){
        it("should work with buttonMode", function(){
            var sprite = new Sprite();
            sprite.buttonMode = 'a';
            expect(sprite.buttonPressed).not.to.be.ok;
            sprite.dispatchEvent(new enchant.Event('touchstart'));
            expect(sprite.buttonPressed).to.be.ok;
            sprite.dispatchEvent(new enchant.Event('touchend'));
            expect(sprite.buttonPressed).not.to.be.ok;
        });
    });

    describe("EventListener", function(){
        it("should be able to add and remove EventListener", function(){
            var sprite = new Sprite();
            listener = function(){};
            sprite.clearEventListener('enterframe');
            sprite.addEventListener('enterframe', listener);
            expect(sprite._listeners['enterframe'].length).to.be.equal(1);
            sprite.removeEventListener('enterframe', listener);
            expect(sprite._listeners['enterframe'].length).to.be.empty;
        });

        it("should be able to add multiple EvenetListeners", function(){
            var sprite = new Sprite();
            var listener1 = function(){};
            var listener2 = function(){};
            sprite.clearEventListener('enterframe');
            sprite.addEventListener('enterframe', listener1);
            expect(sprite._listeners['enterframe'].length).to.be.equal(1);
            sprite.addEventListener('enterframe', listener2);
            expect(sprite._listeners['enterframe'].length).to.be.equal(2);
        });

        it("should remove all EventListeners at once", function(){
            var sprite = new Sprite();
            var listener1 = function(){};
            var listener2 = function(){};
            sprite.clearEventListener('enterframe');
            sprite.addEventListener('enterframe', listener1);
            sprite.addEventListener('enterframe', listener2);
            expect(sprite._listeners['enterframe'].length).to.be.equal(2);
            sprite.clearEventListener('enterframe');
            expect(sprite._listeners['enterframe']).to.be.undefined;
            sprite.addEventListener('enterframe', listener1);
            sprite.addEventListener('enterframe', listener2);
            expect(sprite._listeners['enterframe'].length).to.be.equal(2);
            sprite.clearEventListener();
            expect(sprite._listeners['enterframe']).to.be.undefined;
        });
    });

    describe("#intersects, #within (collision detection)", function(){
        it("should detect collision each entity belongs to different groups.", function(){
            var a = new enchant.Sprite(32, 32),
                b = new enchant.Sprite(32, 32),
                scene = new enchant.Scene(),
                ga = new enchant.Group(),
                gb = new enchant.Group();
            ga.addChild(a);
            gb.addChild(b);
            scene.addChild(ga);
            scene.addChild(gb);
            expect(a.intersect(b)).to.be.true;
            expect(a.within(b)).to.be.true;
            a.x = 64;
            expect(a.intersect(b)).to.be.false;
            expect(a.within(b)).to.be.false;
            ga.x = -64;
            expect(a.intersect(b)).to.be.true;
            expect(a.within(b)).to.be.true;
            b.y = 64;
            expect(a.intersect(b)).to.be.false;
            expect(a.within(b)).to.be.false;
            gb.y = -64;
            expect(a.intersect(b)).to.be.true;
            expect(a.within(b)).to.be.true;
        });
    });

    /**
     * @see https://github.com/wise9/enchant.js/issues/95
     */
    describe("issue #95", function(){
        it("(Sprite) should draw a image repetitively when the image is smaller than the sprite", function(){
            var surface = new enchant.Surface(24, 24);
            var context = surface.context;
            // draw checkerboard pattern
            context.fillStyle = '#FFFFFF';
            context.fillRect(0, 0, 24, 24);
            context.fillStyle = '#000000';
            context.fillRect(0, 0, 12, 12);
            context.fillRect(12, 12, 12, 12);
            var expected = new enchant.Surface(32, 32);
            var ctx = expected.context;
            ctx.fillStyle = '#FFFFFF';
            ctx.fillRect(0, 0, 32, 32);
            ctx.fillStyle = '#000000';
            ctx.fillRect(0, 0, 12, 12);
            ctx.fillRect(12, 12, 12, 12);
            ctx.fillRect(24, 0, 8, 12);
            ctx.fillRect(0, 24, 12, 8);
            ctx.fillRect(24, 24, 8, 8);
            var expectedArray = ctx.getImageData(0, 0, 32, 32).data;
            var sprite = new enchant.Sprite(32, 32);
            sprite.image = surface;
            var actual = new enchant.Surface(32, 32);
            sprite.cvsRender(actual.context);
            var actualArray = actual.context.getImageData(0, 0, 32, 32).data;
            expect(expectedArray.length).to.be.equal(actualArray.length);
            var len = actualArray.length;
            var error = 0;
            var errorCapacity = Math.round(len / 100);
            for(var i = 0; i < len; i++) {
                if(actualArray[i] !== expectedArray[i]) {
                    error++;
                }
            }
            var result = ((len - error) / len * 100).toFixed(2) + "% same";
            expect(error).to.be.below(errorCapacity, result);
        });
    });
});
<commit_msg>added test case for collection behavior when using remove or parentNode.removeChild<commit_after>describe("Entity", function(){
    before(function(){
        enchant();
        var game = new Core(320, 320);
        game.preload('start.png');
        // working around of error "game.assets['start.png'] is undefined"
        game.assets['start.png'] = new Surface();
    });

    /**
     * @see https://github.com/wise9/enchant.js/issues/14
     */
    describe("issue #14", function(){
        it("should not throw error when Sprite.frame set before Sprite.image set.", function(){
            var sprite = new enchant.Sprite(32, 32);
            var error;
            try {
                sprite.frame = 0;
                sprite.image = enchant.Core.instance.assets['start.png'];
            } catch(e) {
                error = e;
            }
            expect(error).to.be.undefined;
        });
    });

    /**
     * @see https://github.com/wise9/enchant.js/issues/18
     */
    describe("issue #18", function(){
        it("should work with buttonMode", function(){
            var sprite = new Sprite();
            sprite.buttonMode = 'a';
            expect(sprite.buttonPressed).not.to.be.ok;
            sprite.dispatchEvent(new enchant.Event('touchstart'));
            expect(sprite.buttonPressed).to.be.ok;
            sprite.dispatchEvent(new enchant.Event('touchend'));
            expect(sprite.buttonPressed).not.to.be.ok;
        });
    });

    describe("EventListener", function(){
        it("should be able to add and remove EventListener", function(){
            var sprite = new Sprite();
            listener = function(){};
            sprite.clearEventListener('enterframe');
            sprite.addEventListener('enterframe', listener);
            expect(sprite._listeners['enterframe'].length).to.be.equal(1);
            sprite.removeEventListener('enterframe', listener);
            expect(sprite._listeners['enterframe'].length).to.be.empty;
        });

        it("should be able to add multiple EvenetListeners", function(){
            var sprite = new Sprite();
            var listener1 = function(){};
            var listener2 = function(){};
            sprite.clearEventListener('enterframe');
            sprite.addEventListener('enterframe', listener1);
            expect(sprite._listeners['enterframe'].length).to.be.equal(1);
            sprite.addEventListener('enterframe', listener2);
            expect(sprite._listeners['enterframe'].length).to.be.equal(2);
        });

        it("should remove all EventListeners at once", function(){
            var sprite = new Sprite();
            var listener1 = function(){};
            var listener2 = function(){};
            sprite.clearEventListener('enterframe');
            sprite.addEventListener('enterframe', listener1);
            sprite.addEventListener('enterframe', listener2);
            expect(sprite._listeners['enterframe'].length).to.be.equal(2);
            sprite.clearEventListener('enterframe');
            expect(sprite._listeners['enterframe']).to.be.undefined;
            sprite.addEventListener('enterframe', listener1);
            sprite.addEventListener('enterframe', listener2);
            expect(sprite._listeners['enterframe'].length).to.be.equal(2);
            sprite.clearEventListener();
            expect(sprite._listeners['enterframe']).to.be.undefined;
        });
    });

    describe("#intersects, #within (collision detection)", function(){
        it("should detect collision each entity belongs to different groups.", function(){
            var a = new enchant.Sprite(32, 32),
                b = new enchant.Sprite(32, 32),
                scene = new enchant.Scene(),
                ga = new enchant.Group(),
                gb = new enchant.Group();
            ga.addChild(a);
            gb.addChild(b);
            scene.addChild(ga);
            scene.addChild(gb);
            expect(a.intersect(b)).to.be.true;
            expect(a.within(b)).to.be.true;
            a.x = 64;
            expect(a.intersect(b)).to.be.false;
            expect(a.within(b)).to.be.false;
            ga.x = -64;
            expect(a.intersect(b)).to.be.true;
            expect(a.within(b)).to.be.true;
            b.y = 64;
            expect(a.intersect(b)).to.be.false;
            expect(a.within(b)).to.be.false;
            gb.y = -64;
            expect(a.intersect(b)).to.be.true;
            expect(a.within(b)).to.be.true;
        });
    });

    /**
     * @see https://github.com/wise9/enchant.js/issues/95
     */
    describe("issue #95", function(){
        it("(Sprite) should draw a image repetitively when the image is smaller than the sprite", function(){
            var surface = new enchant.Surface(24, 24);
            var context = surface.context;
            // draw checkerboard pattern
            context.fillStyle = '#FFFFFF';
            context.fillRect(0, 0, 24, 24);
            context.fillStyle = '#000000';
            context.fillRect(0, 0, 12, 12);
            context.fillRect(12, 12, 12, 12);
            var expected = new enchant.Surface(32, 32);
            var ctx = expected.context;
            ctx.fillStyle = '#FFFFFF';
            ctx.fillRect(0, 0, 32, 32);
            ctx.fillStyle = '#000000';
            ctx.fillRect(0, 0, 12, 12);
            ctx.fillRect(12, 12, 12, 12);
            ctx.fillRect(24, 0, 8, 12);
            ctx.fillRect(0, 24, 12, 8);
            ctx.fillRect(24, 24, 8, 8);
            var expectedArray = ctx.getImageData(0, 0, 32, 32).data;
            var sprite = new enchant.Sprite(32, 32);
            sprite.image = surface;
            var actual = new enchant.Surface(32, 32);
            sprite.cvsRender(actual.context);
            var actualArray = actual.context.getImageData(0, 0, 32, 32).data;
            expect(expectedArray.length).to.be.equal(actualArray.length);
            var len = actualArray.length;
            var error = 0;
            var errorCapacity = Math.round(len / 100);
            for(var i = 0; i < len; i++) {
                if(actualArray[i] !== expectedArray[i]) {
                    error++;
                }
            }
            var result = ((len - error) / len * 100).toFixed(2) + "% same";
            expect(error).to.be.below(errorCapacity, result);
        });
    });

    describe("#collection behavior", function(){
        it("Node.remove", function(){
            var initialCollectionLength = enchant.Sprite.collection.length;
            var a = new enchant.Sprite(32, 32),
                b = new enchant.Sprite(32, 32),
                scene = new enchant.Scene(),
                ga = new enchant.Group();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            scene.addChild(ga);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            scene.addChild(b);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+1);
            ga.addChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+2);
            b.remove();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+1);
            a.remove();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            a = new enchant.Sprite(32, 32)
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            ga.addChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+1);
            ga.remove();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            a.remove();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);

            a = new enchant.Sprite(32, 32)
            ga = new enchant.Group();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            ga.addChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            a.remove();
            ga.remove();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);

            // listener check as remove has been used
            expect(a._listeners).to.be.empty;
            expect(b._listeners).to.be.empty;
            expect(ga._listeners).to.be.empty;
        });

        it("parentNode.removeChild", function(){
            var initialCollectionLength = enchant.Sprite.collection.length;
            var a = new enchant.Sprite(32, 32),
                b = new enchant.Sprite(32, 32),
                scene = new enchant.Scene(),
                ga = new enchant.Group();
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            scene.addChild(ga);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            scene.addChild(b);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+1);
            ga.addChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+2);
            b.parentNode.removeChild(b);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+1);
            a.parentNode.removeChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            ga.addChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength+1);
            ga.parentNode.removeChild(ga);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            a.parentNode.removeChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);

            ga.addChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);
            a.parentNode.removeChild(a);
            expect(enchant.Sprite.collection.length).to.be.equal(initialCollectionLength);

            expect(a._listeners).to.not.be.empty;
            expect(b._listeners).to.not.be.empty;
            expect(ga._listeners).to.not.be.empty;
        });
    });
});
<|endoftext|>


<commit_before>"use strict";

module.exports = exports;

var path = require('path');
var semver = require('semver');
var url = require('url');

var abi_crosswalk;

// This is used for unit testing to provide a fake
// ABI crosswalk that emulates one that is not updated
// for the current version
if (process.env.NODE_PRE_GYP_ABI_CROSSWALK) {
    abi_crosswalk = require(process.env.NODE_PRE_GYP_ABI_CROSSWALK);
} else {
    abi_crosswalk = require('./abi_crosswalk.json');
}

function get_electron_abi(runtime, target_version) {
    if (!runtime) {
        throw new Error("get_electron_abi requires valid runtime arg");
    }
    if (typeof target_version === 'undefined') {
        // erroneous CLI call
        throw new Error("Empty target version is not supported if electron is the target.");
    }
    // Electron guarentees that patch version update won't break native modules.
    var sem_ver = semver.parse(target_version);
    return runtime + '-v' + sem_ver.major + '.' + sem_ver.minor;
}
module.exports.get_electron_abi = get_electron_abi;

function get_node_webkit_abi(runtime, target_version) {
    if (!runtime) {
        throw new Error("get_node_webkit_abi requires valid runtime arg");
    }
    if (typeof target_version === 'undefined') {
        // erroneous CLI call
        throw new Error("Empty target version is not supported if node-webkit is the target.");
    }
    return runtime + '-v' + target_version;
}
module.exports.get_node_webkit_abi = get_node_webkit_abi;

function get_node_abi(runtime, versions) {
    if (!runtime) {
        throw new Error("get_node_abi requires valid runtime arg");
    }
    if (!versions) {
        throw new Error("get_node_abi requires valid process.versions object");
    }
    var sem_ver = semver.parse(versions.node);
    if (sem_ver.major === 0 && sem_ver.minor % 2) { // odd series
        // https://github.com/mapbox/node-pre-gyp/issues/124
        return runtime+'-v'+versions.node;
    } else {
        // process.versions.modules added in >= v0.10.4 and v0.11.7
        // https://github.com/joyent/node/commit/ccabd4a6fa8a6eb79d29bc3bbe9fe2b6531c2d8e
        return versions.modules ? runtime+'-v' + (+versions.modules) :
            'v8-' + versions.v8.split('.').slice(0,2).join('.');
    }
}
module.exports.get_node_abi = get_node_abi;

function get_runtime_abi(runtime, target_version) {
    if (!runtime) {
        throw new Error("get_runtime_abi requires valid runtime arg");
    }
    if (runtime === 'node-webkit') {
        return get_node_webkit_abi(runtime, target_version || process.versions['node-webkit']);
    } else if (runtime === 'electron') {
        return get_electron_abi(runtime, target_version || process.versions.electron);
    } else {
        if (runtime != 'node') {
            throw new Error("Unknown Runtime: '" + runtime + "'");
        }
        if (!target_version) {
            return get_node_abi(runtime,process.versions);
        } else {
            var cross_obj;
            // abi_crosswalk generated with ./scripts/abi_crosswalk.js
            if (abi_crosswalk[target_version]) {
                cross_obj = abi_crosswalk[target_version];
            } else {
                var target_parts = target_version.split('.').map(function(i) { return +i; });
                if (target_parts.length != 3) { // parse failed
                    throw new Error("Unknown target version: " + target_version);
                }
                /*
                    The below code tries to infer the last known ABI compatible version
                    that we have recorded in the abi_crosswalk.json when an exact match
                    is not possible. The reasons for this to exist are complicated:

                       - We support passing --target to be able to allow developers to package binaries for versions of node
                         that are not the same one as they are running. This might also be used in combination with the
                         --target_arch or --target_platform flags to also package binaries for alternative platforms
                       - When --target is passed we can't therefore determine the ABI (process.versions.modules) from the node
                         version that is running in memory
                       - So, therefore node-pre-gyp keeps an "ABI crosswalk" (lib/util/abi_crosswalk.json) to be able to look
                         this info up for all versions
                       - But we cannot easily predict what the future ABI will be for released versions
                       - And node-pre-gyp needs to be a `bundledDependency` in apps that depend on it in order to work correctly
                         by being fully available at install time.
                       - So, the speed of node releases and the bundled nature of node-pre-gyp mean that a new node-pre-gyp release
                         need to happen for every node.js/io.js/node-webkit/nw.js/atom-shell/etc release that might come online if
                         you want the `--target` flag to keep working for the latest version
                       - Which is impractical ^^
                       - Hence the below code guesses about future ABI to make the need to update node-pre-gyp less demanding.

                    In practice then you can have a dependency of your app like `node-sqlite3` that bundles a `node-pre-gyp` that
                    only knows about node v0.10.33 in the `abi_crosswalk.json` but target node v0.10.34 (which is assumed to be
                    ABI compatible with v0.10.33).

                    TODO: use semver module instead of custom version parsing
                */
                var major = target_parts[0];
                var minor = target_parts[1];
                var patch = target_parts[2];
                // io.js: yeah if node.js ever releases 1.x this will break
                // but that is unlikely to happen: https://github.com/iojs/io.js/pull/253#issuecomment-69432616
                if (major === 1) {
                    // look for last release that is the same major version
                    // e.g. we assume io.js 1.x is ABI compatible with >= 1.0.0
                    while (true) {
                        if (minor > 0) --minor;
                        if (patch > 0) --patch;
                        var new_iojs_target = '' + major + '.' + minor + '.' + patch;
                        if (abi_crosswalk[new_iojs_target]) {
                            cross_obj = abi_crosswalk[new_iojs_target];
                            console.log('Warning: node-pre-gyp could not find exact match for ' + target_version);
                            console.log('Warning: but node-pre-gyp successfully choose ' + new_iojs_target + ' as ABI compatible target');
                            break;
                        }
                        if (minor === 0 && patch === 0) {
                            break;
                        }
                    }
                } else if (major === 0) { // node.js
                    if (target_parts[1] % 2 === 0) { // for stable/even node.js series
                        // look for the last release that is the same minor release
                        // e.g. we assume node 0.10.x is ABI compatible with >= 0.10.0
                        while (--patch > 0) {
                            var new_node_target = '' + major + '.' + minor + '.' + patch;
                            if (abi_crosswalk[new_node_target]) {
                                cross_obj = abi_crosswalk[new_node_target];
                                console.log('Warning: node-pre-gyp could not find exact match for ' + target_version);
                                console.log('Warning: but node-pre-gyp successfully choose ' + new_node_target + ' as ABI compatible target');
                                break;
                            }
                        }
                    }
                }
            }
            if (!cross_obj) {
                throw new Error("Unsupported target version: " + target_version);
            }
            // emulate process.versions
            var versions_obj = {
                node: target_version,
                v8: cross_obj.v8+'.0',
                // abi_crosswalk uses 1 for node versions lacking process.versions.modules
                // process.versions.modules added in >= v0.10.4 and v0.11.7
                modules: cross_obj.node_abi > 1 ? cross_obj.node_abi : undefined
            };
            return get_node_abi(runtime, versions_obj);
        }
    }
}
module.exports.get_runtime_abi = get_runtime_abi;

var required_parameters = [
    'module_name',
    'module_path',
    'host'
];

function validate_config(package_json) {
    var msg = package_json.name + ' package.json is not node-pre-gyp ready:\n';
    var missing = [];
    if (!package_json.main) {
        missing.push('main');
    }
    if (!package_json.version) {
        missing.push('version');
    }
    if (!package_json.name) {
        missing.push('name');
    }
    if (!package_json.binary) {
        missing.push('binary');
    }
    var o = package_json.binary;
    required_parameters.forEach(function(p) {
        if (missing.indexOf('binary') > -1) {
            missing.pop('binary');
        }
        if (!o || o[p] === undefined) {
            missing.push('binary.' + p);
        }
    });
    if (missing.length >= 1) {
        throw new Error(msg+"package.json must declare these properties: \n" + missing.join('\n'));
    }
    if (o) {
        // enforce https over http
        var protocol = url.parse(o.host).protocol;
        if (protocol === 'http:') {
            throw new Error("'host' protocol ("+protocol+") is invalid - only 'https:' is accepted");
        }
    }
}

module.exports.validate_config = validate_config;

function eval_template(template,opts) {
    Object.keys(opts).forEach(function(key) {
        var pattern = '{'+key+'}';
        while (template.indexOf(pattern) > -1) {
            template = template.replace(pattern,opts[key]);
        }
    });
    return template;
}

// url.resolve needs single trailing slash
// to behave correctly, otherwise a double slash
// may end up in the url which breaks requests
// and a lacking slash may not lead to proper joining
function fix_slashes(pathname) {
    if (pathname.slice(-1) != '/') {
        return pathname + '/';
    }
    return pathname;
}

// remove double slashes
// note: path.normalize will not work because
// it will convert forward to back slashes
function drop_double_slashes(pathname) {
    return pathname.replace(/\/\//g,'/');
}

var default_package_name = '{module_name}-v{version}-{node_abi}-{platform}-{arch}.tar.gz';
var default_remote_path = '';

module.exports.evaluate = function(package_json,options) {
    options = options || {};
    validate_config(package_json);
    var v = package_json.version;
    var module_version = semver.parse(v);
    var runtime = options.runtime || (process.versions['node-webkit'] ? 'node-webkit' : 'node');
    var opts = {
        name: package_json.name,
        configuration: Boolean(options.debug) ? 'Debug' : 'Release',
        debug: options.debug,
        module_name: package_json.binary.module_name,
        version: module_version.version,
        prerelease: module_version.prerelease.length ? module_version.prerelease.join('.') : '',
        build: module_version.build.length ? module_version.build.join('.') : '',
        major: module_version.major,
        minor: module_version.minor,
        patch: module_version.patch,
        runtime: runtime,
        node_abi: get_runtime_abi(runtime,options.target),
        target: options.target || '',
        platform: options.target_platform || process.platform,
        target_platform: options.target_platform || process.platform,
        arch: options.target_arch || process.arch,
        target_arch: options.target_arch || process.arch,
        module_main: package_json.main,
        toolset : options.toolset || '' // address https://github.com/mapbox/node-pre-gyp/issues/119
    };
    // support host mirror with npm config `--{module_name}_binary_host_mirror`
    // e.g.: https://github.com/node-inspector/v8-profiler/blob/master/package.json#L25
    // > npm install v8-profiler --profiler_binary_host_mirror=https://npm.taobao.org/mirrors/node-inspector/
    var host = process.env['npm_config_' + opts.module_name + '_binary_host_mirror'] || package_json.binary.host;
    opts.host = fix_slashes(eval_template(host,opts));
    opts.module_path = eval_template(package_json.binary.module_path,opts);
    // now we resolve the module_path to ensure it is absolute so that binding.gyp variables work predictably
    if (options.module_root) {
        // resolve relative to known module root: works for pre-binding require
        opts.module_path = path.join(options.module_root,opts.module_path);
    } else {
        // resolve relative to current working directory: works for node-pre-gyp commands
        opts.module_path = path.resolve(opts.module_path);
    }
    opts.module = path.join(opts.module_path,opts.module_name + '.node');
    opts.remote_path = package_json.binary.remote_path ? drop_double_slashes(fix_slashes(eval_template(package_json.binary.remote_path,opts))) : default_remote_path;
    var package_name = package_json.binary.package_name ? package_json.binary.package_name : default_package_name;
    opts.package_name = eval_template(package_name,opts);
    opts.staged_tarball = path.join('build/stage',opts.remote_path,opts.package_name);
    opts.hosted_path = url.resolve(opts.host,opts.remote_path);
    opts.hosted_tarball = url.resolve(opts.hosted_path,opts.package_name);
    return opts;
};
<commit_msg>Fixed versioning.js to use process.versions['electron'] for Electron<commit_after>"use strict";

module.exports = exports;

var path = require('path');
var semver = require('semver');
var url = require('url');

var abi_crosswalk;

// This is used for unit testing to provide a fake
// ABI crosswalk that emulates one that is not updated
// for the current version
if (process.env.NODE_PRE_GYP_ABI_CROSSWALK) {
    abi_crosswalk = require(process.env.NODE_PRE_GYP_ABI_CROSSWALK);
} else {
    abi_crosswalk = require('./abi_crosswalk.json');
}

function get_electron_abi(runtime, target_version) {
    if (!runtime) {
        throw new Error("get_electron_abi requires valid runtime arg");
    }
    if (typeof target_version === 'undefined') {
        // erroneous CLI call
        throw new Error("Empty target version is not supported if electron is the target.");
    }
    // Electron guarentees that patch version update won't break native modules.
    var sem_ver = semver.parse(target_version);
    return runtime + '-v' + sem_ver.major + '.' + sem_ver.minor;
}
module.exports.get_electron_abi = get_electron_abi;

function get_node_webkit_abi(runtime, target_version) {
    if (!runtime) {
        throw new Error("get_node_webkit_abi requires valid runtime arg");
    }
    if (typeof target_version === 'undefined') {
        // erroneous CLI call
        throw new Error("Empty target version is not supported if node-webkit is the target.");
    }
    return runtime + '-v' + target_version;
}
module.exports.get_node_webkit_abi = get_node_webkit_abi;

function get_node_abi(runtime, versions) {
    if (!runtime) {
        throw new Error("get_node_abi requires valid runtime arg");
    }
    if (!versions) {
        throw new Error("get_node_abi requires valid process.versions object");
    }
    var sem_ver = semver.parse(versions.node);
    if (sem_ver.major === 0 && sem_ver.minor % 2) { // odd series
        // https://github.com/mapbox/node-pre-gyp/issues/124
        return runtime+'-v'+versions.node;
    } else {
        // process.versions.modules added in >= v0.10.4 and v0.11.7
        // https://github.com/joyent/node/commit/ccabd4a6fa8a6eb79d29bc3bbe9fe2b6531c2d8e
        return versions.modules ? runtime+'-v' + (+versions.modules) :
            'v8-' + versions.v8.split('.').slice(0,2).join('.');
    }
}
module.exports.get_node_abi = get_node_abi;

function get_runtime_abi(runtime, target_version) {
    if (!runtime) {
        throw new Error("get_runtime_abi requires valid runtime arg");
    }
    if (runtime === 'node-webkit') {
        return get_node_webkit_abi(runtime, target_version || process.versions['node-webkit']);
    } else if (runtime === 'electron') {
        return get_electron_abi(runtime, target_version || process.versions.electron);
    } else {
        if (runtime != 'node') {
            throw new Error("Unknown Runtime: '" + runtime + "'");
        }
        if (!target_version) {
            return get_node_abi(runtime,process.versions);
        } else {
            var cross_obj;
            // abi_crosswalk generated with ./scripts/abi_crosswalk.js
            if (abi_crosswalk[target_version]) {
                cross_obj = abi_crosswalk[target_version];
            } else {
                var target_parts = target_version.split('.').map(function(i) { return +i; });
                if (target_parts.length != 3) { // parse failed
                    throw new Error("Unknown target version: " + target_version);
                }
                /*
                    The below code tries to infer the last known ABI compatible version
                    that we have recorded in the abi_crosswalk.json when an exact match
                    is not possible. The reasons for this to exist are complicated:

                       - We support passing --target to be able to allow developers to package binaries for versions of node
                         that are not the same one as they are running. This might also be used in combination with the
                         --target_arch or --target_platform flags to also package binaries for alternative platforms
                       - When --target is passed we can't therefore determine the ABI (process.versions.modules) from the node
                         version that is running in memory
                       - So, therefore node-pre-gyp keeps an "ABI crosswalk" (lib/util/abi_crosswalk.json) to be able to look
                         this info up for all versions
                       - But we cannot easily predict what the future ABI will be for released versions
                       - And node-pre-gyp needs to be a `bundledDependency` in apps that depend on it in order to work correctly
                         by being fully available at install time.
                       - So, the speed of node releases and the bundled nature of node-pre-gyp mean that a new node-pre-gyp release
                         need to happen for every node.js/io.js/node-webkit/nw.js/atom-shell/etc release that might come online if
                         you want the `--target` flag to keep working for the latest version
                       - Which is impractical ^^
                       - Hence the below code guesses about future ABI to make the need to update node-pre-gyp less demanding.

                    In practice then you can have a dependency of your app like `node-sqlite3` that bundles a `node-pre-gyp` that
                    only knows about node v0.10.33 in the `abi_crosswalk.json` but target node v0.10.34 (which is assumed to be
                    ABI compatible with v0.10.33).

                    TODO: use semver module instead of custom version parsing
                */
                var major = target_parts[0];
                var minor = target_parts[1];
                var patch = target_parts[2];
                // io.js: yeah if node.js ever releases 1.x this will break
                // but that is unlikely to happen: https://github.com/iojs/io.js/pull/253#issuecomment-69432616
                if (major === 1) {
                    // look for last release that is the same major version
                    // e.g. we assume io.js 1.x is ABI compatible with >= 1.0.0
                    while (true) {
                        if (minor > 0) --minor;
                        if (patch > 0) --patch;
                        var new_iojs_target = '' + major + '.' + minor + '.' + patch;
                        if (abi_crosswalk[new_iojs_target]) {
                            cross_obj = abi_crosswalk[new_iojs_target];
                            console.log('Warning: node-pre-gyp could not find exact match for ' + target_version);
                            console.log('Warning: but node-pre-gyp successfully choose ' + new_iojs_target + ' as ABI compatible target');
                            break;
                        }
                        if (minor === 0 && patch === 0) {
                            break;
                        }
                    }
                } else if (major === 0) { // node.js
                    if (target_parts[1] % 2 === 0) { // for stable/even node.js series
                        // look for the last release that is the same minor release
                        // e.g. we assume node 0.10.x is ABI compatible with >= 0.10.0
                        while (--patch > 0) {
                            var new_node_target = '' + major + '.' + minor + '.' + patch;
                            if (abi_crosswalk[new_node_target]) {
                                cross_obj = abi_crosswalk[new_node_target];
                                console.log('Warning: node-pre-gyp could not find exact match for ' + target_version);
                                console.log('Warning: but node-pre-gyp successfully choose ' + new_node_target + ' as ABI compatible target');
                                break;
                            }
                        }
                    }
                }
            }
            if (!cross_obj) {
                throw new Error("Unsupported target version: " + target_version);
            }
            // emulate process.versions
            var versions_obj = {
                node: target_version,
                v8: cross_obj.v8+'.0',
                // abi_crosswalk uses 1 for node versions lacking process.versions.modules
                // process.versions.modules added in >= v0.10.4 and v0.11.7
                modules: cross_obj.node_abi > 1 ? cross_obj.node_abi : undefined
            };
            return get_node_abi(runtime, versions_obj);
        }
    }
}
module.exports.get_runtime_abi = get_runtime_abi;

var required_parameters = [
    'module_name',
    'module_path',
    'host'
];

function validate_config(package_json) {
    var msg = package_json.name + ' package.json is not node-pre-gyp ready:\n';
    var missing = [];
    if (!package_json.main) {
        missing.push('main');
    }
    if (!package_json.version) {
        missing.push('version');
    }
    if (!package_json.name) {
        missing.push('name');
    }
    if (!package_json.binary) {
        missing.push('binary');
    }
    var o = package_json.binary;
    required_parameters.forEach(function(p) {
        if (missing.indexOf('binary') > -1) {
            missing.pop('binary');
        }
        if (!o || o[p] === undefined) {
            missing.push('binary.' + p);
        }
    });
    if (missing.length >= 1) {
        throw new Error(msg+"package.json must declare these properties: \n" + missing.join('\n'));
    }
    if (o) {
        // enforce https over http
        var protocol = url.parse(o.host).protocol;
        if (protocol === 'http:') {
            throw new Error("'host' protocol ("+protocol+") is invalid - only 'https:' is accepted");
        }
    }
}

module.exports.validate_config = validate_config;

function eval_template(template,opts) {
    Object.keys(opts).forEach(function(key) {
        var pattern = '{'+key+'}';
        while (template.indexOf(pattern) > -1) {
            template = template.replace(pattern,opts[key]);
        }
    });
    return template;
}

// url.resolve needs single trailing slash
// to behave correctly, otherwise a double slash
// may end up in the url which breaks requests
// and a lacking slash may not lead to proper joining
function fix_slashes(pathname) {
    if (pathname.slice(-1) != '/') {
        return pathname + '/';
    }
    return pathname;
}

// remove double slashes
// note: path.normalize will not work because
// it will convert forward to back slashes
function drop_double_slashes(pathname) {
    return pathname.replace(/\/\//g,'/');
}

var default_package_name = '{module_name}-v{version}-{node_abi}-{platform}-{arch}.tar.gz';
var default_remote_path = '';

module.exports.evaluate = function(package_json,options) {
    options = options || {};
    validate_config(package_json);
    var v = package_json.version;
    var module_version = semver.parse(v);

    var runtime = options.runtime
    if (!runtime && process.versions['node-webkit']) { runtime = 'node-webkit'; }
    if (!runtime && process.versions['electron']) { runtime = 'electron'; }
    if (!runtime) { runtime = 'node'; }

    var opts = {
        name: package_json.name,
        configuration: Boolean(options.debug) ? 'Debug' : 'Release',
        debug: options.debug,
        module_name: package_json.binary.module_name,
        version: module_version.version,
        prerelease: module_version.prerelease.length ? module_version.prerelease.join('.') : '',
        build: module_version.build.length ? module_version.build.join('.') : '',
        major: module_version.major,
        minor: module_version.minor,
        patch: module_version.patch,
        runtime: runtime,
        node_abi: get_runtime_abi(runtime,options.target),
        target: options.target || '',
        platform: options.target_platform || process.platform,
        target_platform: options.target_platform || process.platform,
        arch: options.target_arch || process.arch,
        target_arch: options.target_arch || process.arch,
        module_main: package_json.main,
        toolset : options.toolset || '' // address https://github.com/mapbox/node-pre-gyp/issues/119
    };
    // support host mirror with npm config `--{module_name}_binary_host_mirror`
    // e.g.: https://github.com/node-inspector/v8-profiler/blob/master/package.json#L25
    // > npm install v8-profiler --profiler_binary_host_mirror=https://npm.taobao.org/mirrors/node-inspector/
    var host = process.env['npm_config_' + opts.module_name + '_binary_host_mirror'] || package_json.binary.host;
    opts.host = fix_slashes(eval_template(host,opts));
    opts.module_path = eval_template(package_json.binary.module_path,opts);
    // now we resolve the module_path to ensure it is absolute so that binding.gyp variables work predictably
    if (options.module_root) {
        // resolve relative to known module root: works for pre-binding require
        opts.module_path = path.join(options.module_root,opts.module_path);
    } else {
        // resolve relative to current working directory: works for node-pre-gyp commands
        opts.module_path = path.resolve(opts.module_path);
    }
    opts.module = path.join(opts.module_path,opts.module_name + '.node');
    opts.remote_path = package_json.binary.remote_path ? drop_double_slashes(fix_slashes(eval_template(package_json.binary.remote_path,opts))) : default_remote_path;
    var package_name = package_json.binary.package_name ? package_json.binary.package_name : default_package_name;
    opts.package_name = eval_template(package_name,opts);
    opts.staged_tarball = path.join('build/stage',opts.remote_path,opts.package_name);
    opts.hosted_path = url.resolve(opts.host,opts.remote_path);
    opts.hosted_tarball = url.resolve(opts.hosted_path,opts.package_name);
    return opts;
};
<|endoftext|>