text:
// Node.js init
if (typeof require !== 'undefined') {
	PackerData = require("./packerData");
	ContextDescriptor = require("./contextDescriptor_node");
}

/**
 * @constructor
 * ShapeShifter is the preprocessor used by RegPack.
 * It shortens the code, without compression, by running those algorithms on the original code according to settings
 *  - puts the code in "with(Math)" environment
 *  - wraps the main code loop into a call to setInterval()
 *  - hashes method / property names for 2D / GL / Audio contexts
 *  - renames the variable to optimize compression
 */
function ShapeShifter() {

	this.contextDescriptor = new ContextDescriptor();

	// hashing functions for method and property renaming
	this.hashFunctions = [
		["w[x]", 0, 2, 0, 0, function(w,x,y) { return w[x]; } ],
		["w[x]+w[y]", 0, 2, 0, 20, function(w,x,y) { return w[x]+w[y]; } ],
		["w[x]+w.length", 0, 2, 0, 0, function(w,x,y) { return w[x]+w.length; } ],
		["w[x]+w[w.length-1]", 0, 2, 0, 0, function(w,x,y) { return w[x]+w[w.length-1]; } ],
		["w[x]+[w[y]]", 0, 2, 3, 20, function(w,x,y) { return w[x]+[w[y]]; } ],
		["w[0]+w[x]+[w[y]]", 0, 20, 3, 20, function(w,x,y) { return w[0]+w[x]+[w[y]]; } ],
		["w[1]+w[x]+[w[y]]", 0, 20, 3, 20, function(w,x,y) { return w[1]+w[x]+[w[y]]; } ],
		["w[2]+w[x]+[w[y]]", 0, 20, 3, 20, function(w,x,y) { return w[2]+w[x]+[w[y]]; } ],
		["w[0]+[w[x]]+[w[y]]", 3, 20, 3, 20, function(w,x,y) { return w[0]+[w[x]]+[w[y]]; } ],
		["w.substr(x,3)", 0, 2, 0, 0, function(w,x,y) { return w.substr(x,3); } ]
	];
}

ShapeShifter.prototype = {

	/**
	 * Preparation stage : attempt to rehash the methods from canvas context
	 * Produces a pair of hashed/not hashed strings for each option
	 * so each selected flag doubles the number of tests.
	 * Creates a list with all the combinations to feed to the packer, one at a time.
	 * "with Math()" option is applied on all entries if selected (does not create a pair)
	 *
	 * @param input : the string to pack
	 * @param options : preprocessing options, as follows
	 *       -  withMath : true if the option "Pack with(Math)" was selected, false otherwise
	 *       -  hash2DContext : true if the option "Hash and rename 2D canvas context" was selected, false otherwise
	 *       -  hashWebGLContext : true if the option "Hash and rename WebGL canvas context" was selected, false otherwise
	 *       -  hashAudioContext : true if the option "Hash and rename AudioContext" was selected, false otherwise
	 *       -  contextVariableName : a string representing the variable holding the context if the "assume context" option was selected, false otherwise
	 *       -  contextType : the context type (0=2D, 1=WebGL) if the "assume context" option was selected, irrelevant otherwise
	 *       -  reassignVars : true to globally reassign variable names
	 *       -  varsNotReassigned : string or array listing all protected variables (whose name will not be modified)
	 *       -  wrapInSetInterval : true to wrap the unpacked code in a setInterval() call instead of eval()
	 *       -  timeVariableName : if "setInterval" option is set, the variable to use for time (zero on first loop, nonzero after)
	 */
	preprocess : function(input, options) {

		// Transform the list of protected variables into a boolean array[128] (true = protected).
		// Same information but easier to access by algorithms.
		var varsNotReassignedRaw = options.varsNotReassigned;
		options.varsNotReassigned = [];
		for (var i=0; i<128; ++i) {	// replace by Array.fill() once ES6 is supported
			options.varsNotReassigned.push(false);
		}
		for (var i=0; i<varsNotReassignedRaw.length; ++i) {
			var ascii = varsNotReassignedRaw[i].charCodeAt(0);
			if (ascii>=0 && ascii<128 && this.isCharAllowedInVariable(ascii)) {
				options.varsNotReassigned[ascii] = true;
			}
		}

		var inputData = new PackerData ('', input);
		if (options.withMath) {
			inputData.contents = input.replace(/Math\./g, '');
			inputData.environment = 'with(Math)';
		}

		var inputList = [ inputData ];
		if (options.wrapInSetInterval) {
			// method stores the refactored code, log and setup change in inputData
			this.refactorToSetInterval(inputData, options);
		}

		// Hash and rename methods of the 2d canvas context
		//  - method hashing only
		//  - method and property
		// then store the results in the inputList
		if (options.hash2DContext) {
			for (var count=inputList.length, i=0; i<count; ++i)
			{
				var result = this.preprocess2DContext(inputList[i], options);
				if (result) {
					var methodHashedData = PackerData.clone(inputList[i], " 2D(methods)", result[0][1], result[0][2]);
					inputList.push(methodHashedData);

					var propertyHashedData = PackerData.clone(inputList[i], " 2D(properties)", result[1][1], result[1][2]);
					inputList.push(propertyHashedData);
				}
			}
		}

		// for WebGL contexts, there are three options
		//   - hash and replace method names only
		//   - as above, plus replace the definitions of constants with their values (magic numbers)
		//   - hash and replace method and property names
		if (options.hashWebGLContext) {
			for (var count=inputList.length, i=0; i<count; ++i)
			{
				var result = this.preprocessWebGLContext(inputList[i], options);
				if (result) {
					var methodHashedData = PackerData.clone(inputList[i], " WebGL(methods)", result[0][1], result[0][2]);
					inputList.push(methodHashedData);

					var constantHashedData = PackerData.clone(inputList[i], " WebGL(methods+constants)", result[1][1], result[1][2]);
					inputList.push(constantHashedData);

					var propertyHashedData = PackerData.clone(inputList[i], " WebGL(properties)", result[2][1], result[2][2]);
					inputList.push(propertyHashedData);
				}
			}
		}

		// for AudioContexts, method hashing only
		if (options.hashAudioContext) {
			for (var count=inputList.length, i=0; i<count; ++i)
	 		{
				var result = this.preprocessAudioContext(inputList[i].contents, options.varsNotReassigned, inputList[i].log);
				if (result) {
					var audioHashedData = PackerData.clone(inputList[i], " Audio", result[1], result[2]);
					inputList.push(audioHashedData);
				}
			}
		}
		inputList[0].name="unhashed";

		if (options.reassignVars)
		{
			for (var i=0; i<inputList.length; ++i) {
				// method stores the refactored code, log and setup change in inputList[i]
				this.reassignVariableNames(inputList[i], options);
			}
		}
		return inputList;
	},

	/**
	 * Rewrites the input code so that it can entirely be executed inside
	 * a setInterval() loop without prior initialization.
	 *
	 * Detects the function that is currently called through setInterval()
	 * and strips it. Wraps the code before that function into a if sequence
	 * at the beginning of the loop, that will only be run once.
	 *
	 * The method makes use of a "time" variable that usually controls
	 * the flow of execution/rendering, and is increased at each loop.
	 * It needs to be zero on the first run to trigger the initialization
	 * sequence, then nonzero on the subsequent runs.
	 *
	 * Output (refactored code and log) is stored in parameter inputData.
	 * Setup for the unpacking routine is also changed in the same object.
	 *
	 * @param inputData (in/out) PackerData structure containing the code to refactor and setup
	 * @param options options set, see below for use details
	 * @return nothing. Result of refactoring is stored in parameter inputData.
	 * Options used are :
	 *  - timeVariableName : the variable containing time, or empty string to allocate one
	 *  - varsNotReassigned : boolean array[128], true to avoid altering variable
	 *
	 */
	refactorToSetInterval : function(inputData, options) {
		var input = inputData.contents;
		var output = input; // initialized from input, in case we bail out early
		var timeVariableName = options.timeVariableName;
		var varsNotReassigned = options.varsNotReassigned;
		var details = "----------- Refactoring to run with setInterval() ---------------\n";
		var timeVariableProvided = true;
		var loopMatch = input.match(/setInterval\(function\(([\w\d.=,]*)\){/);
		if (loopMatch) {
			var initCode = input.substr(0, loopMatch.index);
			// remove any trailing comma or semicolon
			if (initCode[initCode.length-1]==';' || initCode[initCode.length-1]==',') {
				initCode = input.substr(0, initCode.length-1);
			}

			details += "First "+loopMatch.index+" bytes moved to conditional sequence.\n";

			// parameters of the function passed to setInterval() :
			// remove declarations without assignment
			var paramsCode = loopMatch[1];
			var paramsExp = /[\w\d$_]*,|$/;

			var paramsMatch = paramsExp.exec(paramsCode);
			while (paramsMatch[0] != "") {
				paramsCode = paramsCode.substr(0, paramsMatch.index)+paramsCode.substr(paramsMatch.index+paramsMatch[0].length);
				paramsMatch = paramsExp.exec(paramsCode);
			}
			// remove the last variable (without the comma)
			paramsMatch = paramsCode.match(/^[\w\d$_]*$/);
			if (paramsMatch[0] == paramsCode) {
				paramsCode = "";
			}
			// if not empty, add a semicolon
			paramsCode += (paramsCode != "" ? ";" : "");

			if (timeVariableName=="") {
				timeVariableProvided = false;
				timeVariableName = this.allocateNewVariable(input);
				details += "Using variable "+timeVariableName+" for time.\n";
			}

			// Strip the declaration of the time variable from the init code,
			// as it will be defined in the unpacking routine instead.
			var timeDefinitionExp = new RegExp("(^|[^\\w$])"+timeVariableName+"=","g");
			var timeDefinitionMatch=timeDefinitionExp.exec(initCode);
			if (timeDefinitionMatch) {
				var timeDefinitionBegin = timeDefinitionMatch.index+timeDefinitionMatch[1].length;
				var timeDefinitionEnd = timeDefinitionBegin+2;

				// Check if we can strip more than "t=" depending on what comes before and after :
				//  - Brackets means no : the declaration is used as an argument in a function
				//  - Square brackets means no : used to define an array
				//  - Both commas before and after : same context, inside function or array
				//  - a leading = means no : multiple variables are defined at the same time
				//  - anything other than "0" after is no
				//  - other configurations are ok to remove up to the separator
				var canRemoveInitValue = true;
				var leadingChar = timeDefinitionBegin>0 ? initCode[timeDefinitionBegin-1] : "";
				var trailingChar = initCode[timeDefinitionEnd];
				var furtherChar = timeDefinitionEnd+1<initCode.length ? initCode[timeDefinitionEnd+1] : "";
				canRemoveInitValue = canRemoveInitValue && (leadingChar != "=");	// multiple variable init
				canRemoveInitValue = canRemoveInitValue && (trailingChar == "0");	// multiple variable init, or function call
				canRemoveInitValue = canRemoveInitValue && (leadingChar != "("); 	// used as a function argument
				canRemoveInitValue = canRemoveInitValue && (leadingChar != "["); 	// used as array member
				canRemoveInitValue = canRemoveInitValue && (furtherChar != ")"); 	// used as a function argument
				canRemoveInitValue = canRemoveInitValue && (furtherChar != "]"); 	// used as array member
				canRemoveInitValue = canRemoveInitValue && !(leadingChar == "," && furtherChar == ","); 	// used as a function argument
				timeDefinitionEnd+=(canRemoveInitValue?1:0);
				timeDefinitionEnd+=(canRemoveInitValue&&furtherChar==";"?1:0);
				timeDefinitionEnd+=(canRemoveInitValue&&furtherChar==","&&leadingChar==""?1:0);
				timeDefinitionBegin+=(canRemoveInitValue&&furtherChar!=";"&&leadingChar==";"?-1:0);
				timeDefinitionBegin+=(canRemoveInitValue&&furtherChar==""&&leadingChar==","?-1:0);

				details += "Removed declaration \""+initCode.substr(timeDefinitionBegin, timeDefinitionEnd-timeDefinitionBegin)+"\"\n";
				initCode = initCode.substr(0,timeDefinitionBegin)+initCode.substr(timeDefinitionEnd);
			}

			var inString = 0, bracketDepth = 1, index = loopMatch.index+loopMatch[0].length;
			while (bracketDepth>0 && index<input.length)
			{
				if (inString == 0) {
					switch (input.charCodeAt(index)) {
						case 34 : // "
						case 39 : // '
							inString = input.charCodeAt(index);
							break;
						case 123 : // {
							++bracketDepth;
							break;
						case 125 : // }
							--bracketDepth;
							break;
					}
				} else if (input.charCodeAt(index) == inString && inString>0) {
					inString = 0;
				}
				++index;
			}
			var finalCode = input.substr(index);
			var delayMatch = finalCode.match(/,([\w\d.=]*)\);?/);
			if (delayMatch) {
				finalCode = finalCode.substr(delayMatch[0].length);
				if (finalCode.length) {
					details += "Last "+finalCode.length+" bytes also moved there.\n";
					finalCode = ";"+finalCode;
				}
				details += "Interval of "+delayMatch[1]+ "ms pushed to unpacking routine.\n";

				// wrap the initialization code into a conditional sequence :
				//   - if(!t){/*init code*/} if the variable is used (and set) afterwards
				//   - if(!t++){/*init code*/} if it is created only for the test
				var wrapperCode = "if(!"+timeVariableName+(timeVariableProvided?"":"++")+"){";
				// Redefine the "offset zero" of our transformed code,
				// used to hash methods/properties of contexts provided by shim
				inputData.initialDeclarationOffset = wrapperCode.length;
				initCode=wrapperCode+paramsCode+initCode+finalCode+"}";
				output = initCode+input.substr(loopMatch.index+loopMatch[0].length, index-loopMatch.index-loopMatch[0].length-1);

				inputData.interpreterCall = 'setInterval(_,'+delayMatch[1]+')';
				inputData.wrappedInit = timeVariableName+'=0';

				// Special case : the assignment of the time variable is done
				// as a parameter of setInterval()
				// (featured in 2012 - A rose is a rose)
				if (delayMatch[1].indexOf(inputData.wrappedInit) != -1) {
					// in this case, no need to declare the variable again
					inputData.wrappedInit = "";
					details += timeVariableName+" initialized as parameter to setInterval, kept as is.\n";
				}
			 } else {	// delayMatch === false
				details += "Unable to find delay for setInterval, module skipped.\n";
			}

		} else {
			details += "setInterval() loop not found, module skipped.\n";
		}
		details += "\n";

		// output stored in inputData parameter instead of being returned
		inputData.contents = output;
		inputData.log += details;
	},

	/**
	 * Performs an optimal hashing and renaming of the methods/properties of a canvas 2d context.
	 * Uses a context reference passed from a shim (if provided), plus attempts to
	 * identify all contexts created within the code.
	 * Returns an array containing two sub-arrays,
	 * each in the same format as the compression methods :
	 *   [output length, output string, informations],
	 * even if the preprocessing actually lenghtened the string.
	 *
	 *
	 * @param inputData (in/out) PackerData structure containing setup data and the code to preprocess
	 * @param options options set, see below for use details
	 * Options used are :
	 *  - contextType : type of context provided by shim : 0 for 2D, 1 for GL
	 *  - contextVariableName : the variable holding the context if provided by shim, false otherwise
	 *  - varsNotReassigned : boolean array[128], true to avoid altering variable
	 * @return the result array, or false if no 2d context definition is found in the code.
	 */
	preprocess2DContext : function(inputData, options) {
		// Obtain all context definitions (variable name and location in the code)
		var objectNames = [], objectOffsets = [], objectDeclarationLengths = [], searchIndex = 0;
		var input = inputData.contents;
		var initialLog = inputData.log;
		var variableName = (options.contextType==0?options.contextVariableName:false);
		var varsNotReassigned = options.varsNotReassigned;
		initialLog += "----------- Hashing methods/properties for 2D context -----------\n";
		// Start with the preset context, if any
		if (variableName)
		{
			objectNames.push(variableName);
			objectOffsets.push(inputData.initialDeclarationOffset);
			objectDeclarationLengths.push(0);
		}
		// Then search for additional definitions inside the code. Keep name, declaration offset, and declaration length
		var declarations = input.match (/([\w\d.]*)=[\w\d.]*\.getContext\(['"]2d['"]\)/gi);
		if (declarations) {
			for (var declIndex=0; declIndex<declarations.length; ++declIndex)
			{
				var oneDecl = declarations[declIndex];
				objectNames.push(oneDecl.substr(0, oneDecl.indexOf('=')));
				var oneOffset = input.indexOf(oneDecl, searchIndex);
				objectOffsets.push(oneOffset);
				objectDeclarationLengths.push(oneDecl.length);
				searchIndex = oneOffset + oneDecl.length;
			}
		}

		if (objectNames.length) {
			// obtain the list of properties in a 2D context from the ContextDescriptor
			var referenceProperties = this.contextDescriptor.canvas2DContextDescription.properties;
			var hashedCodeM = this.renameObjectMethods(input, objectNames, objectOffsets, objectDeclarationLengths, referenceProperties, varsNotReassigned, initialLog);
			var hashedCodeP = this.hashObjectProperties(input, objectNames, objectOffsets, objectDeclarationLengths, referenceProperties, varsNotReassigned, initialLog);
			return [hashedCodeM, hashedCodeP];
		}
		return false;
	},

	/**
	 * Performs an optimal hashing and renaming of the methods of a canvas WebGL context.
	 * Uses a context reference passed from a shim, or attempts to locate in inside the code.
	 * Features the call to replaceWebGLconstants() as one of the results.
	 * @see replaceWebGLconstants
	 *
	 * Returns an array containing three sub-arrays,
	 *   [output length, output string, informations],
	 *  - first one has method hashing performed
	 *  - second one has method hashing + GL constants replaced by their value
	 *  - third one has method + property renaming
	 *
	 * @param inputData (in/out) PackerData structure containing setup data and the code to preprocess
	 * @param options options set, see below for use details
	 * Options used are :
	 *  - contextType : type of context provided by shim : 0 for 2D, 1 for GL
	 *  - contextVariableName : the variable holding the context if provided by shim, false otherwise
	 *  - varsNotReassigned : boolean array[128], true to avoid altering variable
	 * @return the result array, or false if no webgl context definition is found in the code.
	 */
	preprocessWebGLContext : function(inputData, options) {
		// Obtain all context definitions (variable name and location in the code)
		var objectNames = [], objectOffsets = [], objectDeclarationLengths = [], searchIndex = 0;
		var input = inputData.contents;
		var initialLog = inputData.log;
		var variableName = options.contextType==1?options.contextVariableName:false;
		var varsNotReassigned = options.varsNotReassigned;
		initialLog += "----------- Hashing methods/properties for GL context -----------\n";
		// Start with the preset context, if any
		if (variableName)
		{
			objectNames.push(variableName);
			objectOffsets.push(inputData.initialDeclarationOffset);
			objectDeclarationLengths.push(0);
		}
		// Then search for additional definitions inside the code. Keep name, declaration offset, and declaration length
		var declarations = input.match (/([\w\d.]*)\s*=\s*[\w\d.]*\.getContext\(['"](experimental-)*webgl['"](,[\w\d\s{}:.,!]*)*\)(\s*\|\|\s*[\w\d.]*\.getContext\(['"](experimental-)*webgl['"](,[\w\d\s{}:.,!]*)*\))*/gi);
		if (declarations) {
			for (var declIndex=0; declIndex<declarations.length; ++declIndex)
			{
				var oneDecl = declarations[declIndex];
				objectNames.push(oneDecl.substr(0, oneDecl.indexOf('=')));
				var oneOffset = input.indexOf(oneDecl, searchIndex);
				objectOffsets.push(oneOffset);
				objectDeclarationLengths.push(oneDecl.length);
				searchIndex = oneOffset + oneDecl.length;
			}
		}

		if (objectNames.length) {
			// list of properties in a 2D context
			var referenceProperties = this.contextDescriptor.canvasGLContextDescription.properties;

			// method only hashing
			var hashedCodeM = this.renameObjectMethods(input, objectNames, objectOffsets, objectDeclarationLengths, referenceProperties, varsNotReassigned, initialLog);

			// builds on former, replaces constants as well
			var hashedCodeMC = this.replaceWebGLconstants(hashedCodeM[1], objectNames, this.contextDescriptor.canvasGLContextDescription.constants,  hashedCodeM[2]);

			// method and property hashing
			var hashedCodeP = this.hashObjectProperties(input, objectNames, objectOffsets, objectDeclarationLengths, referenceProperties, varsNotReassigned, initialLog);0
			return [hashedCodeM, hashedCodeMC, hashedCodeP];
		}

		return false;
	},

	/**
	 * Replaces, in the provided code, all definition of WebGL constants with their numerical values
	 * Uses a context reference passed from a shim, or attempts to locate in inside the code.
	 * Returns an array in the same format as the compression methods : [output length, output string, informations],
	 * even if the replacement actually lenghtened the string.
	 * Only the constant values in CAPITALS are replaced. Other properties and methods are untouched.
	 *
	 * @param input the code to perform replacement on
	 * @param objectNames array containing variable names of context objects (mandatory)
	 * @param referenceConstants : object containing all constants of the GL context
	 * @param initialLog : the action log, new logs will be appended
	 * @return an array [length, output, user message]
	 */
	replaceWebGLconstants : function (input, objectNames, referenceConstants, initialLog)
	{
		var output = input, details=initialLog;
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex)
		{
			var exp = new RegExp("(^|[^\\w$])"+objectNames[contextIndex]+"\\.([0-9A-Z_]*)[^\\w\\d_(]","g");
			var constantsInUse=[];
			var result=exp.exec(output);
			while (result) {	// get a set with a unique entry for each method
				if (constantsInUse.indexOf(result[2])==-1) {
					constantsInUse.push(result[2]);
				}
				result=exp.exec(output);
			}

			details += "Replaced constants of "+objectNames[contextIndex]+"\n";
			for (var index=0; index<constantsInUse.length; ++index) {
				if (constantsInUse[index] in referenceConstants) {
					var constant = referenceConstants[constantsInUse[index]];
					var exp = new RegExp("(^|[^\\w$])"+objectNames[contextIndex]+"\\."+constantsInUse[index]+"(^|[^\\w$])","g");
					output = output.replace(exp, "$1"+constant+"$2");
					// show the renaming in the details
					details += constantsInUse[index] + " -> " + constant + "\n";
				}
			}
		}
		details+="\n";
		return [this.getByteLength(output), output, details];

	},

	/**
	 * Performs an optimal hashing and renaming of the methods of an AudioContext.
	 * Unlike 2D contexts, only one audio context is considered.
	 *
	 * Returns an array in the same format as the compression methods : [output length, output string, informations],
	 * even if the preprocessing actually lenghtened the string.
	 *
	 * @param input the code to preprocess
	 * @param varsNotReassigned boolean array[128], true to keep name of variable
	 * @param initialLog : the action log, new logs will be appended
	 * @return the result array, or false if no AudioContext definition is found in the code.
	 */
	preprocessAudioContext : function(input, varsNotReassigned, initialLog) {
		// list of properties in an AudioContext
		var referenceProperties = this.contextDescriptor.audioContextDescription.properties;

		// Initialization of a *AudioContext can be performed in a variety of ways
		// and is usually less consistent that a 2D or WebGL graphic context.
		// Multiple tests cover the most common cases
		var objectOffset = 0;
		var replacementOffset = 0;
		var objectName = "";
		var details = initialLog;
		details += "----------- Hashing methods for AudioContext --------------------\n";

		// direct instanciation of an AudioContext
		// var c = new AudioContext()
		var result = input.match (/([\w\.]*)\s*=\s*new AudioContext/i);
		if (result) {
			objectOffset = input.indexOf(result[0]);
			objectName = result[1];
			// start replacement at the next semicolon
			replacementOffset = 1+input.indexOf(";", objectOffset);
			// unless the object is used before
			replacementOffset = Math.min(replacementOffset, input.indexOf(objectName, objectOffset+result[0].length));
		}
		// direct instanciation of a webkitAudioContext
		// beware, the same code could try to create both (see TestCase audioContext_create1)
		// var c = new webkitAudioContext()
		var resultWebkit = input.match (/([\w\.]*)\s*=\s*new webkitAudioContext/i);
		if (resultWebkit) {

			if (resultWebkit[1] == objectName || objectName == "") {
				// we take the latter declaration, as to add the renaming loop after both of them
				objectOffset = Math.max(objectOffset, input.indexOf(resultWebkit[0]));
				// start replacement at the next semicolon
				replacementOffset = 1+input.indexOf(";", objectOffset);
				// unless the object is used before
				replacementOffset = Math.min(replacementOffset, input.indexOf(objectName, objectOffset+resultWebkit[0].length));
			} else {
				// the webkitAudioContext was created with a different name than the AudioContext
				// in this case, we separately rename objects for both of them
				// (see TestCase audioContext_create2 and audioContext_create3)
				var webkitObjectOffset = input.indexOf(resultWebkit[0]);
				var webkitObjectName = resultWebkit[1];
				// start replacement at the next semicolon
				var webkitReplacementOffset = 1+input.indexOf(";", webkitObjectOffset);
				// unless the object is used before
				webkitReplacementOffset = Math.min(webkitReplacementOffset, input.indexOf(webkitObjectName, webkitObjectOffset+resultWebkit[0].length));

				var secondObjectOffset = replacementOffset>webkitReplacementOffset ? objectOffset : webkitObjectOffset;
				var secondReplacementOffset = replacementOffset>webkitReplacementOffset ? replacementOffset : webkitReplacementOffset;
				var secondObjectName = replacementOffset>webkitReplacementOffset ? objectName : resultWebkit[1];

				objectOffset = replacementOffset>webkitReplacementOffset ? webkitObjectOffset : objectOffset ;
				replacementOffset = replacementOffset>webkitReplacementOffset ? webkitReplacementOffset : replacementOffset ;
				objectName = replacementOffset>webkitReplacementOffset ? resultWebkit[1] : objectName ;

				// perform the replacement for the latter object first, so the offset of the former is not changed

				var halfReplaced =this.renameObjectMethods(input, [secondObjectName], [secondReplacementOffset], [0], referenceProperties, varsNotReassigned, details);
				input = halfReplaced[1];
				details = halfReplaced[2];
			}
		}
		// direct instanciation of the appropriate context
		// var c = new (window.AudioContext||window.webkitAudioContext)()
		result = input.match (/([\w\.]*)\s*=\s*new\s*\(*\s*(window\.)*(webkit)*AudioContext\s*\|\|\s*(window\.)*(webkit)*AudioContext/i);
		if (result) {
			objectOffset = input.indexOf(result[0]);
			objectName = result[1];
			// start replacement at the next semicolon
			replacementOffset = 1+input.indexOf(";", objectOffset);
			// unless the object is used before
			replacementOffset = Math.min(replacementOffset, input.indexOf(objectName, objectOffset+result[0].length));
		}

		// direct instanciation of the appropriate context, not factored in
		// var c = new AudioContext()||new webkitAudioContext()
		// (see TestCase audioContext_create4)
		result = input.match (/([\w\.]*)\s*=\s*new\s*\(*\s*(window\.)*(webkit)*AudioContext(\(\))*\s*\|\|\s*new\s*(window\.)*(webkit)*AudioContext(\(\))*/i);
		if (result) {
			objectOffset = input.indexOf(result[0]);
			objectName = result[1];
			// start replacement at the next semicolon
			replacementOffset = 1+input.indexOf(";", objectOffset);
			// unless the object is used before
			replacementOffset = Math.min(replacementOffset, input.indexOf(objectName, objectOffset+result[0].length));
		}

		// instanciation of the appropriate context, through a temporary variable
		// contextType = window.AudioContext||window.webkitAudioContext; var c = new contextType;
		result = input.match (/([\w\.]*)\s*=\s*\(*\s*(window\.)*(webkit)*AudioContext\s*\|\|\s*(window\.)*(webkit)*AudioContext/i);
		if (result) {
			var contextTypeName = result[1];
			var exp = new RegExp("([\\w\\.]*)\\s*=\\s*new\\s*\\(*\\s*"+contextTypeName);
			result = input.match(exp);
			if (result) {
				objectOffset = input.indexOf(result[0]);
				objectName = result[1];
				// start replacement at the next semicolon
				replacementOffset = 1+input.indexOf(";", objectOffset);
				// unless the object is used before
				replacementOffset = Math.min(replacementOffset, input.indexOf(objectName, objectOffset+result[0].length));
			}
		}

		if (replacementOffset>0) {
			var preprocessedCode = this.renameObjectMethods(input, [objectName], [replacementOffset], [0], referenceProperties, varsNotReassigned, details);
			return preprocessedCode;
		}
		return false;
	},

	/**
	 * Identifies the optimal hashing function (the one returning the shortest result)
	 * then renames all the methods with their respective hash, and preprends the hashing code.
	 *
	 * The hashing loop looks like : for(i in c)c[i[0]+[i[6]]=c[i];
	 * meaning that later one may call c.fc(...) instead of c.fillRect(...)
	 * The newly created properties are reference to existing functions.
	 *
	 * Replacement is performed at the last object assignment(graphic or audio context),
	 * or at the beginning for shim context, hence the offset parameter.
	 *
	 * If there are several contexts, only one hash is used. It is applied to
	 * all or only some of the contexts, depending on the computed gain.
	 * The algorithm will not define different hashes for the multiple
	 * contexts. The rationale behind this is the assumption that the lesser
	 * gain from using the same hash for all will be offset by the better
	 * compression - as the repeated hashing pattern will be picked up by the
	 * packer.
	 *
 	 * Returns an array in the same format as the compression methods : [output length, output string, informations],
	 *
	 * @param input : the string to pack
	 * @param objectNames : array containing variable names of context objects, whose methods to rename in the source string
	 * @param objectOffsets : array, in the same order, of character offset to the beginning of the object declaration. Zero if defined outside (shim)
	 * @param objectDeclarationLengths : array, in the same order, of lengths of the object declaration, starting at offset. Zero if defined outside (shim)
	 * @param referenceProperties : an array of strings containing property names for the appropriate context type
	 * @param varsNotReassigned : boolean array[128], true to keep name of variable
	 * @param initialLog : the action log, new logs will be appended
	 * @return the result of the renaming as an array [output length, output string, informations]
	 */
	renameObjectMethods : function(input, objectNames, objectOffsets, objectDeclarationLengths, referenceProperties, varsNotReassigned, initialLog)
	{

		var details = initialLog || '';
		var methodsInUseByContext=[];
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex)
		{
			var methodsInUse = [];
			var exp = new RegExp("(^|[^\\w$])"+objectNames[contextIndex]+"\\.(\\w*)\\(","g");
			var result=exp.exec(input);
			while (result) {	// get a set with a unique entry for each method
				if (methodsInUse.indexOf(result[2])==-1) {
					methodsInUse.push(result[2]);
				}
				--exp.lastIndex; // the final ( can be reused as initial separator in the next expression
				result=exp.exec(input);
			}
			methodsInUseByContext.push(methodsInUse);
		}

		var bestTotalScore = -999, bestIndex =-1, bestXValue = 0, bestYValue = 0, bestScoreByContext = [];
		// For each hashing function, we compute the hashed names of all methods of the context object
		// All collisions (such as taking the first letter of scale() and save() end up in s()) are eliminated
		// as the order depends on the browser and we cannot assume the browser that will be running the final code
		// A score is then assigned to the hashing function :
		//   - for each context, the algorithm computes the gain obtained by shortening the non-colliding method names to their hash
		//     (the number of occurrences is irrelevant, we assume that the compression step will amount them to one)
		//   - the length of the hashing function is subtracted
		// Only the hashing function with the best score is kept - and applied
		for (var functionIndex=0; functionIndex<this.hashFunctions.length; ++functionIndex) {
			var functionDesc = this.hashFunctions[functionIndex];
			for (var xValue=functionDesc[1]; xValue<=functionDesc[2] ; ++xValue) {
				for (var yValue=functionDesc[3]; yValue<=functionDesc[4] ; ++yValue) {
					var reverseLookup = [], forwardLookup = [];
					for (var index=0; index<referenceProperties.length; ++index) {
						var w = referenceProperties[index];
						var hashedName = functionDesc[5].call(null, w, xValue, yValue);
						reverseLookup[hashedName] = (reverseLookup[hashedName] ? "<collision>" : w);
					}
					for (w in reverseLookup) {
						forwardLookup[reverseLookup[w]]=w;	// keep only the method names with no collisions
					}
					var allScores = [], totalScore = 0;
					for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex)
					{
						var score = 0;
						var methodsInUse = methodsInUseByContext[contextIndex];
						for (var methodIndex=0; methodIndex<methodsInUse.length; ++methodIndex) {
							// Fix for issue #11 : in FF, arrays have a method fill(), as 2D contexts do
							// typeof() discriminates between "string" (hash match), "undefined" (no match) and "function" (array built-in)
							if (typeof(forwardLookup[methodsInUse[methodIndex]])=="string") {
								var delta = methodsInUse[methodIndex].length - forwardLookup[methodsInUse[methodIndex]].length;
								// Complement for issue #23, when the hash could be longer than the original name
								score += Math.max(0, delta);
							}
						}
						score -= 2; // a[hash]=b[hash]=a[i], "[hash]=" is packed for 1, remains "a" total 1+1
						allScores.push(score);
						score = Math.max(0, score); // if the gain is negative, no replacement will be performed
						totalScore += score;
					}
					// the score for the hash is the gain as computed above,
					// minus the length of the hash function itself.
					totalScore-=functionDesc[0].replace(/x/g, xValue).replace(/y/g, yValue).length;

					if (totalScore>bestTotalScore) {
						bestTotalScore = totalScore;
						bestScoreByContext = allScores;
						bestIndex = functionIndex;
						bestXValue = xValue;
						bestYValue = yValue;
					}
				}
			}
		}

		// bail out early if no gain. Keep if just par, to see how compression behaves
		if (bestTotalScore < 0) {
			details += "Best hash loses "+(-bestTotalScore)+" bytes, skipping.\n";
			return [this.getByteLength(input), input, details];
		}

		// best hash function (based on byte gain) found. Apply it
		var reverseLookup = [], forwardLookup = [];
		for (var index=0; index<referenceProperties.length; ++index) {
			var w = referenceProperties[index];
			var hashedName = this.hashFunctions[bestIndex][5].call(null, w, bestXValue, bestYValue);
			reverseLookup[hashedName] = (reverseLookup[hashedName] ? "<collision>" : w);
		}
		for (w in reverseLookup) {
			forwardLookup[reverseLookup[w]]=w;
		}
		var hashedCode = input;

		// Tell the user what is being replaced, and what is ignored
		var renamedList = "", notRenamedList = "";
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex)
		{
			if (bestScoreByContext[contextIndex]>=0) {
				renamedList += (renamedList.length>0?", " : "") + objectNames[contextIndex];
			} else {
				notRenamedList += (notRenamedList.length>0?", " : "") + objectNames[contextIndex];
			}
		}
		if (notRenamedList.length>0) {
			details += "No renaming for "+notRenamedList+"\n";
		}
		if (renamedList.length>0) {
			details += "Renamed methods for "+renamedList+"\n";
		}

		// Perform the replacement inside the code
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex) {
			if (bestScoreByContext[contextIndex]>=0) {	// replace only if the gain is positive
				var methodsInUse = methodsInUseByContext[contextIndex];
				for (var methodIndex=0; methodIndex<methodsInUse.length; ++methodIndex) {

					// Fix for issue #11, needed in this iteration again
					if (typeof(forwardLookup[methodsInUse[methodIndex]])=="string") {
						var gain = methodsInUse[methodIndex].length - forwardLookup[methodsInUse[methodIndex]].length;
						if (gain > 0) {
							// skip replacement if the hash would be longer than the original method

							// otherwise replace all instances of that method ("g" option in the RegExp)
							// The opening bracket at the end avoids triggering on a subset of the name,
							// for instance enable() instead of enableVertexAttribArray() in WebGL contexts
							// The initial \b avoids triggering if one context has a name
							// ending in another context's name (such as 'c' and 'cc')
							var exp = new RegExp("\\b"+objectNames[contextIndex]+"\\."+methodsInUse[methodIndex]+"\\(","g");
							hashedCode = hashedCode.replace(exp, objectNames[contextIndex]+"."+forwardLookup[methodsInUse[methodIndex]]+"(");

							// show the renaming in the details, for used methods only
							details += objectNames[contextIndex]+"."+forwardLookup[methodsInUse[methodIndex]] + " -> " + methodsInUse[methodIndex] + "\n";
						}
					}
				}
			}
		}
		details += "\n";

		// Choose the index variable for the hashing loop
		var loopVarResult = this.getMostFrequentLoopVariable(input, varsNotReassigned);
		var indexName = loopVarResult[0];
		details += loopVarResult[1]; // operation log

		// Create the final hashing expression by replacing the placeholder variables
		var expression = this.hashFunctions[bestIndex][0].replace(/w/g, indexName);
		expression = expression.replace(/x/g, bestXValue);
		expression = expression.replace(/y/g, bestYValue);
		// If the input code uses mostly "" as string delimiters, use it as well in the expression instead of ''
		if (input.split('"').length>input.split("'").length) {
			expression = expression.replace(/'/g, '"');
		}

		// Determine where in the code the hashing loop will be inserted.
		// (at the declaration of the last context that gets hashed).
		var offset = 0, loopContext = 0, shortestContext = 0;
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex) {
			if (bestScoreByContext[contextIndex]>=0) {	// replace only if the gain is positive
				offset = objectOffsets[contextIndex];	// perform the replacement at the latest context definition
				loopContext = contextIndex;
				// retrieve the context with the shortest name, will be used
				// as right-member of the hashing assignment
				if (objectNames[contextIndex].length <  objectNames[shortestContext].length) {
					shortestContext = contextIndex;
				}
			}
		}
		var output = hashedCode.substr(0, offset);

		// Insert the hashing/renaming loop in the code.
		// If the context definition is not included (js1k shim for instance), the loop is prepended to the code and ends with ";"
		// otherwise the loop replaces and includes the last declaration. The code looks like :
		//   for (i in c=a.getContext('2d'))c[...]=c[i] with a single context
		//   for (i in c=a.getContext('2d'))c[...]=b[...]=b[i] with multiple contexts (surprising, but it works)
		// The ending separator is kept, unless it is a comma ",", in which case it is replaced with a semicolon ";"
		// (to avoid including the trailing code in the loop)
		var declarationLength = objectDeclarationLengths[loopContext];
		output+="for("+indexName+" in "+(declarationLength==0?objectNames[loopContext]:hashedCode.substr(offset, declarationLength))+")";
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex) {
			if (bestScoreByContext[contextIndex]>=0) {
				output+=objectNames[contextIndex]+"["+expression+"]=";
				needsComma = true;
			}
		}
		output+=objectNames[shortestContext]+"["+indexName+"]";
		if (hashedCode[offset+declarationLength]==",") {
			// replace the trailing "," with ";" as explained above
			output+=";";
			++declarationLength;
		}
		output+=(declarationLength==0?";":"");
		output+=hashedCode.substr(offset+declarationLength);

		return [this.getByteLength(output), output, details];
	},

	/**
	 * Identifies the optimal hashing function (the one returning the shortest result)
	 * then renames all the properties with their respective hash, and preprends the hashing code.
	 *
	 * The hashing loop looks like : for(i in c)c[i[0]+[i[6]]=i;
	 * The new properties in c contain the full name of actual properties and methods
	 * meaning that later one may call c[c.fc](...) instead of c.fillRect(...)
	 * or c[c.fy] instead of c.fillStyle
	 * Unlike renameObjectMethods(), this works on properties and methods alike.
	 *
	 * Replacement is performed at the last object assignment(graphic or audio context),
	 * or at the beginning for shim context, hence the offset parameter.
	 *
	 * If there are several contexts, only one hash is used. It is applied to
	 * all or only some of the contexts, depending on the computed gain.
	 * The algorithm will not define different hashes for the multiple
	 * contexts. The rationale behind this is the assumption that the lesser
	 * gain from using the same hash for all will be offset by the better
	 * compression - as the repeated hashing pattern will be picked up by the
	 * packer.
	 *
 	 * Returns an array in the same format as the compression methods : [output length, output string, informations],
	 *
	 * @param input : the string to pack
	 * @param objectNames : array containing variable names of context objects, whose methods to rename in the source string
	 * @param objectOffsets : array, in the same order, of character offset to the beginning of the object declaration. Zero if defined outside (shim)
	 * @param objectDeclarationLengths : array, in the same order, of lengths of the object declaration, starting at offset. Zero if defined outside (shim)
	 * @param referenceProperties : an array of strings containing property names for the appropriate context type
	 * @param varsNotReassigned : boolean array[128], true to keep name of variable
	 * @param initialLog : the action log, new logs will be appended
	 * @return the result of the renaming as an array [output length, output string, informations]
	 */
	hashObjectProperties : function(input, objectNames, objectOffsets, objectDeclarationLengths, referenceProperties, varsNotReassigned, initialLog)
	{
		var details = initialLog || '';
		var propertiesInUseByContext=[];
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex)
		{
			var propertiesInUse = [];
			// almost the same expression as for methods, without the final "("
			var exp = new RegExp("(^|[^\\w$])"+objectNames[contextIndex]+"\\.(\\w*)","g");
			var result=exp.exec(input);
			while (result) {	// get a set with a unique entry for each property
				if (propertiesInUse.indexOf(result[2])==-1) {
					propertiesInUse.push(result[2]);
				}
				result=exp.exec(input);
			}
			propertiesInUseByContext.push(propertiesInUse);
		}

		var bestTotalScore = -999, bestIndex =-1, bestYValue = 0, bestXValue = 0, bestScoreByContext = [];
		// For each hashing function, we compute the hashed names of all properties of the context object
		// All collisions (such as taking the first letter of scale() and save() end up in s()) are eliminated
		// as the order depends on the browser and we cannot assume the browser that will be running the final code
		// A score is then assigned to the hashing function :
		//   - for each context, the algorithm computes the gain obtained by shortening the non-colliding property names to their hash
		//     (the number of occurrences is irrelevant, we assume that the compression step will amount them to one)
		//   - the length of the hashing function is subtracted
		// Only the hashing function with the best score is kept - and applied
		for (var functionIndex=0; functionIndex<this.hashFunctions.length; ++functionIndex) {
			var functionDesc = this.hashFunctions[functionIndex];
			for (var xValue=functionDesc[1]; xValue<=functionDesc[2] ; ++xValue) {
				for (var yValue=functionDesc[3]; yValue<=functionDesc[4] ; ++yValue) {
					var reverseLookup = [], forwardLookup = [];
					for (var index=0; index<referenceProperties.length; ++index) {
						var w = referenceProperties[index];
						var hashedName = functionDesc[5].call(null, w, xValue, yValue);
						// a collision means that the hash is unsafe to use
						//  - either another property/method is hashed to the same string
						//  - or an unhashed method used in the code has the same name
						//    (may happen for short names such as arc())
						//    We do not care about methods not used in the code, they can be safely overwritten
						var collision = propertiesInUse.indexOf(hashedName)!=-1 || reverseLookup[hashedName];
						reverseLookup[hashedName] = (collision ? "<collision>" : w);
					}
					for (w in reverseLookup) {
						forwardLookup[reverseLookup[w]]=w;	// keep only the property names with no collisions
					}
					var allScores = [], totalScore = 0;
					for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex)
					{
						var score = 0;
						var propertiesInUse = propertiesInUseByContext[contextIndex];
						for (var propertyIndex=0; propertyIndex<propertiesInUse.length; ++propertyIndex) {
							// Fix for issue #11 : in FF, arrays have a method fill(), as 2D contexts do
							// typeof() discriminates between "string" (hash match), "undefined" (no match) and "function" (array built-in)
							if (typeof(forwardLookup[propertiesInUse[propertyIndex]])=="string") {
								score += propertiesInUse[propertyIndex].length - forwardLookup[propertiesInUse[propertyIndex]].length;
							}
						}
						allScores.push(score);
						score = Math.max(0, score); // if the gain is negative, no replacement will be performed
						totalScore += score;
					}
					// the score for the hash is the gain as computed above,
					// minus the length of the hash function itself.
					totalScore-=functionDesc[0].replace(/x/g, xValue).replace(/y/g, yValue).length;

					// Debug log
					// details +=functionDesc[0].replace(/x/g, xValue).replace(/y/g, yValue) + " : "+totalScore +"\n";

					if (totalScore>bestTotalScore) {
						bestTotalScore = totalScore;
						bestScoreByContext = allScores;
						bestIndex = functionIndex;
						bestXValue = xValue;
						bestYValue = yValue;
					}
				}
			}
		}

		// bail out early if no gain
		if (bestTotalScore < 0) {
			details += "Best hash loses "+(-bestTotalScore)+" bytes, skipping.\n";
			return [this.getByteLength(input), input, details];
		}

		// best hash function (based on byte gain) found. Apply it
		var reverseLookup = [], forwardLookup = [];
		for (var index=0; index<referenceProperties.length; ++index) {
			var w = referenceProperties[index];
			var hashedName = this.hashFunctions[bestIndex][5].call(null, w, bestXValue, bestYValue);
			reverseLookup[hashedName] = (reverseLookup[hashedName] ? "<collision>" : w);
		}
		for (w in reverseLookup) {
			forwardLookup[reverseLookup[w]]=w;
		}
		var hashedCode = input;

		// Tell the user what is being replaced, and what is ignored
		var renamedList = "", notRenamedList = "";
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex)
		{
			if (bestScoreByContext[contextIndex]>=0) {
				renamedList += (renamedList.length>0?", " : "") + objectNames[contextIndex];
			} else {
				notRenamedList += (notRenamedList.length>0?", " : "") + objectNames[contextIndex];
			}
		}
		if (notRenamedList.length>0) {
			details += "No renaming for "+notRenamedList+"\n";
		}
		if (renamedList.length>0) {
			details += "Renamed properties for "+renamedList+"\n";
		}

		// Determine the context with the shortest name
		// It will be used to store the hashes
		// (at the declaration of the last context that gets hashed).
		var shortestContext = 0;
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex) {
			if (objectNames[contextIndex].length <  objectNames[shortestContext].length) {
				shortestContext = contextIndex;
			}
		}

		// Perform the replacement inside the code
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex) {
			if (bestScoreByContext[contextIndex]>=0) {	// replace only if the gain is positive
				var propertiesInUse = propertiesInUseByContext[contextIndex];
				for (var propertyIndex=0; propertyIndex<propertiesInUse.length; ++propertyIndex) {

					// Fix for issue #11, needed in this iteration again
					if (typeof(forwardLookup[propertiesInUse[propertyIndex]])=="string") {
						// replace all instances of that property ("g" option in the RegExp)
						// The nonstring character at the end avoids triggering on a subset of the name,
						// for instance enable() instead of enableVertexAttribArray() in WebGL contexts
						// (see test case webglContext_substringHash.js)
						// The initial character (or line start) avoids triggering if one context has a name
						// ending in another context's name (such as 'c' and 'cc')
						var exp = new RegExp("(^|[^\\w$])"+objectNames[contextIndex]+"\\."+propertiesInUse[propertyIndex]+"($|\\W)","g");
						hashedCode = hashedCode.replace(exp, "$1"+objectNames[contextIndex]+"["+objectNames[shortestContext]+"."+forwardLookup[propertiesInUse[propertyIndex]]+"]$2");

						// show the renaming in the details, for used properties only
						details += objectNames[contextIndex]+"."+forwardLookup[propertiesInUse[propertyIndex]] + " -> " + propertiesInUse[propertyIndex] + "\n";
					}
				}
			}
		}
		details += "\n";

		// Choose the index variable for the hashing loop
		var loopVarResult = this.getMostFrequentLoopVariable(input, varsNotReassigned);
		var indexName = loopVarResult[0];
		details += loopVarResult[1]; // operation log

		// Create the final hashing expression by replacing the placeholder variables
		var expression = this.hashFunctions[bestIndex][0].replace(/w/g, indexName);
		expression = expression.replace(/x/g, bestXValue);
		expression = expression.replace(/y/g, bestYValue);
		// If the input code uses mostly "" as string delimiters, use it as well in the expression instead of ''
		if (input.split('"').length>input.split("'").length) {
			expression = expression.replace(/'/g, '"');
		}

		// Determine where in the code the hashing loop will be inserted.
		// (at the declaration of the last context that gets hashed).
		var offset = 0, loopContext = 0;
		for (var contextIndex=0; contextIndex<objectNames.length; ++contextIndex) {
			if (bestScoreByContext[contextIndex]>=0) {	// replace only if the gain is positive
				offset = objectOffsets[contextIndex];	// perform the replacement at the latest context definition
				loopContext = contextIndex;
			}
		}
		var output = hashedCode.substr(0, offset);

		// Insert the hashing/renaming loop in the code.
		// If the context definition is not included (js1k shim for instance), the loop is prepended to the code and ends with ";"
		// otherwise the loop replaces and includes the last declaration. The code looks like :
		//   for (i in c=a.getContext('2d'))c[...]=i with a single context
		//   for (i in c=a.getContext('2d'))c[...]=b[...]=i with multiple contexts
		// The ending separator is kept, unless it is a comma ",", in which case it is replaced with a semicolon ";"
		// (to avoid including the trailing code in the loop)
		var declarationLength = objectDeclarationLengths[loopContext];
		output+="for("+indexName+" in "+(declarationLength==0?objectNames[loopContext]:hashedCode.substr(offset, declarationLength))+")";
		output+=objectNames[shortestContext]+"["+expression+"]="+indexName;
		if (hashedCode[offset+declarationLength]==",") {
			// replace the trailing "," with ";" as explained above
			output+=";";
			++declarationLength;
		}
		output+=(declarationLength==0?";":"");
		output+=hashedCode.substr(offset+declarationLength);

		return [this.getByteLength(output), output, details];
	},

	/**
	 * Returns the total byte length of a string
	 *  1 for ASCII char
	 *  3 for Unicode (UTF-8)
	 * Issue #5 : final size when featuing unicode characters
	 */
	getByteLength : function (inString)
	{
		return encodeURI(inString).replace(/%../g,'i').length;
	},

	/**
	 * Returns true if the character code is allowed in the name of a variable.
	 * Allowed codes are 36($), 48-57(0-9), 65-90(A-Z), 95(_), 97-122(a-z)
	 */
	isCharAllowedInVariable : function (charCode)
	{
		return (charCode>64 && charCode<91) || (charCode>96 && charCode<123)
			   || (charCode>47 && charCode<58)
			   || charCode==36 || charCode==95;
	},

	/**
	 * Returns true if the character code is a digit
	 */
	isDigit : function (charCode)
	{
		return (charCode>47 && charCode<58);
	},

	/**
	 * Identifies and returns the one-letter variable that is the
	 * most common occurrence as a loop variable in a for(..;..;..) loop
	 *
	 * If no loop is found in the code, returns "i" as default.
	 * Protected variables (from param varsNotReassigned) are not counted
	 * as they should not be reassigned (issue #9), as the goal is to
	 * create another for loop using the same variabled.
	 *
	 * Called by both hashing methods to assign a name to the
	 * renaming loop, in order to benefit most from compression.
	 * @see renameObjectMethods
	 * @see hashObjectProperties
	 *
	 * @param input the code to parse for loop variables
	 * @param varsNotReassigned (from options) boolean array[128], true to avoid altering variable
	 * @return an array [ variable name (String), log ]
	 */
	getMostFrequentLoopVariable : function(input, varsNotReassigned)
	{
			// Choose the index variable for the added hashing code
		// The algorithm counts every instance of "for(*" with individual letters replacing the star
		// then chooses the letter with the most matches, in order to benefit most from compression
		var log ="Loop variables :\n";
		var indexMatches = new Array(128) ;
		var loopIndexRegExp = /for\((\w)/g;
		var loopIndexResult=loopIndexRegExp.exec(input);
		while (loopIndexResult) {	// get a set with a unique entry for each property
			var code = loopIndexResult[1].charCodeAt(0);
			if (!varsNotReassigned[code]) {	// issue #9 : skip protected variable
				indexMatches[code] = (indexMatches[code]||0)+1;
			}
			loopIndexResult=loopIndexRegExp.exec(input);
		}
		var indexName="i"; // default name
		var maxMatches = 0;
		for (var i=0; i<128; ++i) {
			if (indexMatches[i]>maxMatches) {
				maxMatches = indexMatches[i];
				indexName = String.fromCharCode(i);
			}
		}
		for (var i=0; i<128; ++i) {
			if (indexMatches[i]) {
				log += String.fromCharCode(i)+" *"+indexMatches[i]+(indexName == String.fromCharCode(i)?" <-- selected":"")+"\n";
			}
		}
		if (maxMatches == 0) {
			log += "No relevant loop found, defaulting to "+indexName+"\n";
		}
		log += "\n";
		return [ indexName, log ];
	},

	/**
	 * Defines and returns a packer-friendly name for a new variable.
	 *
	 * It first lists characters used in keywords but not in existing variables.
	 * If none is found, it takes the first character not assigned
	 * to a variable.
	 * If none is available, it returns a two-letter variable.
	 *
	 * @param input the input code to preprocess / pack
	 * @see discriminateKeywordsAndVariables
	 */
	allocateNewVariable : function(input)
	{
		var keywordsAndVariables = this.discriminateKeywordsAndVariables(input);
		var keywordChars = keywordsAndVariables[0];
		var variableChars = keywordsAndVariables[1];

		// first, characters already used by functions, keywords ..
		for (var i=33; i<128; ++i) {
			if (keywordChars[i] && !variableChars[i] && this.isCharAllowedInVariable(i) && !this.isDigit(i)) {
				return String.fromCharCode(i);
			}
		}

		// then, one-letter names not used by variables
		for (var i=33; i<128; ++i) {
			if (!variableChars[i] && this.isCharAllowedInVariable(i) && !this.isDigit(i)) {
				return String.fromCharCode(i);
			}
		}

		// if still not, try two-letter names
		for (var i=97; i<122; ++i) {
			for (var j=97; j<122; ++j) {
				name = String.fromCharCode(i,j);
				if (input.indexOf(name)==-1) {
					return name;
				}
			}
		}

		return "__";
	},

	/**
	 * Identify the characters used in user variable names
	 * and those used in keywords. Unicode characters are not supported.
	 *
	 * The result can be used for renaming variables or to
	 * allocate a new variable name
	 * @see reassignVariableNames
	 * @see allocateNewVariable
	 *
	 * @param input the input code to preprocess / pack
	 * @return array [ keywords, variables ], each is a boolean [128]
	 */
	discriminateKeywordsAndVariables : function(input)
	{
		var variableChars = [];
		var keywordChars = [];
		var previousChar = 0;
		var letterCount = 0;
		var isKeyword = false;
		for (var i=0; i<128; ++i) {
			variableChars[i] = keywordChars[i] = false;
		}
		// Identify characters used in the code :
		//  - those used only in keywords, method names.
		//  - those used as one-letter variable or function names only (and candidates to renaming)
		//  - those used for both variable names and within keywords

		for (var i=0; i<input.length; ++i) {
			var currentChar = input.charCodeAt(i);
			if (currentChar<128) {
				if (this.isCharAllowedInVariable(currentChar)) {
					++letterCount;
					if (letterCount>1) {
						isKeyword=true;
						keywordChars[previousChar]=true;
						keywordChars[currentChar]=true;
					} else {
						if (previousChar == 46) { // character .
							isKeyword=true;
							keywordChars[currentChar]=true;
						}
					}
				} else {
					// only consider one-letter variables or functions.
					// Do not include digits, they are not permitted as one-letter variable names.
					// Do not include in variables if preceded by a dot, which would indicate member variable or function
					if (letterCount==1 && !this.isDigit(previousChar) && !isKeyword) {
						variableChars[previousChar]=true;
					}
					letterCount=0;
					isKeyword=false;
				}
				previousChar=currentChar;
			}
		}
		return [ keywordChars, variableChars];
	},

	/**
	 * Renames one-letter variables in the code, in order to group characters in consecutive blocks as much as possible.
	 * This will leave larger empty blocks for tokens, so that the character class that represents them
	 * in the final regular expression will be shorter : a block is represented by three characters (begin,
	 * dash, end), no matter now many are comprised in between.
	 * This operation does not change the length of the code nor its inner workings.
	 *
	 * The method :
	 * - lists all the one-letter variables in the code
	 * - identifies those using a character that is not otherwise present in classes or keywords
	 *   (meaning that renaming them will actually free the character to use as a token)
	 * - identifies all the characters in use by classes or language keywords
	 * - reassign those to variables, if available (not used by other variables)
	 * - if there are remaining variables in need of a name, fill gaps in the ASCII table, starting with the shortest ones.
	 *   (for instance, if a,c,d,e,g,h are in use, it will assign b and f, since [a-h] is shorter than [ac-egh]
	 *
	 * @param inputData (in/out) PackerData structure containing the setup and the code to process
	 * @param options options set, see below for use details
	 * @return nothing. Result of refactoring is stored in parameter inputData.
	 * Options used are :
	 *  - varsNotReassigned : boolean array[128], true to avoid altering variable
	 */
	reassignVariableNames : function (inputData, options)
	{
		var input = inputData.contents;
		var varsNotReassigned = options.varsNotReassigned;
		var keywordsAndVariables = this.discriminateKeywordsAndVariables(input);
		var keywordChars = keywordsAndVariables[0];
		var variableChars = keywordsAndVariables[1];

		var details = "----------- Renaming variables to optimize RegExp blocks --------\n";
		details += "All variables : ";
		for (var i=32; i<128; ++i) {
			if (variableChars[i]) {
				details+=String.fromCharCode(i);
			}
		}
		details +="\n";

		var availableCharList = "";
		var formerVariableCharList = "";
		var detailsSub1 = "";
		var detailsSub2 = "";
		for (var i=32; i<128; ++i) {
			// Identify as available all characters used in keywords but not variables
			if (keywordChars[i] && !variableChars[i] && !this.isDigit(i)) {
				availableCharList+=String.fromCharCode(i);
				detailsSub1+=String.fromCharCode(i);
			}
			// List all variables that can be reassigned a new name.
			// This excludes those with a one-letter name already used in a keyword (no gain in renaming them)
			// and those explicitely excluded from the process by the user.
			if (variableChars[i] && !keywordChars[i] && !varsNotReassigned[i]) {
				formerVariableCharList+=String.fromCharCode(i);
				detailsSub2+=String.fromCharCode(i);
			}
		}
		if (!availableCharList.length) {
			detailsSub1 = "(none)";
		}
		if (!formerVariableCharList.length) {
			detailsSub2 = "(none)";
		}
		details += "in keywords only : " + detailsSub1 + "\nin variables only : " + detailsSub2 + "\n\n";

		// Prepare to rename variables
		// If we have more variables to rename (characters used as variable names only)
		// than characters available (used in keywords only, but not as variables - yet),
		// we need to allocate more characters, among those not in use :
		//   - either those not used at all in the code
		//   - or those used by variables only (which means not renaming the variable by that name)
		//
		// The algorithm attempts to reduce the block count (i.e. chooses characters in between two blocks, that are thus merged)
		// so that the regular expression for tokens can be as short as possible.
		if (availableCharList.length < formerVariableCharList.length) {
			var lettersNeeded = formerVariableCharList.length - availableCharList.length;

			// identify blocs of unused characters
			var unusedBlocks = [];
			var blockStartsAt = -1;
			for (var i=1; i<128; ++i)
			{
				if (!keywordChars[i] && !varsNotReassigned[i]) {
					// not present in code, or used for naming variables only : add to candidate characters
					// variables not reassigned are not included in the pool (we do not want to rename another variable to that)
					if (blockStartsAt==-1) {
						blockStartsAt = i;
					}
				} else {
					// present in code, ends block if started
					if (blockStartsAt!=-1) {
						unusedBlocks.push( {first:blockStartsAt, nextToLast:i});
						blockStartsAt = -1;
					}
				}
			}

			// There will always be enough characters, since we count those we are trying to eliminate
			// In the worst case, variables will be renamed to themselves, with no loss.
			// Sort the blocks, shortest to longest.
			// Fix for #29 : added tiebreaker (ASCII order) to get a consistent result
			// (weight of 1/1000 so it does not interfere with the main comparison)
			unusedBlocks.sort( function(a,b) { return (a.nextToLast-a.first)-(b.nextToLast-b.first)+.001*(a.first-b.first); } );

			detailsSub1 = "Adding letters : ";
			detailsSub2 = "Not renaming : ";
			var blockIndex = 0;
			while (lettersNeeded) {
				for (var i=unusedBlocks[blockIndex].first;  lettersNeeded>0 && i<unusedBlocks[blockIndex].nextToLast; ++i) {
					if (this.isCharAllowedInVariable(i) && !this.isDigit(i)) {
						var variableName = String.fromCharCode(i);
						var indexInFormerList = formerVariableCharList.indexOf(variableName);
						if (indexInFormerList>-1) {
							// variable name already in use : do not rename it
							formerVariableCharList = formerVariableCharList.substr(0,indexInFormerList)
													+formerVariableCharList.substr(indexInFormerList+1);
							detailsSub2+=variableName;
						} else {
							detailsSub1+=variableName;
							availableCharList+=variableName;
						}
						--lettersNeeded;
					}
				}
				++blockIndex;
			}
			details+=detailsSub1+"\n"+detailsSub2+"\n";

		}
		details += formerVariableCharList.length?"Renaming variables : \n":"No variables to rename.\n";
		var output = input;
		// Perform the replacement inside all relevant strings
		for (var i=0; i<formerVariableCharList.length; ++i)
		{
			var oldVarName = formerVariableCharList[i];
			var exp = new RegExp("(^|[^\\w\\d$_])"+(oldVarName=="$"?"\\":"")+oldVarName,"g");
			output = output.replace(exp, "$1"+availableCharList[i]);
			// Perform the replacement on the code appended by refactorToSetInterval()
			inputData.interpreterCall = inputData.interpreterCall.replace(exp, "$1"+availableCharList[i]);
			inputData.wrappedInit = inputData.wrappedInit.replace(exp, "$1"+availableCharList[i]);

			// replace the packed code holder definition and usage as well
			// (some code is designed to reuse the string - see JsCrush or Impossible Road)
			if (formerVariableCharList[i]==inputData.packedCodeVarName) {
				inputData.packedCodeVarName = availableCharList[i];
			}
			details += "  "+oldVarName+ " => "+availableCharList[i]+"\n";
		}

		// output stored in inputData parameter instead of being returned
		inputData.contents = output;
		inputData.log += details;
	}

}

// Node.js exports (for packer)
if (typeof require !== 'undefined') {
	module.exports = ShapeShifter;
}


text:
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('web3-net'), require('web3-utils'), require('web3-core-helpers'), require('web3-providers'), require('@babel/runtime/helpers/classCallCheck'), require('@babel/runtime/helpers/possibleConstructorReturn'), require('@babel/runtime/helpers/getPrototypeOf'), require('@babel/runtime/helpers/inherits'), require('web3-core-method'), require('@babel/runtime/helpers/createClass'), require('@babel/runtime/helpers/set'), require('@babel/runtime/helpers/get'), require('web3-core')) :
    typeof define === 'function' && define.amd ? define(['exports', 'web3-net', 'web3-utils', 'web3-core-helpers', 'web3-providers', '@babel/runtime/helpers/classCallCheck', '@babel/runtime/helpers/possibleConstructorReturn', '@babel/runtime/helpers/getPrototypeOf', '@babel/runtime/helpers/inherits', 'web3-core-method', '@babel/runtime/helpers/createClass', '@babel/runtime/helpers/set', '@babel/runtime/helpers/get', 'web3-core'], factory) :
    (global = global || self, factory(global.Web3EthPersonal = {}, global.web3Net, global.Utils, global.web3CoreHelpers, global.web3Providers, global._classCallCheck, global._possibleConstructorReturn, global._getPrototypeOf, global._inherits, global.web3CoreMethod, global._createClass, global._set, global._get, global.web3Core));
}(this, function (exports, web3Net, Utils, web3CoreHelpers, web3Providers, _classCallCheck, _possibleConstructorReturn, _getPrototypeOf, _inherits, web3CoreMethod, _createClass, _set, _get, web3Core) { 'use strict';

    _classCallCheck = _classCallCheck && _classCallCheck.hasOwnProperty('default') ? _classCallCheck['default'] : _classCallCheck;
    _possibleConstructorReturn = _possibleConstructorReturn && _possibleConstructorReturn.hasOwnProperty('default') ? _possibleConstructorReturn['default'] : _possibleConstructorReturn;
    _getPrototypeOf = _getPrototypeOf && _getPrototypeOf.hasOwnProperty('default') ? _getPrototypeOf['default'] : _getPrototypeOf;
    _inherits = _inherits && _inherits.hasOwnProperty('default') ? _inherits['default'] : _inherits;
    _createClass = _createClass && _createClass.hasOwnProperty('default') ? _createClass['default'] : _createClass;
    _set = _set && _set.hasOwnProperty('default') ? _set['default'] : _set;
    _get = _get && _get.hasOwnProperty('default') ? _get['default'] : _get;

    var MethodFactory =
    function (_AbstractMethodFactor) {
      _inherits(MethodFactory, _AbstractMethodFactor);
      function MethodFactory(utils, formatters) {
        var _this;
        _classCallCheck(this, MethodFactory);
        _this = _possibleConstructorReturn(this, _getPrototypeOf(MethodFactory).call(this, utils, formatters));
        _this.methods = {
          getAccounts: web3CoreMethod.GetAccountsMethod,
          newAccount: web3CoreMethod.NewAccountMethod,
          unlockAccount: web3CoreMethod.UnlockAccountMethod,
          lockAccount: web3CoreMethod.LockAccountMethod,
          importRawKey: web3CoreMethod.ImportRawKeyMethod,
          sendTransaction: web3CoreMethod.PersonalSendTransactionMethod,
          signTransaction: web3CoreMethod.PersonalSignTransactionMethod,
          sign: web3CoreMethod.PersonalSignMethod,
          ecRecover: web3CoreMethod.EcRecoverMethod
        };
        return _this;
      }
      return MethodFactory;
    }(web3CoreMethod.AbstractMethodFactory);

    var Personal =
    function (_AbstractWeb3Module) {
      _inherits(Personal, _AbstractWeb3Module);
      function Personal(provider, methodFactory, net, utils, formatters, options, nodeNet) {
        var _this;
        _classCallCheck(this, Personal);
        _this = _possibleConstructorReturn(this, _getPrototypeOf(Personal).call(this, provider, options, methodFactory, nodeNet));
        _this.utils = utils;
        _this.formatters = formatters;
        _this.net = net;
        return _this;
      }
      _createClass(Personal, [{
        key: "setProvider",
        value: function setProvider(provider, net) {
          return !!(_get(_getPrototypeOf(Personal.prototype), "setProvider", this).call(this, provider, net) && this.net.setProvider(provider, net));
        }
      }, {
        key: "defaultGasPrice",
        set: function set(value) {
          _set(_getPrototypeOf(Personal.prototype), "defaultGasPrice", value, this, true);
          this.net.defaultGasPrice = value;
        }
        ,
        get: function get() {
          return _get(_getPrototypeOf(Personal.prototype), "defaultGasPrice", this);
        }
      }, {
        key: "defaultGas",
        set: function set(value) {
          _set(_getPrototypeOf(Personal.prototype), "defaultGas", value, this, true);
          this.net.defaultGas = value;
        }
        ,
        get: function get() {
          return _get(_getPrototypeOf(Personal.prototype), "defaultGas", this);
        }
      }, {
        key: "transactionBlockTimeout",
        set: function set(value) {
          _set(_getPrototypeOf(Personal.prototype), "transactionBlockTimeout", value, this, true);
          this.net.transactionBlockTimeout = value;
        }
        ,
        get: function get() {
          return _get(_getPrototypeOf(Personal.prototype), "transactionBlockTimeout", this);
        }
      }, {
        key: "transactionConfirmationBlocks",
        set: function set(value) {
          _set(_getPrototypeOf(Personal.prototype), "transactionConfirmationBlocks", value, this, true);
          this.net.transactionConfirmationBlocks = value;
        }
        ,
        get: function get() {
          return _get(_getPrototypeOf(Personal.prototype), "transactionConfirmationBlocks", this);
        }
      }, {
        key: "transactionPollingTimeout",
        set: function set(value) {
          _set(_getPrototypeOf(Personal.prototype), "transactionPollingTimeout", value, this, true);
          this.net.transactionPollingTimeout = value;
        }
        ,
        get: function get() {
          return _get(_getPrototypeOf(Personal.prototype), "transactionPollingTimeout", this);
        }
      }, {
        key: "defaultAccount",
        set: function set(value) {
          _set(_getPrototypeOf(Personal.prototype), "defaultAccount", value, this, true);
          this.net.defaultAccount = value;
        }
        ,
        get: function get() {
          return _get(_getPrototypeOf(Personal.prototype), "defaultAccount", this);
        }
      }, {
        key: "defaultBlock",
        set: function set(value) {
          _set(_getPrototypeOf(Personal.prototype), "defaultBlock", value, this, true);
          this.net.defaultBlock = value;
        }
        ,
        get: function get() {
          return _get(_getPrototypeOf(Personal.prototype), "defaultBlock", this);
        }
      }]);
      return Personal;
    }(web3Core.AbstractWeb3Module);

    function Personal$1(provider) {
      var net = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      var resolvedProvider = new web3Providers.ProviderResolver().resolve(provider, net);
      return new Personal(resolvedProvider, new MethodFactory(Utils, web3CoreHelpers.formatters), new web3Net.Network(resolvedProvider, null, options), Utils, web3CoreHelpers.formatters, options, null);
    }

    exports.Personal = Personal$1;

    Object.defineProperty(exports, '__esModule', { value: true });

}));

redpajama_set_name: RedPajamaGithub


text:
#ifndef __MISCNODE_CCCLIPPING_RECTANGLE_NODE_H__
#define __MISCNODE_CCCLIPPING_RECTANGLE_NODE_H__

#include "2d/CCNode.h"
#include "renderer/CCCustomCommand.h"
#include "platform/CCGL.h"

NS_CC_BEGIN

/**
 * @addtogroup _2d
 * @{
 */

/**
@brief Clipping Rectangle Node.
@details A node that clipped with specified rectangle.
@js NA
*/
class CC_DLL ClippingRectangleNode : public Node
{
public:
    /**
    @brief Create node with specified clipping region.
    @param clippingRegion Specify the clipping rectangle.
    @return If the creation success, return a pointer of ClippingRectangleNode; otherwise return nil.
    */
    static ClippingRectangleNode* create(const Rect& clippingRegion);
    /**
    @brief Create a clipping rectangle node.
    @return If the creation success, return a pointer of ClippingRectangleNode; otherwise return nil.
    */
    static ClippingRectangleNode* create();

    /**
    @brief Get the clipping rectangle.
    @return The clipping rectangle.
    */
    const Rect& getClippingRegion() const {
        return _clippingRegion;
    }
    /**
    @brief Set the clipping rectangle. The rectangle is base on screen coordinate, so ClippingRectangleNode's region doesn't support any transforms, such as setScale, setRotate and so on.
    @param clippingRegion Specify the clipping rectangle.
    */
    void setClippingRegion(const Rect& clippingRegion);

    /**
    @brief Get whether the clipping is enabled or not.
    @return Whether the clipping is enabled or not. Default is true.
    */
    const bool isClippingEnabled() const {
        return _clippingEnabled;
    }

    /**
    @brief Enable/Disable the clipping.
    @param enabled Pass true to enable clipping. Pass false to disable clipping.
    */
    void setClippingEnabled(bool enabled) {
        _clippingEnabled = enabled;
    }

    //virtual void draw(Renderer* renderer, const Mat4 &transform, uint32_t flags) override;
    virtual void visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags) override;

protected:
    ClippingRectangleNode()
    : _clippingEnabled(true)
    {
    }

    void onBeforeVisitScissor();
    void onAfterVisitScissor();

    Rect _clippingRegion;
    bool _clippingEnabled;

    CustomCommand _beforeVisitCmdScissor;
    CustomCommand _afterVisitCmdScissor;
};

// end of _2d group
/// @}

NS_CC_END

#endif


text:
double static const PMTWEEN_TIMESTEP = 0.0001;

@interface PMTweenPhysicsSystem ()

// The initial velocity value set. Used when resetting the system.
@property (nonatomic, assign) double initialVelocity;

// The last timestamp sent via the solveForPosition:currentTime: method.
@property (nonatomic, assign) double lastTimestamp;

// Boolean value representing whether the physics system is currently paused.
@property (nonatomic, assign) BOOL paused;

@end

@implementation PMTweenPhysicsSystem

+ (instancetype)system {

    PMTweenPhysicsSystem *system = [[PMTweenPhysicsSystem alloc] init];

    return system;
}

- (instancetype)initWithVelocity:(double)velocity friction:(double)friction {

    if (self = [super init]) {
        self.velocity = velocity;
        self.friction = friction;
        _initialVelocity = _velocity;
    }

    return self;

}

#pragma mark - PMTweenPhysicsSolving protocol methods

- (double)solveForPosition:(double)position currentTime:(NSTimeInterval)elapsedTime {
    //NSLog(@"====solveForPosition==================================================");
    //NSLog(@"last %f -- elapsed %f", _lastTimestamp, elapsedTime);

    double new_position = position;
    double previous_position = new_position;

    NSTimeInterval time_delta = elapsedTime - _lastTimestamp;
    time_delta = MAX(0.0, time_delta);
    if (time_delta > 0.2) { time_delta = 0.2; }

    if (!_paused && time_delta > 0.0) {
        if (_lastTimestamp > 0.0) {
            double accumulator = 0.0;

            accumulator += time_delta;

            // in this loop we apply a fixed timestep to the position solver as long as there are steps left in the time delta
            while (accumulator >= PMTWEEN_TIMESTEP) {
                previous_position = new_position;

                // use pow here to compensate for floating point errors over time
                double friction_multiplier = pow(1-_friction, PMTWEEN_TIMESTEP);

                _velocity *= friction_multiplier;

                // add just the portion of current velocity that occurred during this time delta
                new_position += (_velocity * PMTWEEN_TIMESTEP);

                // decrement the accumulator by the fixed timestep amount
                accumulator -= PMTWEEN_TIMESTEP;
            }

            // interpolate the remaining time delta to get the final state of position value
            double blending = accumulator / PMTWEEN_TIMESTEP;
            new_position = new_position * blending + (previous_position * (1.0 - blending));

        }
        _lastTimestamp = elapsedTime;

    }

    return new_position;

}

- (void)reverseDirection {

    self.initialVelocity *= -1;
    _velocity *= -1;
}

- (void)resetSystem {

    _velocity = _initialVelocity;

    [self resumeSystem];

}

- (void)pauseSystem {
    self.paused = YES;
}

- (void)resumeSystem {
    self.lastTimestamp = 0;
    self.paused = NO;
}

#pragma mark - Getter/setters

- (double)velocity {
    return _velocity;
}

- (void)setVelocity:(double)velocity {

    _velocity = velocity;

    if (_initialVelocity == 0.0 || _velocity != 0.0) {
        self.initialVelocity = _velocity;
    }
}

- (double)friction {
    return _friction;
}

- (void)setFriction:(double)friction {
    // if we allowed 0, we'd get divide by zero errors
    // besides with 0 friction our value would sail to the stars with a constant velocity
    _friction = (friction > 0.0) ? friction : 0.000001;
}

@end


text:
require 'bundler/setup'
require 'redis'
require 'logger'
require 'telegram/bot'
require 'dotenv'
Dotenv.load

module TelegramSnitch
  class Base
    class << self
      def redis
	$redis ||= Redis.new(timeout: 0)
      end

      def logger
	$logger ||= Logger.new(File.expand_path("../../log/telegram_snitch.log", __FILE__), 'weekly')
      end

      def telegram_bot
	$telegram_bot ||= Telegram::Bot::Client.new(ENV['BOT_TOKEN'], logger: logger)
      end
    end
  end
end


text:
package com.linkedin.pinot.server.util;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import com.linkedin.pinot.common.data.Schema;
import com.linkedin.pinot.core.data.readers.FileFormat;
import com.linkedin.pinot.core.indexsegment.generator.SegmentGeneratorConfig;
import com.linkedin.pinot.core.indexsegment.generator.SegmentVersion;
import com.linkedin.pinot.core.indexsegment.utils.AvroUtils;

public class SegmentTestUtils {

  public static SegmentGeneratorConfig getSegmentGenSpecWithSchemAndProjectedColumns(File inputAvro, File outputDir,
      TimeUnit timeUnit, String clusterName, Schema inputPinotSchema) throws IOException {
    Schema schema;
    if (inputPinotSchema == null) {
      schema = AvroUtils.extractSchemaFromAvro(inputAvro);
    } else {
      schema = inputPinotSchema;
    }
    SegmentGeneratorConfig segmentGenSpec = new SegmentGeneratorConfig(schema);
    segmentGenSpec.setInputFilePath(inputAvro.getAbsolutePath());
    segmentGenSpec.setSegmentTimeUnit(timeUnit);
    if (inputAvro.getName().endsWith("gz")) {
      segmentGenSpec.setFormat(FileFormat.GZIPPED_AVRO);
    } else {
      segmentGenSpec.setFormat(FileFormat.AVRO);
    }
    segmentGenSpec.setSegmentVersion(SegmentVersion.v1);
    segmentGenSpec.setTableName(clusterName);
    segmentGenSpec.setOutDir(outputDir.getAbsolutePath());
    return segmentGenSpec;
  }
}


text:
#ifndef __ADC_17XX_40XX_H_
#define __ADC_17XX_40XX_H_

#ifdef __cplusplus
extern "C" {
#endif

/** @defgroup ADC_17XX_40XX CHIP:  LPC17xx/40xx A/D conversion driver
 * @ingroup CHIP_17XX_40XX_Drivers
 * @{
 */

#define ADC_ACC_12BITS
#define ADC_TRIM_SUPPORT

#if defined(CHIP_LPC175X_6X)
#define ADC_MAX_SAMPLE_RATE 200000
#else
#define ADC_MAX_SAMPLE_RATE 400000
#endif

/**
 * @brief 10 or 12-bit ADC register block structure
 */
typedef struct {					/*!< ADCn Structure */
	__IO uint32_t CR;				/*!< A/D Control Register. The AD0CR register must be written to select the operating mode before A/D conversion can occur. */
	__I  uint32_t GDR;				/*!< A/D Global Data Register. Contains the result of the most recent A/D conversion. */
	__I  uint32_t RESERVED0;
	__IO uint32_t INTEN;			/*!< A/D Interrupt Enable Register. This register contains enable bits that allow the DONE flag of each A/D channel to be included or excluded from contributing to the generation of an A/D interrupt. */
	__I  uint32_t DR[8];			/*!< A/D Channel Data Register. This register contains the result of the most recent conversion completed on channel n. */
	__I  uint32_t STAT;				/*!< A/D Status Register. This register contains DONE and OVERRUN flags for all of the A/D channels, as well as the A/D interrupt flag. */
#if defined(ADC_TRIM_SUPPORT)
	__IO uint32_t ADTRM;
#endif
} LPC_ADC_T;

/**
 * @brief ADC register support bitfields and mask
 */
#if defined(ADC_ACC_12BITS)
 #define ADC_DR_RESULT(n)        ((((n) >> 4) & 0xFFF))	/*!< Mask for getting the 12 bits ADC data read value */
#else
 #define ADC_DR_RESULT(n)        ((((n) >> 6) & 0x3FF))	/*!< Mask for getting the 10 bits ADC data read value */
 #define ADC_CR_BITACC(n)        ((((n) & 0x7) << 17))	/*!< Number of ADC accuracy bits */
#endif

#define ADC_DR_DONE(n)          (((n) >> 31))			/*!< Mask for reading the ADC done status */
#define ADC_DR_OVERRUN(n)       ((((n) >> 30) & (1UL)))	/*!< Mask for reading the ADC overrun status */
#define ADC_CR_CH_SEL(n)        ((1UL << (n)))			/*!< Selects which of the AD0.0:7 pins is (are) to be sampled and converted */
#define ADC_CR_CLKDIV(n)        ((((n) & 0xFF) << 8))	/*!< The APB clock (PCLK) is divided by (this value plus one) to produce the clock for the A/D */
#define ADC_CR_BURST            ((1UL << 16))			/*!< Repeated conversions A/D enable bit */
#define ADC_CR_PDN              ((1UL << 21))			/*!< ADC convert is operational */
#define ADC_CR_START_MASK       ((7UL << 24))			/*!< ADC start mask bits */
#define ADC_CR_START_MODE_SEL(SEL)  ((SEL << 24))		/*!< Select Start Mode */
#define ADC_CR_START_NOW        ((1UL << 24))			/*!< Start conversion now */
#define ADC_CR_START_CTOUT15    ((2UL << 24))			/*!< Start conversion when the edge selected by bit 27 occurs on CTOUT_15 */
#define ADC_CR_START_CTOUT8     ((3UL << 24))			/*!< Start conversion when the edge selected by bit 27 occurs on CTOUT_8 */
#define ADC_CR_START_ADCTRIG0   ((4UL << 24))			/*!< Start conversion when the edge selected by bit 27 occurs on ADCTRIG0 */
#define ADC_CR_START_ADCTRIG1   ((5UL << 24))			/*!< Start conversion when the edge selected by bit 27 occurs on ADCTRIG1 */
#define ADC_CR_START_MCOA2      ((6UL << 24))			/*!< Start conversion when the edge selected by bit 27 occurs on Motocon PWM output MCOA2 */
#define ADC_CR_EDGE             ((1UL << 27))			/*!< Start conversion on a falling edge on the selected CAP/MAT signal */
#if defined(ADC_ACC_12BITS)
#define ADC_SAMPLE_RATE_CONFIG_MASK         (ADC_CR_CLKDIV(0xFF))
#else
#define ADC_SAMPLE_RATE_CONFIG_MASK         (ADC_CR_CLKDIV(0xFF) | ADC_CR_BITACC(0x07))
#endif

/**
 * @brief	ADC status register used for IP drivers
 */
typedef enum IP_ADC_STATUS {
	ADC_DR_DONE_STAT,	/*!< ADC data register staus */
	ADC_DR_OVERRUN_STAT,/*!< ADC data overrun staus */
	ADC_DR_ADINT_STAT	/*!< ADC interrupt status */
} ADC_STATUS_T;

/** The channels on one ADC peripheral*/
typedef enum CHIP_ADC_CHANNEL {
	ADC_CH0 = 0,	/**< ADC channel 0 */
	ADC_CH1,		/**< ADC channel 1 */
	ADC_CH2,		/**< ADC channel 2 */
	ADC_CH3,		/**< ADC channel 3 */
	ADC_CH4,		/**< ADC channel 4 */
	ADC_CH5,		/**< ADC channel 5 */
	ADC_CH6,		/**< ADC channel 6 */
	ADC_CH7,		/**< ADC channel 7 */
} ADC_CHANNEL_T;

/** Edge configuration, which controls rising or falling edge on the selected signal for the start of a conversion */
typedef enum CHIP_ADC_EDGE_CFG {
	ADC_TRIGGERMODE_RISING = 0,		/**< Trigger event: rising edge */
	ADC_TRIGGERMODE_FALLING,		/**< Trigger event: falling edge */
} ADC_EDGE_CFG_T;

/** Start mode, which controls the start of an A/D conversion when the BURST bit is 0. */
typedef enum CHIP_ADC_START_MODE {
	ADC_NO_START = 0,
	ADC_START_NOW,			/*!< Start conversion now */
	ADC_START_ON_CTOUT15,	/*!< Start conversion when the edge selected by bit 27 occurs on CTOUT_15 */
	ADC_START_ON_CTOUT8,	/*!< Start conversion when the edge selected by bit 27 occurs on CTOUT_8 */
	ADC_START_ON_ADCTRIG0,	/*!< Start conversion when the edge selected by bit 27 occurs on ADCTRIG0 */
	ADC_START_ON_ADCTRIG1,	/*!< Start conversion when the edge selected by bit 27 occurs on ADCTRIG1 */
	ADC_START_ON_MCOA2		/*!< Start conversion when the edge selected by bit 27 occurs on Motocon PWM output MCOA2 */
} ADC_START_MODE_T;

/** Clock setup structure for ADC controller passed to the initialize function */
typedef struct {
	uint32_t adcRate;		/*!< ADC rate */
	uint8_t  bitsAccuracy;	/*!< ADC bit accuracy */
	bool     burstMode;		/*!< ADC Burt Mode */
} ADC_CLOCK_SETUP_T;

/**
 * @brief	Initialize the ADC peripheral and the ADC setup structure to default value
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	ADCSetup	: ADC setup structure to be set
 * @return	Nothing
 * @note	Default setting for ADC is 400kHz - 10bits
 */
void Chip_ADC_Init(LPC_ADC_T *pADC, ADC_CLOCK_SETUP_T *ADCSetup);

/**
 * @brief	Shutdown ADC
 * @param	pADC	: The base of ADC peripheral on the chip
 * @return	Nothing
 */
void Chip_ADC_DeInit(LPC_ADC_T *pADC);

/**
 * @brief	Read the ADC value from a channel
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	channel		: ADC channel to read
 * @param	data		: Pointer to where to put data
 * @return	SUCCESS or ERROR if no conversion is ready
 */
Status Chip_ADC_ReadValue(LPC_ADC_T *pADC, uint8_t channel, uint16_t *data);

/**
 * @brief	Read the ADC value and convert it to 8bits value
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	channel:	selected channel
 * @param	data		: Storage for data
 * @return	Status	: ERROR or SUCCESS
 */
Status Chip_ADC_ReadByte(LPC_ADC_T *pADC, ADC_CHANNEL_T channel, uint8_t *data);

/**
 * @brief	Read the ADC channel status
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	channel		: ADC channel to read
 * @param	StatusType	: Status type of ADC_DR_*
 * @return	SET or RESET
 */
FlagStatus Chip_ADC_ReadStatus(LPC_ADC_T *pADC, uint8_t channel, uint32_t StatusType);

/**
 * @brief	Enable/Disable interrupt for ADC channel
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	channel		: ADC channel to read
 * @param	NewState	: New state, ENABLE or DISABLE
 * @return	SET or RESET
 */
void Chip_ADC_Int_SetChannelCmd(LPC_ADC_T *pADC, uint8_t channel, FunctionalState NewState);

/**
 * @brief	Enable/Disable global interrupt for ADC channel
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	NewState	: New state, ENABLE or DISABLE
 * @return	Nothing
 */
STATIC INLINE void Chip_ADC_Int_SetGlobalCmd(LPC_ADC_T *pADC, FunctionalState NewState)
{
	Chip_ADC_Int_SetChannelCmd(pADC, 8, NewState);
}

/**
 * @brief	Select the mode starting the AD conversion
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	mode		: Stating mode, should be :
 *							- ADC_NO_START				: Must be set for Burst mode
 *							- ADC_START_NOW				: Start conversion now
 *							- ADC_START_ON_CTOUT15		: Start conversion when the edge selected by bit 27 occurs on CTOUT_15
 *							- ADC_START_ON_CTOUT8		: Start conversion when the edge selected by bit 27 occurs on CTOUT_8
 *							- ADC_START_ON_ADCTRIG0		: Start conversion when the edge selected by bit 27 occurs on ADCTRIG0
 *							- ADC_START_ON_ADCTRIG1		: Start conversion when the edge selected by bit 27 occurs on ADCTRIG1
 *							- ADC_START_ON_MCOA2		: Start conversion when the edge selected by bit 27 occurs on Motocon PWM output MCOA2
 * @param	EdgeOption	: Stating Edge Condition, should be :
 *							- ADC_TRIGGERMODE_RISING	: Trigger event on rising edge
 *							- ADC_TRIGGERMODE_FALLING	: Trigger event on falling edge
 * @return	Nothing
 */
void Chip_ADC_SetStartMode(LPC_ADC_T *pADC, ADC_START_MODE_T mode, ADC_EDGE_CFG_T EdgeOption);

/**
 * @brief	Set the ADC Sample rate
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	ADCSetup	: ADC setup structure to be modified
 * @param	rate		: Sample rate, should be set so the clock for A/D converter is less than or equal to 4.5MHz.
 * @return	Nothing
 */
void Chip_ADC_SetSampleRate(LPC_ADC_T *pADC, ADC_CLOCK_SETUP_T *ADCSetup, uint32_t rate);

/**
 * @brief	Enable or disable the ADC channel on ADC peripheral
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	channel		: Channel to be enable or disable
 * @param	NewState	: New state, should be:
 *								- ENABLE
 *								- DISABLE
 * @return	Nothing
 */
void Chip_ADC_EnableChannel(LPC_ADC_T *pADC, ADC_CHANNEL_T channel, FunctionalState NewState);

/**
 * @brief	Enable burst mode
 * @param	pADC		: The base of ADC peripheral on the chip
 * @param	NewState	: New state, should be:
 *							- ENABLE
 *							- DISABLE
 * @return	Nothing
 */
void Chip_ADC_SetBurstCmd(LPC_ADC_T *pADC, FunctionalState NewState);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif /* __ADC_17XX_40XX_H_ */