<commit_before>// Copyright 2017-2022, University of Colorado Boulder

/**
 * Runs the lint rules on the specified files.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

// modules
const _ = require( 'lodash' ); // eslint-disable-line require-statement-match
const { ESLint } = require( 'eslint' ); // eslint-disable-line
const fs = require( 'fs' );
const path = require( 'path' );
const grunt = require( 'grunt' );
const crypto = require( 'crypto' );

// constants
const EXCLUDE_PATTERNS = [ // patterns that have no code that should be linted

  '../babel',
  '../decaf',
  '../phet-android-app',
  '../phet-info',
  '../phet-io-client-guides',
  '../phet-io-website',
  '../phet-io-wrapper-arithmetic',
  '../phet-io-wrapper-hookes-law-energy',
  '../phet-ios-app',
  '../qa',
  '../smithers',
  '../tasks'
];

/**
 * Lints the specified repositories.
 * @public
 *
 * @returns {Promise} - results from linting files, see ESLint.lintFiles
 */
const lint = async ( patterns, options ) => {

  options = _.assignIn( {
    cache: true,
    format: false, // append an extra set of rules for formatting code.
    fix: false, // whether fixes should be written to disk
    warn: true, // whether errors should reported with grunt.warn
    typeInfo: false, // (for typescript) whether to include eslint rules that require project info, much slower
    chipAway: false // returns responsible dev info for easier chipping.
  }, options );

  // filter out all unlintable pattern. An unlintable repo is one that has no `js` in it, so it will fail when trying to
  // lint it.  Also, if the user doesn't have some repos checked out, those should be skipped
  patterns = patterns.filter( pattern => !EXCLUDE_PATTERNS.includes( pattern ) &&
                                         fs.existsSync( pattern ) );

  const hash = crypto.createHash( 'md5' )
    .update( patterns.join( ',' ) )
    .digest( 'hex' );

  const eslintConfig = {

    // optional auto-fix
    fix: options.fix,

    // Caching only checks changed files or when the list of rules is changed.  Changing the implementation of a
    // custom rule does not invalidate the cache.  Caches are declared in .eslintcache files in the directory where
    // grunt was run from.
    cache: options.cache,

    // Where to store the target-specific cache file
    cacheLocation: `../chipper/eslint/cache/${hash}.eslintcache`,

    ignorePath: '../chipper/eslint/.eslintignore',

    resolvePluginsRelativeTo: '../chipper/',

    // Our custom rules live here
    rulePaths: [ '../chipper/eslint/rules' ],

    extensions: [ '.js', '.ts' ]
  };

  const config = {};
  const configExtends = [];
  if ( options.format ) {
    configExtends.push( '../chipper/eslint/format_eslintrc.js' );
  }
  if ( options.typeInfo ) {
    if ( patterns.length !== 1 ) {
      grunt.fail.warn( 'typeInfo can only work for one repository at a time' );
    }

    // include the rules that use type information
    configExtends.push( '../chipper/eslint/type_info_eslintrc.js' );

    // signify where the project configuration lives for this repo - if we apply this to all files
    // ESLint complains that .js files are not in project configurations
    config.overrides = [ {
      files: [
        '**/*.ts'
      ],
      parserOptions: {
        project: [ `${patterns[ 0 ]}/tsconfig.json` ]
      }
    } ];
  }

  config.extends = configExtends;
  eslintConfig.baseConfig = config;

  const eslint = new ESLint( eslintConfig );

  grunt.verbose.writeln( `linting: ${patterns.join( ', ' )}` );

  // 2. Lint files. This doesn't modify target files.
  const results = await eslint.lintFiles( patterns );

  // 3. Modify the files with the fixed code.
  if ( options.fix ) {
    await ESLint.outputFixes( results );
  }

  // 4. Parse the results.
  const totalWarnings = _.sum( results.map( result => result.warningCount ) );
  const totalErrors = _.sum( results.map( result => result.errorCount ) );

  // 5. Output results on errors.
  if ( totalWarnings + totalErrors > 0 ) {
    const formatter = await eslint.loadFormatter( 'stylish' );
    const resultText = formatter.format( results );
    console.log( resultText );
    // TODO: Add documentation & refactor see: https://github.com/phetsims/chipper/issues/1253
    if ( options.chipAway ) {
      const repos = results.map( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] );
      const uniqueRepos = _.uniq( repos ).filter( repo => repo !== 'perennial-alias' );

      // NOTE: This should never be run in a maintenance mode since this loads a file from phet-info which
      // does not have its SHA tracked as a dependency.
      // TODO: For the reviewer, is this OK? https://github.com/phetsims/chipper/issues/1253
      const responsibleDevs = JSON.parse( fs.readFileSync( '../phet-info/sim-info/responsible_dev.json' ) );
      const reposWithErrors = uniqueRepos.filter( repo => {
        const filteredResults = results.filter( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] === repo );
        const errorCount = _.sum( filteredResults.map( file => file.errorCount + file.warningCount ) );

        return errorCount > 0;
      } );

      const assignments = reposWithErrors.map( repo => {
        const filteredResults = results.filter( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] === repo );
        const fileCount = filteredResults.filter( result => result.errorCount + result.warningCount > 0 ).length;
        const errorCount = _.sum( filteredResults.map( file => file.errorCount + file.warningCount ) );

        return ` - [ ] ${repo}: ${responsibleDevs[ repo ].responsibleDevs.join( ', ' )} ${errorCount} errors in ${fileCount} files.`;
      } );

      console.log( assignments.join( '\n' ) );
    }

    options.warn && grunt.fail.warn( `${totalErrors} errors and ${totalWarnings} warnings` );
  }

  return results;
};

// Mark the version so that the pre-commit hook will only try to use the promise-based API, this means
// it won't run lint precommit hook on SHAs before the promise-based API
lint.chipperAPIVersion = 'promises1';

module.exports = lint;<commit_msg>Address memory leaks and strings, see: https://github.com/phetsims/mean-share-and-balance/issues/3<commit_after>// Copyright 2017-2022, University of Colorado Boulder

/**
 * Runs the lint rules on the specified files.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

// modules
const _ = require( 'lodash' ); // eslint-disable-line require-statement-match
const { ESLint } = require( 'eslint' ); // eslint-disable-line
const fs = require( 'fs' );
const path = require( 'path' );
const grunt = require( 'grunt' );
const crypto = require( 'crypto' );

// constants
const EXCLUDE_PATTERNS = [ // patterns that have no code that should be linted

  '../babel',
  '../decaf',
  '../phet-android-app',
  '../phet-info',
  '../phet-io-client-guides',
  '../phet-io-website',
  '../phet-io-wrapper-arithmetic',
  '../phet-io-wrapper-hookes-law-energy',
  '../phet-ios-app',
  '../qa',
  '../smithers',
  '../tasks'
];

/**
 * Lints the specified repositories.
 * @public
 *
 * @returns {Promise} - results from linting files, see ESLint.lintFiles
 */
const lint = async ( patterns, options ) => {

  options = _.assignIn( {
    cache: true,
    format: false, // append an extra set of rules for formatting code.
    fix: false, // whether fixes should be written to disk
    warn: true, // whether errors should reported with grunt.warn
    typeInfo: false, // (for typescript) whether to include eslint rules that require project info, much slower
    chipAway: false // returns responsible dev info for easier chipping.
  }, options );

  // filter out all unlintable pattern. An unlintable repo is one that has no `js` in it, so it will fail when trying to
  // lint it.  Also, if the user doesn't have some repos checked out, those should be skipped
  patterns = patterns.filter( pattern => !EXCLUDE_PATTERNS.includes( pattern ) &&
                                         fs.existsSync( pattern ) );

  const hash = crypto.createHash( 'md5' )
    .update( patterns.join( ',' ) )
    .digest( 'hex' );

  const eslintConfig = {

    // optional auto-fix
    fix: options.fix,

    // Caching only checks changed files or when the list of rules is changed.  Changing the implementation of a
    // custom rule does not invalidate the cache.  Caches are declared in .eslintcache files in the directory where
    // grunt was run from.
    cache: options.cache,

    // Where to store the target-specific cache file
    cacheLocation: `../chipper/eslint/cache/${hash}.eslintcache`,

    ignorePath: '../chipper/eslint/.eslintignore',

    resolvePluginsRelativeTo: '../chipper/',

    // Our custom rules live here
    rulePaths: [ '../chipper/eslint/rules' ],

    extensions: [ '.js', '.ts' ]
  };

  const config = {};
  const configExtends = [];
  if ( options.format ) {
    configExtends.push( '../chipper/eslint/format_eslintrc.js' );
  }
  if ( options.typeInfo ) {
    if ( patterns.length !== 1 ) {
      grunt.fail.warn( 'typeInfo can only work for one repository at a time' );
    }

    // include the rules that use type information
    configExtends.push( '../chipper/eslint/type_info_eslintrc.js' );

    // signify where the project configuration lives for this repo - if we apply this to all files
    // ESLint complains that .js files are not in project configurations
    config.overrides = [ {
      files: [
        '**/*.ts'
      ],
      parserOptions: {
        project: [ `${patterns[ 0 ]}/tsconfig.json` ]
      }
    } ];
  }

  config.extends = configExtends;
  eslintConfig.baseConfig = config;

  const eslint = new ESLint( eslintConfig );

  grunt.verbose.writeln( `linting: ${patterns.join( ', ' )}` );

  // 2. Lint files. This doesn't modify target files.
  const results = await eslint.lintFiles( patterns );

  // 3. Modify the files with the fixed code.
  if ( options.fix ) {
    await ESLint.outputFixes( results );
  }

  // 4. Parse the results.
  const totalWarnings = _.sum( results.map( result => result.warningCount ) );
  const totalErrors = _.sum( results.map( result => result.errorCount ) );

  // 5. Output results on errors.
  if ( totalWarnings + totalErrors > 0 ) {
    const formatter = await eslint.loadFormatter( 'stylish' );
    const resultText = formatter.format( results );
    console.log( resultText );

    // The Chip Away option provides a quick and easy method to assign devs to their respective repositories
    // for ease in adopting and applying new typescript linting rules.
    // Chip Away will return a markdown formatted checklist with the repository name, responsible dev,
    // and number of errors.
    // Response  format:
    // - [ ] {{REPO}}: @{{GITHUB_USERNAME}} {{NUMBER}} errors in {{NUMBER}} files.
    if ( options.chipAway ) {
      const repos = results.map( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] );
      const uniqueRepos = _.uniq( repos ).filter( repo => repo !== 'perennial-alias' );

      // NOTE: This should never be run in a maintenance mode since this loads a file from phet-info which
      // does not have its SHA tracked as a dependency.
      // TODO: For the reviewer, is this OK? https://github.com/phetsims/chipper/issues/1253
      const responsibleDevs = JSON.parse( fs.readFileSync( '../phet-info/sim-info/responsible_dev.json' ) );

      // We only want a list of repos that report lint errors
      const reposWithErrors = uniqueRepos.filter( repo => {
        return errorReport( results, repo ).errorCount > 0;
      } );

      // Format chip away assignments. '{{REPO}} @github # errors in # files'
      const assignments = reposWithErrors.map( repo => {
        const fileCount = errorReport( results, repo ).fileCount;
        const errorCount = errorReport( results, repo ).errorCount;

        return ` - [ ] ${repo}: ${responsibleDevs[ repo ].responsibleDevs.join( ', ' )} ${errorCount} errors in ${fileCount} files.`;
      } );
      console.log( assignments.join( '\n' ) );
    }

    options.warn && grunt.fail.warn( `${totalErrors} errors and ${totalWarnings} warnings` );
  }

  return results;
};

function errorReport( results, repo ) {
  const filteredResults = results.filter( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] === repo );
  const fileCount = filteredResults.filter( result => result.errorCount + result.warningCount > 0 ).length;
  const errorCount = _.sum( filteredResults.map( file => file.errorCount + file.warningCount ) );

  return { errorCount: errorCount, fileCount: fileCount };
}

// Mark the version so that the pre-commit hook will only try to use the promise-based API, this means
// it won't run lint precommit hook on SHAs before the promise-based API
lint.chipperAPIVersion = 'promises1';

module.exports = lint;<|endoftext|>


<commit_before>exports.drop = function (driver, opts, cb) {
	var i, queries = [], pending;

	queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.table));

	for (i = 0; i < opts.many_associations.length; i++) {
		queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable));
	}

	pending = queries.length;
	for (i = 0; i < queries.length; i++) {
		driver.execQuery(queries[i], function (err) {
			if (--pending === 0) {
				return cb(err);
			}
		});
	}
};

exports.sync = function (driver, opts, cb) {
	var tables = [];
	var subqueries = [];
	var typequeries = [];
	var definitions = [];
	var k, i, pending;
	var primary_keys = opts.keys.map(function (k) { return driver.query.escapeId(k); });
	var keys = [];

	for (i = 0; i < opts.keys.length; i++) {
		if (opts.properties.hasOwnProperty(opts.keys[i])) continue;

		keys.push(driver.query.escapeId(opts.keys[i]));
	}

	for (i = 0; i < keys.length; i++) {
		definitions.push(keys[i] + " INTEGER NOT NULL");
	}
	if (opts.keys.length == 1) {
		definitions[definitions.length - 1] = keys[0] + " SERIAL";
	}

	for (k in opts.properties) {
		definitions.push(buildColumnDefinition(driver, opts.table, k, opts.properties[k]));

		if (opts.properties[k].type == "enum") {
			typequeries.push(
				"CREATE TYPE " + driver.query.escapeId("enum_" + opts.table + "_" + k) + " AS ENUM (" +
				opts.properties[k].values.map(driver.query.escapeVal.bind(driver)) + ")"
			);
		}
	}

	for (i = 0; i < opts.one_associations.length; i++) {
		if (opts.one_associations[i].reversed) continue;
		definitions.push(
			driver.query.escapeId(opts.one_associations[i].field) + " INTEGER" +
			(opts.one_associations[i].required ? ' NOT NULL' : '')
		);
	}

	for (k in opts.properties) {
		if (opts.properties[k].unique === true) {
			definitions.push("UNIQUE (" + driver.query.escapeId(k) + ")");
		} else if (opts.properties[k].index) {
			definitions.push("INDEX (" + driver.query.escapeId(k) + ")");
		}
	}

	definitions.push("PRIMARY KEY (" + primary_keys.join(", ") + ")");

	tables.push({
		name       : opts.table,
		query      : "CREATE TABLE " + driver.query.escapeId(opts.table) +
		             " (" + definitions.join(", ") + ")",
		typequeries: typequeries,
		subqueries : subqueries
	});

	for (i = 0; i < opts.one_associations.length; i++) {
		if (opts.one_associations[i].reversed) continue;
		tables[tables.length - 1].subqueries.push(
			"CREATE INDEX ON " + driver.query.escapeId(opts.table) +
			" (" + driver.query.escapeId(opts.one_associations[i].field) + ")"
		);
	}

	for (i = 0; i < opts.indexes.length; i++) {
		tables[tables.length - 1].subqueries.push(
			"CREATE INDEX ON " + driver.query.escapeId(opts.table) +
			" (" + opts.indexes[i].split(/[,;]+/).map(function (el) {
				return driver.query.escapeId(el);
			}).join(", ") + ")"
		);
	}

	for (i = 0; i < opts.many_associations.length; i++) {
		definitions = [];
		typequeries = [];

		definitions.push(driver.query.escapeId(opts.many_associations[i].mergeId) + " INTEGER NOT NULL");
		definitions.push(driver.query.escapeId(opts.many_associations[i].mergeAssocId) + " INTEGER NOT NULL");

		for (k in opts.many_associations[i].props) {
			definitions.push(buildColumnDefinition(driver, opts.many_associations[i].mergeTable,
			                                       k, opts.many_associations[i].props[k]));
			if (opts.many_associations[i].props[k].type == "enum") {
				typequeries.push(
					"CREATE TYPE " + driver.query.escapeId("enum_" + opts.many_associations[i].mergeTable + "_" + k) + " AS ENUM (" +
					opts.many_associations[i].props[k].values.map(driver.query.escapeVal.bind(driver)) + ")"
				);
			}
		}

		tables.push({
			name       : opts.many_associations[i].mergeTable,
			query      : "CREATE TABLE IF NOT EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
			             " (" + definitions.join(", ") + ")",
			typequeries: typequeries,
			subqueries : []
		});
		tables[tables.length - 1].subqueries.push(
			"CREATE INDEX ON " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
			" (" +
			driver.query.escapeId(opts.many_associations[i].mergeId) + ", " +
			driver.query.escapeId(opts.many_associations[i].mergeAssocId) +
			")"
		);
	}

	pending = tables.length;

	for (i = 0; i < tables.length; i++) {
		createTableSchema(driver, tables[i], function (err) {
			if (--pending === 0) {
				// this will bring trouble in the future...
				// some errors are not avoided (like ENUM types already defined, etc..)
				return cb(err);
			}
		});
	}
};

function createTableSchema(driver, table, cb) {
	var pending = table.typequeries.length;
	var createTable = function () {
		driver.execQuery(table.query, function (err) {
			if (err || table.subqueries.length === 0) {
				return cb();
			}

			var pending = table.subqueries.length;

			for (var i = 0; i < table.subqueries.length; i++) {
				driver.execQuery(table.subqueries[i], function (err) {
					if (--pending === 0) {
						return cb();
					}
				});
			}
		});
	};

	if (pending === 0) {
		return createTable();
	}

	for (var i = 0; i < table.typequeries.length; i++) {
		driver.execQuery(table.typequeries[i], function (err) {
			if (--pending === 0) {
				return createTable();
			}
		});
	}
}

function buildColumnDefinition(driver, table, name, prop) {
	var def;

	switch (prop.type) {
		case "text":
			def = driver.query.escapeId(name) + " VARCHAR(" + Math.min(Math.max(parseInt(prop.size, 10) || 255, 1), 65535) + ")";
			break;
		case "number":
			if (prop.rational === false) {
				def = driver.query.escapeId(name) + " INTEGER";
				if (typeof prop.size !== 'undefined') {
					def += '('+ driver.query.escapeVal(prop.size) +')';
				} else if (typeof prop.length != 'undefined') {
					def += '('+ driver.query.escapeVal(prop.length) +')';
				}
			} else {
				def = driver.query.escapeId(name) + " REAL";
			}
			break;
		case "boolean":
			def = driver.query.escapeId(name) + " BOOLEAN";
			break;
		case "date":
			if (prop.time === false) {
				def = driver.query.escapeId(name) + " DATE";
			} else {
				def = driver.query.escapeId(name) + " TIMESTAMP WITHOUT TIME ZONE";
			}
			break;
		case "binary":
		case "object":
			def = driver.query.escapeId(name) + " BYTEA";
			break;
		case "enum":
			def = driver.query.escapeId(name) + " " + driver.query.escapeId("enum_" + table + "_" + name);
			break;
		default:
			throw new Error("Unknown property type: '" + prop.type + "'");
	}
	if (prop.required === true) {
		def += " NOT NULL";
	}
	if (prop.hasOwnProperty("defaultValue")) {
		def += " DEFAULT " + driver.query.escapeVal(prop.defaultValue);
	}
	return def;
}
<commit_msg>Report postgres createTable errors<commit_after>exports.drop = function (driver, opts, cb) {
	var i, queries = [], pending;

	queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.table));

	for (i = 0; i < opts.many_associations.length; i++) {
		queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable));
	}

	pending = queries.length;
	for (i = 0; i < queries.length; i++) {
		driver.execQuery(queries[i], function (err) {
			if (--pending === 0) {
				return cb(err);
			}
		});
	}
};

exports.sync = function (driver, opts, cb) {
	var tables = [];
	var subqueries = [];
	var typequeries = [];
	var definitions = [];
	var k, i, pending;
	var primary_keys = opts.keys.map(function (k) { return driver.query.escapeId(k); });
	var keys = [];

	for (i = 0; i < opts.keys.length; i++) {
		if (opts.properties.hasOwnProperty(opts.keys[i])) continue;

		keys.push(driver.query.escapeId(opts.keys[i]));
	}

	for (i = 0; i < keys.length; i++) {
		definitions.push(keys[i] + " INTEGER NOT NULL");
	}
	if (opts.keys.length == 1) {
		definitions[definitions.length - 1] = keys[0] + " SERIAL";
	}

	for (k in opts.properties) {
		definitions.push(buildColumnDefinition(driver, opts.table, k, opts.properties[k]));

		if (opts.properties[k].type == "enum") {
			typequeries.push(
				"CREATE TYPE " + driver.query.escapeId("enum_" + opts.table + "_" + k) + " AS ENUM (" +
				opts.properties[k].values.map(driver.query.escapeVal.bind(driver)) + ")"
			);
		}
	}

	for (i = 0; i < opts.one_associations.length; i++) {
		if (opts.one_associations[i].reversed) continue;
		definitions.push(
			driver.query.escapeId(opts.one_associations[i].field) + " INTEGER" +
			(opts.one_associations[i].required ? ' NOT NULL' : '')
		);
	}

	for (k in opts.properties) {
		if (opts.properties[k].unique === true) {
			definitions.push("UNIQUE (" + driver.query.escapeId(k) + ")");
		} else if (opts.properties[k].index) {
			definitions.push("INDEX (" + driver.query.escapeId(k) + ")");
		}
	}

	definitions.push("PRIMARY KEY (" + primary_keys.join(", ") + ")");

	tables.push({
		name       : opts.table,
		query      : "CREATE TABLE " + driver.query.escapeId(opts.table) +
		             " (" + definitions.join(", ") + ")",
		typequeries: typequeries,
		subqueries : subqueries
	});

	for (i = 0; i < opts.one_associations.length; i++) {
		if (opts.one_associations[i].reversed) continue;
		tables[tables.length - 1].subqueries.push(
			"CREATE INDEX ON " + driver.query.escapeId(opts.table) +
			" (" + driver.query.escapeId(opts.one_associations[i].field) + ")"
		);
	}

	for (i = 0; i < opts.indexes.length; i++) {
		tables[tables.length - 1].subqueries.push(
			"CREATE INDEX ON " + driver.query.escapeId(opts.table) +
			" (" + opts.indexes[i].split(/[,;]+/).map(function (el) {
				return driver.query.escapeId(el);
			}).join(", ") + ")"
		);
	}

	for (i = 0; i < opts.many_associations.length; i++) {
		definitions = [];
		typequeries = [];

		definitions.push(driver.query.escapeId(opts.many_associations[i].mergeId) + " INTEGER NOT NULL");
		definitions.push(driver.query.escapeId(opts.many_associations[i].mergeAssocId) + " INTEGER NOT NULL");

		for (k in opts.many_associations[i].props) {
			definitions.push(buildColumnDefinition(driver, opts.many_associations[i].mergeTable,
			                                       k, opts.many_associations[i].props[k]));
			if (opts.many_associations[i].props[k].type == "enum") {
				typequeries.push(
					"CREATE TYPE " + driver.query.escapeId("enum_" + opts.many_associations[i].mergeTable + "_" + k) + " AS ENUM (" +
					opts.many_associations[i].props[k].values.map(driver.query.escapeVal.bind(driver)) + ")"
				);
			}
		}

		tables.push({
			name       : opts.many_associations[i].mergeTable,
			query      : "CREATE TABLE IF NOT EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
			             " (" + definitions.join(", ") + ")",
			typequeries: typequeries,
			subqueries : []
		});
		tables[tables.length - 1].subqueries.push(
			"CREATE INDEX ON " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
			" (" +
			driver.query.escapeId(opts.many_associations[i].mergeId) + ", " +
			driver.query.escapeId(opts.many_associations[i].mergeAssocId) +
			")"
		);
	}

	pending = tables.length;

	for (i = 0; i < tables.length; i++) {
		createTableSchema(driver, tables[i], function (err) {
			if (--pending === 0) {
				// this will bring trouble in the future...
				// some errors are not avoided (like ENUM types already defined, etc..)
				return cb(err);
			}
		});
	}
};

function createTableSchema(driver, table, cb) {
	var pending = table.typequeries.length;
	var createTable = function () {
		driver.execQuery(table.query, function (err) {
			if (err || table.subqueries.length === 0) {
				return cb(err);
			}

			var pending = table.subqueries.length;

			for (var i = 0; i < table.subqueries.length; i++) {
				driver.execQuery(table.subqueries[i], function (err) {
					if (--pending === 0) {
						return cb();
					}
				});
			}
		});
	};

	if (pending === 0) {
		return createTable();
	}

	for (var i = 0; i < table.typequeries.length; i++) {
		driver.execQuery(table.typequeries[i], function (err) {
			if (--pending === 0) {
				return createTable();
			}
		});
	}
}

function buildColumnDefinition(driver, table, name, prop) {
	var def;

	switch (prop.type) {
		case "text":
			def = driver.query.escapeId(name) + " VARCHAR(" + Math.min(Math.max(parseInt(prop.size, 10) || 255, 1), 65535) + ")";
			break;
		case "number":
			if (prop.rational === false) {
				def = driver.query.escapeId(name) + " INTEGER";
				if (typeof prop.size !== 'undefined') {
					def += '('+ driver.query.escapeVal(prop.size) +')';
				} else if (typeof prop.length != 'undefined') {
					def += '('+ driver.query.escapeVal(prop.length) +')';
				}
			} else {
				def = driver.query.escapeId(name) + " REAL";
			}
			break;
		case "boolean":
			def = driver.query.escapeId(name) + " BOOLEAN";
			break;
		case "date":
			if (prop.time === false) {
				def = driver.query.escapeId(name) + " DATE";
			} else {
				def = driver.query.escapeId(name) + " TIMESTAMP WITHOUT TIME ZONE";
			}
			break;
		case "binary":
		case "object":
			def = driver.query.escapeId(name) + " BYTEA";
			break;
		case "enum":
			def = driver.query.escapeId(name) + " " + driver.query.escapeId("enum_" + table + "_" + name);
			break;
		default:
			throw new Error("Unknown property type: '" + prop.type + "'");
	}
	if (prop.required === true) {
		def += " NOT NULL";
	}
	if (prop.hasOwnProperty("defaultValue")) {
		def += " DEFAULT " + driver.query.escapeVal(prop.defaultValue);
	}
	return def;
}
<|endoftext|>


<commit_before>(function($) {
    $(document).ready(function(){
        $(window).scroll(function(){
            if ($(this).scrollTop() > 5) {
                $('#hidingmenu').fadeOut(1000);
            } else {
                $('#hidingmenu').fadeIn(1000);
            }
        });
    });
})(jQuery);<commit_msg>Delete hidingmenu.js<commit_after><|endoftext|>


<commit_before>var waitForFinalEvent = (function () {
  var timers = {};
  return function (callback, ms, uniqueId) {
    if (timers[uniqueId]) {
      clearTimeout(timers[uniqueId]);
    }
    timers[uniqueId] = setTimeout(callback, ms);
  };
})();

var current_lesson = 0;

function load_project_uri(uri, callback) {
  var request = new XMLHttpRequest ();
  request.onload = function () {
    if (callback !== undefined) {
      callback(this.responseText);
    }
    else {
      load_project_xml(this.responseText);
    }
  };
  request.open("get", uri, true);
  request.send();
}

function load_project_xml(text) {
  return document.getElementById('snap').contentWindow.load_project_xml(text);
}

function export_project_xml() {
  return document.getElementById('snap').contentWindow.export_project_xml();
}

function xmlToString(xmlData) {

    var xmlString;
    //IE
    if (window.ActiveXObject){
        xmlString = xmlData.xml;
    }
    // code for Mozilla, Firefox, Opera, etc.
    else{
        xmlString = (new XMLSerializer()).serializeToString(xmlData);
    }
    return xmlString;
}

function partial_load_xml(answer, ownXML) {
  if (ownXML === undefined) {
    ownXML = export_project_xml();
  }
  var myXML = $.parseXML(ownXML);
  var otherXML = $.parseXML(answer);
  var oldHidden = $(myXML).find('hidden').text().split(' ');
  var newHidden = $(otherXML).find('hidden').text().split(' ');
  var newBlocks = [];
  for (var i in oldHidden) {
    if (newHidden.indexOf(oldHidden[i]) === -1) {
      newBlocks.push(oldHidden[i]);
    }
  }
  $(myXML).find('hidden').text($(otherXML).find('hidden').text());
  var project = myXML.getElementsByTagName('project')[0];
  var newBlocksNode = myXML.createElement('new');
  newBlocksNode.appendChild(myXML.createTextNode(newBlocks.join(' ')));
  project.appendChild(newBlocksNode);
  var str = xmlToString(myXML);
  load_project_xml(str);
  return str;
}

function host_xml(xml) {
  var hash = hex_sha512(xml);
  $.post("http://snap.berkeley.edu/hoc/store/store.php", {xml: xml, hash: hash});
  return hash;
}

function generate_url(hash, callback) {
  var url = "http://www.corsproxy.com/tinyurl.com/api-create.php?url=" +
    encodeURIComponent("http://snap.berkeley.edu/snapsource/snap.html#run:http://snap.berkeley.edu/hoc/store/" + hash + ".xml");
  $.get(url, callback);
}

function share(callback) {
    generate_url(host_xml(export_project_xml()), callback);
}

var congrats_html = null;

function preload_congrats () {
  /*var url = 'congrats.html';
  var request = new XMLHttpRequest ();
  request.onload = function() {
    congrats_html = this.responseText;
  };
  request.open("get", url, true);
  request.send();*/
}

preload_congrats();

function congrats() {
    $('.modal-body').html(congrats_html);
    $('#myModal').modal('show');
    share(function(data) {
      $('.modal-body').html(congrats_html + "

Use this link to share your code: " + data + "
");
    });
}

function place_corral_cover () {
  var pos = document.getElementById('snap').contentWindow.corralPos;
  var snap = $('#snap').offset();
  var padding = 5;
  var corral_cover = $("#corral-cover");
  if (pos !== undefined) {
    corral_cover.offset({
      top: pos.y + snap.top + padding,
      left: pos.x + snap.left + padding
      });
    corral_cover.width(pos.width - padding);
    corral_cover.height(pos.height - 2 * padding);
    corral_cover.children().each(function (i,j) {
      var v = $(this).offsetWidth;
    });
  }
  check_lg_buttons ();
}

function check_lg_buttons () {
  var corral_cover = $("#corral-cover");
  if (corral_cover.width() < 300) {
    var large_buttons = $('.btn-lg');
    large_buttons.removeClass('btn-lg');
    large_buttons.addClass('had-btn-lg');
  }
  else {
    $('.had-btn-lg').addClass('btn-lg').removeClass('had-btn-lg');
  }
}

var btn_to_left = [
  ];

function preload_left () {
  for (var i in btn_to_name) {
    var url = 'lefttext/' + btn_to_name[i] + '.html';
    var request = new XMLHttpRequest ();
    request.onload = function(idx) {
      return function () {
      	btn_to_left[idx] = this.responseText;
    } }(i);
    request.open("get", url, true);
    request.send();
  }
}

preload_left();

function click_btn_num ( i ) {
  $('.btn-top').eq(i).click();
}

function place_in_corral_cover(elems) {
  var corralCover = $('#corral-cover');
  corralCover.empty();
  var inner = $('
', {class: 'div-corral-cover-inner'});
  corralCover.append($('
', {class: 'div-corral-cover'}).append(inner));
  inner.append(elems);
  check_lg_buttons();
}

function do_it_for_me() {
  if (current_lesson !== btn_to_name.length - 1) {
    var current_xml = export_project_xml();
    load_project_uri("xml/" + btn_to_name[current_lesson + 1] + ".xml",
        function (xml) {
          partial_load_xml(current_xml, xml);
        });
  }
  // The do it for me button should not exist otherwise.
}

function fix_code() {
  load_project_uri("xml/" + btn_to_name[current_lesson] + ".xml");
}

function corralBtn(text, callback) {
  return $('<button>', {class: 'btn btn-primary btn-lg btn-corral-cover'}).text(text).click(callback)
}

function show_answer() {
  var answer_png = 'answers/' + btn_to_name[current_lesson] + '.png';
  place_in_corral_cover ([
      $('', {'href':answer_png, 'target':'_blank'}).append(
        $('', {'class': 'answer-png', 'src': answer_png})),
      //corralBtn('Do it for me.', do_it_for_me)
    ]);
}

function killvideo() {
	src = $('#video').attr('src');
	$('#video').attr('src', '');
	$('#video').attr('src', src);
}

function load_left (idx, callback) {
  var leftText = btn_to_left[idx];
  if (leftText !== undefined) {
    callback(leftText);
  }
  else {
    setTimeout(function () {load_left(idx, callback)}, 100);
  }
}

function get_proj_xml ( uri, callback ) {
  var request = new XMLHttpRequest ();
  request.onload = function () {
    callback(this.responseText);
  };
  request.open("get", uri, true);
  request.send();
}

function btn_click () {
  var index = parseInt($(this).data('index'));
  var name = btn_to_name[index];
  var first_click_copy = first_click;
  $('.btn-top').eq(current_lesson).button('toggle');
  if (index === btn_to_name.length - 1) {
    $('#corral-cover').addClass('my-hidden');
    get_proj_xml ( "xml/" + name + ".xml", function (lastXML) {
      var xml = partial_load_xml(lastXML);
      if ( first_click_copy ) {
        $('#snap').load(function () {
          load_project_uri("xml/" + btn_to_name[index] + '.xml');
        });
      }
      else {
        $('#snap').load(function () {
          load_project_xml(xml);
        });
      }
      $('#snap').attr('src', '../../full-interface/snap.html');
    });
  }
  else {
    $('#corral-cover').removeClass('my-hidden');
    if (index >= 4) {
      document.getElementById('snap').contentWindow.show_make_a_variable = true;
    }
    else {
      document.getElementById('snap').contentWindow.show_make_a_variable = false;
    }
    // If this is the first click, then the project has already been loaded.
    if (!first_click) {
      get_proj_xml ( "xml/" + name + ".xml", partial_load_xml);
    }
  }
  $('.btn-top').eq(index).button('toggle');
  current_lesson = index;
  if (current_lesson + 1 === btn_to_name.length) {
    //$('#done-button').removeClass('hidden');
    $('#snaplogo-img').addClass('hidden');
    $('#page-subtitle').addClass('hidden');
    $('#next-button').addClass('hidden');
  }
  else {
    $('#next-button').removeClass('hidden');
  }
  location.hash = "#" + (current_lesson + 1);
  if (current_lesson !== btn_to_name.length - 1) {
    place_in_corral_cover([
      corralBtn('Show me the answer.', show_answer),
      //corralBtn('Replace my code.', fix_code)
      ]);
  } else {
    place_in_corral_cover([
      //corralBtn('Replace my code.', fix_code)
      ]);
  }
  load_left(index, function (leftText) {
    $('#left').html(leftText);
  });
  prepare_modal(current_lesson, function () {
    $('#myModal').modal('toggle');
  });
  first_click = false;
}

function next_lesson() {
  click_btn_num(current_lesson + 1);
}

function prepare_modal(idx, callback) {
  load_left(idx, function (leftText) {
    $.ajax({
      url : "modaltext/" + btn_to_name[idx] + "_modal.html",
      dataType: "text",
      success : function (data) {
        $('.modal-body').html(data);
        $('.modal-body').append($('<button>',
          {class:'btn btn-lg btn-primary', style: 'margin-left:80%;', text:'OK'}
          ).click(function () {
            $('#myModal').modal('toggle');
        }));
        callback();
      }
    });
  });
}

$(document).ready(function () {
  document.getElementById('snap').contentWindow.corralCover = $('#corral-cover');
  document.getElementById('snap').contentWindow.dont_export_hidden = true;
  $(".modal").click( function() { killvideo(); } );
  var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
  if (!(is_chrome)) {
    $('#snap').attr('src', '');
    $("#right").empty();
    $("#myModal").remove();
    $("#right").append("
Welcome to our Hour of Code! Please use us on Google Chrome.
");
    $("#chrome-message").show();
  }
});

var first_lesson_loaded = false;

var first_click = true;
$(window).load(function () {
  var top_buttons = $('#buttons-top')
  var i;

  var num = window.location.hash.substring(1);
  window.corralCover = $('#corral-cover');

  if (num === '') {
    num = 1;
    location.hash = "#" + num;
  }
  else {
    current_lesson = parseInt(num) - 1;
  }

  for ( i in btn_to_name ) {
    i = parseInt(i);
    top_buttons.append($('<button>',
      {class:'btn-top btn btn-lg btn-default'})
      .text('#' + (i + 1)).data('index', i).on('click', btn_click));
    }
  load_project_uri("xml/" + btn_to_name[current_lesson] + '.xml',
      function (xml) {
        load_project_xml(xml);
        place_corral_cover();
        // Why is this still necessary?
        // It seems Snap! is asynchronously loading the xml,
        // despite there being no blocking action taking place.
        setTimeout(place_corral_cover, 100);
      });
  $(".btn-top").eq(current_lesson).button('toggle');
  $(".btn-top").eq(current_lesson).click();
  $("#next-button").on('click', next_lesson);
});

$(window).resize(function () {
  waitForFinalEvent(place_corral_cover, 10, "place_corral_cover");
});
<commit_msg>It moves<commit_after>var waitForFinalEvent = (function () {
  var timers = {};
  return function (callback, ms, uniqueId) {
    if (timers[uniqueId]) {
      clearTimeout(timers[uniqueId]);
    }
    timers[uniqueId] = setTimeout(callback, ms);
  };
})();

var current_lesson = 0;

function load_project_uri(uri, callback) {
  var request = new XMLHttpRequest ();
  request.onload = function () {
    if (callback !== undefined) {
      callback(this.responseText);
    }
    else {
      load_project_xml(this.responseText);
    }
  };
  request.open("get", uri, true);
  request.send();
}

function load_project_xml(text) {
  return document.getElementById('snap').contentWindow.load_project_xml(text);
}

function export_project_xml() {
  return document.getElementById('snap').contentWindow.export_project_xml();
}

function xmlToString(xmlData) {

    var xmlString;
    //IE
    if (window.ActiveXObject){
        xmlString = xmlData.xml;
    }
    // code for Mozilla, Firefox, Opera, etc.
    else{
        xmlString = (new XMLSerializer()).serializeToString(xmlData);
    }
    return xmlString;
}

function partial_load_xml(answer, ownXML) {
  if (ownXML === undefined) {
    ownXML = export_project_xml();
  }
  var myXML = $.parseXML(ownXML);
  var otherXML = $.parseXML(answer);
  var oldHidden = $(myXML).find('hidden').text().split(' ');
  var newHidden = $(otherXML).find('hidden').text().split(' ');
  var newBlocks = [];
  for (var i in oldHidden) {
    if (newHidden.indexOf(oldHidden[i]) === -1) {
      newBlocks.push(oldHidden[i]);
    }
  }
  $(myXML).find('hidden').text($(otherXML).find('hidden').text());
  var project = myXML.getElementsByTagName('project')[0];
  var newBlocksNode = myXML.createElement('new');
  newBlocksNode.appendChild(myXML.createTextNode(newBlocks.join(' ')));
  project.appendChild(newBlocksNode);
  project.attributes['name'] = "potato";
  var str = xmlToString(myXML);
  load_project_xml(str);
  return str;
}

function host_xml(xml) {
  var hash = hex_sha512(xml);
  $.post("http://snap.berkeley.edu/hoc/store/store.php", {xml: xml, hash: hash});
  return hash;
}

function generate_url(hash, callback) {
  var url = "http://www.corsproxy.com/tinyurl.com/api-create.php?url=" +
    encodeURIComponent("http://snap.berkeley.edu/snapsource/snap.html#run:http://snap.berkeley.edu/hoc/store/" + hash + ".xml");
  $.get(url, callback);
}

function share(callback) {
    generate_url(host_xml(export_project_xml()), callback);
}

var congrats_html = null;

function preload_congrats () {
  /*var url = 'congrats.html';
  var request = new XMLHttpRequest ();
  request.onload = function() {
    congrats_html = this.responseText;
  };
  request.open("get", url, true);
  request.send();*/
}

preload_congrats();

function congrats() {
    $('.modal-body').html(congrats_html);
    $('#myModal').modal('show');
    share(function(data) {
      $('.modal-body').html(congrats_html + "

Use this link to share your code: " + data + "
");
    });
}

function place_corral_cover () {
  var pos = document.getElementById('snap').contentWindow.corralPos;
  var snap = $('#snap').offset();
  var padding = 5;
  var corral_cover = $("#corral-cover");
  if (pos !== undefined) {
    corral_cover.offset({
      top: pos.y + snap.top + padding,
      left: pos.x + snap.left + padding
      });
    corral_cover.width(pos.width - padding);
    corral_cover.height(pos.height - 2 * padding);
    corral_cover.children().each(function (i,j) {
      var v = $(this).offsetWidth;
    });
  }
  check_lg_buttons ();
}

function check_lg_buttons () {
  var corral_cover = $("#corral-cover");
  if (corral_cover.width() < 300) {
    var large_buttons = $('.btn-lg');
    large_buttons.removeClass('btn-lg');
    large_buttons.addClass('had-btn-lg');
  }
  else {
    $('.had-btn-lg').addClass('btn-lg').removeClass('had-btn-lg');
  }
}

var btn_to_left = [
  ];

function preload_left () {
  for (var i in btn_to_name) {
    var url = 'lefttext/' + btn_to_name[i] + '.html';
    var request = new XMLHttpRequest ();
    request.onload = function(idx) {
      return function () {
      	btn_to_left[idx] = this.responseText;
    } }(i);
    request.open("get", url, true);
    request.send();
  }
}

preload_left();

function click_btn_num ( i ) {
  $('.btn-top').eq(i).click();
}

function place_in_corral_cover(elems) {
  var corralCover = $('#corral-cover');
  corralCover.empty();
  var inner = $('
', {class: 'div-corral-cover-inner'});
  corralCover.append($('
', {class: 'div-corral-cover'}).append(inner));
  inner.append(elems);
  check_lg_buttons();
}

function do_it_for_me() {
  if (current_lesson !== btn_to_name.length - 1) {
    var current_xml = export_project_xml();
    load_project_uri("xml/" + btn_to_name[current_lesson + 1] + ".xml",
        function (xml) {
          partial_load_xml(current_xml, xml);
        });
  }
  // The do it for me button should not exist otherwise.
}

function fix_code() {
  load_project_uri("xml/" + btn_to_name[current_lesson] + ".xml");
}

function corralBtn(text, callback) {
  return $('<button>', {class: 'btn btn-primary btn-lg btn-corral-cover'}).text(text).click(callback)
}

function show_answer() {
  var answer_png = 'answers/' + btn_to_name[current_lesson] + '.png';
  place_in_corral_cover ([
      $('', {'href':answer_png, 'target':'_blank'}).append(
        $('', {'class': 'answer-png', 'src': answer_png})),
      //corralBtn('Do it for me.', do_it_for_me)
    ]);
}

function killvideo() {
	src = $('#video').attr('src');
	$('#video').attr('src', '');
	$('#video').attr('src', src);
}

function load_left (idx, callback) {
  var leftText = btn_to_left[idx];
  if (leftText !== undefined) {
    callback(leftText);
  }
  else {
    setTimeout(function () {load_left(idx, callback)}, 100);
  }
}

function get_proj_xml ( uri, callback ) {
  var request = new XMLHttpRequest ();
  request.onload = function () {
    callback(this.responseText);
  };
  request.open("get", uri, true);
  request.send();
}

function btn_click () {
  var index = parseInt($(this).data('index'));
  var name = btn_to_name[index];
  var first_click_copy = first_click;
  $('.btn-top').eq(current_lesson).button('toggle');
  if (index === btn_to_name.length - 1) {
    $('#corral-cover').addClass('my-hidden');
    get_proj_xml ( "xml/" + name + ".xml", function (lastXML) {
      var xml = partial_load_xml(lastXML);
      if ( first_click_copy ) {
        $('#snap').load(function () {
          load_project_uri("xml/" + btn_to_name[index] + '.xml');
        });
      }
      else {
        $('#snap').load(function () {
          load_project_xml(xml);
        });
      }
      $('#snap').attr('src', '../../full-interface/snap.html');
    });
  }
  else {
    $('#corral-cover').removeClass('my-hidden');
    if (index >= 4) {
      document.getElementById('snap').contentWindow.show_make_a_variable = true;
    }
    else {
      document.getElementById('snap').contentWindow.show_make_a_variable = false;
    }
    // If this is the first click, then the project has already been loaded.
    if (!first_click) {
      get_proj_xml ( "xml/" + name + ".xml", partial_load_xml);
    }
  }
  $('.btn-top').eq(index).button('toggle');
  current_lesson = index;
  if (current_lesson + 1 === btn_to_name.length) {
    //$('#done-button').removeClass('hidden');
    $('#snaplogo-img').addClass('hidden');
    $('#page-subtitle').addClass('hidden');
    $('#next-button').addClass('hidden');
  }
  else {
    $('#next-button').removeClass('hidden');
  }
  location.hash = "#" + (current_lesson + 1);
  if (current_lesson !== btn_to_name.length - 1) {
    place_in_corral_cover([
      corralBtn('Show me the answer.', show_answer),
      //corralBtn('Replace my code.', fix_code)
      ]);
  } else {
    place_in_corral_cover([
      //corralBtn('Replace my code.', fix_code)
      ]);
  }
  load_left(index, function (leftText) {
    $('#left').html(leftText);
  });
  prepare_modal(current_lesson, function () {
    $('#myModal').modal('toggle');
  });
  first_click = false;
}

function next_lesson() {
  click_btn_num(current_lesson + 1);
}

function prepare_modal(idx, callback) {
  load_left(idx, function (leftText) {
    $.ajax({
      url : "modaltext/" + btn_to_name[idx] + "_modal.html",
      dataType: "text",
      success : function (data) {
        $('.modal-body').html(data);
        $('.modal-body').append($('<button>',
          {class:'btn btn-lg btn-primary', style: 'margin-left:80%;', text:'OK'}
          ).click(function () {
            $('#myModal').modal('toggle');
        }));
        callback();
      }
    });
  });
}

$(document).ready(function () {
  document.getElementById('snap').contentWindow.corralCover = $('#corral-cover');
  document.getElementById('snap').contentWindow.dont_export_hidden = true;
  $(".modal").click( function() { killvideo(); } );
  var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
  if (!(is_chrome)) {
    $('#snap').attr('src', '');
    $("#right").empty();
    $("#myModal").remove();
    $("#right").append("
Welcome to our Hour of Code! Please use us on Google Chrome.
");
    $("#chrome-message").show();
  }
});

var first_lesson_loaded = false;

var first_click = true;
$(window).load(function () {
  var top_buttons = $('#buttons-top')
  var i;

  var num = window.location.hash.substring(1);
  window.corralCover = $('#corral-cover');

  if (num === '') {
    num = 1;
    location.hash = "#" + num;
  }
  else {
    current_lesson = parseInt(num) - 1;
  }

  for ( i in btn_to_name ) {
    i = parseInt(i);
    top_buttons.append($('<button>',
      {class:'btn-top btn btn-lg btn-default'})
      .text('#' + (i + 1)).data('index', i).on('click', btn_click));
    }
  load_project_uri("xml/" + btn_to_name[current_lesson] + '.xml',
      function (xml) {
        load_project_xml(xml);
        place_corral_cover();
        // Why is this still necessary?
        // It seems Snap! is asynchronously loading the xml,
        // despite there being no blocking action taking place.
        setTimeout(place_corral_cover, 100);
      });
  $(".btn-top").eq(current_lesson).button('toggle');
  $(".btn-top").eq(current_lesson).click();
  $("#next-button").on('click', next_lesson);
});

$(window).resize(function () {
  waitForFinalEvent(place_corral_cover, 10, "place_corral_cover");
});
<|endoftext|>


<commit_before>document.documentElement.innerHTML='\
\
	<title>Mass uploader</title>\
	<meta http-equiv="Cache-Control" content="no-store"/>\
	<meta content="text/html" charset="utf-8" http-equiv="Content-Type"/>\
	\
	\
	\
	\
	\
	\
\
\

Booru Mass-Uploader v1.4.3
\

This script allows you to mass-upload images to imageboard sites running *booru software.\
	Select a number of files and they\'re sent to the website along with the metadata you include such as\
	the tags retrived from the filenames.
\
\
<fieldset style="padding: 2px 1em">\
	<legend>\
		Filename syntax for correct uploads\
		\
		  [+/-]\
		\
	</legend>\
\

\

\
			Example filename: <q>q nagisa muted_color tagme Filename.jpg</q>, where:\

\

\

 <q>q </q> is the image rating:\
				\
				<q>s </q> = Safe, <q>q </q> = Questionable, and <q>e </q> = Explicit;\
				this part is optional.\
				+\

The next section allows to set image ratings based on the button selected or the filenames\
				and/or the button selected. The ratings of can be set either by forcing all\
				images in an upload session to have the same rating regardless of the filenames\
				or by the first filename element with fallback to options.\

\

 Tags separated by spaces. Here are 3 of them: <q>nagisa</q>, <q>muted_color</q> and <q>tagme</q>.\
				+\

Tags should be in ANSI format, use <q>_</q> for spaces between words of a single tag.\
				The <q>tagme</q> tag might be added by some boorus if there are under ~5 tags.\

\

 The filename is either ignored or used as image title on Gelbooru, here it is "Filename".\
				+\

Keep it if describes the image well or can be Googled to find the source.\
				Don\'t keep it if the filenames are numbered like "q ascii 1.jpg", "q ascii 2.jpg",\
				"q ascii 3.jpg"	to avoid duplicate filenames.\

\

\

\
</fieldset>\
\
<fieldset>\
	<legend>Image ratings</legend>\
\

\
		<input type="radio" name="rating-when" id="forceRating" checked="checked"/>\
		Force all ratings regardless of filename.\
		<input type="radio" name="rating-when" id="ratingAsDefault"/>\
		Only set rating if failed to determine it from the filename.\

\
\

\
		<input type="radio" name="rating" id="setSafe" checked="checked"/>\
		Safe\
		<input type="radio" name="rating" id="setQuest"/>\
		Questionable\
		<input type="radio" name="rating" id="setExplicit"/>\
		Explicit\

\
</fieldset>\
\
<fieldset>\
	<legend>Tagging</legend>\
\
    <input type="radio" name="tag-when" id="sidecarTags" onchange="onSidecarChange(event)" value="sidecar"/>\
    Ignore filenames, use sidecar .txt files as sources of tags for each image.\

\
\
	<input type="radio" name="tag-when" id="forceTags" checked="checked" onchange="onSidecarChange(event)" value="force"/>\
	Ignore filenames, force tags of all images.\

\
\
	<input type="radio" name="tag-when" id="addTags" onchange="onSidecarChange(event)" value="add"/>\
	Use tags from filenames and add these tags to each image:\

\
\

\
		Tag list (separate with spaces):\
		<input type="text" id="tags" style="width: 77%"/>\

\

\

Your tags:
\

\

\
</fieldset>\
\
<fieldset style="padding: 2px 1em">\
	<legend>\
		Other settings\
		\
		  [+/-]\
		\
	</legend>\
\

\

\

\
				<input type="checkbox" id="title"/>\
				Set Title of each image to its original filename\

\

\
				Set Source field of each image to\
				<input type="text" id="source" placeholder="Booru mass uploader" style="width:200px;"/>\

\

\

\
			Select booru engine: <select id="engine" style="text-align:center; padding-top:3px;">\
			<option value="gelbooru" selected>Gelbooru</option>\
			<option value="moebooru">Moebooru</option>\
			<option value="danbooru">Danbooru</option>\
		</select>\
			<input type="checkbox" id="onlyErrors">\
			 Log only errors\

\

\
</fieldset>\

Selection mode:\
	<input type="radio" name="selection" id="asFiles" checked="checked">\
	files\
	<input type="radio" name="selection" id="asFolder">\
	folder\

\

\
	Images:\
	<input type="file" id="files" multiple="true" accept="image/*" style="width:90%;" onchange="onFileSelect(event.target.files)"/>
\
	\

\

\
\

You are  to a  site.
\
<button disabled="" id="submit" onclick="FilesSelected( $(\'files\').files );">Upload!</button>\
\

\

\

\

\

Download .bat error log
\

\
';
<commit_msg>explaining sidecar files<commit_after>document.documentElement.innerHTML='\
\
	<title>Mass uploader</title>\
	<meta http-equiv="Cache-Control" content="no-store"/>\
	<meta content="text/html" charset="utf-8" http-equiv="Content-Type"/>\
	\
	\
	\
	\
	\
	\
\
\

Booru Mass-Uploader v1.4.3
\

This script allows you to mass-upload images to imageboard sites running *booru software.\
	Select a number of files and they\'re sent to the website along with the metadata you include such as\
	the tags retrived from the filenames.
\
\
<fieldset style="padding: 2px 1em">\
	<legend>\
		Filename syntax for correct uploads\
		\
		  [+/-]\
		\
	</legend>\
\

\

\
			Example filename: <q>q nagisa muted_color tagme Filename.jpg</q>, where:\

\

\

 <q>q </q> is the image rating:\
				\
				<q>s </q> = Safe, <q>q </q> = Questionable, and <q>e </q> = Explicit;\
				this part is optional.\
				+\

The next section allows to set image ratings based on the button selected or the filenames\
				and/or the button selected. The ratings of can be set either by forcing all\
				images in an upload session to have the same rating regardless of the filenames\
				or by the first filename element with fallback to options.\

\

 Tags separated by spaces. Here are 3 of them: <q>nagisa</q>, <q>muted_color</q> and <q>tagme</q>.\
				+\

Tags should be in ANSI format, use <q>_</q> for spaces between words of a single tag.\
				The <q>tagme</q> tag might be added by some boorus if there are under ~5 tags.\

\

 The filename is either ignored or used as image title on Gelbooru, here it is "Filename".\
				+\

Keep it if describes the image well or can be Googled to find the source.\
				Don\'t keep it if the filenames are numbered like "q ascii 1.jpg", "q ascii 2.jpg",\
				"q ascii 3.jpg"	to avoid duplicate filenames.\

\

\

\
			Example of a sidecar text file:

Filename: Filename.jpg.txt

Contents:
8288girls
blue_plastic_funnel\

emoji_on_mylar_balloon
OR
extreme presbyphonia
laptop in landfill
moldy arachnid

\

\

\
</fieldset>\
\
<fieldset>\
	<legend>Image ratings</legend>\
\

\
		<input type="radio" name="rating-when" id="forceRating" checked="checked"/>\
		Force all ratings regardless of filename.\
		<input type="radio" name="rating-when" id="ratingAsDefault"/>\
		Only set rating if failed to determine it from the filename.\

\
\

\
		<input type="radio" name="rating" id="setSafe" checked="checked"/>\
		Safe\
		<input type="radio" name="rating" id="setQuest"/>\
		Questionable\
		<input type="radio" name="rating" id="setExplicit"/>\
		Explicit\

\
</fieldset>\
\
<fieldset>\
	<legend>Tagging</legend>\
\
    <input type="radio" name="tag-when" id="sidecarTags" onchange="onSidecarChange(event)" value="sidecar"/>\
    Ignore filenames, use sidecar files as sources of tags for each \
    image (see above at §Filename syntax).\

\
\
	<input type="radio" name="tag-when" id="forceTags" checked="checked" onchange="onSidecarChange(event)" value="force"/>\
	Ignore filenames, force tags of all images.\

\
\
	<input type="radio" name="tag-when" id="addTags" onchange="onSidecarChange(event)" value="add"/>\
	Use tags from filenames and add these tags to each image:\

\
\

\
		Tag list (separate with spaces):\
		<input type="text" id="tags" style="width: 77%"/>\

\

\

Your tags:
\

\

\
</fieldset>\
\
<fieldset style="padding: 2px 1em">\
	<legend>\
		Other settings\
		\
		  [+/-]\
		\
	</legend>\
\

\

\

\
				<input type="checkbox" id="title"/>\
				Set Title of each image to its original filename\

\

\
				Set Source field of each image to\
				<input type="text" id="source" placeholder="Booru mass uploader" style="width:200px;"/>\

\

\

\
			Select booru engine: <select id="engine" style="text-align:center; padding-top:3px;">\
			<option value="gelbooru" selected>Gelbooru</option>\
			<option value="moebooru">Moebooru</option>\
			<option value="danbooru">Danbooru</option>\
		</select>\
			<input type="checkbox" id="onlyErrors">\
			 Log only errors\

\

\
</fieldset>\

Selection mode:\
	<input type="radio" name="selection" id="asFiles" checked="checked">\
	files\
	<input type="radio" name="selection" id="asFolder">\
	folder\

\

\
	Images:\
	<input type="file" id="files" multiple="true" accept="image/*" style="width:90%;" onchange="onFileSelect(event.target.files)"/>
\
	\

\

\
\

You are  to a  site.
\
<button disabled="" id="submit" onclick="FilesSelected( $(\'files\').files );">Upload!</button>\
\

\

\

\

\

Download .bat error log
\

\
';
<|endoftext|>


<commit_before>/**
 * Created by Артем on 25.11.13.
 */
;(function($){

    var input = $('input');
    console.log(input.prop({value:'asd',title:'qwe'}));
    console.log(input.prop('title',function(index,value){
        //console.log($(this).val());
        console.log(this.value);
        console.log(arguments);
    }));

})(jQuery);<commit_msg>(Добавление ноды) Создание элементов через jQuery<commit_after>/**
 * Created by Артем on 25.11.13.
 */
;(function($){

    //$('<input type="password">').appendTo('body');
    //Создание nod-ы

    $('<input type="password">')
        .prop({
        value: 'asd'
        }).appendTo('body')
    ;

})(jQuery);<|endoftext|>


<commit_before>// extend String and define String#endsWith
String.prototype.endsWith = function(suffix) {
  return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

// Lemmatizer constructor
var Lemmatizer = function() {
  this.wn_files = {
    noun: [
      '../dict/index.noun.json',
      '../dict/noun.exc.json'
    ],
    verb: [
      '../dict/index.verb.json',
      '../dict/verb.exc.json'
    ],
    adj:  [
      '../dict/index.adj.json',
      '../dict/adj.exc.json'
    ],
    adv:  [
      '../dict/index.adv.json',
      '../dict/adv.exc.json'
    ]
  };

  this.morphological_substitutions = {
    noun: [
      ['s',    ''   ],
      ['ses',  's'  ],
      ['ves',  'f'  ],
      ['xes',  'x'  ],
      ['zes',  'z'  ],
      ['ches', 'ch' ],
      ['shes', 'sh' ],
      ['men',  'man'],
      ['ies',  'y'  ]
    ],
    verb: [
      ['s',   '' ],
      ['ies', 'y'],
      ['es',  'e'],
      ['es',  '' ],
      ['ed',  'e'],
      ['ed',  '' ],
      ['ing', 'e'],
      ['ing', '' ]
    ],
    adj:  [
      ['er',  '' ],
      ['est', '' ],
      ['er',  'e'],
      ['est', 'e'],
      ['ier', 'y'],
      ['iest', 'y']
    ],
    adv:  [
      ['er',  '' ],
      ['est', '' ],
      ['er',  'e'],
      ['est', 'e'],
      ['ier', 'y'],
      ['iest', 'y']
    ]
  };

  this.wordlists  = {};
  this.exceptions = {};

  // initialize wordlists and exceptions
  for (var key in this.morphological_substitutions) {
    this.wordlists[key] = {};
    this.exceptions[key] = {};
  }

  // store dictionary data to localStorage from wn_files
  for (var pos in this.wn_files) {
    this.load_wordnet_files(pos, this.wn_files[pos][0], this.wn_files[pos][1]);
  }

  // fetch dictionary data from localStorage, then set up wordlists and exceptions
  for (var pos in this.wn_files) {
    this.setup_dic_data(pos);
  }
};

// Lemmatizer properties
Lemmatizer.prototype = {
  form: '',
  idx: '_idx',
  exc: '_exc',
  lems: [], // -> [ [lemma1, "verb"], [lemma2, "noun"]... ]

  // public
  lemmas: function(form, pos) {
    var self = this;
    this.lems = [];
    this.form = form;

    var parts = ['verb', 'noun', 'adj', 'adv'];
    if ( pos && !_.include( parts, pos ) ) {
      console.log("warning: pos must be 'verb' or 'noun' or 'adj' or 'adv'.");
      return;
    }

    if (!pos) {
      _.each( parts, function(pos) { self.irregular_bases(pos); } );
      _.each( parts, function(pos) { self.regular_bases(pos); } );

      // when lemma not found and the form is included in wordlists.
      if ( this.is_lemma_empty() ) {
        _.chain(parts)
         .select( function(pos) { return self.wordlists[pos][form]; } )
         .each( function(pos) { self.lems.push([ form, pos ]); } );
      }
      // when lemma not found and the form is not included in wordlists.
      if ( this.is_lemma_empty() ) {
        this.lems.push([ form, '' ]);
      }
    } else {
      this.base_forms(pos);
      if ( this.is_lemma_empty() ) {
        this.lems.push([ form, pos ]);
      }
    }

    // sort to verb -> noun -> adv -> adj
    return _.sortBy( this.uniq_lemmas(this.lems), function(val) { return val[1]; } ).reverse();
  },

  // return only uniq lemmas without pos like [ 'high' ] or [ 'leave', 'leaf' ]
  only_lemmas: function(form, pos) {
    var result = _.map( this.lemmas(form, pos), function(val) { return val[0]; } );
    return _.uniq(result);
  },

  // **************************************************
  // private
  // The following properties(methods) are only used by
  // Lemmatizer inside, so don't call them from outside.
  // **************************************************
  is_lemma_empty: function() {
    return this.lems.length == 0;
  },

  // set up dictionary data
  load_wordnet_files: function(pos, list, exc) {
    var key_idx = pos + this.idx;
    this.open_file(key_idx, list);
    var key_exc = pos + this.exc;
    this.open_file(key_exc, exc);
  },

  setup_dic_data: function(pos) {
    var self = this;
    var key_idx = pos + this.idx;
    _.each( this.fetch_idx_data(key_idx), function(w) {
      self.wordlists[pos][w] = w;
    });
    var key_exc = pos + this.exc;
    _.each( this.fetch_exc_data(key_exc), function(item) {
      var w = item[0];
      var s = item[1];
      self.exceptions[pos][w] = s;
    });
  },

  open_file: function(key, file) {
    if (!localStorage[key]) {
      var self = this;
      // when using async ajax, localStorage[key] return undefined at first. (186)
      // $.get(file, function(data){
      //   self.store_data(key, data);
      // });

      // so use sync networking only at the first time.
      $.ajax({
        url: file,
        type: 'get',
        async: false,
        success: function(data) {
          self.store_data(key, data);
        }
      });
    }
  },

  store_data: function(key, data) {
    localStorage[key] = data;
  },

  // somehow JSON.parse(localStorage[key]) does not work, so build array data from string.
  fetch_idx_data: function(key) {
    arr = localStorage[key].split(',');
    return arr;
  },

  fetch_exc_data: function(key) {
    data = localStorage[key].split(',');
    var len = data.length;
    var index = 0;
    var arr = [];
    for (var i = 0; i < len; i++) {
      if (i % 2 != 0) {
        continue;
      }
      arr[index] = [];
      arr[index][0] = data[i];
      arr[index][1] = data[i+1];
      index++;
    }
    return arr;
  },
  // end of set up dictionary data

  base_forms: function(pos) {
    this.irregular_bases(pos);
    this.regular_bases(pos);
  },

  // build array lemmas(this.lems) like [ [lemma1, "verb"], [lemma2, "noun"]... ]
  irregular_bases: function(pos) {
    if (this.exceptions[pos][this.form] && this.exceptions[pos][this.form] != this.form) {
      this.lems.push( [this.exceptions[pos][this.form], pos] );
    }
  },

  // build array lemmas(this.lems) like [ [lemma1, "verb"], [lemma2, "noun"]... ]
  regular_bases: function(pos) {
    var bases = null;
    // bases -> [ [lemma1, lemma2, lemma3...], pos ]
    bases = this.possible_bases(pos);
    if (bases) {
      this.check_lemmas(bases);
    }
  },

  // check if possible bases are include in lemma wordlists and push
  check_lemmas: function(bases) {
    var self = this;
    // bases -> [ [lemma1, lemma2, lemma3...], pos ]
    var lemmas = bases[0];
    var pos = bases[1];
    _.each( lemmas, function(lemma) {
      if ( self.wordlists[pos][lemma] && self.wordlists[pos][lemma] == lemma && lemma != self.form ) {
        self.lems.push( [lemma, pos] );
      }
    });
  },

  possible_bases: function(pos) {
    var self = this;
    var form = this.form;
    var lemmas = [];

    _.each(this.morphological_substitutions[pos], function(entry) {
      var morpho = entry[0];
      var origin = entry[1];
      if ( form.endsWith(morpho) ) {
        if ( pos == 'verb' && morpho == 'ing' && self.double_consonant(morpho) ) {
          lemmas.push( form.slice( 0, -(morpho.length + 1) + origin ) );
        }
        if ( (pos == 'adj' || pos == 'adv') && morpho == 'est' && self.double_consonant(morpho) ) {
          lemmas.push( form.slice( 0, -(morpho.length + 1) + origin ) );
        }
        if ( (pos == 'adj' || pos == 'adv') && morpho == 'er' && self.double_consonant(morpho) ) {
          lemmas.push( form.slice( 0, -(morpho.length + 1) + origin ) );
        }
        lemmas.push( form.slice( 0, -(morpho.length) ) + origin );
      }
    });

    if (lemmas.length == 0) {
      lemmas.push(form);
    }

    return [ lemmas, pos ];
  },

  double_consonant: function(suffix) {
    // for like bigger -> big
    var form = this.form;
    // length after removing suffix from form
    var len = form.length - suffix.length;
    return this.is_vowel(form[len - 3]) && !this.is_vowel(form[len - 2]) && form[len - 2] === form[len - 1];
  },

  is_vowel: function(letter) {
    return _.include(["a", "e", "i", "o", "u"], letter);
  },

  is_end_with_es: function() {
    var form = this.form;
    if ( form.endsWith('ses') || form.endsWith('xes') || form.endsWith('zes') || form.endsWith('shes') || form.endsWith('ches') ) {
      return true;
    } else {
      return false;
    }
  },

  // [ ["leave", "verb"], ["leaf", "noun"], ["leave", "verb"], ["leave", "noun"] ];
  // -> [ ["leave", "verb"], ["leaf", "noun"], ["leave", "noun"] ];
  uniq_lemmas: function(lemmas) {
    var u_lemmas = [];
    var len = lemmas.length;
    for (var i = 0; i < len; i++) {
      var val = lemmas[i];
      if (!this.is_include(u_lemmas, val)) {
        u_lemmas.push(val);
      }
    }
    return u_lemmas;
  },

  is_include: function(lemmas, target) {
    var len = lemmas.length;
    for (var i = 0; i < len; i++) {
      if (lemmas[i][0] == target[0] && lemmas[i][1] == target[1]) {
        return true;
      }
    }
    return false;
  },

  // for debug to use like $('#lem-confirm').html( lem.confirm_dic('exc') )
  confirm_dic: function(type) {
    var words = null;
    if (type == 'exc') {
      words = this.exceptions;
    } else if (type == 'idx') {
      words = this.wordlists;
    }
    var html = '*** ' + type + ' ***
';
    var parts = ['verb', 'noun', 'adj', 'adv'];
    var len = parts.length;
    for (var i = 0; i < len; i++) {
      var pos = parts[i];
      var pos_comment = '--- ' + pos + ' ---
';
      var html = html + pos_comment;
      for (var w in words[pos]) {
        var item = w + ' -> ' + words[pos][w] + '
';
        var html = html + item;
      }
    }
    return html;
  }
};
<commit_msg>remove not-used method<commit_after>// extend String and define String#endsWith
String.prototype.endsWith = function(suffix) {
  return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

// Lemmatizer constructor
var Lemmatizer = function() {
  this.wn_files = {
    noun: [
      '../dict/index.noun.json',
      '../dict/noun.exc.json'
    ],
    verb: [
      '../dict/index.verb.json',
      '../dict/verb.exc.json'
    ],
    adj:  [
      '../dict/index.adj.json',
      '../dict/adj.exc.json'
    ],
    adv:  [
      '../dict/index.adv.json',
      '../dict/adv.exc.json'
    ]
  };

  this.morphological_substitutions = {
    noun: [
      ['s',    ''   ],
      ['ses',  's'  ],
      ['ves',  'f'  ],
      ['xes',  'x'  ],
      ['zes',  'z'  ],
      ['ches', 'ch' ],
      ['shes', 'sh' ],
      ['men',  'man'],
      ['ies',  'y'  ]
    ],
    verb: [
      ['s',   '' ],
      ['ies', 'y'],
      ['es',  'e'],
      ['es',  '' ],
      ['ed',  'e'],
      ['ed',  '' ],
      ['ing', 'e'],
      ['ing', '' ]
    ],
    adj:  [
      ['er',  '' ],
      ['est', '' ],
      ['er',  'e'],
      ['est', 'e'],
      ['ier', 'y'],
      ['iest', 'y']
    ],
    adv:  [
      ['er',  '' ],
      ['est', '' ],
      ['er',  'e'],
      ['est', 'e'],
      ['ier', 'y'],
      ['iest', 'y']
    ]
  };

  this.wordlists  = {};
  this.exceptions = {};

  // initialize wordlists and exceptions
  for (var key in this.morphological_substitutions) {
    this.wordlists[key] = {};
    this.exceptions[key] = {};
  }

  // store dictionary data to localStorage from wn_files
  for (var pos in this.wn_files) {
    this.load_wordnet_files(pos, this.wn_files[pos][0], this.wn_files[pos][1]);
  }

  // fetch dictionary data from localStorage, then set up wordlists and exceptions
  for (var pos in this.wn_files) {
    this.setup_dic_data(pos);
  }
};

// Lemmatizer properties
Lemmatizer.prototype = {
  form: '',
  idx: '_idx',
  exc: '_exc',
  lems: [], // -> [ [lemma1, "verb"], [lemma2, "noun"]... ]

  // **************************************************
  // public
  // **************************************************
  // reuturn Array of ["lemma", "pos"] pairs
  // like [ ["lemma1", "verb"], ["lemma2", "noun"]... ]
  lemmas: function(form, pos) {
    var self = this;
    this.lems = [];
    this.form = form;

    var parts = ['verb', 'noun', 'adj', 'adv'];
    if ( pos && !_.include( parts, pos ) ) {
      console.log("warning: pos must be 'verb' or 'noun' or 'adj' or 'adv'.");
      return;
    }

    if (!pos) {
      _.each( parts, function(pos) { self.irregular_bases(pos); } );
      _.each( parts, function(pos) { self.regular_bases(pos); } );

      // when lemma not found and the form is included in wordlists.
      if ( this.is_lemma_empty() ) {
        _.chain(parts)
         .select( function(pos) { return self.wordlists[pos][form]; } )
         .each( function(pos) { self.lems.push([ form, pos ]); } );
      }
      // when lemma not found and the form is not included in wordlists.
      if ( this.is_lemma_empty() ) {
        this.lems.push([ form, '' ]);
      }
    } else {
      this.base_forms(pos);
      if ( this.is_lemma_empty() ) {
        this.lems.push([ form, pos ]);
      }
    }

    // sort to verb -> noun -> adv -> adj
    return _.sortBy( this.uniq_lemmas(this.lems), function(val) { return val[1]; } ).reverse();
  },

  // return only uniq lemmas without pos like [ 'high' ] or [ 'leave', 'leaf' ]
  only_lemmas: function(form, pos) {
    var result = _.map( this.lemmas(form, pos), function(val) { return val[0]; } );
    return _.uniq(result);
  },

  // **************************************************
  // private
  // The following properties(methods) are only used by
  // Lemmatizer inside, so don't call them from outside.
  // **************************************************
  is_lemma_empty: function() {
    return this.lems.length == 0;
  },

  // set up dictionary data
  load_wordnet_files: function(pos, list, exc) {
    var key_idx = pos + this.idx;
    this.open_file(key_idx, list);
    var key_exc = pos + this.exc;
    this.open_file(key_exc, exc);
  },

  setup_dic_data: function(pos) {
    var self = this;
    var key_idx = pos + this.idx;
    _.each( this.fetch_idx_data(key_idx), function(w) {
      self.wordlists[pos][w] = w;
    });
    var key_exc = pos + this.exc;
    _.each( this.fetch_exc_data(key_exc), function(item) {
      var w = item[0];
      var s = item[1];
      self.exceptions[pos][w] = s;
    });
  },

  open_file: function(key, file) {
    if (!localStorage[key]) {
      var self = this;
      // when using async ajax, localStorage[key] return undefined at first. (186)
      // $.get(file, function(data){
      //   self.store_data(key, data);
      // });

      // so use sync networking only at the first time.
      $.ajax({
        url: file,
        type: 'get',
        async: false,
        success: function(data) {
          self.store_data(key, data);
        }
      });
    }
  },

  store_data: function(key, data) {
    localStorage[key] = data;
  },

  // somehow JSON.parse(localStorage[key]) does not work, so build array data from string.
  fetch_idx_data: function(key) {
    arr = localStorage[key].split(',');
    return arr;
  },

  fetch_exc_data: function(key) {
    data = localStorage[key].split(',');
    var len = data.length;
    var index = 0;
    var arr = [];
    for (var i = 0; i < len; i++) {
      if (i % 2 != 0) {
        continue;
      }
      arr[index] = [];
      arr[index][0] = data[i];
      arr[index][1] = data[i+1];
      index++;
    }
    return arr;
  },
  // end of set up dictionary data

  base_forms: function(pos) {
    this.irregular_bases(pos);
    this.regular_bases(pos);
  },

  // build array lemmas(this.lems) like [ [lemma1, "verb"], [lemma2, "noun"]... ]
  irregular_bases: function(pos) {
    if (this.exceptions[pos][this.form] && this.exceptions[pos][this.form] != this.form) {
      this.lems.push( [this.exceptions[pos][this.form], pos] );
    }
  },

  // build array lemmas(this.lems) like [ [lemma1, "verb"], [lemma2, "noun"]... ]
  regular_bases: function(pos) {
    var bases = null;
    // bases -> [ [lemma1, lemma2, lemma3...], pos ]
    bases = this.possible_bases(pos);
    if (bases) {
      this.check_lemmas(bases);
    }
  },

  // check if possible bases are include in lemma wordlists and push
  check_lemmas: function(bases) {
    var self = this;
    // bases -> [ [lemma1, lemma2, lemma3...], pos ]
    var lemmas = bases[0];
    var pos = bases[1];
    _.each( lemmas, function(lemma) {
      if ( self.wordlists[pos][lemma] && self.wordlists[pos][lemma] == lemma && lemma != self.form ) {
        self.lems.push( [lemma, pos] );
      }
    });
  },

  possible_bases: function(pos) {
    var self = this;
    var form = this.form;
    var lemmas = [];

    _.each(this.morphological_substitutions[pos], function(entry) {
      var morpho = entry[0];
      var origin = entry[1];
      if ( form.endsWith(morpho) ) {
        if ( pos == 'verb' && morpho == 'ing' && self.double_consonant(morpho) ) {
          lemmas.push( form.slice( 0, -(morpho.length + 1) + origin ) );
        }
        if ( (pos == 'adj' || pos == 'adv') && morpho == 'est' && self.double_consonant(morpho) ) {
          lemmas.push( form.slice( 0, -(morpho.length + 1) + origin ) );
        }
        if ( (pos == 'adj' || pos == 'adv') && morpho == 'er' && self.double_consonant(morpho) ) {
          lemmas.push( form.slice( 0, -(morpho.length + 1) + origin ) );
        }
        lemmas.push( form.slice( 0, -(morpho.length) ) + origin );
      }
    });

    if (lemmas.length == 0) {
      lemmas.push(form);
    }

    return [ lemmas, pos ];
  },

  double_consonant: function(suffix) {
    // for like bigger -> big
    var form = this.form;
    // length after removing suffix from form
    var len = form.length - suffix.length;
    return this.is_vowel(form[len - 3]) && !this.is_vowel(form[len - 2]) && form[len - 2] === form[len - 1];
  },

  is_vowel: function(letter) {
    return _.include(["a", "e", "i", "o", "u"], letter);
  },

  // [ ["leave", "verb"], ["leaf", "noun"], ["leave", "verb"], ["leave", "noun"] ];
  // -> [ ["leave", "verb"], ["leaf", "noun"], ["leave", "noun"] ];
  uniq_lemmas: function(lemmas) {
    var u_lemmas = [];
    var len = lemmas.length;
    for (var i = 0; i < len; i++) {
      var val = lemmas[i];
      if (!this.is_include(u_lemmas, val)) {
        u_lemmas.push(val);
      }
    }
    return u_lemmas;
  },

  is_include: function(lemmas, target) {
    var len = lemmas.length;
    for (var i = 0; i < len; i++) {
      if (lemmas[i][0] == target[0] && lemmas[i][1] == target[1]) {
        return true;
      }
    }
    return false;
  },

  // for debug to use like $('#lem-confirm').html( lem.confirm_dic('exc') )
  confirm_dic: function(type) {
    var words = null;
    if (type == 'exc') {
      words = this.exceptions;
    } else if (type == 'idx') {
      words = this.wordlists;
    }
    var html = '*** ' + type + ' ***
';
    var parts = ['verb', 'noun', 'adj', 'adv'];
    var len = parts.length;
    for (var i = 0; i < len; i++) {
      var pos = parts[i];
      var pos_comment = '--- ' + pos + ' ---
';
      var html = html + pos_comment;
      for (var w in words[pos]) {
        var item = w + ' -> ' + words[pos][w] + '
';
        var html = html + item;
      }
    }
    return html;
  }
};
<|endoftext|>


<commit_before>/*exported MeanValue*/
var MeanValue = (function() {
  'use strict';

  /**
   * modulo with Euclidean division.
   * Always the same sign as the divisor (d).
   * Useful for accessing arrays using negative indices.
   *
   * Example:
   *   modulo( -1, 3 ) => 2
   */
  function modulo( n, d ) {
    return ( ( n % d ) + d  ) % d;
  }

  /**
   * Converts (x, y) to a set of mean-value coordinate weights.
   *
   * Note that vertices should be arranged counter-clockwise or weights will be
   * negative.
   */
  function convert2d( x, y, vertices ) {
    var vertexCount = 0.5 * vertices.length;

    var weights = [];
    var sum = 0;

    // Note that (x1, y1) and a1 represent the current vertex and angle.
    var x0, y0, x1, y1, x2, y2;
    var dx0, dy0, dx1, dy1, dx2, dy2;
    var a0, a1;
    var distance;
    var weight;
    var i;
    for ( i = 0; i < vertexCount; i++ ) {
      // Previous vertex.
      x0 = vertices[ 2 * modulo( i - 1, vertexCount ) ];
      y0 = vertices[ 2 * modulo( i - 1, vertexCount ) + 1 ];
      // Current vertex.
      x1 = vertices[ 2 * i ];
      y1 = vertices[ 2 * i + 1 ];
      // Next vertex.
      x2 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) ];
      y2 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) + 1 ];

      // Calculate angles.
      dx0 = x0 - x;
      dy0 = y0 - y;

      dx1 = x1 - x;
      dy1 = y1 - y;

      dx2 = x2 - x;
      dy2 = y2 - y;

      a0 = Math.atan2( dy1, dx1 ) - Math.atan2( dy0, dx0 );
      a1 = Math.atan2( dy2, dx2 ) - Math.atan2( dy1, dx1 );

      distance = Math.sqrt( dx1 * dx1 + dy1 * dy1 );

      /**
       * Calculate weight:
       *
       *           tan( a0 / 2 ) + tan( a1 / 2 )
       * weight = --------------------------------
       *                   || ai - a1 ||
       */
      weight = ( Math.tan( 0.5 * a0 ) + Math.tan( 0.5 * a1 ) ) / distance;
      weights.push( weight );
      sum += weight;
    }

    // If the sum of weights is infinite, then the point lies on either
    // a vertex or an edge.
    var il;
    var i0, i1;
    var indices;
    var dx, dy;
    if ( !isFinite( sum ) ) {
      sum = 0;
      indices = [];
      // Convert all infinite weight values to one.
      // All other values are zeroed.
      for ( i = 0, il = weights.length; i < il; i++ ) {
        if ( isFinite( weights[i] ) ) {
          weights[i] = 0;
        } else {
          weights[i] = 1;
          indices.push(i);
          sum++;
        }
      }

      // The point is on a vertex.
      // No need to normalize weights.
      if ( sum === 1 ) {
        return weights;
      }

      // The points lies on an edge.
      if ( sum === 2 ) {
        i0 = indices[0];
        i1 = indices[1];

        x0 = vertices[ 2 * modulo( i0, vertexCount ) ];
        y0 = vertices[ 2 * modulo( i0, vertexCount ) + 1 ];
        x1 = vertices[ 2 * modulo( i1, vertexCount ) ];
        y1 = vertices[ 2 * modulo( i1, vertexCount ) + 1 ];

        dx1 = x1 - x;
        dy1 = y1 - y;

        dx = x1 - x0;
        dy = y1 - y0;

        // Determine the lerp parameter with the dot product.
        weights[ i0 ] = ( dx1 * dx + dy1 * dy ) / ( dx * dx + dy * dy );
        weights[ i1 ] = 1 - weights[ i0 ];

        // As the combined weights must sum up to one, it is not necessary to
        // normalize weights.
        return weights;
      }
    }

    // Normalize weights.
    var sumInverse = 1 / sum;
    for ( i = 0, il = weights.length; i < il; i++ ) {
      weights[i] *= sumInverse;
    }

    return weights;
  }

  /**
   * Interpolates mean-value coordinate weights along vertices.
   */
  function interpolate2d( weights, vertices ) {
    var vertexCount = 0.5 * vertices.length;
    if ( vertexCount > weights.length ) {
      return;
    }

    var x = 0,
        y = 0;

    for ( var i = 0; i < vertexCount; i++ ) {
      x += weights[i] * vertices[ 2 * i ];
      y += weights[i] * vertices[ 2 * i + 1 ];
    }

    return {
      x: x,
      y: y
    };
  }

  return {
    convert2d: convert2d,
    interpolate2d: interpolate2d
  };
}) ();
<commit_msg>Handle MeanValue case with overlapping vertices.<commit_after>/*exported MeanValue*/
var MeanValue = (function() {
  'use strict';

  /**
   * modulo with Euclidean division.
   * Always the same sign as the divisor (d).
   * Useful for accessing arrays using negative indices.
   *
   * Example:
   *   modulo( -1, 3 ) => 2
   */
  function modulo( n, d ) {
    return ( ( n % d ) + d  ) % d;
  }

  /**
   * Converts (x, y) to a set of mean-value coordinate weights.
   *
   * Note that vertices should be arranged counter-clockwise or weights will be
   * negative.
   */
  function convert2d( x, y, vertices ) {
    var vertexCount = 0.5 * vertices.length;

    var weights = [];
    var sum = 0;

    // Note that (x1, y1) and a1 represent the current vertex and angle.
    var x0, y0, x1, y1, x2, y2;
    var dx0, dy0, dx1, dy1, dx2, dy2;
    var a0, a1;
    var distance;
    var weight;
    var i;
    for ( i = 0; i < vertexCount; i++ ) {
      // Previous vertex.
      x0 = vertices[ 2 * modulo( i - 1, vertexCount ) ];
      y0 = vertices[ 2 * modulo( i - 1, vertexCount ) + 1 ];
      // Current vertex.
      x1 = vertices[ 2 * i ];
      y1 = vertices[ 2 * i + 1 ];
      // Next vertex.
      x2 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) ];
      y2 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) + 1 ];

      // Calculate angles.
      dx0 = x0 - x;
      dy0 = y0 - y;

      dx1 = x1 - x;
      dy1 = y1 - y;

      dx2 = x2 - x;
      dy2 = y2 - y;

      a0 = Math.atan2( dy1, dx1 ) - Math.atan2( dy0, dx0 );
      a1 = Math.atan2( dy2, dx2 ) - Math.atan2( dy1, dx1 );

      distance = Math.sqrt( dx1 * dx1 + dy1 * dy1 );

      /**
       * Calculate weight:
       *
       *           tan( a0 / 2 ) + tan( a1 / 2 )
       * weight = --------------------------------
       *                   || ai - a1 ||
       */
      weight = ( Math.tan( 0.5 * a0 ) + Math.tan( 0.5 * a1 ) ) / distance;
      weights.push( weight );
      sum += weight;
    }

    // If the sum of weights is infinite, then the point lies on either
    // a vertex or an edge.
    var il;
    var i0, i1;
    var indices;
    var dx, dy;
    var distanceSquared;
    if ( !isFinite( sum ) ) {
      sum = 0;
      indices = [];
      // Convert all infinite weight values to one.
      // All other values are zeroed.
      for ( i = 0, il = weights.length; i < il; i++ ) {
        if ( isFinite( weights[i] ) ) {
          weights[i] = 0;
        } else {
          weights[i] = 1;
          indices.push(i);
          sum++;
        }
      }

      // The point is on a vertex.
      // No need to normalize weights.
      if ( sum === 1 ) {
        return weights;
      }

      // The points lies on an edge.
      if ( sum === 2 ) {
        i0 = indices[0];
        i1 = indices[1];

        x0 = vertices[ 2 * modulo( i0, vertexCount ) ];
        y0 = vertices[ 2 * modulo( i0, vertexCount ) + 1 ];
        x1 = vertices[ 2 * modulo( i1, vertexCount ) ];
        y1 = vertices[ 2 * modulo( i1, vertexCount ) + 1 ];

        dx1 = x1 - x;
        dy1 = y1 - y;

        dx = x1 - x0;
        dy = y1 - y0;

        distanceSquared = dx * dx + dy * dy;

        // Handle degenerate distances (two vertices have the same position).
        if ( !distanceSquared ) {
          weights[ i0 ] = 1;
          weights[ i1 ] = 0;
          return weights;
        }

        // Determine the lerp parameter with the dot product.
        weights[ i0 ] = ( dx1 * dx + dy1 * dy ) / distanceSquared;
        weights[ i1 ] = 1 - weights[ i0 ];

        // As the combined weights must sum up to one, it is not necessary to
        // normalize weights.
        return weights;
      }
    }

    // Normalize weights.
    var sumInverse = 1 / sum;
    for ( i = 0, il = weights.length; i < il; i++ ) {
      weights[i] *= sumInverse;
    }

    return weights;
  }

  /**
   * Interpolates mean-value coordinate weights along vertices.
   */
  function interpolate2d( weights, vertices ) {
    var vertexCount = 0.5 * vertices.length;
    if ( vertexCount > weights.length ) {
      return;
    }

    var x = 0,
        y = 0;

    for ( var i = 0; i < vertexCount; i++ ) {
      x += weights[i] * vertices[ 2 * i ];
      y += weights[i] * vertices[ 2 * i + 1 ];
    }

    return {
      x: x,
      y: y
    };
  }

  return {
    convert2d: convert2d,
    interpolate2d: interpolate2d
  };
}) ();
<|endoftext|>