<commit_before>module.exports = function(grunt) {
  'use strict';

  require('time-grunt')(grunt);
  require('jit-grunt')(grunt)({
    customTasksDir: 'helpers/grunt/tasks'
  });

  // Initialize config
  grunt.initConfig({
    pkg: require('./package.json')
  });

  // load tasks config per file
  grunt.loadTasks('helpers/grunt/config');

  //--- grunt tasks

  grunt.registerTask('start', ['clean', 'lintspaces:all', 'newer:jshint']);

  grunt.registerTask('default', ['start']); // TODO: check grunt-prompt

  //---

  // @begin: build tasks
  grunt.registerTask('build', function(target) {
    if(target === 'dev') {
      return grunt.task.run([
        'start',
        'copy:dev_tobuild',
        'copy:dev_jstobuild',
        'copy:dev_vendortobuild',
        'cleanempty:build',
        'less:dev'
      ]);

    } else if(target === 'prod') {
      return  grunt.task.run([
        'start',
        'copy:prod_jstobuild',
        'html2js:prod',
        'rewriterequireconfig',
        'requirejs',
        'clean:build',
        'copy:prod_todist',
        'cleanempty:dist',
        'less:prod',
        'htmlmin',
        'imagemin',
        'uglify'
      ]);

    }
  });
  // @end: build tasks

  //---

  // @begin: dev tasks
    // @begin: dev with livereload
  grunt.registerTask('server:livereload', ['connect:livereload', 'watch:livereload']);
  grunt.registerTask('server:livereload:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'configureProxies',
      'connect:livereloadProxy',
      'watch:livereload'
    ]);
  });

  grunt.registerTask('dev:livereload', ['build:dev','concurrent:livereload']);
  grunt.registerTask('dev:livereload:proxy', ['build:dev', 'concurrent:livereloadProxy']);
    // @end: dev with livereload

    // @begin: dev with browser sync
  grunt.registerTask('dev:sync', ['build:dev', 'browserSync:dev', 'watch:project']);
  grunt.registerTask('dev:sync:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'build:dev',
      'configureProxies',
      'browserSync:devProxy',
      'watch:project'
    ]);
  });
    // @end: dev with browser sync

    // @begin: dev alias
  grunt.registerTask('dev', ['dev:livereload']);
  grunt.registerTask('dev:proxy', ['dev:livereload:proxy']);
    // @end: dev alias
  // @end: dev tasks

  //---

  // @begin: distribution preview tasks
  grunt.registerTask('dist', ['build:prod', 'connect:dist']);
  grunt.registerTask('dist:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'build:prod',
      'configureProxies',
      'connect:distProxy'
    ]);
  });

    // @begin: preview with browser sync support
  grunt.registerTask('dist:sync', ['build:prod', 'browserSync:dist']);
  grunt.registerTask('dist:sync:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'build:prod',
      'configureProxies',
      'browserSync:distProxy'
    ]);
  });
    // @end: preview with browser sync support

  // @end: distribution preview tasks

  //---

  //--- @begin: spec's tasks

  //grunt.registerTask('specs:run:unit', ['karma:background:start', 'watch:unit']); // TODO: review :: needed?
  grunt.registerTask('specs:run:coverage', ['connect:coverage', 'watch:coverage']);

  grunt.registerTask('specs', ['start', 'karma:coverage', 'concurrent:specs']);

  //--- @end: spec's tasks

};
<commit_msg>tools grunt specs tasks reviewed #7<commit_after>module.exports = function(grunt) {
  'use strict';

  require('time-grunt')(grunt);
  require('jit-grunt')(grunt)({
    customTasksDir: 'helpers/grunt/tasks'
  });

  // Initialize config
  grunt.initConfig({
    pkg: require('./package.json')
  });

  // load tasks config per file
  grunt.loadTasks('helpers/grunt/config');

  //--- grunt tasks

  grunt.registerTask('start', ['clean', 'lintspaces:all', 'newer:jshint']);

  grunt.registerTask('default', ['start']); // TODO: check grunt-prompt

  //---

  // @begin: build tasks
  grunt.registerTask('build', function(target) {
    if(target === 'dev') {
      return grunt.task.run([
        'start',
        'copy:dev_tobuild',
        'copy:dev_jstobuild',
        'copy:dev_vendortobuild',
        'cleanempty:build',
        'less:dev'
      ]);

    } else if(target === 'prod') {
      return  grunt.task.run([
        'start',
        'copy:prod_jstobuild',
        'html2js:prod',
        'rewriterequireconfig',
        'requirejs',
        'clean:build',
        'copy:prod_todist',
        'cleanempty:dist',
        'less:prod',
        'htmlmin',
        'imagemin',
        'uglify'
      ]);

    }
  });
  // @end: build tasks

  //---

  // @begin: dev tasks
    // @begin: dev with livereload
  grunt.registerTask('server:livereload', ['connect:livereload', 'watch:livereload']);
  grunt.registerTask('server:livereload:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'configureProxies',
      'connect:livereloadProxy',
      'watch:livereload'
    ]);
  });

  grunt.registerTask('dev:livereload', ['build:dev','concurrent:livereload']);
  grunt.registerTask('dev:livereload:proxy', ['build:dev', 'concurrent:livereloadProxy']);
    // @end: dev with livereload

    // @begin: dev with browser sync
  grunt.registerTask('dev:sync', ['build:dev', 'browserSync:dev', 'watch:project']);
  grunt.registerTask('dev:sync:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'build:dev',
      'configureProxies',
      'browserSync:devProxy',
      'watch:project'
    ]);
  });
    // @end: dev with browser sync

    // @begin: dev alias
  grunt.registerTask('dev', ['dev:livereload']);
  grunt.registerTask('dev:proxy', ['dev:livereload:proxy']);
    // @end: dev alias
  // @end: dev tasks

  //---

  // @begin: distribution preview tasks
  grunt.registerTask('dist', ['build:prod', 'connect:dist']);
  grunt.registerTask('dist:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'build:prod',
      'configureProxies',
      'connect:distProxy'
    ]);
  });

    // @begin: preview with browser sync support
  grunt.registerTask('dist:sync', ['build:prod', 'browserSync:dist']);
  grunt.registerTask('dist:sync:proxy', function() {
    grunt.loadNpmTasks('grunt-connect-proxy');
    return grunt.task.run([
      'build:prod',
      'configureProxies',
      'browserSync:distProxy'
    ]);
  });
    // @end: preview with browser sync support

  // @end: distribution preview tasks

  //---

  //--- @begin: spec's tasks

  //grunt.registerTask('specs:run:unit', ['karma:background:start', 'watch:unit']); // TODO: review :: needed?
  grunt.registerTask('specs:run:coverage', ['connect:coverage', 'watch:coverage']);

  grunt.registerTask('specs', ['lintspaces:all', 'newer:jshint', 'karma:coverage', 'concurrent:specs']);

  //--- @end: spec's tasks

};
<|endoftext|>


<commit_before>var x,y,z,mcd,text,text2,resulta;
function myFunction() {
    x = parseFloat(document.getElementById("num1").value);
    y = parseFloat(document.getElementById("num2").value);
    z = parseFloat(document.getElementById("num3").value);
    document.getElementById("calculo").style.color="#0A8A0A";
    if (isNaN(x) || isNaN(y) || x%1!==0 || y%1!==0 || x<1 || y<1 ) {
        text = "Es necesario introducir dos números válidos. El tercer valor es opcional.";
        document.getElementById("calculo").style.color="#FF0000";
				var text2 = "";
    } else {
			factorizame(x);
    	text = resulta+"
";
    	factorizame(y);
    	text += resulta+'
';
    	if (!isNaN(z) && z%1==0 && z>=1){
    		factorizame(z);
				text += resulta+"
";
    	}

			if (!isNaN(x) && !isNaN(y) && isNaN(z)){             //solo x e y
				calculaMCD(x,y);
			} else if (!isNaN(x) && !isNaN(y) && !isNaN(z)){     //intervienen x, y, z
				calculaMCD(x,y);
				calculaMCD(mcd,z);                                 //propiedad recursiva para calcular el MCD de tres números
			}
			var text2="MCD="+mcd
    }
		document.getElementById("calculo").innerHTML = text;
		document.getElementById("calculo2").innerHTML = text2;
		document.getElementById("calculo2").style.color="blue";
}

function calculaMCD(n1,n2){
	if (n2>n1){                                              //queremos que n1 sea el mayor
		var aux=n1;
		n1=n2;
		n2=aux
	}
	var a=n1;
	var b=n2;

	do {                                                     //algoritmo de Euclides
		mcd=n2;
		var resto=n1%n2;
		n1=n2;
		n2=resto;
	} while (resto!=0);
}

function factorizame(n){
	resulta=n+' = ';
	var contador=0;
	while (n%2===0) {
   		n=n/2;
   		contador++;
	}
	if (contador>1){
		resulta += 2+""+contador+" × ";
	} else if (contador===1){
		resulta += "2 × ";
	}
	for (var i=3;i<=n;i=i+2){
		contador=0;
		while (n%i===0) {
   			n=n/i;
   			contador++;
		}
		if (contador>1){
			resulta += i+""+contador+" × ";
		} else if (contador===1){
			resulta += i+" × ";
		}
	}
		resulta += 1;
}
<commit_msg>Update mcdmcm2.js<commit_after>var x,y,z,mcd,text,text2,text3,resulta;
function myFunction() {
    x = parseFloat(document.getElementById("num1").value);
    y = parseFloat(document.getElementById("num2").value);
    z = parseFloat(document.getElementById("num3").value);
    document.getElementById("calculo").style.color="#0A8A0A";
    if (isNaN(x) || isNaN(y) || x%1!==0 || y%1!==0 || x<1 || y<1 ) {
        text = "Es necesario introducir dos números válidos. El tercer valor es opcional.";
        document.getElementById("calculo").style.color="#FF0000";
				var text2 = "";
    } else {
			factorizame(x);
    	text = resulta+"
";
    	factorizame(y);
    	text += resulta+'
';
    	if (!isNaN(z) && z%1==0 && z>=1){
    		factorizame(z);
				text += resulta+"
";
    	}

			if (!isNaN(x) && !isNaN(y) && isNaN(z)){             //solo x e y
				calculaMCD(x,y);
			} else if (!isNaN(x) && !isNaN(y) && !isNaN(z)){     //intervienen x, y, z
				calculaMCD(x,y);
				calculaMCD(mcd,z);                                 //propiedad recursiva para calcular el MCD de tres números
			}
			var text2="MCD="+mcd
    }
		document.getElementById("calculo").innerHTML = text;
		document.getElementById("calculo2").innerHTML = text2;
		document.getElementById("calculo2").style.color="blue";

		var text3=x+' / '+mcd+' = '+x/mcd+'
'+y+' / '+mcd+' = '+y/mcd+'
';
		if (!isNaN(z)){text3 += z+' / '+mcd+' = '+z/mcd+'
'}
		document.getElementById("calculo3").innerHTML = text3;
		document.getElementById("calculo3").style.color="magenta";
}

function calculaMCD(n1,n2){
	if (n2>n1){                                              //queremos que n1 sea el mayor
		var aux=n1;
		n1=n2;
		n2=aux
	}
	var a=n1;
	var b=n2;

	do {                                                     //algoritmo de Euclides
		mcd=n2;
		var resto=n1%n2;
		n1=n2;
		n2=resto;
	} while (resto!=0);
}

function factorizame(n){
	resulta=n+' = ';
	var contador=0;
	while (n%2===0) {
   		n=n/2;
   		contador++;
	}
	if (contador>1){
		resulta += 2+""+contador+" × ";
	} else if (contador===1){
		resulta += "2 × ";
	}
	for (var i=3;i<=n;i=i+2){
		contador=0;
		while (n%i===0) {
   			n=n/i;
   			contador++;
		}
		if (contador>1){
			resulta += i+""+contador+" × ";
		} else if (contador===1){
			resulta += i+" × ";
		}
	}
		resulta += 1;
}
<|endoftext|>


<commit_before>/**
 * Derequire-ifies a require generated minified module.
 * Replaces all define calls of the form
 * `define('moduleName', [dependencies...], function (solvedDependencies...) { return Module; }`
 * with
 * `goo.Module = (function (solvedDependencies...) { return Module })(namespacedDependencies...);`
 */

'use strict';

var esprima = require('esprima');
var escodegen = require('escodegen');
var _ = require('underscore');
var fs = require('fs');

function prefix(moduleName) {
	return {
		"type": "MemberExpression",
			"computed": false,
			"object": {
			"type": "Identifier",
				"name": "goo"
		},
		"property": {
			"type": "Identifier",
				"name": moduleName
		}
	};
}

function getAnonymousFunctionCall(callee, args) {
	return {
		"type": "CallExpression",
		"callee": callee,
		"arguments": args
	};
}

function getAssignment(left, right) {
	return {
		"type": "AssignmentExpression",
		"operator": "=",
		"left": left,
		"right": right
	};
}

function getSequence(subexpressios) {
	return {
		"type": "SequenceExpression",
		"expressions": subexpressios
	};
}

function getProgram(body) {
	return {
		"type": "Program",
		"body": [{
			"type": "ExpressionStatement",
			"expression": body
		}]
	};
}

function extractModuleName(completeName) {
	var index = completeName.lastIndexOf('/');
	return index === -1 ? completeName : completeName.substr(index + 1);
}

function transform(defineExpression) {
	var moduleName = extractModuleName(defineExpression.arguments[0].value);
	var requiredModules = defineExpression.arguments[1].elements;
	var wrapperFunction = defineExpression.arguments[2];

	var namespacedArgs = _.chain(requiredModules)
		.pluck('value')
		.map(extractModuleName)
		.map(prefix)
		.value();

	var functionCall = getAnonymousFunctionCall(wrapperFunction, namespacedArgs);
	var assigment = getAssignment(prefix(moduleName), functionCall);
	return assigment;
}

var inFileName = process.argv[2] || 'out/fish.js';
var outFileName = inFileName.substr(0, inFileName.length - 3) + '.dereq.js';

var source = fs.readFileSync(inFileName, 'utf8');

var tree = esprima.parse(source);

var moduleDefinitions = tree.body[0].expression.expressions;
console.log('Processing ' + (moduleDefinitions.length - 2) + ' modules...');

// filter out the last 2: which are added by our minifier
moduleDefinitions = moduleDefinitions.slice(0, moduleDefinitions.length - 2);

var processedModules = moduleDefinitions.map(transform);
var sequence = getSequence(processedModules);
var program = getProgram(sequence);

var generatorOptions = {
	format: {
		indent: {
			style: ''
		}
	},
	newline: '',
	space: '',
	compact: true
};

var outSource = escodegen.generate(program, generatorOptions);

fs.writeFileSync(outFileName, outSource);
console.log('Done; see ' + outFileName);<commit_msg>Even smaller output from the derequireifier - using uglify<commit_after>/**
 * Derequire-ifies a require generated minified module.
 * Replaces all define calls of the form
 * `define('moduleName', [dependencies...], function (solvedDependencies...) { return Module; }`
 * with
 * `goo.Module = (function (solvedDependencies...) { return Module })(namespacedDependencies...);`
 */

'use strict';

var esprima = require('esprima');
var escodegen = require('escodegen');
var _ = require('underscore');
var fs = require('fs');
var uglify = require('uglify-js');

function prefix(moduleName) {
	return {
		"type": "MemberExpression",
			"computed": false,
			"object": {
			"type": "Identifier",
				"name": "goo"
		},
		"property": {
			"type": "Identifier",
				"name": moduleName
		}
	};
}

function getAnonymousFunctionCall(callee, args) {
	return {
		"type": "CallExpression",
		"callee": callee,
		"arguments": args
	};
}

function getAssignment(left, right) {
	return {
		"type": "AssignmentExpression",
		"operator": "=",
		"left": left,
		"right": right
	};
}

function getSequence(subexpressios) {
	return {
		"type": "SequenceExpression",
		"expressions": subexpressios
	};
}

function getProgram(body) {
	return {
		"type": "Program",
		"body": [{
			"type": "ExpressionStatement",
			"expression": body
		}]
	};
}

function extractModuleName(completeName) {
	var index = completeName.lastIndexOf('/');
	return index === -1 ? completeName : completeName.substr(index + 1);
}

function transform(defineExpression) {
	var moduleName = extractModuleName(defineExpression.arguments[0].value);
	var requiredModules = defineExpression.arguments[1].elements;
	var wrapperFunction = defineExpression.arguments[2];

	var namespacedArgs = _.chain(requiredModules)
		.pluck('value')
		.map(extractModuleName)
		.map(prefix)
		.value();

	var functionCall = getAnonymousFunctionCall(wrapperFunction, namespacedArgs);
	var assigment = getAssignment(prefix(moduleName), functionCall);
	return assigment;
}

var inFileName = process.argv[2] || 'out/fish.js';
var outFileName = inFileName.substr(0, inFileName.length - 3) + '.dereq.js';

var source = fs.readFileSync(inFileName, 'utf8');

var tree = esprima.parse(source);

var moduleDefinitions = tree.body[0].expression.expressions;
console.log('Processing ' + (moduleDefinitions.length - 2) + ' modules...');

// filter out the last 2: which are added by our minifier
moduleDefinitions = moduleDefinitions.slice(0, moduleDefinitions.length - 2);

var processedModules = moduleDefinitions.map(transform);
var sequence = getSequence(processedModules);
var program = getProgram(sequence);

var generatorOptions = {
	format: {
		indent: {
			style: ''
		}
	},
	newline: '',
	space: '',
	compact: true
};

var outSource = escodegen.generate(program, generatorOptions);

var uglifyOptions = {
	fromString: true
};

var outMinifiedSource = uglify.minify(outSource, uglifyOptions);

fs.writeFileSync(outFileName, outMinifiedSource.code);
console.log('Done; see ' + outFileName);<|endoftext|>


<commit_before>
/**
 * Exports the current runtime environment, by processing
 * the query-params of the URL (window.location.search
 *
 *  currently supported settings are
 *

 *
browser

 *
cordova

 *
android

 *
ios

 *

 *
 *  @exports {Object} a singleton object with information about the runtime setting:
 *
{
 *  			isBrowserEnv: [true|false],
 *  			isCordovaEnv: [true|false],
 *  			platform: ["browser" | "android" | "ios" | "node" | "default"],
 *  		}

 */
define(['mmirf/paramsParseFunc'], function(paramsParseFunc) {

	var ctx = typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : typeof global !== 'undefined' ? global : this;
	var paramsStr = ctx && ctx.location? ctx.location.search : '?env=node';
	var params = paramsParseFunc( paramsStr );

	var isBrowserEnv;
	var isCordovaEnv;
	var isNodeEnv;
	var envSetting = '';
	var envParamSetting = '';

	if(typeof cordova !== 'undefined'){
		envSetting = cordova.platformId? cordova.platformId : envSetting;
		isCordovaEnv = true;
	}

	if(params.has('env')){

		envParamSetting = params['env'];
		envSetting = !envSetting? envParamSetting : envSetting;
	}

	if(envSetting){

		if(envSetting === 'browser'){
			isBrowserEnv = true;
		}
		else {
			isBrowserEnv = false;
		}

		if(envSetting === 'cordova' || envSetting === 'android' || envSetting === 'ios'){
			isCordovaEnv = true;
//			isBrowserEnv = false;
		}
		else {
			isCordovaEnv = false;
		}

		if(envSetting === 'node'){
			isNodeEnv = true;
		}
		else {
			isNodeEnv = false;
		}
	}
	else {
		isBrowserEnv = true;
		isCordovaEnv = false;
		isNodeEnv = false;
	}

	var env;
	if(isBrowserEnv){
		env = 'browser';
	} else {

		//if available, use plugin cordova-plugin-device for detecting specific env
		if(typeof device !== 'undefined' && device.platform){

			var platform = device.platform;
			if(/\bios\b/i.test(platform)){
				env = 'ios';
			} else if(/\bandroid\b/i.test(platform)){
				env = 'android';
			} else {//TODO handle other platforms
				console.warn('Unknown platform "'+platform+'"');
				env = 'default';
			}

		} else if(typeof navigator !== 'undefined') {

			//fallback: use UserAgent for detecting env
			var userAgent = navigator.userAgent;
			if(/(iPad|iPhone|iPod)/ig.test(userAgent)){
				env = 'ios';
			} else if(/android/i.test(userAgent)){
				env = 'android';
			} else {//TODO handle other platforms
				console.warn('Unknown platform for userAgent "'+userAgent+'"');
				env = 'default';
			}

		} else if(isNodeEnv) {
			env = 'node';
		} else {//TODO handle other platforms
			console.warn('Unknown platform');
			env = 'default';
		}

	}

	return {
		  isBrowserEnv: isBrowserEnv,
		  isCordovaEnv: isCordovaEnv,
		  isNodeEnv: isNodeEnv,
		  envSetting: envSetting,
		  platform: env
//		, params : params
	};
});
<commit_msg>add/detect env 'windows'<commit_after>
/**
 * Exports the current runtime environment, by processing
 * the query-params of the URL (window.location.search
 *
 *  currently supported settings are
 *

 *
browser

 *
cordova

 *
android

 *
ios

 *

 *
 *  @exports {Object} a singleton object with information about the runtime setting:
 *
{
 *  			isBrowserEnv: [true|false],
 *  			isCordovaEnv: [true|false],
 *  			platform: ["browser" | "android" | "ios" | "node" | "default"],
 *  		}

 */
define(['mmirf/paramsParseFunc'], function(paramsParseFunc) {

	var ctx = typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : typeof global !== 'undefined' ? global : this;
	var paramsStr = ctx && ctx.location? ctx.location.search : '?env=node';
	var params = paramsParseFunc( paramsStr );

	var isBrowserEnv;
	var isCordovaEnv;
	var isNodeEnv;
	var envSetting = '';
	var envParamSetting = '';

	if(typeof cordova !== 'undefined'){
		envSetting = cordova.platformId? cordova.platformId : envSetting;
		isCordovaEnv = true;
	}

	if(params.has('env')){

		envParamSetting = params['env'];
		envSetting = !envSetting? envParamSetting : envSetting;
	}

	if(envSetting){

		if(envSetting === 'browser'){
			isBrowserEnv = true;
		}
		else {
			isBrowserEnv = false;
		}

		if(envSetting === 'cordova' || envSetting === 'android' || envSetting === 'ios' || envSetting === 'windows'){
			isCordovaEnv = true;
//			isBrowserEnv = false;
		}
		else {
			isCordovaEnv = false;
		}

		if(envSetting === 'node'){
			isNodeEnv = true;
		}
		else {
			isNodeEnv = false;
		}
	}
	else {
		isBrowserEnv = true;
		isCordovaEnv = false;
		isNodeEnv = false;
	}

	var env;
	if(isBrowserEnv){
		env = 'browser';
	} else {

		//if available, use plugin cordova-plugin-device for detecting specific env
		if(typeof device !== 'undefined' && device.platform){

			var platform = device.platform;
			if(/\bios\b/i.test(platform)){
				env = 'ios';
			} else if(/\bandroid\b/i.test(platform)){
				env = 'android';
			} else if(/\bwindows\b/i.test(platform)){
				env = 'windows';
			} else {//TODO handle other platforms
				console.warn('Unknown platform "'+platform+'"');
				env = 'default';
			}

		} else if(typeof navigator !== 'undefined') {

			//fallback: use UserAgent for detecting env
			var userAgent = navigator.userAgent;
			if(/(iPad|iPhone|iPod)/ig.test(userAgent)){
				env = 'ios';
			} else if(/android/i.test(userAgent)){
				env = 'android';
			} else if(/MSAppHost/i.test(userAgent)){
				env = 'windows';
			} else {//TODO handle other platforms
				console.warn('Unknown platform for userAgent "'+userAgent+'"');
				env = 'default';
			}

		} else if(isNodeEnv) {
			env = 'node';
		} else {//TODO handle other platforms
			console.warn('Unknown platform');
			env = 'default';
		}

	}

	return {
		  isBrowserEnv: isBrowserEnv,
		  isCordovaEnv: isCordovaEnv,
		  isNodeEnv: isNodeEnv,
		  envSetting: envSetting,
		  platform: env
//		, params : params
	};
});
<|endoftext|>


<commit_before><commit_msg>update tools/fixFormat.js to fix author/authors issue<commit_after><|endoftext|>


<commit_before>'use strict';

var util = require('util');
var JobBase = require('./job_base');
var jobStatus = require('../job_status');
var QueryFallback = require('./query/query_fallback');
var MainFallback = require('./query/main_fallback');
var QueryFactory = require('./query/query_factory');

var JobUtils = require('./job_state_machine');
var jobUtils = new JobUtils();

function JobFallback(jobDefinition) {
    JobBase.call(this, jobDefinition);

    this.init();

    this.queries = [];
    for (var i = 0; i < this.data.query.query.length; i++) {
        this.queries[i] = QueryFactory.create(this.data, i);
    }

    if (MainFallback.is(this.data)) {
        this.fallback = new MainFallback();
    }
}
util.inherits(JobFallback, JobBase);

module.exports = JobFallback;

// 1. from user: {
//     query: {
//         query: [{
//             query: 'select ...',
//             onsuccess: 'select ..'
//         }],
//         onerror: 'select ...'
//     }
// }
//
// 2. from redis: {
//     status: 'pending',
//     fallback_status: 'pending'
//     query: {
//         query: [{
//             query: 'select ...',
//             onsuccess: 'select ..'
//             status: 'pending',
//             fallback_status: 'pending',
//         }],
//         onerror: 'select ...'
//     }
// }

JobFallback.is = function (query) {
    if (!query.query) {
        return false;
    }

    if (!Array.isArray(query.query)) {
        return false;
    }

    for (var i = 0; i < query.query.length; i++) {
        if (!QueryFallback.is(query.query[i])) {
            return false;
        }
    }

    return true;
};

JobFallback.prototype.init = function () {
    for (var i = 0; i < this.data.query.query.length; i++) {
        if (shouldInitStatus(this.data.query.query[i])){
            this.data.query.query[i].status = jobStatus.PENDING;
        }
        if (shouldInitQueryFallbackStatus(this.data.query.query[i])) {
            this.data.query.query[i].fallback_status = jobStatus.PENDING;
        }
    }

    if (shouldInitStatus(this.data)) {
        this.data.status = jobStatus.PENDING;
    }

    if (shouldInitFallbackStatus(this.data)) {
        this.data.fallback_status = jobStatus.PENDING;
    }
};

function shouldInitStatus(jobOrQuery) {
    return !jobOrQuery.status;
}

function shouldInitQueryFallbackStatus(query) {
    return (query.onsuccess || query.onerror) && !query.fallback_status;
}

function shouldInitFallbackStatus(job) {
    return (job.query.onsuccess || job.query.onerror) && !job.fallback_status;
}

JobFallback.prototype.getNextQueryFromQueries = function () {
    for (var i = 0; i < this.queries.length; i++) {
        if (this.queries[i].hasNextQuery(this.data)) {
            return this.queries[i].getNextQuery(this.data);
        }
    }
};

JobFallback.prototype.hasNextQueryFromQueries = function () {
    return !!this.getNextQueryFromQueries();
};

JobFallback.prototype.getNextQueryFromFallback = function () {
    if (this.fallback && this.fallback.hasNextQuery(this.data)) {

        return this.fallback.getNextQuery(this.data);
    }
};

JobFallback.prototype.getNextQuery = function () {
    var query = this.getNextQueryFromQueries();

    if (!query) {
        query = this.getNextQueryFromFallback();
    }

    return query;
};

JobFallback.prototype.setQuery = function (query) {
    if (!JobFallback.is(query)) {
        throw new Error('You must indicate a valid SQL');
    }

    JobFallback.super_.prototype.setQuery.call(this, query);
};

JobFallback.prototype.setStatus = function (status, errorMesssage) {
    var now = new Date().toISOString();

    var hasChanged = this.setQueryStatus(status, this.data, errorMesssage);
    hasChanged = this.setJobStatus(status, this.data, hasChanged, errorMesssage);
    hasChanged = this.setFallbackStatus(status, this.data, hasChanged);

    if (!hasChanged.isValid) {
        throw new Error('Cannot set status to ' + status);
    }

    this.data.updated_at = now;
};

JobFallback.prototype.setQueryStatus = function (status, job, errorMesssage) {
    return this.queries.reduce(function (hasChanged, query) {
        var result = query.setStatus(status, this.data, hasChanged, errorMesssage);
        return result.isValid ? result : hasChanged;
    }.bind(this), { isValid: false, appliedToFallback: false });
};

JobFallback.prototype.setJobStatus = function (status, job, hasChanged, errorMesssage) {
    var result = {
        isValid: false,
        appliedToFallback: false
    };

    status = this.shiftStatus(status, hasChanged);

    result.isValid = this.isValidTransition(job.status, status);
    if (result.isValid) {
        job.status = status;
        if (status === jobStatus.FAILED && errorMesssage && !hasChanged.appliedToFallback) {
            job.failed_reason = errorMesssage;
        }
    }

    return result.isValid ? result : hasChanged;
};

JobFallback.prototype.setFallbackStatus = function (status, job, hasChanged) {
    var result = hasChanged;

    if (this.fallback && !this.hasNextQueryFromQueries()) {
        result = this.fallback.setStatus(status, job, hasChanged);
    }

    return result.isValid ? result : hasChanged;
};

JobFallback.prototype.shiftStatus = function (status, hasChanged) {
    // jshint maxcomplexity: 7
    if (hasChanged.appliedToFallback) {
        if (!this.hasNextQueryFromQueries() && (status === jobStatus.DONE || status === jobStatus.FAILED)) {
            status = this.getLastFinishedStatus();
        } else if (status === jobStatus.DONE || status === jobStatus.FAILED){
            status = jobStatus.PENDING;
        }
    } else if (this.hasNextQueryFromQueries() && status !== jobStatus.RUNNING) {
        status = jobStatus.PENDING;
    }

    return status;
};

JobFallback.prototype.getLastFinishedStatus = function () {
    return this.queries.reduce(function (lastFinished, query) {
        var status = query.getStatus(this.data);
        return this.isFinalStatus(status) ? status : lastFinished;
    }.bind(this), jobStatus.DONE);
};

JobFallback.prototype.log = function(logger) {
    if (!isFinished(this)) {
        return;
    }

    var queries = this.data.query.query;

    for (var i = 0; i < queries.length; i++) {
        var query = queries[i];

        if (!query.id) {
            continue;
        }

        var node = parseQueryId(query.id);
        var output = {
            username: this.data.user,
            job: this.data.job_id,
            analysis: node.analysis,
            node: node.id,
            type: node.type,
            elapsedTime: calculateElpasedTime(query.started_at, query.ended_at)
        };

        logger.info(output);
    }

};

function isFinished (job) {
    return jobUtils.isFinalStatus(job.data.status) &&
        (!job.data.fallback_status || jobUtils.isFinalStatus(job.data.fallback_status));
}

function parseQueryId (queryId) {
    var data = queryId.split(':');

    return {
        analysis: data[0],
        id: data[1],
        type: data[2]
    };
}

function calculateElpasedTime (started_at, ended_at) {
    if (!started_at || !ended_at) {
        return;
    }

    var start = new Date(started_at);
    var end = new Date(ended_at);
    var elapsedTimeMilliseconds = end.getTime() - start.getTime();

    return elapsedTimeMilliseconds;
}
<commit_msg>Return on boolean on log<commit_after>'use strict';

var util = require('util');
var JobBase = require('./job_base');
var jobStatus = require('../job_status');
var QueryFallback = require('./query/query_fallback');
var MainFallback = require('./query/main_fallback');
var QueryFactory = require('./query/query_factory');

var JobUtils = require('./job_state_machine');
var jobUtils = new JobUtils();

function JobFallback(jobDefinition) {
    JobBase.call(this, jobDefinition);

    this.init();

    this.queries = [];
    for (var i = 0; i < this.data.query.query.length; i++) {
        this.queries[i] = QueryFactory.create(this.data, i);
    }

    if (MainFallback.is(this.data)) {
        this.fallback = new MainFallback();
    }
}
util.inherits(JobFallback, JobBase);

module.exports = JobFallback;

// 1. from user: {
//     query: {
//         query: [{
//             query: 'select ...',
//             onsuccess: 'select ..'
//         }],
//         onerror: 'select ...'
//     }
// }
//
// 2. from redis: {
//     status: 'pending',
//     fallback_status: 'pending'
//     query: {
//         query: [{
//             query: 'select ...',
//             onsuccess: 'select ..'
//             status: 'pending',
//             fallback_status: 'pending',
//         }],
//         onerror: 'select ...'
//     }
// }

JobFallback.is = function (query) {
    if (!query.query) {
        return false;
    }

    if (!Array.isArray(query.query)) {
        return false;
    }

    for (var i = 0; i < query.query.length; i++) {
        if (!QueryFallback.is(query.query[i])) {
            return false;
        }
    }

    return true;
};

JobFallback.prototype.init = function () {
    for (var i = 0; i < this.data.query.query.length; i++) {
        if (shouldInitStatus(this.data.query.query[i])){
            this.data.query.query[i].status = jobStatus.PENDING;
        }
        if (shouldInitQueryFallbackStatus(this.data.query.query[i])) {
            this.data.query.query[i].fallback_status = jobStatus.PENDING;
        }
    }

    if (shouldInitStatus(this.data)) {
        this.data.status = jobStatus.PENDING;
    }

    if (shouldInitFallbackStatus(this.data)) {
        this.data.fallback_status = jobStatus.PENDING;
    }
};

function shouldInitStatus(jobOrQuery) {
    return !jobOrQuery.status;
}

function shouldInitQueryFallbackStatus(query) {
    return (query.onsuccess || query.onerror) && !query.fallback_status;
}

function shouldInitFallbackStatus(job) {
    return (job.query.onsuccess || job.query.onerror) && !job.fallback_status;
}

JobFallback.prototype.getNextQueryFromQueries = function () {
    for (var i = 0; i < this.queries.length; i++) {
        if (this.queries[i].hasNextQuery(this.data)) {
            return this.queries[i].getNextQuery(this.data);
        }
    }
};

JobFallback.prototype.hasNextQueryFromQueries = function () {
    return !!this.getNextQueryFromQueries();
};

JobFallback.prototype.getNextQueryFromFallback = function () {
    if (this.fallback && this.fallback.hasNextQuery(this.data)) {

        return this.fallback.getNextQuery(this.data);
    }
};

JobFallback.prototype.getNextQuery = function () {
    var query = this.getNextQueryFromQueries();

    if (!query) {
        query = this.getNextQueryFromFallback();
    }

    return query;
};

JobFallback.prototype.setQuery = function (query) {
    if (!JobFallback.is(query)) {
        throw new Error('You must indicate a valid SQL');
    }

    JobFallback.super_.prototype.setQuery.call(this, query);
};

JobFallback.prototype.setStatus = function (status, errorMesssage) {
    var now = new Date().toISOString();

    var hasChanged = this.setQueryStatus(status, this.data, errorMesssage);
    hasChanged = this.setJobStatus(status, this.data, hasChanged, errorMesssage);
    hasChanged = this.setFallbackStatus(status, this.data, hasChanged);

    if (!hasChanged.isValid) {
        throw new Error('Cannot set status to ' + status);
    }

    this.data.updated_at = now;
};

JobFallback.prototype.setQueryStatus = function (status, job, errorMesssage) {
    return this.queries.reduce(function (hasChanged, query) {
        var result = query.setStatus(status, this.data, hasChanged, errorMesssage);
        return result.isValid ? result : hasChanged;
    }.bind(this), { isValid: false, appliedToFallback: false });
};

JobFallback.prototype.setJobStatus = function (status, job, hasChanged, errorMesssage) {
    var result = {
        isValid: false,
        appliedToFallback: false
    };

    status = this.shiftStatus(status, hasChanged);

    result.isValid = this.isValidTransition(job.status, status);
    if (result.isValid) {
        job.status = status;
        if (status === jobStatus.FAILED && errorMesssage && !hasChanged.appliedToFallback) {
            job.failed_reason = errorMesssage;
        }
    }

    return result.isValid ? result : hasChanged;
};

JobFallback.prototype.setFallbackStatus = function (status, job, hasChanged) {
    var result = hasChanged;

    if (this.fallback && !this.hasNextQueryFromQueries()) {
        result = this.fallback.setStatus(status, job, hasChanged);
    }

    return result.isValid ? result : hasChanged;
};

JobFallback.prototype.shiftStatus = function (status, hasChanged) {
    // jshint maxcomplexity: 7
    if (hasChanged.appliedToFallback) {
        if (!this.hasNextQueryFromQueries() && (status === jobStatus.DONE || status === jobStatus.FAILED)) {
            status = this.getLastFinishedStatus();
        } else if (status === jobStatus.DONE || status === jobStatus.FAILED){
            status = jobStatus.PENDING;
        }
    } else if (this.hasNextQueryFromQueries() && status !== jobStatus.RUNNING) {
        status = jobStatus.PENDING;
    }

    return status;
};

JobFallback.prototype.getLastFinishedStatus = function () {
    return this.queries.reduce(function (lastFinished, query) {
        var status = query.getStatus(this.data);
        return this.isFinalStatus(status) ? status : lastFinished;
    }.bind(this), jobStatus.DONE);
};

JobFallback.prototype.log = function(logger) {
    if (!isFinished(this)) {
        return false;
    }

    var queries = this.data.query.query;

    for (var i = 0; i < queries.length; i++) {
        var query = queries[i];

        if (!query.id) {
            continue;
        }

        var node = parseQueryId(query.id);
        var output = {
            username: this.data.user,
            job: this.data.job_id,
            analysis: node.analysis,
            node: node.id,
            type: node.type,
            elapsedTime: calculateElpasedTime(query.started_at, query.ended_at)
        };

        logger.info(output);
    }

    return true;
};

function isFinished (job) {
    return jobUtils.isFinalStatus(job.data.status) &&
        (!job.data.fallback_status || jobUtils.isFinalStatus(job.data.fallback_status));
}

function parseQueryId (queryId) {
    var data = queryId.split(':');

    return {
        analysis: data[0],
        id: data[1],
        type: data[2]
    };
}

function calculateElpasedTime (started_at, ended_at) {
    if (!started_at || !ended_at) {
        return;
    }

    var start = new Date(started_at);
    var end = new Date(ended_at);
    var elapsedTimeMilliseconds = end.getTime() - start.getTime();

    return elapsedTimeMilliseconds;
}
<|endoftext|>


<commit_before><commit_msg>delete unnecessary codes<commit_after><|endoftext|>


<commit_before><commit_msg>Fix _isVisible for attributes<commit_after><|endoftext|>


<commit_before>import axios from 'axios';
export const FETCH_POSTS = 'fetch_posts';
export const CREATE_POST = 'create_post'

const ROOT_URL = 'http://reduxblog.herokuapp.com/api';
const API_KEY ='?key=BOA123';

export function fetchPosts() {
	//pass in request url
		const request = axios.get(`${ROOT_URL}/posts${API_KEY}`);
	return {
		type: FETCH_POSTS,
		payload: request
	};
}

export function createPost(values, callback) {
	const request = axios.post(`${ROOT_URL}/posts${API_KEY}`, values)
	.then(() => callback());

	return {
		type: CREATE_POST,
		payload: request
	};
}<commit_msg>added individual Post action<commit_after>import axios from 'axios';
export const FETCH_POSTS = 'fetch_posts';
export const FETCH_POST = 'fetch_post';
export const CREATE_POST = 'create_post';

const ROOT_URL = 'http://reduxblog.herokuapp.com/api';
const API_KEY ='?key=BOA123';

export function fetchPosts() {
	//pass in request url
		const request = axios.get(`${ROOT_URL}/posts${API_KEY}`);
	return {
		type: FETCH_POSTS,
		payload: request
	};
}

export function createPost(values, callback) {
	const request = axios.post(`${ROOT_URL}/posts${API_KEY}`, values)
	.then(() => callback());

	return {
		type: CREATE_POST,
		payload: request
	};
}

export function fetchPost(id) {
	const request = axios.get(`${ROOT_URL}/posts/${id}${API_KEY}`);

	return {
		type: FETCH_POST,
		payload: request
	};
}<|endoftext|>


<commit_before>Ext.define('devilry_subjectadmin.controller.AllWhereIsAdmin', {
    extend: 'Ext.app.Controller',

    views: [
        'allwhereisadmin.AllWhereIsAdminPanel'
    ],

    stores: [
        'AllWhereIsAdmin'
    ],

    refs: [{
        ref: 'allWhereIsAdminList',
        selector: 'allwhereisadminlist'
    }],

    init: function() {
        this.control({
            'viewport allwhereisadminpanel allwhereisadminlist': {
                render: this._onRenderAllWhereIsAdminList
            }
        });
    },

    _onRenderAllWhereIsAdminList: function() {
        this.getAllWhereIsAdminStore().load({
            scope: this,
            callback: function(records, op) {
                if(op.success) {
                    this._onLoadSuccess(records);
                } else {
                    // NOTE: Errors are handled in _onProxyError
                }
            }
        });
        var label = interpolate(gettext('All %(subjects_term)s'), {
            subjects_term: gettext('subjects')
        }, true);
        this.application.breadcrumbs.set([], label);
    },

    _onLoadSuccess: function(records) {
        this.getAllWhereIsAdminList().update({
            loadingtext: null,
            subjects: records
        });
    },
});
<commit_msg>devilry_subjectadmin...AllWhereIsAdmin: Removed trailing comma.<commit_after>Ext.define('devilry_subjectadmin.controller.AllWhereIsAdmin', {
    extend: 'Ext.app.Controller',

    views: [
        'allwhereisadmin.AllWhereIsAdminPanel'
    ],

    stores: [
        'AllWhereIsAdmin'
    ],

    refs: [{
        ref: 'allWhereIsAdminList',
        selector: 'allwhereisadminlist'
    }],

    init: function() {
        this.control({
            'viewport allwhereisadminpanel allwhereisadminlist': {
                render: this._onRenderAllWhereIsAdminList
            }
        });
    },

    _onRenderAllWhereIsAdminList: function() {
        this.getAllWhereIsAdminStore().load({
            scope: this,
            callback: function(records, op) {
                if(op.success) {
                    this._onLoadSuccess(records);
                } else {
                    // NOTE: Errors are handled in _onProxyError
                }
            }
        });
        var label = interpolate(gettext('All %(subjects_term)s'), {
            subjects_term: gettext('subjects')
        }, true);
        this.application.breadcrumbs.set([], label);
    },

    _onLoadSuccess: function(records) {
        this.getAllWhereIsAdminList().update({
            loadingtext: null,
            subjects: records
        });
    }
});
<|endoftext|>


<commit_before>Ext.define('devilry_subjectadmin.store.AbstractRelatedUsers', {
    extend: 'Ext.data.Store',

    loadInPeriod: function(periodId, loadConfig) {
        this.setPeriod(periodId);
        this.load(loadConfig);
    },

    setPeriod: function(periodId) {
        this.proxy.url = Ext.String.format(this.proxy.urlpatt, periodId);
    }
});
<commit_msg>devilry_subjectadmin...AbstractRelatedUsers: Added loadWithAutomaticErrorHandling.<commit_after>Ext.define('devilry_subjectadmin.store.AbstractRelatedUsers', {
    extend: 'Ext.data.Store',

    requires: [
        'devilry_extjsextras.DjangoRestframeworkProxyErrorHandler',
        'devilry_extjsextras.HtmlErrorDialog'
    ],

    loadInPeriod: function(periodId, loadConfig) {
        this.setPeriod(periodId);
        this.load(loadConfig);
    },

    setPeriod: function(periodId) {
        this.proxy.url = Ext.String.format(this.proxy.urlpatt, periodId);
    },

    /**
     * @param {Function} [config.success]
     *     Callback invoked in ``config.scope``
     *     when the store loads successfully. Parameters are ``records`` and
     *     ``operation``.
     * @param {Boolean} [config.scope]
     *     Scope to invoke ``config.success`` in.
     * @param {String} [config.errortitle] The title of the error message shown on load error.
     */
    loadWithAutomaticErrorHandling: function(config) {
        this.load({
            scope: this,
            callback: function(records, operation) {
                if(operation.success) {
                    Ext.callback(config.success, config.scope, [records, operation]);
                } else {
                    this._onLoadFailure(operation, config.errortitle);
                }
            }
        });
    },
    _onLoadFailure: function(operation, errortitle) {
        var error = Ext.create('devilry_extjsextras.DjangoRestframeworkProxyErrorHandler', operation);
        error.addErrors(null, operation);
        var errormessage = error.asHtmlList();
        Ext.widget('htmlerrordialog', {
            title: errortitle,
            bodyHtml: errormessage
        }).show();
    }
});
<|endoftext|>


<commit_before>(function($) {
  'use strict';

  //////////////////////////////////////////////////////
  // Swipe Gestures for ChocolateChip-UI.
  // Includes mouse gestures for desktop compatibility.
  //////////////////////////////////////////////////////
  var touch = {};
  var touchTimeout;
  var swipeTimeout;
  var tapTimeout;
  var longTapDelay = 750;
  var singleTapDelay = 150;
  var longTapTimeout;

  function parentIfText(node) {
    return 'tagName' in node ? node : node.parentNode;
  }

  function swipeDirection(x1, x2, y1, y2) {
    return Math.abs(x1 - x2) >=
    Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'left' : 'right') : (y1 - y2 > 0 ? 'up' : 'down');
  }

  function longTap() {
    longTapTimeout = null;
    if (touch.last) {
      try {
        if (touch && touch.el) {
          touch.el.trigger('longtap');
          touch = {};
        }
      } catch(err) { }
    }
  }

  function cancelLongTap() {
    if (longTapTimeout) clearTimeout(longTapTimeout);
    longTapTimeout = null;
  }

  function cancelAll() {
    if (touchTimeout) clearTimeout(touchTimeout);
    if (tapTimeout) clearTimeout(tapTimeout);
    if (swipeTimeout) clearTimeout(swipeTimeout);
    if (longTapTimeout) clearTimeout(longTapTimeout);
    touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null;
    touch = {};
  }

  $(function(){
    var now;
    var delta;
    var body = $(document.body);
    var twoTouches = false;
    body.on($.eventStart, function(e) {
      now = Date.now();
      delta = now - (touch.last || now);
      if (e.originalEvent) e = e.originalEvent;

      // Handle MSPointer Events:
      if (window.navigator.msPointerEnabled  || window.navigator.pointerEnabled) {
        if (window && window.jQuery && $ === window.jQuery) {
          if (e.originalEvent && !e.originalEvent.isPrimary) return;
        } else {
          if (!e.isPrimary) return;
        }
        e = e.originalEvent ? e.originalEvent : e;
        body.on('MSHoldVisual', function (e) {
          e.preventDefault();
        });
        touch.el = $(parentIfText(e.target));
        touchTimeout && clearTimeout(touchTimeout);
        touch.x1 = e.pageX;
        touch.y1 = e.pageY;
        twoTouches = false;
      } else {
        if ($.eventStart === 'mousedown') {
          touch.el = $(parentIfText(e.target));
          touchTimeout && clearTimeout(touchTimeout);
          touch.x1 = e.pageX;
          touch.y1 = e.pageY;
          twoTouches = false;
        } else {
          // User to detect two or more finger gestures:
          if (e.touches.length === 1) {
            touch.el = $(parentIfText(e.touches[0].target));
            touchTimeout && clearTimeout(touchTimeout);
            touch.x1 = e.touches[0].pageX;
            touch.y1 = e.touches[0].pageY;
            if (e.targetTouches.length === 2) {
              twoTouches = true;
            } else {
              twoTouches = false;
            }
          }
        }
      }
      if (delta > 0 && delta <= 250) {
        touch.isDoubleTap = true;
      }
      touch.last = now;
      longTapTimeout = setTimeout(longTap, longTapDelay);
    });
    body.on($.eventMove, function(e) {
      if (e.originalEvent) e = e.originalEvent;
      if (window.navigator.msPointerEnabled) {
        if (window && window.jQuery && $ === window.jQuery) {
          if (e.originalEvent && !e.originalEvent.isPrimary) return;
        } else {
          if (!e.isPrimary) return;
        }
        e = e.originalEvent ? e.originalEvent : e;
        cancelLongTap();
        touch.x2 = e.pageX;
        touch.y2 = e.pageY;
      } else {
        cancelLongTap();
        if ($.eventMove === 'mousemove') {
          touch.x2 = e.pageX;
          touch.y2 = e.pageY;
        } else {
          // One finger gesture:
          if (e.touches.length === 1) {
            touch.x2 = e.touches[0].pageX;
            touch.y2 = e.touches[0].pageY;
          }
        }
      }
    });
    body.on($.eventEnd, function(e) {
      if (window.navigator.msPointerEnabled) {
        if (window && window.jQuery && $ === window.jQuery) {
          if (e.originalEvent && !e.originalEvent.isPrimary) return;
        } else {
          if (!e.isPrimary) return;
        }
      }
      cancelLongTap();
      if (!!touch.el) {
        // Swipe detection:
        if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > $.gestureLength) ||
        (touch.y2 && Math.abs(touch.y1 - touch.y2) > $.gestureLength))  {
          swipeTimeout = setTimeout(function() {
            if (touch && touch.el) {
              touch.el.trigger('swipe');
              touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
              touch = {};
            }
          }, 0);

        // Normal tap:
        } else if ('last' in touch) {

          // Delay by one tick so we can cancel the 'tap' event if 'scroll' fires:
          tapTimeout = setTimeout(function() {

            // Trigger universal 'tap' with the option to cancelTouch():
            if (touch && touch.el) {
              touch.el.trigger('tap');
            }

            // Trigger double tap immediately:
            if (touch && touch.isDoubleTap) {
              if (touch && touch.el) {
                touch.el.trigger('doubletap');
                touch = {};
              }
            } else {
              // Trigger single tap after singleTapDelay:
              touchTimeout = setTimeout(function(){
                touchTimeout = null;
                if (touch && touch.el) {
                  touch.el.trigger('singletap');
                  touch = {};
                  return false;
                }
              }, singleTapDelay);
            }

          }, 0);
        }
      } else { return; }
    });
    body.on('touchcancel', cancelAll);

  });

  ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown', 'doubletap', 'tap', 'singletap', 'longtap'].forEach(function(method){
    // Add gesture events to ChocolateChipJS:
    $.fn.extend({
      method : function(callback){
        return this.on(method, callback);
      }
    });
  });
})(window.jQuery);<commit_msg>Fix #36 - Gestures for Android Chrome browser.<commit_after>(function($) {
  'use strict';

  //////////////////////////////////////////////////////
  // Swipe Gestures for ChocolateChip-UI.
  // Includes mouse gestures for desktop compatibility.
  //////////////////////////////////////////////////////
  var touch = {};
  var touchTimeout;
  var swipeTimeout;
  var tapTimeout;
  var longTapDelay = 750;
  var singleTapDelay = 150;
  var longTapTimeout;

  function parentIfText(node) {
    return 'tagName' in node ? node : node.parentNode;
  }

  function swipeDirection(x1, x2, y1, y2) {
    return Math.abs(x1 - x2) >=
    Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'left' : 'right') : (y1 - y2 > 0 ? 'up' : 'down');
  }

  function longTap() {
    longTapTimeout = null;
    if (touch.last) {
      try {
        if (touch && touch.el) {
          touch.el.trigger('longtap');
          touch = {};
        }
      } catch(err) { }
    }
  }

  function cancelLongTap() {
    if (longTapTimeout) clearTimeout(longTapTimeout);
    longTapTimeout = null;
  }

  function cancelAll() {
    if (touchTimeout) clearTimeout(touchTimeout);
    if (tapTimeout) clearTimeout(tapTimeout);
    if (swipeTimeout) clearTimeout(swipeTimeout);
    if (longTapTimeout) clearTimeout(longTapTimeout);
    touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null;
    touch = {};
  }

  $(function(){
    var now;
    var delta;
    var body = $(document.body);
    var twoTouches = false;
    body.on($.eventStart, function(e) {
      now = Date.now();
      delta = now - (touch.last || now);
      if (e.originalEvent) e = e.originalEvent;

      // Handle MSPointer Events:
      if (window.navigator.msPointerEnabled  || window.navigator.pointerEnabled) {
        if (window && window.jQuery && $ === window.jQuery) {
          if (e.originalEvent && !e.originalEvent.isPrimary) return;
        } else {
          if (!e.isPrimary) return;
        }
        e = e.originalEvent ? e.originalEvent : e;
        body.on('MSHoldVisual', function (e) {
          e.preventDefault();
        });
        touch.el = $(parentIfText(e.target));
        touchTimeout && clearTimeout(touchTimeout);
        touch.x1 = e.pageX;
        touch.y1 = e.pageY;
        twoTouches = false;
      } else {
        if ($.eventStart === 'mousedown') {
          touch.el = $(parentIfText(e.target));
          touchTimeout && clearTimeout(touchTimeout);
          touch.x1 = e.pageX;
          touch.y1 = e.pageY;
          twoTouches = false;
        } else {
          // User to detect two or more finger gestures:
          if (e.touches.length === 1) {
            touch.el = $(parentIfText(e.touches[0].target));
            touchTimeout && clearTimeout(touchTimeout);
            touch.x1 = e.touches[0].pageX;
            touch.y1 = e.touches[0].pageY;
            if (e.targetTouches.length === 2) {
              twoTouches = true;
            } else {
              twoTouches = false;
            }
          }
        }
      }
      if (delta > 0 && delta <= 250) {
        touch.isDoubleTap = true;
      }
      touch.last = now;
      longTapTimeout = setTimeout(longTap, longTapDelay);
    });
    body.on($.eventMove, function(e) {
      if (e.originalEvent) e = e.originalEvent;
      if (window.navigator.msPointerEnabled) {
        if (window && window.jQuery && $ === window.jQuery) {
          if (e.originalEvent && !e.originalEvent.isPrimary) return;
        } else {
          if (!e.isPrimary) return;
        }
        e = e.originalEvent ? e.originalEvent : e;
        cancelLongTap();
        touch.x2 = e.pageX;
        touch.y2 = e.pageY;
      } else {
        cancelLongTap();
        if ($.eventMove === 'mousemove') {
          touch.x2 = e.pageX;
          touch.y2 = e.pageY;
        } else {
          // One finger gesture:
          if (e.touches.length === 1) {
            touch.x2 = e.touches[0].pageX;
            touch.y2 = e.touches[0].pageY;
          }
        }
      }

      if ($.isAndroid) {
        $.gestureLength = 10;

        if (!!touch.el) {
          // Swipe detection:
          if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > $.gestureLength) ||
        (touch.y2 && Math.abs(touch.y1 - touch.y2) > $.gestureLength))  {
            swipeTimeout = setTimeout(function() {
              if (touch && touch.el) {
                touch.el.trigger('swipe');
                touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
                touch = {};
                e.preventDefault();
              }
            }, 0);

          // Normal tap:
          } else if ('last' in touch) {

            // Delay by one tick so we can cancel the 'tap' event if 'scroll' fires:
            tapTimeout = setTimeout(function() {

            // Trigger universal 'tap' with the option to cancelTouch():
            if (touch && touch.el) {
              touch.el.trigger('tap');
            }

            // Trigger double tap immediately:
            if (touch && touch.isDoubleTap) {
              if (touch && touch.el) {
              touch.el.trigger('doubletap');
              touch = {};
              }
            } else {
              // Trigger single tap after singleTapDelay:
              touchTimeout = setTimeout(function(){
              touchTimeout = null;
              if (touch && touch.el) {
                touch.el.trigger('singletap');
                touch = {};
                return false;
              }
              }, singleTapDelay);
            }

            }, 0);
          }
        } else { return; }
      }

    });
    body.on($.eventEnd, function(e) {
      if (window.navigator.msPointerEnabled) {
        if (window && window.jQuery && $ === window.jQuery) {
          if (e.originalEvent && !e.originalEvent.isPrimary) return;
        } else {
          if (!e.isPrimary) return;
        }
      }
      cancelLongTap();
      if (!!touch.el) {
        // Swipe detection:
        if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > $.gestureLength) ||
        (touch.y2 && Math.abs(touch.y1 - touch.y2) > $.gestureLength))  {
          swipeTimeout = setTimeout(function() {
            if (touch && touch.el) {
              touch.el.trigger('swipe');
              touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
              touch = {};
            }
          }, 0);

        // Normal tap:
        } else if ('last' in touch) {

          // Delay by one tick so we can cancel the 'tap' event if 'scroll' fires:
          tapTimeout = setTimeout(function() {

            // Trigger universal 'tap' with the option to cancelTouch():
            if (touch && touch.el) {
              touch.el.trigger('tap');
            }

            // Trigger double tap immediately:
            if (touch && touch.isDoubleTap) {
              if (touch && touch.el) {
                touch.el.trigger('doubletap');
                touch = {};
              }
            } else {
              // Trigger single tap after singleTapDelay:
              touchTimeout = setTimeout(function(){
                touchTimeout = null;
                if (touch && touch.el) {
                  touch.el.trigger('singletap');
                  touch = {};
                  return false;
                }
              }, singleTapDelay);
            }

          }, 0);
        }
      } else { return; }
    });
    body.on('touchcancel', cancelAll);

  });

  ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown', 'doubletap', 'tap', 'singletap', 'longtap'].forEach(function(method){
    // Add gesture events to ChocolateChipJS:
    $.fn.extend({
      method : function(callback){
        return this.on(method, callback);
      }
    });
  });
})(window.jQuery);<|endoftext|>


<commit_before>/**
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
*
* @class SAT
*/

// TODO: true circles and curves

var SAT = {};

module.exports = SAT;

var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');

(function() {

    /**
     * Detect collision between two bodies using the Separating Axis Theorem.
     * @method collides
     * @param {body} bodyA
     * @param {body} bodyB
     * @param {collision} previousCollision
     * @return {collision} collision
     */
    SAT.collides = function(bodyA, bodyB, previousCollision) {
        var overlapAB,
            overlapBA,
            minOverlap,
            collision,
            canReusePrevCol = false;

        if (previousCollision) {
            // estimate total motion
            var parentA = bodyA.parent,
                parentB = bodyB.parent,
                motion = parentA.speed * parentA.speed + parentA.angularSpeed * parentA.angularSpeed
                       + parentB.speed * parentB.speed + parentB.angularSpeed * parentB.angularSpeed;

            // we may be able to (partially) reuse collision result
            // but only safe if collision was resting
            canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2;

            // reuse collision object
            collision = previousCollision;
        } else {
            collision = { collided: false, bodyA: bodyA, bodyB: bodyB };
        }

        if (previousCollision && canReusePrevCol) {
            // if we can reuse the collision result
            // we only need to test the previously found axis
            var axisBodyA = collision.axisBody,
                axisBodyB = axisBodyA === bodyA ? bodyB : bodyA,
                axes = [axisBodyA.axes[previousCollision.axisNumber]];

            minOverlap = SAT._overlapAxes(axisBodyA.vertices, axisBodyB.vertices, axes);
            collision.reused = true;

            if (minOverlap.overlap <= 0) {
                collision.collided = false;
                return collision;
            }
        } else {
            // if we can't reuse a result, perform a full SAT test

            overlapAB = SAT._overlapAxes(bodyA.vertices, bodyB.vertices, bodyA.axes);

            if (overlapAB.overlap <= 0) {
                collision.collided = false;
                return collision;
            }

            overlapBA = SAT._overlapAxes(bodyB.vertices, bodyA.vertices, bodyB.axes);

            if (overlapBA.overlap <= 0) {
                collision.collided = false;
                return collision;
            }

            if (overlapAB.overlap < overlapBA.overlap) {
                minOverlap = overlapAB;
                collision.axisBody = bodyA;
            } else {
                minOverlap = overlapBA;
                collision.axisBody = bodyB;
            }

            // important for reuse later
            collision.axisNumber = minOverlap.axisNumber;
        }

        collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
        collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
        collision.collided = true;
        collision.depth = minOverlap.overlap;
        collision.parentA = collision.bodyA.parent;
        collision.parentB = collision.bodyB.parent;

        bodyA = collision.bodyA;
        bodyB = collision.bodyB;

        // ensure normal is facing away from bodyA
        if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) {
            collision.normal = {
                x: minOverlap.axis.x,
                y: minOverlap.axis.y
            };
        } else {
            collision.normal = {
                x: -minOverlap.axis.x,
                y: -minOverlap.axis.y
            };
        }

        collision.tangent = Vector.perp(collision.normal);

        collision.penetration = collision.penetration || {};
        collision.penetration.x = collision.normal.x * collision.depth;
        collision.penetration.y = collision.normal.y * collision.depth;

        // find support points, there is always either exactly one or two
        var verticesB = SAT._findSupports(bodyA, bodyB, collision.normal, 1),
            supports = [];

        // find the supports from bodyB that are inside bodyA
        if (Vertices.contains(bodyA.vertices, verticesB[0]))
            supports.push(verticesB[0]);

        if (Vertices.contains(bodyA.vertices, verticesB[1]))
            supports.push(verticesB[1]);

        // find the supports from bodyA that are inside bodyB
        if (supports.length < 2) {
            var verticesA = SAT._findSupports(bodyB, bodyA, collision.normal, -1);

            if (Vertices.contains(bodyB.vertices, verticesA[0]))
                supports.push(verticesA[0]);

            if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1]))
                supports.push(verticesA[1]);
        }

        // account for the edge case of overlapping but no vertex containment
        if (supports.length < 1)
            supports = [verticesB[0]];

        collision.supports = supports;

        return collision;
    };

    /**
     * Find the overlap between two sets of vertices.
     * @method _overlapAxes
     * @private
     * @param {} verticesA
     * @param {} verticesB
     * @param {} axes
     * @return result
     */
    SAT._overlapAxes = function(verticesA, verticesB, axes) {
        var projectionA = Vector._temp[0],
            projectionB = Vector._temp[1],
            result = { overlap: Number.MAX_VALUE },
            overlap,
            axis;

        for (var i = 0; i < axes.length; i++) {
            axis = axes[i];

            SAT._projectToAxis(projectionA, verticesA, axis);
            SAT._projectToAxis(projectionB, verticesB, axis);

            overlap = Math.min(projectionA.max - projectionB.min, projectionB.max - projectionA.min);

            if (overlap <= 0) {
                result.overlap = overlap;
                return result;
            }

            if (overlap < result.overlap) {
                result.overlap = overlap;
                result.axis = axis;
                result.axisNumber = i;
            }
        }

        return result;
    };

    /**
     * Projects vertices on an axis and returns an interval.
     * @method _projectToAxis
     * @private
     * @param {} projection
     * @param {} vertices
     * @param {} axis
     */
    SAT._projectToAxis = function(projection, vertices, axis) {
        var min = Vector.dot(vertices[0], axis),
            max = min;

        for (var i = 1; i < vertices.length; i += 1) {
            var dot = Vector.dot(vertices[i], axis);

            if (dot > max) {
                max = dot;
            } else if (dot < min) {
                min = dot;
            }
        }

        projection.min = min;
        projection.max = max;
    };

    /**
     * Finds supporting vertices given two bodies along a given direction using hill-climbing.
     * @method _findSupports
     * @private
     * @param {body} bodyA
     * @param {body} bodyB
     * @param {vector} normal
     * @param {number} direction
     * @return [vector]
     */
    SAT._findSupports = function(bodyA, bodyB, normal, direction) {
        var vertices = bodyB.vertices,
            verticesLength = vertices.length,
            bodyAPositionX = bodyA.position.x,
            bodyAPositionY = bodyA.position.y,
            normalX = normal.x * direction,
            normalY = normal.y * direction,
            nearestDistance = Infinity,
            vertexA,
            vertexB,
            vertexC,
            distance,
            j;

        // find deepest vertex relative to the axis
        for (j = 0; j < verticesLength; j += 1) {
            vertexB = vertices[j];
            distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);

            // convex hill-climbing
            if (distance < nearestDistance) {
                nearestDistance = distance;
                vertexA = vertexB;
            }
        }

        // measure next vertex
        vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];
        nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);

        // compare with previous vertex
        vertexB = vertices[(vertexA.index + 1) % verticesLength];
        if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {
            return [vertexA, vertexB];
        }

        return [vertexA, vertexC];
    };

})();
<commit_msg>optimised SAT._overlapAxes<commit_after>/**
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
*
* @class SAT
*/

// TODO: true circles and curves

var SAT = {};

module.exports = SAT;

var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');

(function() {

    var _overlapAB = {
        overlap: 0,
        axis: null,
        axisNumber: 0
    };

    var _overlapBA = {
        overlap: 0,
        axis: null,
        axisNumber: 0
    };

    /**
     * Detect collision between two bodies using the Separating Axis Theorem.
     * @method collides
     * @param {body} bodyA
     * @param {body} bodyB
     * @param {collision} previousCollision
     * @return {collision} collision
     */
    SAT.collides = function(bodyA, bodyB, previousCollision) {
        var minOverlap,
            collision,
            canReusePrevCol = false;

        if (previousCollision) {
            // estimate total motion
            var parentA = bodyA.parent,
                parentB = bodyB.parent,
                motion = parentA.speed * parentA.speed + parentA.angularSpeed * parentA.angularSpeed
                       + parentB.speed * parentB.speed + parentB.angularSpeed * parentB.angularSpeed;

            // we may be able to (partially) reuse collision result
            // but only safe if collision was resting
            canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2;

            // reuse collision object
            collision = previousCollision;
        } else {
            collision = { collided: false, bodyA: bodyA, bodyB: bodyB };
        }

        if (previousCollision && canReusePrevCol) {
            // if we can reuse the collision result
            // we only need to test the previously found axis
            var axisBodyA = collision.axisBody,
                axisBodyB = axisBodyA === bodyA ? bodyB : bodyA,
                axes = [axisBodyA.axes[previousCollision.axisNumber]];

            SAT._overlapAxes(_overlapAB, axisBodyA.vertices, axisBodyB.vertices, axes);
            collision.reused = true;

            if (_overlapAB.overlap <= 0) {
                collision.collided = false;
                return collision;
            }

            minOverlap = _overlapAB;
        } else {
            // if we can't reuse a result, perform a full SAT test

            SAT._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes);

            if (_overlapAB.overlap <= 0) {
                collision.collided = false;
                return collision;
            }

            SAT._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes);

            if (_overlapBA.overlap <= 0) {
                collision.collided = false;
                return collision;
            }

            if (_overlapAB.overlap < _overlapBA.overlap) {
                minOverlap = _overlapAB;
                collision.axisBody = bodyA;
            } else {
                minOverlap = _overlapBA;
                collision.axisBody = bodyB;
            }

            // important for reuse later
            collision.axisNumber = minOverlap.axisNumber;
        }

        collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
        collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
        collision.collided = true;
        collision.depth = minOverlap.overlap;
        collision.parentA = collision.bodyA.parent;
        collision.parentB = collision.bodyB.parent;

        bodyA = collision.bodyA;
        bodyB = collision.bodyB;

        // ensure normal is facing away from bodyA
        if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) {
            collision.normal = {
                x: minOverlap.axis.x,
                y: minOverlap.axis.y
            };
        } else {
            collision.normal = {
                x: -minOverlap.axis.x,
                y: -minOverlap.axis.y
            };
        }

        collision.tangent = Vector.perp(collision.normal);

        collision.penetration = collision.penetration || {};
        collision.penetration.x = collision.normal.x * collision.depth;
        collision.penetration.y = collision.normal.y * collision.depth;

        // find support points, there is always either exactly one or two
        var verticesB = SAT._findSupports(bodyA, bodyB, collision.normal, 1),
            supports = [];

        // find the supports from bodyB that are inside bodyA
        if (Vertices.contains(bodyA.vertices, verticesB[0]))
            supports.push(verticesB[0]);

        if (Vertices.contains(bodyA.vertices, verticesB[1]))
            supports.push(verticesB[1]);

        // find the supports from bodyA that are inside bodyB
        if (supports.length < 2) {
            var verticesA = SAT._findSupports(bodyB, bodyA, collision.normal, -1);

            if (Vertices.contains(bodyB.vertices, verticesA[0]))
                supports.push(verticesA[0]);

            if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1]))
                supports.push(verticesA[1]);
        }

        // account for the edge case of overlapping but no vertex containment
        if (supports.length < 1)
            supports = [verticesB[0]];

        collision.supports = supports;

        return collision;
    };

    /**
     * Find the overlap between two sets of vertices.
     * @method _overlapAxes
     * @private
     * @param {object} result
     * @param {vertices} verticesA
     * @param {vertices} verticesB
     * @param {axes} axes
     */
    SAT._overlapAxes = function(result, verticesA, verticesB, axes) {
        var verticesALength = verticesA.length,
            verticesBLength = verticesB.length,
            axesLength = axes.length,
            dot,
            overlap,
            overlapAB,
            overlapBA,
            i,
            j;

        result.overlap = Number.MAX_VALUE;

        for (i = 0; i < axesLength; i++) {
            var axis = axes[i],
                axisX = axis.x,
                axisY = axis.y,
                minA = verticesA[0].x * axisX + verticesA[0].y * axisY,
                minB = verticesB[0].x * axisX + verticesB[0].y * axisY,
                maxA = minA,
                maxB = minB;

            for (j = 1; j < verticesALength; j += 1) {
                dot = verticesA[j].x * axisX + verticesA[j].y * axisY;

                if (dot > maxA) {
                    maxA = dot;
                } else if (dot < minA) {
                    minA = dot;
                }
            }

            for (j = 1; j < verticesBLength; j += 1) {
                dot = verticesB[j].x * axisX + verticesB[j].y * axisY;

                if (dot > maxB) {
                    maxB = dot;
                } else if (dot < minB) {
                    minB = dot;
                }
            }

            overlapAB = maxA - minB;
            overlapBA = maxB - minA;
            overlap = overlapAB < overlapBA ? overlapAB : overlapBA;

            if (overlap <= 0) {
                result.overlap = overlap;
                result.axisNumber = i;
                return;
            }

            if (overlap < result.overlap) {
                result.overlap = overlap;
                result.axis = axis;
                result.axisNumber = i;
            }
        }
    };

    /**
     * Projects vertices on an axis and returns an interval.
     * @method _projectToAxis
     * @private
     * @param {} projection
     * @param {} vertices
     * @param {} axis
     */
    SAT._projectToAxis = function(projection, vertices, axis) {
        var min = Vector.dot(vertices[0], axis),
            max = min;

        for (var i = 1; i < vertices.length; i += 1) {
            var dot = Vector.dot(vertices[i], axis);

            if (dot > max) {
                max = dot;
            } else if (dot < min) {
                min = dot;
            }
        }

        projection.min = min;
        projection.max = max;
    };

    /**
     * Finds supporting vertices given two bodies along a given direction using hill-climbing.
     * @method _findSupports
     * @private
     * @param {body} bodyA
     * @param {body} bodyB
     * @param {vector} normal
     * @param {number} direction
     * @return [vector]
     */
    SAT._findSupports = function(bodyA, bodyB, normal, direction) {
        var vertices = bodyB.vertices,
            verticesLength = vertices.length,
            bodyAPositionX = bodyA.position.x,
            bodyAPositionY = bodyA.position.y,
            normalX = normal.x * direction,
            normalY = normal.y * direction,
            nearestDistance = Number.MAX_VALUE,
            vertexA,
            vertexB,
            vertexC,
            distance,
            j;

        // find deepest vertex relative to the axis
        for (j = 0; j < verticesLength; j += 1) {
            vertexB = vertices[j];
            distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);

            // convex hill-climbing
            if (distance < nearestDistance) {
                nearestDistance = distance;
                vertexA = vertexB;
            }
        }

        // measure next vertex
        vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];
        nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);

        // compare with previous vertex
        vertexB = vertices[(vertexA.index + 1) % verticesLength];
        if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {
            return [vertexA, vertexB];
        }

        return [vertexA, vertexC];
    };

})();
<|endoftext|>


<commit_before>casper.test.begin('Test the project-m-staging', 6, function suite(test) {
    casper.start('https://project-m-staging.herokuapp.com/', function () {
        test.assertTitle('Express');
        test.assertSelectorHasText('h1.form-title', 'Membership Type');  //find the title
    });

    casper.then(function () {

      //test for error
      casper.then(function() {
        this.click('input[name="isEnrolled"][value="No"]');
        this.click('input[name="residentialStatus"][value="I am an Australian citizen."]');
        this.click('input[name="isMemberOfOtherParty"][value="Yes"]');

        test.assertExist('div.validationErrors');
      });

      // test for correct
      casper.then(function() {
        this.click('input[name="isEnrolled"][value="Yes"]');

        test.assertExist('div.info-box');
        test.assertSelectorHasText('h3[data-reactid=".0.0.0.1.1.5.0.0"]', 'You are entitled to a Supporter Membership.'); //呀，这么简单。。。要哭了都，整了一晚上。。
      });

      // //test for jump to second page
      // casper.then(function() {
      //   this.click('button[data-reactid=".0.0.0.1.0"]')
      //   casper.then(function() {
      //     test.assertSelectorHasText('h1.form-title', 'Details');  //find the title
      //   });
      // });
      });

      casper.run(function () {
        test.done();
    })
});
<commit_msg>the testing code clean-up<commit_after><|endoftext|>


<commit_before><commit_msg>Remove unnecessary parameter<commit_after><|endoftext|>


<commit_before>'use strict'

// There's no strict rule about "what is a helper" but generally,
// helpers are about data manipulation.

const cacheTemplates = process.env.CACHE_TEMPLATES // Do not recompile templates on every request. Enable in prod for perf boost
const _ = require('lodash')
const { head, some, trim, get, eq, includes, concat, sortBy, capitalize,
	flatMap, isString, isArray, isObject, difference } = _
const { count: countEmoji } = require('emoji-king')
const pug = require('pug')
const URI = require('urijs')
const entities = require('entities')
const cheerio = require('cheerio')
const gravatarUrl = require('gravatar-url')
const log = require('debug')('sweetroll-fe:helpers')
const markdown = require('remark')()
	.use(require('remark-math'))
	.use(require('remark-html-katex'))
	.use(require('remark-highlight.js'))
	.use(require('remark-html'))

module.exports = {
	insertParams (name, params) {
		// TODO: make this more efficient
		let result = name
		for (const k of Object.keys(params)) {
			result = result.replace(`{${k}}`, params[k])
		}
		return result
	},

	matchingFeeds (feeds, obj) {
		return flatMap(feeds, feed => flatMap(feed.properties.filter, filter => {
			let matches = true
			const params = {}
			const walk = (x, y) => {
				for (const k of Object.keys(x)) {
					if (x[k].length === 1 && isString(x[k][0]) &&
						x[k][0].startsWith('{') && x[k][0].endsWith('}') && isArray(y[k])) {
						const p = trim(x[k][0], '{}')
						params[p] = concat(params[p] || [], y[k])
					} else if (isArray(x[k]) && isArray(y[k])) {
						matches = matches && difference(x[k], y[k]).length === 0
					} else if (isObject(x[k]) && isObject(y[k])) {
						walk(x[k], y[k])
					} else {
						matches = matches && eq(x[k], y[k])
					}
					if (!matches) return
				}
			}
			walk(filter, obj.properties)
			if (matches) {
				const base = new URI(feed.properties.url[0])
				if (Object.keys(params).length === 0) {
					return [{
						name: get(feed, 'properties.name[0]', ''),
						url: base.toString(),
						feedObj: feed,
						params: {}
					}]
				}
				return flatMap(Object.keys(params), k =>
					params[k].map(v => {
						const params = {[k]: v}
						return {
							name: this.insertParams(get(feed, 'properties.name[0]', ''), params),
							url: base.clone().search(params).toString(),
							feedObj: feed,
							params
						}
					}))
			}
		})).filter(isObject)
	},

	onlyHttpUrl (x) {
		if (!x) return 'javascript:void(0)'
		if (x.startsWith('/') || x.startsWith('http://') || x.startsWith('https://') || x.startsWith('//')) return x
		return 'javascript:void(0)'
	},

	isValidRef (url, x) {
		return some(x, v => some(url, u => v && ((v.startsWith && v.startsWith(u)) ||
			(v.value && v.value.startsWith && v.value.startsWith(u)))))
	},

	separateComments (url, comments) {
		const result = { replies: [], likes: [], reposts: [], bookmarks: [], quotations: [], mentions: [] }
		for (const comment of comments) {
			const properties = comment.properties || {}
			if (this.isValidRef(url, properties['in-reply-to'])) {
				const text = trim(get(properties, 'content[0].value', get(properties, 'name[0]', 'xxxxxxxxxx')))
				if (text.length < 16) {
					const emoji = countEmoji(text)
					if (emoji && Object.keys(emoji).length >= 1) {
						for (const e of Object.keys(emoji)) {
							result[e] = result[e] || []
							result[e].push(comment)
						}
						continue
					}
				}
				result.replies.push(comment)
			} else if (this.isValidRef(url, properties['like-of'])) {
				result.likes.push(comment)
			} else if (this.isValidRef(url, properties['repost-of'])) {
				result.reposts.push(comment)
			} else if (this.isValidRef(url, properties['bookmark-of'])) {
				result.bookmarks.push(comment)
			} else if (this.isValidRef(url, properties['quotation-of'])) {
				result.quotations.push(comment)
			} else {
				result.mentions.push(comment)
			}
		}
		return result
	},

	syndicationName (x) {
		if (includes(x, 'twitter.com')) return 'Twitter'
		if (includes(x, 'tumblr.com')) return 'Tumblr'
		if (includes(x, 'facebook.com')) return 'Facebook'
		if (includes(x, 'instagram.com')) return 'Instagram'
		const matches = x.match(/^https?:\/\/([^/?#]+)/)
		return (matches && matches[1]) || x
	},

	showAvatar (author) {
		return get(author, 'properties.photo[0]') ||
			gravatarUrl(
				get(author, 'properties.email[0]', 'test@example.com').replace('mailto:', ''),
				{ size: 256, default: 'identicon' }
			)
	},

	entryName (obj) {
		return get(obj, 'properties.name[0]') || get(obj, 'properties.published[0]', 'Untitled page')
	},

	ratingStars (rating, best) {
		if (rating > best) {
			return [best, 0, 0]
		}
		if (rating - Math.floor(rating) > 0.001) {
			return [Math.floor(rating), 1, best - Math.floor(rating) - 1]
		}
		return [Math.floor(rating), 0, best - Math.floor(rating)]
	},

	renderMarkdown (content) {
		return markdown.processSync(content).contents
	},

	getHtml (content) {
		if (isObject(content)) {
			if (isString(content.html)) {
				return content.html
			}
			if (isString(content.markdown || content.value)) {
				return this.renderMarkdown(content.markdown || content.value)
			}
		}
		if (isString(content)) {
			return this.renderMarkdown(content)
		}
	},

	getContent (properties, { preferSummary, onlySummary }) {
		const content = head(onlySummary ? properties.summary : (
			preferSummary
				? concat(properties.summary || [], properties.content || [], properties.name || [])
				: concat(properties.content || [], properties.summary || [], properties.name || [])
			)
		) || ''
		return this.getHtml(content)
	},

	processContent (properties, opts) {
		const textContent = this.getContent(properties, opts)
		const media = {
			photo: properties.photo || [],
			video: properties.video || [],
			audio: properties.audio || [],
		}
		if (!isString(textContent)) {
			log('non-string content from getContent to processContent')
			return Object.assign({ textContent }, media)
		}
		// NOTE: do not use => functions for cheerio!
		const $ = cheerio.load(textContent)
		// detwitterize emoji
		$('img.Emoji').each(function (i) {
			const img = $(this)
			img.replaceWith(`<span class="emoji">${img.attr('alt')}</span>`)
		})
		//$('img').each(function (i) { const img = $(this) })
		const helpers = this
		for (const mediaType of Object.keys(media)) {
			$(`${mediaType}-here`).each(function (i) {
				const el = $(this)
				let idx = media[mediaType].length
				while (idx--) {
					const obj = media[mediaType][idx]
					if (obj.id === el.attr('id')) {
						el.replaceWith($(pug.render(`include /_media.pug\n+show${capitalize(mediaType)}(media)`,
							{ media: obj, helpers, _, basedir: './views', cacheTemplates })))
						media[mediaType].splice(idx, 1)
					}
				}
			})
		}
		return Object.assign({ textContent: $('body').html() }, media)
	},

	findMentionedLinks (obj) {
		const fromCtxs = concat(
			get(obj, 'properties.in-reply-to', []),
			get(obj, 'properties.like-of', []),
			get(obj, 'properties.repost-of', []),
			get(obj, 'properties.quotation-of', [])
		).map(ctx => isObject(ctx) ? get(ctx, 'properties.url.0') : ctx)
		let fromContent = []
		try {
			const $ = cheerio.load(this.getContent(obj.properties, true, false))
			fromContent = $('a, link').toArray().map(el => el.attribs['href'])
		} catch (err) {
			log('HTML content parse error: %O', err)
		}
		return concat(fromCtxs, fromContent).filter(isString)
	},

	getHtmlLinksByRel (content) {
		const $ = cheerio.load(content)
		return $('link[rel], a[rel]').toArray()
			.filter(el => includes(el.attribs['rel'].split(/\s+/), 'webmention') && isString(el.attribs['href']))
			.map(el => el.attribs['href'])
	},

	isActuallyTheSameDamnThing(name, content) {
		const process = x => entities.decodeHTML(x).replace(/\s+/g, '').replace(/<[^>]+>/g, '')
		const n = process(name)
		const c = process(content)
		return n.length > 2 && c.length > 2 && n.includes(c)
	},

	containerStyle (media) {
		let result = ''
		if (!media) {
			return result
		}
		const color = head(sortBy(media.palette, 'population'))
		const preview = media.tiny_preview
		if (color || preview) {
			result += 'background:'
			if (color) {
				result += color.color
			}
			if (preview) {
				result += ` url('${preview}')`
			}
			result += ';'
		}
		if (media.width && media.height) {
			result += `padding-bottom:${(media.height / media.width * 100).toPrecision(4)}%`
		}
		return result
	},

	galleryRows (entries) {
		const result = []
		let cur = []
		let cur_slots = 0
		for (const entry of entries) {
			cur.push(entry)
			const media = get(entry, 'properties.photo[0]', get(entry, 'properties.video[0]', {}))
			cur_slots += media.width > media.height ? 2 : 1
			if (cur_slots >= 4) {
				result.push(cur)
				cur = []
				cur_slots = 0
			}
		}
		if (cur.length !== 0) {
			result.push(cur)
		}
		return result
	}

}
<commit_msg>Skip nulls when displaying content<commit_after>'use strict'

// There's no strict rule about "what is a helper" but generally,
// helpers are about data manipulation.

const cacheTemplates = process.env.CACHE_TEMPLATES // Do not recompile templates on every request. Enable in prod for perf boost
const _ = require('lodash')
const { head, some, trim, get, eq, includes, concat, sortBy, capitalize,
	flatMap, isString, isArray, isObject, compact, difference } = _
const { count: countEmoji } = require('emoji-king')
const pug = require('pug')
const URI = require('urijs')
const entities = require('entities')
const cheerio = require('cheerio')
const gravatarUrl = require('gravatar-url')
const log = require('debug')('sweetroll-fe:helpers')
const markdown = require('remark')()
	.use(require('remark-math'))
	.use(require('remark-html-katex'))
	.use(require('remark-highlight.js'))
	.use(require('remark-html'))

module.exports = {
	insertParams (name, params) {
		// TODO: make this more efficient
		let result = name
		for (const k of Object.keys(params)) {
			result = result.replace(`{${k}}`, params[k])
		}
		return result
	},

	matchingFeeds (feeds, obj) {
		return flatMap(feeds, feed => flatMap(feed.properties.filter, filter => {
			let matches = true
			const params = {}
			const walk = (x, y) => {
				for (const k of Object.keys(x)) {
					if (x[k].length === 1 && isString(x[k][0]) &&
						x[k][0].startsWith('{') && x[k][0].endsWith('}') && isArray(y[k])) {
						const p = trim(x[k][0], '{}')
						params[p] = concat(params[p] || [], y[k])
					} else if (isArray(x[k]) && isArray(y[k])) {
						matches = matches && difference(x[k], y[k]).length === 0
					} else if (isObject(x[k]) && isObject(y[k])) {
						walk(x[k], y[k])
					} else {
						matches = matches && eq(x[k], y[k])
					}
					if (!matches) return
				}
			}
			walk(filter, obj.properties)
			if (matches) {
				const base = new URI(feed.properties.url[0])
				if (Object.keys(params).length === 0) {
					return [{
						name: get(feed, 'properties.name[0]', ''),
						url: base.toString(),
						feedObj: feed,
						params: {}
					}]
				}
				return flatMap(Object.keys(params), k =>
					params[k].map(v => {
						const params = {[k]: v}
						return {
							name: this.insertParams(get(feed, 'properties.name[0]', ''), params),
							url: base.clone().search(params).toString(),
							feedObj: feed,
							params
						}
					}))
			}
		})).filter(isObject)
	},

	onlyHttpUrl (x) {
		if (!x) return 'javascript:void(0)'
		if (x.startsWith('/') || x.startsWith('http://') || x.startsWith('https://') || x.startsWith('//')) return x
		return 'javascript:void(0)'
	},

	isValidRef (url, x) {
		return some(x, v => some(url, u => v && ((v.startsWith && v.startsWith(u)) ||
			(v.value && v.value.startsWith && v.value.startsWith(u)))))
	},

	separateComments (url, comments) {
		const result = { replies: [], likes: [], reposts: [], bookmarks: [], quotations: [], mentions: [] }
		for (const comment of comments) {
			const properties = comment.properties || {}
			if (this.isValidRef(url, properties['in-reply-to'])) {
				const text = trim(get(properties, 'content[0].value', get(properties, 'name[0]', 'xxxxxxxxxx')))
				if (text.length < 16) {
					const emoji = countEmoji(text)
					if (emoji && Object.keys(emoji).length >= 1) {
						for (const e of Object.keys(emoji)) {
							result[e] = result[e] || []
							result[e].push(comment)
						}
						continue
					}
				}
				result.replies.push(comment)
			} else if (this.isValidRef(url, properties['like-of'])) {
				result.likes.push(comment)
			} else if (this.isValidRef(url, properties['repost-of'])) {
				result.reposts.push(comment)
			} else if (this.isValidRef(url, properties['bookmark-of'])) {
				result.bookmarks.push(comment)
			} else if (this.isValidRef(url, properties['quotation-of'])) {
				result.quotations.push(comment)
			} else {
				result.mentions.push(comment)
			}
		}
		return result
	},

	syndicationName (x) {
		if (includes(x, 'twitter.com')) return 'Twitter'
		if (includes(x, 'tumblr.com')) return 'Tumblr'
		if (includes(x, 'facebook.com')) return 'Facebook'
		if (includes(x, 'instagram.com')) return 'Instagram'
		const matches = x.match(/^https?:\/\/([^/?#]+)/)
		return (matches && matches[1]) || x
	},

	showAvatar (author) {
		return get(author, 'properties.photo[0]') ||
			gravatarUrl(
				get(author, 'properties.email[0]', 'test@example.com').replace('mailto:', ''),
				{ size: 256, default: 'identicon' }
			)
	},

	entryName (obj) {
		return get(obj, 'properties.name[0]') || get(obj, 'properties.published[0]', 'Untitled page')
	},

	ratingStars (rating, best) {
		if (rating > best) {
			return [best, 0, 0]
		}
		if (rating - Math.floor(rating) > 0.001) {
			return [Math.floor(rating), 1, best - Math.floor(rating) - 1]
		}
		return [Math.floor(rating), 0, best - Math.floor(rating)]
	},

	renderMarkdown (content) {
		return markdown.processSync(content).contents
	},

	getHtml (content) {
		if (isObject(content)) {
			if (isString(content.html)) {
				return content.html
			}
			if (isString(content.markdown || content.value)) {
				return this.renderMarkdown(content.markdown || content.value)
			}
		}
		if (isString(content)) {
			return this.renderMarkdown(content)
		}
	},

	getContent (properties, { preferSummary, onlySummary }) {
		const content = head(compact(onlySummary ? properties.summary : (
			preferSummary
				? concat(properties.summary || [], properties.content || [], properties.name || [])
				: concat(properties.content || [], properties.summary || [], properties.name || [])
			)
		)) || ''
		return this.getHtml(content)
	},

	processContent (properties, opts) {
		const textContent = this.getContent(properties, opts)
		const media = {
			photo: properties.photo || [],
			video: properties.video || [],
			audio: properties.audio || [],
		}
		if (!isString(textContent)) {
			log('non-string content from getContent to processContent')
			return Object.assign({ textContent }, media)
		}
		// NOTE: do not use => functions for cheerio!
		const $ = cheerio.load(textContent)
		// detwitterize emoji
		$('img.Emoji').each(function (i) {
			const img = $(this)
			img.replaceWith(`<span class="emoji">${img.attr('alt')}</span>`)
		})
		//$('img').each(function (i) { const img = $(this) })
		const helpers = this
		for (const mediaType of Object.keys(media)) {
			$(`${mediaType}-here`).each(function (i) {
				const el = $(this)
				let idx = media[mediaType].length
				while (idx--) {
					const obj = media[mediaType][idx]
					if (obj.id === el.attr('id')) {
						el.replaceWith($(pug.render(`include /_media.pug\n+show${capitalize(mediaType)}(media)`,
							{ media: obj, helpers, _, basedir: './views', cacheTemplates })))
						media[mediaType].splice(idx, 1)
					}
				}
			})
		}
		return Object.assign({ textContent: $('body').html() }, media)
	},

	findMentionedLinks (obj) {
		const fromCtxs = concat(
			get(obj, 'properties.in-reply-to', []),
			get(obj, 'properties.like-of', []),
			get(obj, 'properties.repost-of', []),
			get(obj, 'properties.quotation-of', [])
		).map(ctx => isObject(ctx) ? get(ctx, 'properties.url.0') : ctx)
		let fromContent = []
		try {
			const $ = cheerio.load(this.getContent(obj.properties, true, false))
			fromContent = $('a, link').toArray().map(el => el.attribs['href'])
		} catch (err) {
			log('HTML content parse error: %O', err)
		}
		return concat(fromCtxs, fromContent).filter(isString)
	},

	getHtmlLinksByRel (content) {
		const $ = cheerio.load(content)
		return $('link[rel], a[rel]').toArray()
			.filter(el => includes(el.attribs['rel'].split(/\s+/), 'webmention') && isString(el.attribs['href']))
			.map(el => el.attribs['href'])
	},

	isActuallyTheSameDamnThing(name, content) {
		const process = x => entities.decodeHTML(x).replace(/\s+/g, '').replace(/<[^>]+>/g, '')
		const n = process(name)
		const c = process(content)
		return n.length > 2 && c.length > 2 && n.includes(c)
	},

	containerStyle (media) {
		let result = ''
		if (!media) {
			return result
		}
		const color = head(sortBy(media.palette, 'population'))
		const preview = media.tiny_preview
		if (color || preview) {
			result += 'background:'
			if (color) {
				result += color.color
			}
			if (preview) {
				result += ` url('${preview}')`
			}
			result += ';'
		}
		if (media.width && media.height) {
			result += `padding-bottom:${(media.height / media.width * 100).toPrecision(4)}%`
		}
		return result
	},

	galleryRows (entries) {
		const result = []
		let cur = []
		let cur_slots = 0
		for (const entry of entries) {
			cur.push(entry)
			const media = get(entry, 'properties.photo[0]', get(entry, 'properties.video[0]', {}))
			cur_slots += media.width > media.height ? 2 : 1
			if (cur_slots >= 4) {
				result.push(cur)
				cur = []
				cur_slots = 0
			}
		}
		if (cur.length !== 0) {
			result.push(cur)
		}
		return result
	}

}
<|endoftext|>


<commit_before><commit_msg>Bugfix. trigger for non-mockup patterns isn't guaranteed<commit_after><|endoftext|>