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

"use strict";

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

/**
 * @typedef {Object} RuleCondition
 * @property {string} property
 * @property {boolean} matchWhenEmpty
 * @property {function(string): boolean} fn
 */

/**
 * @typedef {Object} Condition
 * @property {boolean} matchWhenEmpty
 * @property {function(string): boolean} fn
 */

/**
 * @typedef {Object} CompiledRule
 * @property {RuleCondition[]} conditions
 * @property {(Effect|function(object): Effect[])[]} effects
 * @property {CompiledRule[]=} rules
 * @property {CompiledRule[]=} oneOf
 */

/**
 * @typedef {Object} Effect
 * @property {string} type
 * @property {any} value
 */

/**
 * @typedef {Object} RuleSet
 * @property {Map<string, any>} references map of references in the rule set (may grow over time)
 * @property {function(object): Effect[]} exec execute the rule set
 */

class RuleSetCompiler {
	constructor(plugins) {
		this.hooks = Object.freeze({
			/** @type {SyncHook<[string, object, Set<string>, CompiledRule, Map<string, any>]>} */
			rule: new SyncHook([
				"path",
				"rule",
				"unhandledProperties",
				"compiledRule",
				"references"
			])
		});
		if (plugins) {
			for (const plugin of plugins) {
				plugin.apply(this);
			}
		}
	}

	/**
	 * @param {object[]} ruleSet raw user provided rules
	 * @returns {RuleSet} compiled RuleSet
	 */
	compile(ruleSet) {
		const refs = new Map();
		const rules = this.compileRules("ruleSet", ruleSet, refs);

		/**
		 * @param {object} data data passed in
		 * @param {CompiledRule} rule the compiled rule
		 * @param {Effect[]} effects an array where effects are pushed to
		 * @returns {boolean} true, if the rule has matched
		 */
		const execRule = (data, rule, effects) => {
			for (const condition of rule.conditions) {
				const p = condition.property;
				if (p in data) {
					const value = data[p];
					if (!condition.fn(value)) return false;
				} else if (!condition.matchWhenEmpty) {
					return false;
				}
			}
			for (const effect of rule.effects) {
				if (typeof effect === "function") {
					const returnedEffects = effect(data);
					for (const effect of returnedEffects) {
						effects.push(effect);
					}
				} else {
					effects.push(effect);
				}
			}
			if (rule.rules) {
				for (const childRule of rule.rules) {
					execRule(data, childRule, effects);
				}
			}
			if (rule.oneOf) {
				for (const childRule of rule.oneOf) {
					if (execRule(data, childRule, effects)) {
						break;
					}
				}
			}
			return true;
		};

		return {
			references: refs,
			exec: data => {
				/** @type {Effect[]} */
				const effects = [];
				for (const rule of rules) {
					execRule(data, rule, effects);
				}
				return effects;
			}
		};
	}

	/**
	 * @param {string} path current path
	 * @param {object[]} rules the raw rules provided by user
	 * @param {Map<string, any>} refs references
	 * @returns {CompiledRule[]} rules
	 */
	compileRules(path, rules, refs) {
		return rules.map((rule, i) =>
			this.compileRule(`${path}[${i}]`, rule, refs)
		);
	}

	/**
	 * @param {string} path current path
	 * @param {object} rule the raw rule provided by user
	 * @param {Map<string, any>} refs references
	 * @returns {CompiledRule} normalized and compiled rule for processing
	 */
	compileRule(path, rule, refs) {
		const unhandledProperties = new Set(Object.keys(rule));

		/** @type {CompiledRule} */
		const compiledRule = {
			conditions: [],
			effects: [],
			rules: undefined,
			oneOf: undefined
		};

		this.hooks.rule.call(path, rule, unhandledProperties, compiledRule, refs);

		if (unhandledProperties.has("rules")) {
			unhandledProperties.delete("rules");
			const rules = rule.rules;
			if (!Array.isArray(rules))
				throw this.error(path, rules, "Rule.rules must be an array of rules");
			compiledRule.rules = this.compileRules(`${path}.rules`, rules, refs);
		}

		if (unhandledProperties.has("oneOf")) {
			unhandledProperties.delete("oneOf");
			const oneOf = rule.oneOf;
			if (!Array.isArray(oneOf))
				throw this.error(path, oneOf, "Rule.oneOf must be an array of oneOf");
			compiledRule.oneOf = this.compileRules(`${path}.oneOf`, oneOf, refs);
		}

		if (unhandledProperties.size > 0) {
			throw this.error(
				path,
				rule,
				`Properties ${Array.from(unhandledProperties).join(", ")} are unknown`
			);
		}

		return compiledRule;
	}

	/**
	 * @param {string} path current path
	 * @param {any} condition user provided condition value
	 * @returns {Condition} compiled condition
	 */
	compileCondition(path, condition) {
		if (!condition) {
			throw this.error(
				path,
				condition,
				"Expected condition but got falsy value"
			);
		}
		if (typeof condition === "string") {
			return {
				matchWhenEmpty: condition.length === 0,
				fn: str => str.startsWith(condition)
			};
		}
		if (typeof condition === "function") {
			try {
				return {
					matchWhenEmpty: condition(""),
					fn: condition
				};
			} catch (err) {
				throw this.error(
					path,
					condition,
					"Evaluation of condition function threw error"
				);
			}
		}
		if (condition instanceof RegExp) {
			return {
				matchWhenEmpty: condition.test(""),
				fn: v => condition.test(v)
			};
		}
		if (Array.isArray(condition)) {
			const items = condition.map((c, i) =>
				this.compileCondition(`${path}[${i}]`, c)
			);
			return this.combineConditionsOr(items);
		}

		if (typeof condition !== "object") {
			throw this.error(
				path,
				condition,
				`Unexcepted ${typeof condition} when condition was expected`
			);
		}

		const conditions = [];
		for (const key of Object.keys(condition)) {
			const value = condition[key];
			switch (key) {
				case "or":
					if (value) {
						if (!Array.isArray(value)) {
							throw this.error(
								`${path}.or`,
								condition.and,
								"Expected array of conditions"
							);
						}
						conditions.push(this.compileCondition(`${path}.or`, value));
					}
					break;
				case "and":
					if (value) {
						if (!Array.isArray(value)) {
							throw this.error(
								`${path}.and`,
								condition.and,
								"Expected array of conditions"
							);
						}
						let i = 0;
						for (const item of value) {
							conditions.push(this.compileCondition(`${path}.and[${i}]`, item));
							i++;
						}
					}
					break;
				case "not":
					if (value) {
						const matcher = this.compileCondition(`${path}.not`, value);
						const fn = matcher.fn;
						conditions.push({
							matchWhenEmpty: !matcher.matchWhenEmpty,
							fn: v => !fn(v)
						});
					}
					break;
				default:
					throw this.error(
						`${path}.${key}`,
						condition[key],
						`Unexcepted property ${key} in condition`
					);
			}
		}
		if (conditions.length === 0) {
			throw this.error(
				path,
				condition,
				"Expected condition, but got empty thing"
			);
		}
		return this.combineConditionsAnd(conditions);
	}

	/**
	 * @param {Condition[]} conditions some conditions
	 * @returns {Condition} merged condition
	 */
	combineConditionsOr(conditions) {
		if (conditions.length === 0) {
			return {
				matchWhenEmpty: false,
				fn: () => false
			};
		} else if (conditions.length === 1) {
			return conditions[0];
		} else {
			return {
				matchWhenEmpty: conditions.some(c => c.matchWhenEmpty),
				fn: v => conditions.some(c => c.fn(v))
			};
		}
	}

	/**
	 * @param {Condition[]} conditions some conditions
	 * @returns {Condition} merged condition
	 */
	combineConditionsAnd(conditions) {
		if (conditions.length === 0) {
			return {
				matchWhenEmpty: false,
				fn: () => false
			};
		} else if (conditions.length === 1) {
			return conditions[0];
		} else {
			return {
				matchWhenEmpty: conditions.every(c => c.matchWhenEmpty),
				fn: v => conditions.every(c => c.fn(v))
			};
		}
	}

	/**
	 * @param {string} path current path
	 * @param {any} value value at the error location
	 * @param {string} message message explaning the problem
	 * @returns {Error} an error object
	 */
	error(path, value, message) {
		return new Error(
			`Compiling RuleSet failed: ${message} (at ${path}: ${value})`
		);
	}
}

module.exports = RuleSetCompiler;
<commit_msg>fix typo<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

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

/**
 * @typedef {Object} RuleCondition
 * @property {string} property
 * @property {boolean} matchWhenEmpty
 * @property {function(string): boolean} fn
 */

/**
 * @typedef {Object} Condition
 * @property {boolean} matchWhenEmpty
 * @property {function(string): boolean} fn
 */

/**
 * @typedef {Object} CompiledRule
 * @property {RuleCondition[]} conditions
 * @property {(Effect|function(object): Effect[])[]} effects
 * @property {CompiledRule[]=} rules
 * @property {CompiledRule[]=} oneOf
 */

/**
 * @typedef {Object} Effect
 * @property {string} type
 * @property {any} value
 */

/**
 * @typedef {Object} RuleSet
 * @property {Map<string, any>} references map of references in the rule set (may grow over time)
 * @property {function(object): Effect[]} exec execute the rule set
 */

class RuleSetCompiler {
	constructor(plugins) {
		this.hooks = Object.freeze({
			/** @type {SyncHook<[string, object, Set<string>, CompiledRule, Map<string, any>]>} */
			rule: new SyncHook([
				"path",
				"rule",
				"unhandledProperties",
				"compiledRule",
				"references"
			])
		});
		if (plugins) {
			for (const plugin of plugins) {
				plugin.apply(this);
			}
		}
	}

	/**
	 * @param {object[]} ruleSet raw user provided rules
	 * @returns {RuleSet} compiled RuleSet
	 */
	compile(ruleSet) {
		const refs = new Map();
		const rules = this.compileRules("ruleSet", ruleSet, refs);

		/**
		 * @param {object} data data passed in
		 * @param {CompiledRule} rule the compiled rule
		 * @param {Effect[]} effects an array where effects are pushed to
		 * @returns {boolean} true, if the rule has matched
		 */
		const execRule = (data, rule, effects) => {
			for (const condition of rule.conditions) {
				const p = condition.property;
				if (p in data) {
					const value = data[p];
					if (!condition.fn(value)) return false;
				} else if (!condition.matchWhenEmpty) {
					return false;
				}
			}
			for (const effect of rule.effects) {
				if (typeof effect === "function") {
					const returnedEffects = effect(data);
					for (const effect of returnedEffects) {
						effects.push(effect);
					}
				} else {
					effects.push(effect);
				}
			}
			if (rule.rules) {
				for (const childRule of rule.rules) {
					execRule(data, childRule, effects);
				}
			}
			if (rule.oneOf) {
				for (const childRule of rule.oneOf) {
					if (execRule(data, childRule, effects)) {
						break;
					}
				}
			}
			return true;
		};

		return {
			references: refs,
			exec: data => {
				/** @type {Effect[]} */
				const effects = [];
				for (const rule of rules) {
					execRule(data, rule, effects);
				}
				return effects;
			}
		};
	}

	/**
	 * @param {string} path current path
	 * @param {object[]} rules the raw rules provided by user
	 * @param {Map<string, any>} refs references
	 * @returns {CompiledRule[]} rules
	 */
	compileRules(path, rules, refs) {
		return rules.map((rule, i) =>
			this.compileRule(`${path}[${i}]`, rule, refs)
		);
	}

	/**
	 * @param {string} path current path
	 * @param {object} rule the raw rule provided by user
	 * @param {Map<string, any>} refs references
	 * @returns {CompiledRule} normalized and compiled rule for processing
	 */
	compileRule(path, rule, refs) {
		const unhandledProperties = new Set(Object.keys(rule));

		/** @type {CompiledRule} */
		const compiledRule = {
			conditions: [],
			effects: [],
			rules: undefined,
			oneOf: undefined
		};

		this.hooks.rule.call(path, rule, unhandledProperties, compiledRule, refs);

		if (unhandledProperties.has("rules")) {
			unhandledProperties.delete("rules");
			const rules = rule.rules;
			if (!Array.isArray(rules))
				throw this.error(path, rules, "Rule.rules must be an array of rules");
			compiledRule.rules = this.compileRules(`${path}.rules`, rules, refs);
		}

		if (unhandledProperties.has("oneOf")) {
			unhandledProperties.delete("oneOf");
			const oneOf = rule.oneOf;
			if (!Array.isArray(oneOf))
				throw this.error(path, oneOf, "Rule.oneOf must be an array of rules");
			compiledRule.oneOf = this.compileRules(`${path}.oneOf`, oneOf, refs);
		}

		if (unhandledProperties.size > 0) {
			throw this.error(
				path,
				rule,
				`Properties ${Array.from(unhandledProperties).join(", ")} are unknown`
			);
		}

		return compiledRule;
	}

	/**
	 * @param {string} path current path
	 * @param {any} condition user provided condition value
	 * @returns {Condition} compiled condition
	 */
	compileCondition(path, condition) {
		if (!condition) {
			throw this.error(
				path,
				condition,
				"Expected condition but got falsy value"
			);
		}
		if (typeof condition === "string") {
			return {
				matchWhenEmpty: condition.length === 0,
				fn: str => str.startsWith(condition)
			};
		}
		if (typeof condition === "function") {
			try {
				return {
					matchWhenEmpty: condition(""),
					fn: condition
				};
			} catch (err) {
				throw this.error(
					path,
					condition,
					"Evaluation of condition function threw error"
				);
			}
		}
		if (condition instanceof RegExp) {
			return {
				matchWhenEmpty: condition.test(""),
				fn: v => condition.test(v)
			};
		}
		if (Array.isArray(condition)) {
			const items = condition.map((c, i) =>
				this.compileCondition(`${path}[${i}]`, c)
			);
			return this.combineConditionsOr(items);
		}

		if (typeof condition !== "object") {
			throw this.error(
				path,
				condition,
				`Unexcepted ${typeof condition} when condition was expected`
			);
		}

		const conditions = [];
		for (const key of Object.keys(condition)) {
			const value = condition[key];
			switch (key) {
				case "or":
					if (value) {
						if (!Array.isArray(value)) {
							throw this.error(
								`${path}.or`,
								condition.and,
								"Expected array of conditions"
							);
						}
						conditions.push(this.compileCondition(`${path}.or`, value));
					}
					break;
				case "and":
					if (value) {
						if (!Array.isArray(value)) {
							throw this.error(
								`${path}.and`,
								condition.and,
								"Expected array of conditions"
							);
						}
						let i = 0;
						for (const item of value) {
							conditions.push(this.compileCondition(`${path}.and[${i}]`, item));
							i++;
						}
					}
					break;
				case "not":
					if (value) {
						const matcher = this.compileCondition(`${path}.not`, value);
						const fn = matcher.fn;
						conditions.push({
							matchWhenEmpty: !matcher.matchWhenEmpty,
							fn: v => !fn(v)
						});
					}
					break;
				default:
					throw this.error(
						`${path}.${key}`,
						condition[key],
						`Unexcepted property ${key} in condition`
					);
			}
		}
		if (conditions.length === 0) {
			throw this.error(
				path,
				condition,
				"Expected condition, but got empty thing"
			);
		}
		return this.combineConditionsAnd(conditions);
	}

	/**
	 * @param {Condition[]} conditions some conditions
	 * @returns {Condition} merged condition
	 */
	combineConditionsOr(conditions) {
		if (conditions.length === 0) {
			return {
				matchWhenEmpty: false,
				fn: () => false
			};
		} else if (conditions.length === 1) {
			return conditions[0];
		} else {
			return {
				matchWhenEmpty: conditions.some(c => c.matchWhenEmpty),
				fn: v => conditions.some(c => c.fn(v))
			};
		}
	}

	/**
	 * @param {Condition[]} conditions some conditions
	 * @returns {Condition} merged condition
	 */
	combineConditionsAnd(conditions) {
		if (conditions.length === 0) {
			return {
				matchWhenEmpty: false,
				fn: () => false
			};
		} else if (conditions.length === 1) {
			return conditions[0];
		} else {
			return {
				matchWhenEmpty: conditions.every(c => c.matchWhenEmpty),
				fn: v => conditions.every(c => c.fn(v))
			};
		}
	}

	/**
	 * @param {string} path current path
	 * @param {any} value value at the error location
	 * @param {string} message message explaning the problem
	 * @returns {Error} an error object
	 */
	error(path, value, message) {
		return new Error(
			`Compiling RuleSet failed: ${message} (at ${path}: ${value})`
		);
	}
}

module.exports = RuleSetCompiler;
<|endoftext|>


<commit_before>'use strict';
/* eslint-disable no-console, node/no-extraneous-require, node/no-unpublished-require */
const fs = require('fs');
const path = require('path');
const { shellSync } = require('execa');
// apparently violates no-extraneous require? /shrug
const debug = require('debug')('test-external');
const rimraf = require('rimraf');

const projectRoot = path.resolve(__dirname, '../../');
const externalProjectName = process.argv[2];
const gitUrl = process.argv[3];
const tempDir = path.join(projectRoot, '../__external-test-cache');
const projectTempDir = path.join(tempDir, externalProjectName);

if (!gitUrl) {
  throw new Error(
    'No git url provided to `node ./lib/scripts/test-external`. An https git url should be the first argument.'
  );
} else if (gitUrl.indexOf('https') !== 0) {
  throw new Error(
    `The git url provided to \`node ./lib/scripts/test-external\` should use https. Received '${gitUrl}'`
  );
}

console.log(
  `Preparing to test external project ${externalProjectName} located at ${gitUrl} against this ember-data commit.`
);

function execWithLog(command, force) {
  if (debug.enabled || force) {
    return shellSync(command, { stdio: [0, 1, 2] });
  }

  return shellSync(command);
}

if (!fs.existsSync(tempDir)) {
  fs.mkdirSync(tempDir);
}

if (fs.existsSync(projectTempDir)) {
  rimraf.sync(projectTempDir);
}

// install the project
try {
  execWithLog(
    `cd ../__external-test-cache && git clone --depth=1 ${gitUrl} ./${externalProjectName}`
  );
} catch (e) {
  debug(e);
  throw new Error(
    `Install of ${gitUrl} for external project ${externalProjectName} testing failed.`
  );
}

const useYarn = fs.existsSync(path.join(projectTempDir, 'yarn.lock'));
const useBower = fs.existsSync(path.join(projectTempDir, 'bower.json'));

// install project dependencies and link our local version of ember-data
try {
  execWithLog(
    `${
      useYarn ? 'yarn link' : 'npm link'
    } && cd ../__external-test-cache/${externalProjectName} && ${useYarn ? 'yarn' : 'npm install'}${
      useBower ? ' && bower install' : ''
    }`
  );
} catch (e) {
  debug(e);
  throw new Error(
    `Unable to complete install of dependencies for external project ${externalProjectName}`
  );
}

// run project tests
console.log(`Running tests for ${externalProjectName}`);

let smokeTestPassed = true;
let commitTestPassed = true;

try {
  debug('Running Smoke Test');
  execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`, true);
} catch (e) {
  smokeTestPassed = false;
}

try {
  execWithLog(`${useYarn ? 'yarn link ember-data' : 'npm link ember-data'}`);
} catch (e) {
  debug(e);
  throw new Error(
    `Unable to \`${useYarn ? 'yarn' : 'npm'} link ember-data\` for ${externalProjectName}`
  );
}

try {
  debug('Re-running tests against EmberData commit');
  execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`, true);
} catch (e) {
  commitTestPassed = false;
}

if (!smokeTestPassed && !commitTestPassed) {
  throw new Error(
    `Commit may result in a regression, but the smoke test for ${externalProjectName} also failed.`
  );
} else if (smokeTestPassed && !commitTestPassed) {
  throw new Error(`Commit results in a regression in ${externalProjectName}`);
} else if (!smokeTestPassed) {
  console.log(`Commit may resolve issues present in the smoke test for ${externalProjectName}`);
} else {
  console.log(`Commit does not regress ${externalProjectName}`);
}
<commit_msg>[BUGFIX] ensure external-partner tests correctly symlink<commit_after>'use strict';
/* eslint-disable no-console, node/no-extraneous-require, node/no-unpublished-require */
const fs = require('fs');
const path = require('path');
const { shellSync } = require('execa');
// apparently violates no-extraneous require? /shrug
const debug = require('debug')('test-external');
const rimraf = require('rimraf');

const projectRoot = path.resolve(__dirname, '../../');
const externalProjectName = process.argv[2];
const gitUrl = process.argv[3];
const tempDir = path.join(projectRoot, '../__external-test-cache');
const projectTempDir = path.join(tempDir, externalProjectName);

if (!gitUrl) {
  throw new Error(
    'No git url provided to `node ./lib/scripts/test-external`. An https git url should be the first argument.'
  );
} else if (gitUrl.indexOf('https') !== 0) {
  throw new Error(
    `The git url provided to \`node ./lib/scripts/test-external\` should use https. Received '${gitUrl}'`
  );
}

console.log(
  `Preparing to test external project ${externalProjectName} located at ${gitUrl} against this ember-data commit.`
);

function execExternal(command, force) {
  command = `cd ../__external-test-cache/${externalProjectName} && ${command}`;
  return execWithLog(command, force);
}

function execWithLog(command, force) {
  if (debug.enabled || force) {
    return shellSync(command, { stdio: [0, 1, 2] });
  }

  return shellSync(command);
}

if (!fs.existsSync(tempDir)) {
  fs.mkdirSync(tempDir);
}

if (fs.existsSync(projectTempDir)) {
  rimraf.sync(projectTempDir);
}

// install the project
try {
  execWithLog(`git clone --depth=1 ${gitUrl} ../__external-test-cache/${externalProjectName}`);
} catch (e) {
  debug(e);
  throw new Error(
    `Install of ${gitUrl} for external project ${externalProjectName} testing failed.`
  );
}

const useYarn = fs.existsSync(path.join(projectTempDir, 'yarn.lock'));
const useBower = fs.existsSync(path.join(projectTempDir, 'bower.json'));

// install project dependencies and link our local version of ember-data
try {
  execWithLog(`${useYarn ? 'yarn link' : 'npm link'}`);
  execExternal(`${useYarn ? 'yarn' : 'npm install'}${useBower ? ' && bower install' : ''}`);
} catch (e) {
  debug(e);
  throw new Error(
    `Unable to complete install of dependencies for external project ${externalProjectName}`
  );
}

// run project tests
console.log(`Running tests for ${externalProjectName}`);

let smokeTestPassed = true;
let commitTestPassed = true;

try {
  debug('Running Smoke Test');
  execExternal(`ember test`, true);
} catch (e) {
  smokeTestPassed = false;
}

try {
  execExternal(`${useYarn ? 'yarn link ember-data' : 'npm link ember-data'}`);
} catch (e) {
  debug(e);
  throw new Error(
    `Unable to \`${useYarn ? 'yarn' : 'npm'} link ember-data\` for ${externalProjectName}`
  );
}

try {
  debug('Re-running tests against EmberData commit');
  execExternal(`ember test`, true);
} catch (e) {
  commitTestPassed = false;
}

if (!smokeTestPassed && !commitTestPassed) {
  throw new Error(
    `Commit may result in a regression, but the smoke test for ${externalProjectName} also failed.`
  );
} else if (smokeTestPassed && !commitTestPassed) {
  throw new Error(`Commit results in a regression in ${externalProjectName}`);
} else if (!smokeTestPassed) {
  console.log(`Commit may resolve issues present in the smoke test for ${externalProjectName}`);
} else {
  console.log(`Commit does not regress ${externalProjectName}`);
}
<|endoftext|>


<commit_before>define(['underscore'], function (_) {

    'use strict';

    return {

        getParams: function (request) {
            var params = {},
                reqParams,
                qryParams,
                key;

            if ((reqParams = _.extend(request.params, request.payload ? request.payload : {}))) {
                for (key in reqParams) {
                    params[key] = reqParams[key];
                }
            }
            if ((qryParams = request.query)) {
                for (key in qryParams) {
                    params[key] = qryParams[key];
                }
            }

            return params;
        },

        getCookies: function (request) {
            var cookies = {},
                state;
            if (!(state = request.state)) {
                return cookies;
            }

            for (var key in state) {
                cookies[key] = decodeURIComponent(state[key]);
            }

            return cookies;
        }

    };

});<commit_msg>added back missing util functions<commit_after>define(['underscore'], function (_) {

    'use strict';

    return {

        getParams: function (request) {
            var params = {},
                reqParams,
                qryParams,
                key;

            if ((reqParams = _.extend(request.params, request.payload ? request.payload : {}))) {
                for (key in reqParams) {
                    params[key] = reqParams[key];
                }
            }
            if ((qryParams = request.query)) {
                for (key in qryParams) {
                    params[key] = qryParams[key];
                }
            }

            return params;
        },

        getCookies: function (request) {
            var cookies = {},
                state;
            if (!(state = request.state)) {
                return cookies;
            }

            for (var key in state) {
                cookies[key] = decodeURIComponent(state[key]);
            }

            return cookies;
        },

        getHeaders: function (request) {
            return request.raw.req.headers;
        },

        getParsedUrl: function (request) {
            return request.url;
        }

    };

});<|endoftext|>


<commit_before>'use strict';

const Router = require('./index');
const log = require('../../logger');
const middleware = require('storj-service-middleware');
const farmerMiddleware = require('../middleware/farmer-auth');
const rawBody = require('../middleware/raw-body');
const errors = require('storj-service-error-types');
const StorageModels = require('storj-service-storage-models');
const points = StorageModels.constants.POINTS;
const inherits = require('util').inherits;
const BucketsRouter = require('./buckets');
const constants = require('../../constants');
const async = require('async');
const storj = require('storj-lib');
const limiter = require('../limiter').DEFAULTS;
const utils = require('../../utils');

/**
 * Handles endpoints for reporting
 * @constructor
 * @extends {Router}
 */
function ReportsRouter(options) {
  if (!(this instanceof ReportsRouter)) {
    return new ReportsRouter(options);
  }

  Router.apply(this, arguments);

  this.getLimiter = middleware.rateLimiter(options.redis);
  this.userAuthMiddlewares = middleware.authenticate(this.storage);
}

inherits(ReportsRouter, Router);

ReportsRouter.prototype.authMiddleware = function(req, res, next) {
  const isUser = (req.headers['authorization'] !== undefined ||
                  req.headers['x-pubkey'] !== undefined);
  const isFarmer = (req.headers['x-node-id'] !== undefined);

  if (isUser) {
    this.userAuthMiddlewares[0](req, res, (err) => {
      if (err) {
        return next(err);
      }
      this.userAuthMiddlewares[1](req, res, next);
    });
  } else if (isFarmer) {
    rawBody(req, res, (err) => {
      if (err) {
        return next(err);
      }
      farmerMiddleware.authFarmer(req, res, next)
    });
  } else {
    next(new errors.NotAuthorizedError('No authentication strategy detected'));
  }
};

ReportsRouter.prototype.updateReputation = function(nodeID, points) {
  this.storage.models.Contact.findOne({_id: nodeID}, (err, contact) => {
    if (err || !contact) {
      this._logger.warn('updateReputation: Error trying to find contact ' +
                        ' %s, reason: %s', nodeID, err.message);
      return;
    }
    contact.recordPoints(points).save((err) => {
      if (err) {
        this._logger.warn('updateReputation: Error saving contact ' +
                          ' %s, reason: %s', nodeID, err.message);
      };
    });;
  });
}

ReportsRouter.prototype.validateExchangeReport = function(report) {
  // TODO
}

/**
 * Creates an exchange report
 * @param {http.IncomingMessage} req
 * @param {http.ServerResponse} res
 * @param {Function} next
 */
ReportsRouter.prototype.createExchangeReport = function(req, res, next) {
  const token = req.body.token;

  this.storage.models.StorageEvent.findOne({token: token}, (err, event) => {
    if (err) {
      return next(new errors.InternalError(err.message));
    }

    if (!event) {
      return next(new errors.NotFoundError('Storage event not found'));
    }

    const report = {
      exchangeStart: req.body.exchangeStart,
      exchangeEnd: req.body.exchangeEnd,
      exchangeResultCode: req.body.exchangeResultCode,
      exchangeResultMessage: req.body.exchangeResultMessage
    }

    if (!this.validateExchangeReport(report)) {
      return next(new errors.BadRequestError('Invalid exchange report'));
    }

    const isUserReport = (event.user === req.user.id ||
                          event.user === req.farmerNodeID);
    const isFarmerReport = (event.farmer === req.farmerNodeID);

    if (!isUserReport && !isFarmerReport) {
      return next(new errors.NotAuthorized('Not authorized to report'));
    }

    let modified = false;

    if (isUserReport && !event.userReport) {
      modified = true;
      event.userReport = report
      if (Number(req.body.exchangeResultCode) === 1000) {
        event.success = true;
        this.updateReputation(event.farmer, points.TRANSFER_SUCCESS)
      } else {
        this.updateReputation(event.farmer, points.TRANSFER_FAILURE)
      }
    } else if (isFarmerReport && !event.farmerReport) {
      modified = true;
      event.farmerReport = report
    }

    if (modified) {
      event.save((err) => {
        if (err) {
          return next(new errors.InternalError(err.message));
        }

        // Kick off mirroring if needed
        self._handleExchangeReport({
          dataHash: req.body.dataHash,
          exchangeResultMessage: req.body.exchangeResultMessage
        }, (err) => {
          /* istanbul ignore next */
          if (err) {
            return log.warn(err.message);
          }
        });

        res.status(201).send({});
      });

    } else {
      res.status(200).send({});
    }

  });
};

/**
 * @private
 */
ReportsRouter.prototype._handleExchangeReport = function(report, callback) {
  const {dataHash, exchangeResultMessage} = report;

  switch (exchangeResultMessage) {
    case 'MIRROR_SUCCESS':
    case 'SHARD_UPLOADED':
    case 'DOWNLOAD_ERROR':
      this._triggerMirrorEstablish(constants.M_REPLICATE, dataHash, callback);
      break;
    default:
      callback(new Error('Exchange result type will not trigger action'));
  }
};

ReportsRouter._sortByTimeoutRate = function(a, b) {
  const a1 = a.contact.timeoutRate >= 0 ? a.contact.timeoutRate : 0;
  const b1 = b.contact.timeoutRate >= 0 ? b.contact.timeoutRate : 0;
  return (a1 === b1) ? 0 : (a1 > b1) ? 1 : -1;
};

ReportsRouter._sortByResponseTime = function(a, b) {
  const aTime = a.contact.responseTime || Infinity;
  const bTime = b.contact.responseTime || Infinity;
  return (aTime === bTime) ? 0 : (aTime > bTime) ? 1 : -1;
};

/**
 * Loads some mirrors for the hash and establishes them
 * @private
 */
ReportsRouter.prototype._triggerMirrorEstablish = function(n, hash, done) {
  const self = this;
  let item = null;

  function _loadShard(callback) {
    self.contracts.load(hash, (err, _item) => {
      if (err) {
        return callback(err);
      }
      item = _item;
      callback();
    });
  }

  function _getMirrors(callback) {
    self.storage.models.Mirror.find({ shardHash: hash })
      .populate('contact')
      .exec(callback);
  }

  function _getMirrorCandidate(mirrors, callback) {
    let established = [], available = [];

    mirrors.forEach((m) => {
      if (!m.contact) {
        log.warn('Mirror %s is missing contact in database', m._id);
      } else if (!m.isEstablished) {
        available.push(m);
      } else {
        established.push(m);
      }
    });

    if (available.length === 0) {
      return callback(new Error('No available mirrors'));
    }

    if (established.length >= n) {
      return callback(new Error('Auto mirroring limit is reached'));
    }

    available.sort(utils.sortByReputation);

    callback(null, available.shift());
  }

  function _getRetrievalTokenFromFarmer(mirror, callback) {
    let farmers = Object.keys(item.contracts);
    let pointer = null;
    let test = () => farmers.length === 0 || pointer !== null;
    let contact = storj.Contact(mirror.contact.toObject());

    async.until(test, (done) => {
      self.getContactById(farmers.pop(), (err, result) => {
        if (err) {
          return done();
        }

        let farmer = storj.Contact(result.toObject());

        self.network.getRetrievalPointer(
          farmer,
          item.getContract(farmer),
          (err, result) => {
            // NB: Make sure that we don't set pointer to undefined
            // instead of null that would trigger the until loop to quit
            if (err) {
              log.warn('Unable to get pointer for mirroring, reason: %s',
                       err.message);
            } else {
              pointer = result;
            }
            done();
          }
        );
      });
    }, () => {
      if (!pointer) {
        return callback(new Error('Failed to get pointer'));
      }

      // CREATE STORAGE EVENT HERE
      // token (id) - unique identifier for this event
      // bucket (id)
      // bucketEntry (id)
      // client (user-id)
      // farmer (farmer-id)
      // timestamp (number)
      // downloadBandwidth (number) (nothing)
      // storage (number) (nothing)
      // mirror (number) (add to this)
      // shardHash (id)
      // success (boolean) default false
      // storeEnd (empty)

      callback(null, pointer, mirror, contact);
    });
  }

  function _establishMirror(source, mirror, contact, callback) {
    self.network.getMirrorNodes(
      [source],
      [contact],
      (err) => {
        if (err) {
          return callback(err);
        }

        mirror.isEstablished = true;
        mirror.save();
        item.addContract(contact, storj.Contract(mirror.contract));
        self.contracts.save(item, callback);
      }
    );
  }

  async.waterfall([
    _loadShard,
    _getMirrors,
    _getMirrorCandidate,
    _getRetrievalTokenFromFarmer,
    _establishMirror
  ], done);
};

/**
 * @private
 */
ReportsRouter.prototype.getContactById = BucketsRouter.prototype.getContactById;

/**
 * @private
 */
ReportsRouter.prototype._definitions = function() {
  return [
    ['POST', '/reports/exchanges', this.getLimiter(limiter(1000)), this.authMiddleware.bind(this),
     this.createExchangeReport.bind(this)]
  ];
};

module.exports = ReportsRouter;
<commit_msg>Validate report<commit_after>'use strict';

const Router = require('./index');
const log = require('../../logger');
const middleware = require('storj-service-middleware');
const farmerMiddleware = require('../middleware/farmer-auth');
const rawBody = require('../middleware/raw-body');
const errors = require('storj-service-error-types');
const StorageModels = require('storj-service-storage-models');
const points = StorageModels.constants.POINTS;
const inherits = require('util').inherits;
const BucketsRouter = require('./buckets');
const constants = require('../../constants');
const async = require('async');
const storj = require('storj-lib');
const limiter = require('../limiter').DEFAULTS;
const utils = require('../../utils');

/**
 * Handles endpoints for reporting
 * @constructor
 * @extends {Router}
 */
function ReportsRouter(options) {
  if (!(this instanceof ReportsRouter)) {
    return new ReportsRouter(options);
  }

  Router.apply(this, arguments);

  this.getLimiter = middleware.rateLimiter(options.redis);
  this.userAuthMiddlewares = middleware.authenticate(this.storage);
}

inherits(ReportsRouter, Router);

ReportsRouter.prototype.authMiddleware = function(req, res, next) {
  const isUser = (req.headers['authorization'] !== undefined ||
                  req.headers['x-pubkey'] !== undefined);
  const isFarmer = (req.headers['x-node-id'] !== undefined);

  if (isUser) {
    this.userAuthMiddlewares[0](req, res, (err) => {
      if (err) {
        return next(err);
      }
      this.userAuthMiddlewares[1](req, res, next);
    });
  } else if (isFarmer) {
    rawBody(req, res, (err) => {
      if (err) {
        return next(err);
      }
      farmerMiddleware.authFarmer(req, res, next)
    });
  } else {
    next(new errors.NotAuthorizedError('No authentication strategy detected'));
  }
};

ReportsRouter.prototype.updateReputation = function(nodeID, points) {
  this.storage.models.Contact.findOne({_id: nodeID}, (err, contact) => {
    if (err || !contact) {
      this._logger.warn('updateReputation: Error trying to find contact ' +
                        ' %s, reason: %s', nodeID, err.message);
      return;
    }
    contact.recordPoints(points).save((err) => {
      if (err) {
        this._logger.warn('updateReputation: Error saving contact ' +
                          ' %s, reason: %s', nodeID, err.message);
      };
    });;
  });
}

ReportsRouter.prototype.validateExchangeReport = function(report) {
  if (!Number.isFinite(report.exchangeStart)) {
    return false;
  }
  if (!Number.isFinite(report.exchangeEnd)) {
    return false;
  }

  if (report.exchangeResultCode !== 1100 ||
      report.exchangeResultCode !== 1000 || ) {
    return false;
  }

  const validMessages = [
    'FAILED_INTEGRITY',
    'SHARD_DOWNLOADED',
    'SHARD_UPLOADED',
    'DOWNLOAD_ERROR',
    'TRANSFER_FAILED'
  ];

  if (!validMessages.includes(report.exchangeResultMessage)) {
    return false;
  }

  return true;
}

/**
 * Creates an exchange report
 * @param {http.IncomingMessage} req
 * @param {http.ServerResponse} res
 * @param {Function} next
 */
ReportsRouter.prototype.createExchangeReport = function(req, res, next) {
  const token = req.body.token;

  this.storage.models.StorageEvent.findOne({token: token}, (err, event) => {
    if (err) {
      return next(new errors.InternalError(err.message));
    }

    if (!event) {
      return next(new errors.NotFoundError('Storage event not found'));
    }

    const report = {
      exchangeStart: req.body.exchangeStart,
      exchangeEnd: req.body.exchangeEnd,
      exchangeResultCode: req.body.exchangeResultCode,
      exchangeResultMessage: req.body.exchangeResultMessage
    };

    if (!this.validateExchangeReport(report)) {
      return next(new errors.BadRequestError('Invalid exchange report'));
    }

    const isUserReport = (event.user === req.user.id ||
                          event.user === req.farmerNodeID);
    const isFarmerReport = (event.farmer === req.farmerNodeID);

    if (!isUserReport && !isFarmerReport) {
      return next(new errors.NotAuthorized('Not authorized to report'));
    }

    let modified = false;

    if (isUserReport && !event.userReport) {
      modified = true;
      event.userReport = report;
      if (Number(req.body.exchangeResultCode) === 1000) {
        event.success = true;
        this.updateReputation(event.farmer, points.TRANSFER_SUCCESS);
      } else {
        this.updateReputation(event.farmer, points.TRANSFER_FAILURE);
      }
    } else if (isFarmerReport && !event.farmerReport) {
      modified = true;
      event.farmerReport = report;
    }

    if (modified) {
      event.save((err) => {
        if (err) {
          return next(new errors.InternalError(err.message));
        }

        // Kick off mirroring if needed
        self._handleExchangeReport({
          dataHash: req.body.dataHash,
          exchangeResultMessage: req.body.exchangeResultMessage
        }, (err) => {
          /* istanbul ignore next */
          if (err) {
            return log.warn(err.message);
          }
        });

        res.status(201).send({});
      });

    } else {
      res.status(200).send({});
    }

  });
};

/**
 * @private
 */
ReportsRouter.prototype._handleExchangeReport = function(report, callback) {
  const {dataHash, exchangeResultMessage} = report;

  switch (exchangeResultMessage) {
    case 'MIRROR_SUCCESS':
    case 'SHARD_UPLOADED':
    case 'DOWNLOAD_ERROR':
      this._triggerMirrorEstablish(constants.M_REPLICATE, dataHash, callback);
      break;
    default:
      callback(new Error('Exchange result type will not trigger action'));
  }
};

ReportsRouter._sortByTimeoutRate = function(a, b) {
  const a1 = a.contact.timeoutRate >= 0 ? a.contact.timeoutRate : 0;
  const b1 = b.contact.timeoutRate >= 0 ? b.contact.timeoutRate : 0;
  return (a1 === b1) ? 0 : (a1 > b1) ? 1 : -1;
};

ReportsRouter._sortByResponseTime = function(a, b) {
  const aTime = a.contact.responseTime || Infinity;
  const bTime = b.contact.responseTime || Infinity;
  return (aTime === bTime) ? 0 : (aTime > bTime) ? 1 : -1;
};

/**
 * Loads some mirrors for the hash and establishes them
 * @private
 */
ReportsRouter.prototype._triggerMirrorEstablish = function(n, hash, done) {
  const self = this;
  let item = null;

  function _loadShard(callback) {
    self.contracts.load(hash, (err, _item) => {
      if (err) {
        return callback(err);
      }
      item = _item;
      callback();
    });
  }

  function _getMirrors(callback) {
    self.storage.models.Mirror.find({ shardHash: hash })
      .populate('contact')
      .exec(callback);
  }

  function _getMirrorCandidate(mirrors, callback) {
    let established = [], available = [];

    mirrors.forEach((m) => {
      if (!m.contact) {
        log.warn('Mirror %s is missing contact in database', m._id);
      } else if (!m.isEstablished) {
        available.push(m);
      } else {
        established.push(m);
      }
    });

    if (available.length === 0) {
      return callback(new Error('No available mirrors'));
    }

    if (established.length >= n) {
      return callback(new Error('Auto mirroring limit is reached'));
    }

    available.sort(utils.sortByReputation);

    callback(null, available.shift());
  }

  function _getRetrievalTokenFromFarmer(mirror, callback) {
    let farmers = Object.keys(item.contracts);
    let pointer = null;
    let test = () => farmers.length === 0 || pointer !== null;
    let contact = storj.Contact(mirror.contact.toObject());

    async.until(test, (done) => {
      self.getContactById(farmers.pop(), (err, result) => {
        if (err) {
          return done();
        }

        let farmer = storj.Contact(result.toObject());

        self.network.getRetrievalPointer(
          farmer,
          item.getContract(farmer),
          (err, result) => {
            // NB: Make sure that we don't set pointer to undefined
            // instead of null that would trigger the until loop to quit
            if (err) {
              log.warn('Unable to get pointer for mirroring, reason: %s',
                       err.message);
            } else {
              pointer = result;
            }
            done();
          }
        );
      });
    }, () => {
      if (!pointer) {
        return callback(new Error('Failed to get pointer'));
      }

      // CREATE STORAGE EVENT HERE
      // token (id) - unique identifier for this event
      // bucket (id)
      // bucketEntry (id)
      // client (user-id)
      // farmer (farmer-id)
      // timestamp (number)
      // downloadBandwidth (number) (nothing)
      // storage (number) (nothing)
      // mirror (number) (add to this)
      // shardHash (id)
      // success (boolean) default false
      // storeEnd (empty)

      callback(null, pointer, mirror, contact);
    });
  }

  function _establishMirror(source, mirror, contact, callback) {
    self.network.getMirrorNodes(
      [source],
      [contact],
      (err) => {
        if (err) {
          return callback(err);
        }

        mirror.isEstablished = true;
        mirror.save();
        item.addContract(contact, storj.Contract(mirror.contract));
        self.contracts.save(item, callback);
      }
    );
  }

  async.waterfall([
    _loadShard,
    _getMirrors,
    _getMirrorCandidate,
    _getRetrievalTokenFromFarmer,
    _establishMirror
  ], done);
};

/**
 * @private
 */
ReportsRouter.prototype.getContactById = BucketsRouter.prototype.getContactById;

/**
 * @private
 */
ReportsRouter.prototype._definitions = function() {
  return [
    ['POST', '/reports/exchanges', this.getLimiter(limiter(1000)), this.authMiddleware.bind(this),
     this.createExchangeReport.bind(this)]
  ];
};

module.exports = ReportsRouter;
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var clutch = require('extern/clutch');
var templates =  require('./templates');
var db = require('util/db');
var fs = require('util/fs');
var path = require('path');
var gravatar = require('util/gravatar');

function getmodule(name, cb) {
  db.get_package_by_name(name, function(err, module) {
    if (err) {
      res.writeHead(404, {'Content-Type': 'text/plain'});
      res.end('404, unknown module: '+ name);
      return;
    }

    db.get_package_reverse_dependencies(module.name, function(err, reverse_dependencies) {
      if (err) {
        reverse_dependencies = [];
      }
      cb(module, reverse_dependencies);
    });
  });
}

function modinfo(req, res, modname)
{
  getmodule(modname, function(module, reverse_dependencies) {
    function dorender(err, files) {
      var i = 0;
      if (err) {
        res.writeHead(500, {'Content-Type': 'text/plain'});
        res.end('500, messed up module: '+ err);
        return;
      }

      if (module.maintainers) {
        for (i = 0; i != module.maintainers.length; i++){
          var author =  module.maintainers[i];
          if (author.email) {
            author.avatar_url = gravatar.get_gravatar_url(author.email);
          }
          else {
            author.avatar_url = undefined;
          }
        }
      }

      if (module.dependencies) {
        var rep = [];
        for (var k in module.dependencies) {
          if (module.dependencies.hasOwnProperty(k)) {
            rep.unshift({name: k, version: module.dependencies[k]});
          }
        }
        module.dependencies = rep;
      }
      else {
        module.dependencies = [];
      }
      templates.render('module.html', {modname: module._id, files: files, reverse_dependencies: reverse_dependencies,
                                      module: module, debug_plaintext: JSON.stringify(module, null, 4)}, req, res);
    }
    if (!module) {
      res.writeHead(404, {'Content-Type': 'text/plain'});
      res.end('404, module not found: '+ modname);
      return;
    }
    if (module.meta && module.meta.source_files_path) {
      fs.get_path_file_list_array(module.meta.source_files_path, null, dorender);
    }
    else {
      dorender(undefined, undefined);
    }
  });
}

function modlist(req, res)
{
  db.get_packages_result_array('name', 'asc', function(err, results) {
    if (err) {
      res.writeHead(500, {'Content-Type': 'text/plain'});
      res.end('Err: '+ err);
      return;
    }
    results.sort(function(a_, b_) {
      var a = a_.name.toLowerCase();
      var b = b_.name.toLowerCase();
       if (a < b) {
         return -1;
       }
       if (a > b) {
        return 1;
      }
      return 0;
    });
    templates.render('modules.html', {modules: results}, req, res);
  });
}

function feed(req, res)
{
  db.get_packages_result_array('date_modified', 'desc', function(err, results) {
    if (err) {
      res.writeHead(500, {'Content-Type': 'text/plain'});
      res.end('Err: '+ err);
      return;
    }

    results = results.slice(0, 25);
    templates.render('modules.xml', {'headers': {'Content-type': 'application/rss+xml'}, modules: results}, req, res);
  });
}

exports.urls = clutch.route([
  ['GET /feed\.atom$', feed],
  ['GET /([^/]+)$', modinfo],
  ['GET /$', modlist]
]);
<commit_msg>prevent latest commit fuckup<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var clutch = require('extern/clutch');
var templates =  require('./templates');
var db = require('util/db');
var fs = require('util/fs');
var path = require('path');
var gravatar = require('util/gravatar');

function getmodule(name, cb) {
  db.get_package_by_name(name, function(err, module) {
    if (err) {
      res.writeHead(404, {'Content-Type': 'text/plain'});
      res.end('404, unknown module: '+ name);
      return;
    }

    db.get_package_reverse_dependencies(module.name, function(err, reverse_dependencies) {
      if (err) {
        reverse_dependencies = [];
      }
      cb(module, reverse_dependencies);
    });
  });
}

function modinfo(req, res, modname)
{
  getmodule(modname, function(module, reverse_dependencies) {
    function dorender(err, files) {
      var i = 0;
      if (err) {
        res.writeHead(500, {'Content-Type': 'text/plain'});
        res.end('500, messed up module: '+ err);
        return;
      }

      if (module.maintainers) {
        for (i = 0; i != module.maintainers.length; i++){
          var author =  module.maintainers[i];
          if (author.email) {
            author.avatar_url = gravatar.get_gravatar_url(author.email);
          }
          else {
            author.avatar_url = undefined;
          }
        }
      }

      if (module.dependencies) {
        var rep = [];
        for (var k in module.dependencies) {
          if (module.dependencies.hasOwnProperty(k)) {
            rep.unshift({name: k, version: module.dependencies[k]});
          }
        }
        module.dependencies = rep;
      }
      else {
        module.dependencies = [];
      }
      if (module.latest_commit === null) {
        module.latest_commit = undefined;
      }
      templates.render('module.html', {modname: module._id, files: files, reverse_dependencies: reverse_dependencies,
                                      module: module, debug_plaintext: JSON.stringify(module, null, 4)}, req, res);
    }
    if (!module) {
      res.writeHead(404, {'Content-Type': 'text/plain'});
      res.end('404, module not found: '+ modname);
      return;
    }
    if (module.meta && module.meta.source_files_path) {
      fs.get_path_file_list_array(module.meta.source_files_path, null, dorender);
    }
    else {
      dorender(undefined, undefined);
    }
  });
}

function modlist(req, res)
{
  db.get_packages_result_array('name', 'asc', function(err, results) {
    if (err) {
      res.writeHead(500, {'Content-Type': 'text/plain'});
      res.end('Err: '+ err);
      return;
    }
    results.sort(function(a_, b_) {
      var a = a_.name.toLowerCase();
      var b = b_.name.toLowerCase();
       if (a < b) {
         return -1;
       }
       if (a > b) {
        return 1;
      }
      return 0;
    });
    templates.render('modules.html', {modules: results}, req, res);
  });
}

function feed(req, res)
{
  db.get_packages_result_array('date_modified', 'desc', function(err, results) {
    if (err) {
      res.writeHead(500, {'Content-Type': 'text/plain'});
      res.end('Err: '+ err);
      return;
    }

    results = results.slice(0, 25);
    templates.render('modules.xml', {'headers': {'Content-type': 'application/rss+xml'}, modules: results}, req, res);
  });
}

exports.urls = clutch.route([
  ['GET /feed\.atom$', feed],
  ['GET /([^/]+)$', modinfo],
  ['GET /$', modlist]
]);
<|endoftext|>


<commit_before>var Utils = require('../../utils');

var OPERATORS = {
  not: '!=',
  gt: '>',
  gte: '=>',
  lt: '<',
  lte: '=<',
  like: 'like',
  not_like: 'not like',
  between: 'between',
  ilike: 'ilike'
};

/*
 * MODEL
 */
exports.model = {
  find: function(){
    var args = Utils.args(arguments);
    var primary_keys = this.definition.primary_keys;

    var where = {};
    var callback;
    var find_one = true;

    if(typeof args[args.length -1] == 'function'){
      callback = args.pop();
    }

    if(args.length == primary_keys.length){
      for(var i = 0; i < primary_keys.length; i++){
        where[primary_keys[i]] = args[i];

        if(args[i] instanceof Array){
          find_one = false;
        }
      }
      args = [where];
    }

    if(callback){
      args.push(callback);
    }

    var self = this.where.apply(this, args);
    if(find_one) self.limit(1);

    return self;
  },

  where: function(){
    var self = this.chain();
    var args = Utils.args(arguments);

    var callback;

    if(typeof args[args.length -1] == 'function'){
      callback = args.pop();
    }

    var sanitize = function(conditions, table){

      if(conditions[0] instanceof Array){
        return sanitize(conditions[0], table);
      }

      var model = self.definition.store.getByTableName(table);

      //if we use something like ["login = ?", "phil"]
      if(typeof conditions[0] == 'string'){
        var query = conditions.shift();
        var args = conditions;
        if(args.length == 1 && typeof args[0] == 'object' && !(args[0] instanceof Array)){

          //if we use ["login = :login", {login:"phil"}]
          var values = conditions[0];
          var tmp = [];
          args = [];
          query = query.replace(/\:(\w+)/g, function(result, field){
            args.push(values[field]);
            return '?';
          });
        }

        self.addInternal('conditions', {type:'raw', query:query, args:args});

      }else{

        //if we use {login:'phil'} or {login_like:'phil'}
        for(var i in conditions){
          for(var name in conditions[i]){
            if(typeof conditions[i][name] == 'object' && !(conditions[i][name] instanceof Array)){
              sanitize([conditions[i][name]], name);
            }else{
              var tmp = name.match(
                new RegExp('(.+?)(_(' + Object.keys(OPERATORS).join('|') + ')|)$', 'i')
              );

              self.addInternal('conditions', {
                type:'hash',
                table: table,
                field: tmp[1],
                operator: OPERATORS[tmp[3]] || '=',
                value: model ? model.definition.cast(tmp[1], conditions[i][name]) : conditions[i][name]
              });
            }
          }
        }
      }
    };

    sanitize(args, self.definition.table_name);

    if(callback){
      self.exec(callback);
    }

    return self;
  }

};

/*
 * DEFINITION
 */
exports.definition = {
  mixinCallback: function(){

    this.beforeFind(function(query){
      var conditions = this.getInternal('conditions') || [];

      for(var i in conditions){
        if(conditions[i].type == 'raw'){
          query.whereRaw(conditions[i].query, conditions[i].args);
        }else{
          var name = conditions[i].field;
          var table = conditions[i].table;
          var value = conditions[i].value;
          var operator = conditions[i].operator;

          if(value instanceof Array){
            if(operator == '!='){
              query.whereNotIn(table + '.' + name, value);
            }else{
              if(operator == '='){
                query.whereIn(table + '.' + name, value);
              }else{
                query.where(function(){
                  for(var i in value){
                    this.orWhere(table + '.' + name, operator, value[i]);
                  }
                });
              }
            }
          }else{
            query.where(table + '.' + name, operator, value);
          }
        }
      }

      return true;
    });

  }

};<commit_msg>attr_like: [] bugfix<commit_after>var Utils = require('../../utils');

var OPERATORS = {
  not: '!=',
  gt: '>',
  gte: '=>',
  lt: '<',
  lte: '=<',
  like: 'like',
  not_like: 'not like',
  between: 'between',
  ilike: 'ilike'
};

/*
 * MODEL
 */
exports.model = {
  find: function(){
    var args = Utils.args(arguments);
    var primary_keys = this.definition.primary_keys;

    var where = {};
    var callback;
    var find_one = true;

    if(typeof args[args.length -1] == 'function'){
      callback = args.pop();
    }

    if(args.length == primary_keys.length){
      for(var i = 0; i < primary_keys.length; i++){
        where[primary_keys[i]] = args[i];

        if(args[i] instanceof Array){
          find_one = false;
        }
      }
      args = [where];
    }

    if(callback){
      args.push(callback);
    }

    var self = this.where.apply(this, args);
    if(find_one) self.limit(1);

    return self;
  },

  where: function(){
    var self = this.chain();
    var args = Utils.args(arguments);

    var callback;

    if(typeof args[args.length -1] == 'function'){
      callback = args.pop();
    }

    var sanitize = function(conditions, table){

      if(conditions[0] instanceof Array){
        return sanitize(conditions[0], table);
      }

      var model = self.definition.store.getByTableName(table);

      //if we use something like ["login = ?", "phil"]
      if(typeof conditions[0] == 'string'){
        var query = conditions.shift();
        var args = conditions;
        if(args.length == 1 && typeof args[0] == 'object' && !(args[0] instanceof Array)){

          //if we use ["login = :login", {login:"phil"}]
          var values = conditions[0];
          var tmp = [];
          args = [];
          query = query.replace(/\:(\w+)/g, function(result, field){
            args.push(values[field]);
            return '?';
          });
        }

        self.addInternal('conditions', {type:'raw', query:query, args:args});

      }else{

        //if we use {login:'phil'} or {login_like:'phil'}
        for(var i in conditions){
          for(var name in conditions[i]){
            if(typeof conditions[i][name] == 'object' && !(conditions[i][name] instanceof Array)){
              sanitize([conditions[i][name]], name);
            }else{
              var tmp = name.match(
                new RegExp('(.+?)(_(' + Object.keys(OPERATORS).join('|') + ')|)$', 'i')
              );

              var value = conditions[i][name];
              if(tmp[3] == 'like' || tmp[3] == 'not_like' || tmp[3] == 'ilike'){
                if(value instanceof Array){
                  value = value.map(function(val){
                    return '%' + val + '%';
                  });
                }else{
                  value = '%' + value + '%';
                }
              }

              self.addInternal('conditions', {
                type:'hash',
                table: table,
                field: tmp[1],
                operator: OPERATORS[tmp[3]] || '=',
                value: model ? model.definition.cast(tmp[1], value) : value
              });
            }
          }
        }
      }
    };

    sanitize(args, self.definition.table_name);

    if(callback){
      self.exec(callback);
    }

    return self;
  }

};

/*
 * DEFINITION
 */
exports.definition = {
  mixinCallback: function(){

    this.beforeFind(function(query){
      var conditions = this.getInternal('conditions') || [];

      for(var i in conditions){
        if(conditions[i].type == 'raw'){
          query.whereRaw(conditions[i].query, conditions[i].args);
        }else{
          var name = conditions[i].field;
          var table = conditions[i].table;
          var value = conditions[i].value;
          var operator = conditions[i].operator;

          if(value instanceof Array){
            if(operator == '!='){
              query.whereNotIn(table + '.' + name, value);
            }else{
              if(operator == '='){
                query.whereIn(table + '.' + name, value);
              }else{
                query.where(function(){
                  for(var i in value){
                    this.orWhere(table + '.' + name, operator, value[i]);
                  }
                });
              }
            }
          }else{
            query.where(table + '.' + name, operator, value);
          }
        }
      }

      return true;
    });

  }

};<|endoftext|>


<commit_before>var torque = require('../');
var cartocss = require('./cartocss_render');
var Profiler = require('../profiler');
var carto = global.carto || require('carto');

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  var COMP_OP_TO_CANVAS = {
    "src": 'source-over',
    "src-over": 'source-over',
    "dst-over": 'destination-over',
    "src-in": 'source-in',
    "dst-in": 'destination-in',
    "src-out": 'source-out',
    "dst-out": 'destination-out',
    "src-atop": 'source-atop',
    "dst-atop": 'destination-atop',
    "xor": 'xor',
    "darken": 'darken',
    "lighten": 'lighten'
  }

  function compop2canvas(compop) {
    return COMP_OP_TO_CANVAS[compop] || compop;
  }

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
    this._icons = {};
  }

  PointRenderer.prototype = {

    clearCanvas: function() {
      var canvas = this._canvas;
      var color = this._Map['-torque-clear-color']
      // shortcut for the default value
      if (color  === "rgba(255, 255, 255, 0)" || !color) {
        this._canvas.width = this._canvas.width;
      } else {
        var ctx = this._ctx;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        var compop = this._Map['comp-op']
        ctx.globalCompositeOperation = compop2canvas(compop);
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }
    },

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
      this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle({
        value: value
      }, shaderVars);

      var pointSize = st['marker-width'];
      if (!pointSize) {
        return null;
      }

      if (st['marker-opacity'] === 0 && !st['marker-line-opacity']) {
        return null;
      }

      var canvas = this._createCanvas();
      // take into account the exterior ring to calculate the size
      var canvasSize = (st['marker-line-width'] || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);
      var img_name = st['point-file'] || st['marker-file'];
      if(img_name) {
        if(!(img_name in this._icons)){
          var new_img = new Image();
          new_img.src = img_name;
          this._icons[img_name] = new_img;
        }
        var img = this._icons[img_name];
        img.w = st['marker-width'] || img.width;
        img.h = st['marker-width'] || st['marker-height'];
        cartocss.renderSprite(ctx, img);
      } else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          cartocss.renderRectangle(ctx, st);
        } else {
          cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      if (torque.flags.sprites_to_images) {
        var i = this._createImage();
        i.src = canvas.toDataURL();
        return i;
      }
      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    _createCanvas: function() {
      return this.options.canvasClass
        ? new this.options.canvasClass()
        : document.createElement('canvas');
    },

    _createImage: function() {
      return this.options.imageClass
        ? new this.options.imageClass()
        : new Image();
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1);
             var y = tileMax - tile.y[posIdx]; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    }

  };

  // exports public api
module.exports = PointRenderer;
<commit_msg>adds icon preload before animation<commit_after>var torque = require('../');
var cartocss = require('./cartocss_render');
var Profiler = require('../profiler');
var carto = global.carto || require('carto');

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  var COMP_OP_TO_CANVAS = {
    "src": 'source-over',
    "src-over": 'source-over',
    "dst-over": 'destination-over',
    "src-in": 'source-in',
    "dst-in": 'destination-in',
    "src-out": 'source-out',
    "dst-out": 'destination-out',
    "src-atop": 'source-atop',
    "dst-atop": 'destination-atop',
    "xor": 'xor',
    "darken": 'darken',
    "lighten": 'lighten'
  }

  function compop2canvas(compop) {
    return COMP_OP_TO_CANVAS[compop] || compop;
  }

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
    this._icons = {};
    this._preloadIcons();
  }

  PointRenderer.prototype = {

    clearCanvas: function() {
      var canvas = this._canvas;
      var color = this._Map['-torque-clear-color']
      // shortcut for the default value
      if (color  === "rgba(255, 255, 255, 0)" || !color) {
        this._canvas.width = this._canvas.width;
      } else {
        var ctx = this._ctx;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        var compop = this._Map['comp-op']
        ctx.globalCompositeOperation = compop2canvas(compop);
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }
    },

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
      this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle({
        value: value
      }, shaderVars);

      var pointSize = st['marker-width'];
      if (!pointSize) {
        return null;
      }

      if (st['marker-opacity'] === 0 && !st['marker-line-opacity']) {
        return null;
      }

      var canvas = this._createCanvas();
      // take into account the exterior ring to calculate the size
      var canvasSize = (st['marker-line-width'] || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);
      var img_name = st['point-file'] || st['marker-file'];
      if(img_name) {

        var img = this._icons[img_name];
        img.w = st['marker-width'] || img.width;
        img.h = st['marker-width'] || st['marker-height'];
        cartocss.renderSprite(ctx, img);
      } else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          cartocss.renderRectangle(ctx, st);
        } else {
          cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      if (torque.flags.sprites_to_images) {
        var i = this._createImage();
        i.src = canvas.toDataURL();
        return i;
      }
      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    _createCanvas: function() {
      return this.options.canvasClass
        ? new this.options.canvasClass()
        : document.createElement('canvas');
    },

    _createImage: function() {
      return this.options.imageClass
        ? new this.options.imageClass()
        : new Image();
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1);
             var y = tileMax - tile.y[posIdx]; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    },
    _preloadIcons: function(){
      var img_name = this._shader.layers[1].shader["marker-file"];
      var imagesToLoad = 1;
      if(img_name && !(img_name in this._icons)){
        var new_img = new Image();
        new_img.onload(function(){
          imagesToLoad--;
          if(imagesToLoad == 0){
            this.fire("iconsloaded");
          }
        });
        new_img.src = img_name;
        this._icons[img_name] = new_img;
      }
      else{
        this.fire("iconsloaded");
      }

      // TODO: get icons for conditional styles too
      // if (typeof obj["marker-file"] !== 'undefined'){
      //   iconFiles.push(obj["marker-file"]);
      // }
      // for(var i = 0; i< layers.length){

      // }
      // }
    }

  };

  // exports public api
module.exports = PointRenderer;
<|endoftext|>


<commit_before>(function(exports) {
  exports.torque = exports.torque || {};
  exports.torque.renderer = exports.torque.renderer || {};

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
  }

  PointRenderer.prototype = {

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle('canvas-2d', {
        value: value
      }, shaderVars);

      var pointSize = st['point-radius'];
      if (!pointSize) {
        return null;
      }

      if (st.fillOpacity === 0 && !st.strokeOpacity) {
        return null;
      }

      var canvas = document.createElement('canvas');

      // take into account the exterior ring to calculate the size
      var canvasSize = (st.lineWidth || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      if(st['point-file'] || st['marker-file']) {
        torque.cartocss.renderSprite(ctx, st);
      } else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          torque.cartocss.renderRectangle(ctx, st);
        } else {
          torque.cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      var i = new Image();
      i.src = canvas.toDataURL();
      return i;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = shader.eval('comp-op') || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, _.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1);
             var y = tileMax - tile.y[posIdx]; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    }

  };

  // exports public api
  exports.torque.renderer.Point = PointRenderer;

})(typeof exports === "undefined" ? this : exports);
<commit_msg>don't use dump to images when using safari<commit_after>(function(exports) {
  exports.torque = exports.torque || {};
  exports.torque.renderer = exports.torque.renderer || {};

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
  }

  PointRenderer.prototype = {

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle('canvas-2d', {
        value: value
      }, shaderVars);

      var pointSize = st['point-radius'];
      if (!pointSize) {
        return null;
      }

      if (st.fillOpacity === 0 && !st.strokeOpacity) {
        return null;
      }

      var canvas = document.createElement('canvas');

      // take into account the exterior ring to calculate the size
      var canvasSize = (st.lineWidth || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      if(st['point-file'] || st['marker-file']) {
        torque.cartocss.renderSprite(ctx, st);
      } else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          torque.cartocss.renderRectangle(ctx, st);
        } else {
          torque.cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      if (torque.flags.sprites_to_images) {
        var i = new Image();
        i.src = canvas.toDataURL();
        return i;
      }
      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = shader.eval('comp-op') || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, _.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1);
             var y = tileMax - tile.y[posIdx]; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    }

  };

  // exports public api
  exports.torque.renderer.Point = PointRenderer;

})(typeof exports === "undefined" ? this : exports);
<|endoftext|>


<commit_before>// This transport generally works in any browser, but will cause a
// spinning cursor to appear in any browser other than IE.
// We may test this transport in all browsers - why not, but in
// production it should be only run in IE.

var HtmlFileIframeTransport = SockJS['iframe-htmlfile'] = function () {
    var that = this;
    that.protocol = 'w-iframe-htmlfile';
    that.i_constructor.apply(that, arguments);
};

// Inheritance.
HtmlFileIframeTransport.prototype = new IframeTransport();

HtmlFileIframeTransport.enabled = function (options) {
    // Development or IE  _and_  iframe postWindow working.
    var ie = isIeHtmlfileCapable();
    return (options.devel || ie) && IframeTransport.enabled();
};

var HtmlFileTransport = FacadeJS['w-iframe-htmlfile'] = function (ri, trans_url) {
    utils.polluteGlobalNamespace();

    var that = this;
    that.trans_url = trans_url;
    that.send_constructor(ajaxSender);
    that.poll = new Polling(ri, HtmlfileReceiver, trans_url + '/htmlfile');
};

// Inheritnace
HtmlFileTransport.prototype = new BufferedSender();

HtmlFileTransport.prototype.doCleanup = function() {
    var that = this;
    if (that.poll) {
        that.poll.abort();
        that.poll = null;
    }
};
<commit_msg>No need for that, polluting is already done in the HtmlfileReceiver constructor.<commit_after>// This transport generally works in any browser, but will cause a
// spinning cursor to appear in any browser other than IE.
// We may test this transport in all browsers - why not, but in
// production it should be only run in IE.

var HtmlFileIframeTransport = SockJS['iframe-htmlfile'] = function () {
    var that = this;
    that.protocol = 'w-iframe-htmlfile';
    that.i_constructor.apply(that, arguments);
};

// Inheritance.
HtmlFileIframeTransport.prototype = new IframeTransport();

HtmlFileIframeTransport.enabled = function (options) {
    // Development or IE  _and_  iframe postWindow working.
    var ie = isIeHtmlfileCapable();
    return (options.devel || ie) && IframeTransport.enabled();
};

var HtmlFileTransport = FacadeJS['w-iframe-htmlfile'] = function (ri, trans_url) {
    var that = this;
    that.trans_url = trans_url;
    that.send_constructor(ajaxSender);
    that.poll = new Polling(ri, HtmlfileReceiver, trans_url + '/htmlfile');
};

// Inheritnace
HtmlFileTransport.prototype = new BufferedSender();

HtmlFileTransport.prototype.doCleanup = function() {
    var that = this;
    if (that.poll) {
        that.poll.abort();
        that.poll = null;
    }
};
<|endoftext|>