<commit_before>const ByteBuffer = require('bytebuffer');
const EventEmitter = require('events').EventEmitter;
const SteamID = require('steamid');
const Util = require('util');

const Language = require('./language.js');
const Protos = require('./protobufs/generated/_load.js');

const STEAM_APPID = 730;

module.exports = GlobalOffensive;

Util.inherits(GlobalOffensive, EventEmitter);

function GlobalOffensive(steam) {
	if (steam.packageName != 'steam-user' || !steam.packageVersion || !steam.constructor) {
		throw new Error('globaloffensive v2 only supports steam-user v4.2.0 or later.');
	} else {
		let parts = steam.packageVersion.split('.');
		if (parts[0] < 4 || parts[1] < 2) {
			throw new Error(`globaloffensive v2 only supports steam-user v4.2.0 or later. ${steam.constructor.name} v${steam.packageVersion} given.`);
		}
	}

	this._steam = steam;
	this.haveGCSession = false;
	this._isInCSGO = false;

	this._steam.on('receivedFromGC', (appid, msgType, payload) => {
		if (appid != STEAM_APPID) {
			return; // we don't care
		}

		let isProtobuf = !Buffer.isBuffer(payload);
		let handler = null;

		if (this._handlers[msgType]) {
			handler = this._handlers[msgType];
		}

		let msgName = msgType;
		for (let i in Language) {
			if (Language.hasOwnProperty(i) && Language[i] == msgType) {
				msgName = i;
				break;
			}
		}

		this.emit('debug', "Got " + (handler ? "handled" : "unhandled") + " GC message " + msgName + (isProtobuf ? " (protobuf)" : ""));
		if (handler) {
			handler.call(this, isProtobuf ? payload : ByteBuffer.wrap(payload, ByteBuffer.LITTLE_ENDIAN));
		}
	});

	this._steam.on('appLaunched', (appid) => {
		if (this._isInCSGO) {
			return; // we don't care if it was launched again
		}

		if (appid == STEAM_APPID) {
			this._isInCSGO = true;
			if (!this.haveGCSession) {
				this._connect();
			}
		}
	});

	let handleAppQuit = (emitDisconnectEvent) => {
		if (this._helloInterval) {
			clearInterval(this._helloInterval);
			this._helloInterval = null;
		}

		if (this.haveGCSession && emitDisconnectEvent) {
			this.emit('disconnectedFromGC', GlobalOffensive.GCConnectionStatus.NO_SESSION);
		}

		this.haveGCSession = false;
	};

	this._steam.on('appQuit', (appid) => {
		if (!this._isInCSGO) {
			return;
		}

		if (appid == STEAM_APPID) {
			handleAppQuit(false);
		}
	});

	this._steam.on('disconnected', () => {
		handleAppQuit(true);
	});

	this._steam.on('error', (err) => {
		handleAppQuit(true);
	});
}

GlobalOffensive.prototype._connect = function() {
	if (!this._isInCSGO || this._helloTimer) {
		this.emit('debug', "Not trying to connect due to " + (!this._isInCSGO ? "not in CS:GO" : "has helloTimer"));
		return; // We're not in CS:GO or we're already trying to connect
	}

	let sendHello = () => {
		if (!this._isInCSGO) {
			this.emit('debug', "Not sending hello because we're no longer in CS:GO");
			delete this._helloTimer;
			return;
		} else if (this.haveGCSession) {
			this.emit('debug', "Not sending hello because we have a session");
			clearTimeout(this._helloTimer);
			delete this._helloTimer;
			return;
		}

		this._send(Language.ClientHello, Protos.CMsgClientHello, {});
		this._helloTimerMs = Math.min(60000, (this._helloTimerMs || 1000) * 2); // exponential backoff, max 60 seconds
		this._helloTimer = setTimeout(sendHello, this._helloTimerMs);
		this.emit('debug', "Sending hello, setting timer for next attempt to " + this._helloTimerMs + " ms");
	};

	this._helloTimer = setTimeout(sendHello, 500);
};

GlobalOffensive.prototype._send = function(type, protobuf, body) {
	if (!this._steam.steamID) {
		return false;
	}

	let msgName = type;
	for (let i in Language) {
		if (Language[i] == type) {
			msgName = i;
			break;
		}
	}

	this.emit('debug', "Sending GC message " + msgName);

	if (protobuf) {
		this._steam.sendToGC(STEAM_APPID, type, {}, protobuf.encode(body).finish());
	} else {
		// This is a ByteBuffer
		this._steam.sendToGC(STEAM_APPID, type, null, body.flip().toBuffer());
	}

	return true;
};

GlobalOffensive.prototype.requestLiveGames = function() {
	this._send(Language.MatchListRequestCurrentLiveGames, Protos.CMsgGCCStrike15_v2_MatchListRequestCurrentLiveGames, {});
};

GlobalOffensive.prototype.requestRecentGames = function(steamid) {
	if (typeof steamid === 'string') {
		steamid = new SteamID(steamid);
	}

	if (!steamid.isValid() || steamid.universe != SteamID.Universe.PUBLIC || steamid.type != SteamID.Type.INDIVIDUAL || steamid.instance != SteamID.Instance.DESKTOP) {
		return false;
	}

	this._send(Language.MatchListRequestRecentUserGames, Protos.CMsgGCCStrike15_v2_MatchListRequestRecentUserGames, {
		accountid: steamid.accountid
	});
};

GlobalOffensive.prototype.requestLiveGameForUser = function(steamid) {
	if (typeof steamid === 'string') {
		steamid = new SteamID(steamid);
	}

	if (!steamid.isValid() || steamid.universe != SteamID.Universe.PUBLIC || steamid.type != SteamID.Type.INDIVIDUAL || steamid.instance != SteamID.Instance.DESKTOP) {
		return false;
	}

	this._send(Language.MatchListRequestLiveGameForUser, Protos.CMsgGCCStrike15_v2_MatchListRequestLiveGameForUser, {
		accountid: sid.accountid
	});
};

GlobalOffensive.prototype.inspectItem = function(owner, assetid, d, callback) {
	let match;
	if (typeof owner === 'string' && (match = owner.match(/[SM](\d+)A(\d+)D(\d+)$/))) {
		callback = assetid;
		owner = match[1];
		assetid = match[2];
		d = match[3];
	}

	let msg = {
		"param_a": assetid,
		"param_d": d,
		"param_s": 0,
		"param_m": 0
	};

	if (typeof owner === 'object') {
		owner = owner.toString();
	}

	try {
		let sid = new SteamID(owner);
		if (!sid.isValid() || sid.universe != SteamID.Universe.PUBLIC || sid.type != SteamID.Type.INDIVIDUAL || sid.instance != SteamID.Instance.DESKTOP) {
			throw 0;
		}
		// it's a valid steamid
		msg.param_s = owner;
	} catch (e) {
		msg.param_m = owner;
	}

	this._send(Language.Client2GCEconPreviewDataBlockRequest, Protos.CMsgGCCStrike15_v2_Client2GCEconPreviewDataBlockRequest, msg);
	if (callback) {
		this.once('inspectItemInfo#' + assetid, callback);
	}
};

GlobalOffensive.prototype.requestPlayersProfile = function(steamid, callback) {
	if (typeof steamid == 'string') {
		steamid = new SteamID(steamid);
	}

	if (!steamid.isValid() || steamid.universe != SteamID.Universe.PUBLIC || steamid.type != SteamID.Type.INDIVIDUAL || steamid.instance != SteamID.Instance.DESKTOP) {
		return false;
	}

	this._send(Language.ClientRequestPlayersProfile, Protos.CMsgGCCStrike15_v2_ClientRequestPlayersProfile, {
		account_id: steamid.accountid,
		request_level: 32
	});

	if (callback) {
		this.once('playersProfile#' + steamid.getSteamID64(), callback);
	}
};

GlobalOffensive.prototype.deleteItem = function(item) {
	let buffer = new ByteBuffer(8, ByteBuffer.LITTLE_ENDIAN);
	buffer.writeUint64(item);
	this._send(Language.Delete, null, buffer);
};

GlobalOffensive.prototype._handlers = {};

require('./enums.js');
require('./handlers.js');
<commit_msg>fix incorrect name for steamid variable in requestLiveGameForUser<commit_after>const ByteBuffer = require('bytebuffer');
const EventEmitter = require('events').EventEmitter;
const SteamID = require('steamid');
const Util = require('util');

const Language = require('./language.js');
const Protos = require('./protobufs/generated/_load.js');

const STEAM_APPID = 730;

module.exports = GlobalOffensive;

Util.inherits(GlobalOffensive, EventEmitter);

function GlobalOffensive(steam) {
	if (steam.packageName != 'steam-user' || !steam.packageVersion || !steam.constructor) {
		throw new Error('globaloffensive v2 only supports steam-user v4.2.0 or later.');
	} else {
		let parts = steam.packageVersion.split('.');
		if (parts[0] < 4 || parts[1] < 2) {
			throw new Error(`globaloffensive v2 only supports steam-user v4.2.0 or later. ${steam.constructor.name} v${steam.packageVersion} given.`);
		}
	}

	this._steam = steam;
	this.haveGCSession = false;
	this._isInCSGO = false;

	this._steam.on('receivedFromGC', (appid, msgType, payload) => {
		if (appid != STEAM_APPID) {
			return; // we don't care
		}

		let isProtobuf = !Buffer.isBuffer(payload);
		let handler = null;

		if (this._handlers[msgType]) {
			handler = this._handlers[msgType];
		}

		let msgName = msgType;
		for (let i in Language) {
			if (Language.hasOwnProperty(i) && Language[i] == msgType) {
				msgName = i;
				break;
			}
		}

		this.emit('debug', "Got " + (handler ? "handled" : "unhandled") + " GC message " + msgName + (isProtobuf ? " (protobuf)" : ""));
		if (handler) {
			handler.call(this, isProtobuf ? payload : ByteBuffer.wrap(payload, ByteBuffer.LITTLE_ENDIAN));
		}
	});

	this._steam.on('appLaunched', (appid) => {
		if (this._isInCSGO) {
			return; // we don't care if it was launched again
		}

		if (appid == STEAM_APPID) {
			this._isInCSGO = true;
			if (!this.haveGCSession) {
				this._connect();
			}
		}
	});

	let handleAppQuit = (emitDisconnectEvent) => {
		if (this._helloInterval) {
			clearInterval(this._helloInterval);
			this._helloInterval = null;
		}

		if (this.haveGCSession && emitDisconnectEvent) {
			this.emit('disconnectedFromGC', GlobalOffensive.GCConnectionStatus.NO_SESSION);
		}

		this.haveGCSession = false;
	};

	this._steam.on('appQuit', (appid) => {
		if (!this._isInCSGO) {
			return;
		}

		if (appid == STEAM_APPID) {
			handleAppQuit(false);
		}
	});

	this._steam.on('disconnected', () => {
		handleAppQuit(true);
	});

	this._steam.on('error', (err) => {
		handleAppQuit(true);
	});
}

GlobalOffensive.prototype._connect = function() {
	if (!this._isInCSGO || this._helloTimer) {
		this.emit('debug', "Not trying to connect due to " + (!this._isInCSGO ? "not in CS:GO" : "has helloTimer"));
		return; // We're not in CS:GO or we're already trying to connect
	}

	let sendHello = () => {
		if (!this._isInCSGO) {
			this.emit('debug', "Not sending hello because we're no longer in CS:GO");
			delete this._helloTimer;
			return;
		} else if (this.haveGCSession) {
			this.emit('debug', "Not sending hello because we have a session");
			clearTimeout(this._helloTimer);
			delete this._helloTimer;
			return;
		}

		this._send(Language.ClientHello, Protos.CMsgClientHello, {});
		this._helloTimerMs = Math.min(60000, (this._helloTimerMs || 1000) * 2); // exponential backoff, max 60 seconds
		this._helloTimer = setTimeout(sendHello, this._helloTimerMs);
		this.emit('debug', "Sending hello, setting timer for next attempt to " + this._helloTimerMs + " ms");
	};

	this._helloTimer = setTimeout(sendHello, 500);
};

GlobalOffensive.prototype._send = function(type, protobuf, body) {
	if (!this._steam.steamID) {
		return false;
	}

	let msgName = type;
	for (let i in Language) {
		if (Language[i] == type) {
			msgName = i;
			break;
		}
	}

	this.emit('debug', "Sending GC message " + msgName);

	if (protobuf) {
		this._steam.sendToGC(STEAM_APPID, type, {}, protobuf.encode(body).finish());
	} else {
		// This is a ByteBuffer
		this._steam.sendToGC(STEAM_APPID, type, null, body.flip().toBuffer());
	}

	return true;
};

GlobalOffensive.prototype.requestLiveGames = function() {
	this._send(Language.MatchListRequestCurrentLiveGames, Protos.CMsgGCCStrike15_v2_MatchListRequestCurrentLiveGames, {});
};

GlobalOffensive.prototype.requestRecentGames = function(steamid) {
	if (typeof steamid === 'string') {
		steamid = new SteamID(steamid);
	}

	if (!steamid.isValid() || steamid.universe != SteamID.Universe.PUBLIC || steamid.type != SteamID.Type.INDIVIDUAL || steamid.instance != SteamID.Instance.DESKTOP) {
		return false;
	}

	this._send(Language.MatchListRequestRecentUserGames, Protos.CMsgGCCStrike15_v2_MatchListRequestRecentUserGames, {
		accountid: steamid.accountid
	});
};

GlobalOffensive.prototype.requestLiveGameForUser = function(steamid) {
	if (typeof steamid === 'string') {
		steamid = new SteamID(steamid);
	}

	if (!steamid.isValid() || steamid.universe != SteamID.Universe.PUBLIC || steamid.type != SteamID.Type.INDIVIDUAL || steamid.instance != SteamID.Instance.DESKTOP) {
		return false;
	}

	this._send(Language.MatchListRequestLiveGameForUser, Protos.CMsgGCCStrike15_v2_MatchListRequestLiveGameForUser, {
		accountid: steamid.accountid
	});
};

GlobalOffensive.prototype.inspectItem = function(owner, assetid, d, callback) {
	let match;
	if (typeof owner === 'string' && (match = owner.match(/[SM](\d+)A(\d+)D(\d+)$/))) {
		callback = assetid;
		owner = match[1];
		assetid = match[2];
		d = match[3];
	}

	let msg = {
		"param_a": assetid,
		"param_d": d,
		"param_s": 0,
		"param_m": 0
	};

	if (typeof owner === 'object') {
		owner = owner.toString();
	}

	try {
		let sid = new SteamID(owner);
		if (!sid.isValid() || sid.universe != SteamID.Universe.PUBLIC || sid.type != SteamID.Type.INDIVIDUAL || sid.instance != SteamID.Instance.DESKTOP) {
			throw 0;
		}
		// it's a valid steamid
		msg.param_s = owner;
	} catch (e) {
		msg.param_m = owner;
	}

	this._send(Language.Client2GCEconPreviewDataBlockRequest, Protos.CMsgGCCStrike15_v2_Client2GCEconPreviewDataBlockRequest, msg);
	if (callback) {
		this.once('inspectItemInfo#' + assetid, callback);
	}
};

GlobalOffensive.prototype.requestPlayersProfile = function(steamid, callback) {
	if (typeof steamid == 'string') {
		steamid = new SteamID(steamid);
	}

	if (!steamid.isValid() || steamid.universe != SteamID.Universe.PUBLIC || steamid.type != SteamID.Type.INDIVIDUAL || steamid.instance != SteamID.Instance.DESKTOP) {
		return false;
	}

	this._send(Language.ClientRequestPlayersProfile, Protos.CMsgGCCStrike15_v2_ClientRequestPlayersProfile, {
		account_id: steamid.accountid,
		request_level: 32
	});

	if (callback) {
		this.once('playersProfile#' + steamid.getSteamID64(), callback);
	}
};

GlobalOffensive.prototype.deleteItem = function(item) {
	let buffer = new ByteBuffer(8, ByteBuffer.LITTLE_ENDIAN);
	buffer.writeUint64(item);
	this._send(Language.Delete, null, buffer);
};

GlobalOffensive.prototype._handlers = {};

require('./enums.js');
require('./handlers.js');
<|endoftext|>


<commit_before>#!/usr/bin/env node
/* eslint-disable no-case-declarations */
/* eslint-disable global-require */

const program = require('commander')
const { TerminalUtils } = require('constellate-dev-utils')
const { configureGracefulExit, loadEnvVars } = require('constellate-utils')

const rollbackRepo = require('../utils/rollbackRepo')
const packageJson = require('../../package.json')

const noop = () => undefined

TerminalUtils.header(`constellate v${packageJson.version || '0.0.0-develop'}`)

program.version(packageJson.version || '0.0.0-develop')

const ArgParsers = {
  list: val => val.split(','),
}

const createAction = ({
  defaultEnv = 'production',
  resolveScript,
  gracefulExit = noop,
  errorMsg,
  preScript,
}) => async (...originalArgs) => {
  try {
    configureGracefulExit({
      onExit: gracefulExit,
      name: 'constellate',
    })
    if (!process.env.NODE_ENV) {
      process.env.NODE_ENV = defaultEnv
    }
    loadEnvVars()
    if (preScript) {
      await preScript()
    }

    let options
    let args = []
    if (args.length === 1) {
      options = originalArgs[0]
    } else {
      args = originalArgs.slice(0, originalArgs.length - 1)
      options = originalArgs[originalArgs.length - 1]
    }

    const script = resolveScript(options, args)
    await script()
    process.exit(0)
  } catch (err) {
    TerminalUtils.error('Argh! An unexpected error has occurred', err)
    if (errorMsg) {
      TerminalUtils.error(errorMsg)
    }
    gracefulExit()
    process.exit(1)
  }
}

program.command('build').description('Builds the projects').action(
  createAction({
    resolveScript: () => require('../scripts/build'),
  }),
)

program
  .command('clean')
  .description('Deletes the build output and node_modules files for projects')
  .option(
    '-p, --projects <projects>',
    'Specify the projects to run the install for (defaults to all)',
    ArgParsers.list,
  )
  .option('-n, --node-modules', 'Removes node_modules for each project')
  .option('-l, --package-lock', 'Removes package-lock.json for each project')
  .option('-b, --build', 'Removes build output for each project')
  .action(
    createAction({
      resolveScript: options => () => require('../scripts/clean')(options),
    }),
  )

program.command('deploy').description('Deploys the projects').action(
  createAction({
    resolveScript: () => require('../scripts/deploy'),
    errorMsg: 'Your projects may not have been fully deployed. Please check your expected deployment targets.',
  }),
)

program
  .command('develop')
  .description('Runs a development environment for the projects')
  .action(
    createAction({
      defaultEnv: 'development',
      preScript: () => {
        TerminalUtils.title('Kickstarting development hyperengine...')
        console.log(`\n${require('../utils/getCarlSaganQuote')()}\n`)
        return new Promise(resolve => setTimeout(resolve, 3000))
      },
      resolveScript: () => require('../scripts/develop'),
    }),
  )

program
  .command('install')
  .description('Installs the dependencies for every project')
  .option(
    '-p, --projects <projects>',
    'Specify the projects to run the install for',
    ArgParsers.list,
  )
  .option('-c, --clean', 'Removes existing node_modules for each project')
  .option(
    '-h, --hard-clean',
    'Removes existing node_modules and package-lock.json for each project',
  )
  .action(
    createAction({
      // We should not use "production" as a NODE_ENV because then only our
      // production dependencies will get installed, i.e. no devDependencies
      defaultEnv: 'development',
      resolveScript: options => () => require('../scripts/install')(options),
    }),
  )

program
  .command('link-projects')
  .description('Links project(s) to a project')
  .action(
    createAction({
      resolveScript: () => require('../scripts/linkProjects'),
    }),
  )

program
  .command('release')
  .description(
    'Creates a new release, versioning the app, the changed projects, and published the changed projects to NPM',
  )
  .action(
    createAction({
      resolveScript: () => require('../scripts/release'),
      gracefulExit: rollbackRepo,
    }),
  )

program
  .command('test [...passThroughArgs]')
  .description('Runs the tests')
  .action(
    createAction({
      defaultEnv: 'test',
      resolveScript: (options, args) => () =>
        require('../scripts/test')({
          passThroughArgs: args,
        }),
    }),
  )

program.command('exec').description('Executed a provided command').action(
  createAction({
    resolveScript: () => () =>
      require('../scripts/exec')({
        passThroughArgs: process.argv.slice(3),
      }),
  }),
)

program
  .command('update')
  .description(
    'Runs an interactive dependency update process for every project',
  )
  .action(
    createAction({
      // We should not use "production" as a NODE_ENV because then only our
      // production dependencies will get installed, i.e. no devDependencies
      defaultEnv: 'development',
      resolveScript: () => require('../scripts/update'),
    }),
  )

// If the user passes no args, or an unknown arg then we will show the help
const showHelp = () => {
  program.outputHelp(x => console.log(x))
  process.exit(0)
}
program.command('*').action(showHelp)
if (!process.argv.slice(2).length) {
  showHelp()
}

program.parse(process.argv)

// Prevent node process from exiting. (until CTRL + C or process.exit is called)
// We do this to allow our scripts to respont to process exit events and do
// cleaning up etc.
const preventScriptExit = () => {
  (function wait() {
    // eslint-disable-next-line no-constant-condition
    if (true) setTimeout(wait, 1000)
  }())
}
preventScriptExit()
<commit_msg>Trying to decrease test output noise.<commit_after>#!/usr/bin/env node
/* eslint-disable no-case-declarations */
/* eslint-disable global-require */

const program = require('commander')
const { TerminalUtils } = require('constellate-dev-utils')
const { configureGracefulExit, loadEnvVars } = require('constellate-utils')

const rollbackRepo = require('../utils/rollbackRepo')
const packageJson = require('../../package.json')

const noop = () => undefined

TerminalUtils.header(`constellate v${packageJson.version || '0.0.0-develop'}`)

program.version(packageJson.version || '0.0.0-develop')

const ArgParsers = {
  list: val => val.split(','),
}

const createAction = ({
  defaultEnv = 'production',
  resolveScript,
  gracefulExit = noop,
  errorMsg,
  preScript,
}) => async (...originalArgs) => {
  try {
    configureGracefulExit({
      onExit: gracefulExit,
      name: 'constellate',
    })
    if (!process.env.NODE_ENV) {
      process.env.NODE_ENV = defaultEnv
    }
    loadEnvVars()
    if (preScript) {
      await preScript()
    }

    let options
    let args = []
    if (args.length === 1) {
      options = originalArgs[0]
    } else {
      args = originalArgs.slice(0, originalArgs.length - 1)
      options = originalArgs[originalArgs.length - 1]
    }

    const script = resolveScript(options, args)
    await script()
    process.exit(0)
  } catch (err) {
    TerminalUtils.error('Argh! An unexpected error has occurred', err)
    if (errorMsg) {
      TerminalUtils.error(errorMsg)
    }
    gracefulExit()
    process.exit(1)
  }
}

program.command('build').description('Builds the projects').action(
  createAction({
    resolveScript: () => require('../scripts/build'),
  }),
)

program
  .command('clean')
  .description('Deletes the build output and node_modules files for projects')
  .option(
    '-p, --projects <projects>',
    'Specify the projects to run the install for (defaults to all)',
    ArgParsers.list,
  )
  .option('-n, --node-modules', 'Removes node_modules for each project')
  .option('-l, --package-lock', 'Removes package-lock.json for each project')
  .option('-b, --build', 'Removes build output for each project')
  .action(
    createAction({
      resolveScript: options => () => require('../scripts/clean')(options),
    }),
  )

program.command('deploy').description('Deploys the projects').action(
  createAction({
    resolveScript: () => require('../scripts/deploy'),
    errorMsg: 'Your projects may not have been fully deployed. Please check your expected deployment targets.',
  }),
)

program
  .command('develop')
  .description('Runs a development environment for the projects')
  .action(
    createAction({
      defaultEnv: 'development',
      preScript: () => {
        TerminalUtils.title('Kickstarting development hyperengine...')
        console.log(`\n${require('../utils/getCarlSaganQuote')()}\n`)
        return new Promise(resolve => setTimeout(resolve, 3000))
      },
      resolveScript: () => require('../scripts/develop'),
    }),
  )

program
  .command('install')
  .description('Installs the dependencies for every project')
  .option(
    '-p, --projects <projects>',
    'Specify the projects to run the install for',
    ArgParsers.list,
  )
  .option('-c, --clean', 'Removes existing node_modules for each project')
  .option(
    '-h, --hard-clean',
    'Removes existing node_modules and package-lock.json for each project',
  )
  .action(
    createAction({
      // We should not use "production" as a NODE_ENV because then only our
      // production dependencies will get installed, i.e. no devDependencies
      defaultEnv: 'development',
      resolveScript: options => () => require('../scripts/install')(options),
    }),
  )

program
  .command('link-projects')
  .description('Links project(s) to a project')
  .action(
    createAction({
      resolveScript: () => require('../scripts/linkProjects'),
    }),
  )

program
  .command('release')
  .description(
    'Creates a new release, versioning the app, the changed projects, and published the changed projects to NPM',
  )
  .action(
    createAction({
      resolveScript: () => require('../scripts/release'),
      gracefulExit: rollbackRepo,
    }),
  )

/*
program
  .command('test [...passThroughArgs]')
  .description('Runs the tests')
  .action(
    createAction({
      defaultEnv: 'test',
      resolveScript: (options, args) => () =>
        require('../scripts/test')({
          passThroughArgs: args,
        }),
    }),
  )

program.command('exec').description('Executed a provided command').action(
  createAction({
    resolveScript: () => () =>
      require('../scripts/exec')({
        passThroughArgs: process.argv.slice(3),
      }),
  }),
)
*/

program
  .command('update')
  .description(
    'Runs an interactive dependency update process for every project',
  )
  .action(
    createAction({
      // We should not use "production" as a NODE_ENV because then only our
      // production dependencies will get installed, i.e. no devDependencies
      defaultEnv: 'development',
      resolveScript: () => require('../scripts/update'),
    }),
  )

// If the user passes no args, or an unknown arg then we will show the help
const showHelp = () => {
  program.outputHelp(x => console.log(x))
  process.exit(0)
}
program.command('*').action(showHelp)
if (!process.argv.slice(2).length) {
  showHelp()
}

const [cmd, args] = process.argv.slice(2)

if (cmd === 'test' || cmd === 'exec') {
  if (args.find(x => x === '--help' || x === '-h')) {
    // TODO: Print help.
  }
  const execScript = async (scriptThunk) => {
    loadEnvVars()
    await scriptThunk()
    process.exit(0)
  }

  switch (cmd) {
    case 'test': {
      execScript(() =>
        require('../scripts/test')({
          passThroughArgs: args,
        }),
      )
      break
    }
    case 'exec': {
      execScript(() =>
        require('../scripts/exec')({
          passThroughArgs: args,
        }),
      )
      break
    }
    default: {
      throw new Error('unkown')
    }
  }
} else {
  program.parse(process.argv)
}

// Prevent node process from exiting. (until CTRL + C or process.exit is called)
// We do this to allow our scripts to respont to process exit events and do
// cleaning up etc.
const preventScriptExit = () => {
  (function wait() {
    // eslint-disable-next-line no-constant-condition
    if (true) setTimeout(wait, 1000)
  }())
}
preventScriptExit()
<|endoftext|>


<commit_before>(function(){

    $(function() {
      $('#tipue_search_input').tipuesearch();
    });

})();
<commit_msg>add code that changes no-js to js for tipue demo...add comments<commit_after>(function(){

    // The Tipue-powered code that returns search results to
    // "search.html".
    $(function() {
      $('#tipue_search_input').tipuesearch();
    });

    // If JavaScript is enabled, this code will change the "no-js"
    // class on the opening <html> element to "js". This code is stolen
    // from Modernizr, so if Modernizr is already on your web page,
    // don't use this part od the code.
    var docElement = document.documentElement;
    docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') + ('js');

})();<|endoftext|>


<commit_before>'use strict';

const yeoman = require('yeoman-generator');
const yosay  = require('yosay');

function cleanAppname(appname) {
    return appname.replace(/\s/g, '-');
}

module.exports = yeoman.Base.extend({
    prompting: function () {
        this.log(yosay(
            'You are about to build a simple React/Redux application!'
        ));

        const prompts = [
            {
                type   : 'input',
                name   : 'appname',
                message: 'Enter your application name',
                default: cleanAppname(this.appname)
            },
            {
                type   : 'input',
                name   : 'description',
                message: 'Enter your application description',
                default: ''
            },
            {
                type   : 'input',
                name   : 'authorName',
                message: 'Author name?',
                default: ''
            },
            {
                type: 'input',
                name: 'authorEmail',
                message: 'Author\'s email?',
                default: ''
            },
            {
                type   : 'confirm',
                name   : 'npmInstall',
                message: 'Would you like to install dependencies?',
                default: true
            }
        ];

        return this.prompt(prompts).then(props => this.props = props);
    },

    writing: function () {
        // templated files
        this.fs.copyTpl(
            this.templatePath('package.json'),
            this.destinationPath('package.json'),
            this.props
        );

        this.fs.copyTpl(
            this.templatePath('index.js'),
            this.destinationPath('index.js'),
            this.props
        );

        // root files
        this.fs.copy(this.templatePath('.eslintrc'), this.destinationPath('.eslintrc'));
        this.fs.copy(this.templatePath('.babelrc'), this.destinationPath('.babelrc'));
        this.fs.copy(this.templatePath('webpack.config.js'), this.destinationPath('webpack.config.js'));

        // directories
        this.fs.copy(this.templatePath('config/'), this.destinationPath('config/'));
        this.fs.copy(this.templatePath('src'), this.destinationPath('src'));
    },

    install: function () {
        if (!this.props.npmInstall) {
            return;
        }

        this.npmInstall();
    }
});
<commit_msg>fix appname clean on prompt<commit_after>'use strict';

const yeoman = require('yeoman-generator');
const yosay  = require('yosay');

function cleanAppname(appname) {
    return appname.replace(/\s/g, '-');
}

module.exports = yeoman.Base.extend({
    prompting: function () {
        this.log(yosay(
            'You are about to build a simple React/Redux application!'
        ));

        const prompts = [
            {
                type   : 'input',
                name   : 'appname',
                message: 'Enter your application name',
                default: cleanAppname(this.appname)
            },
            {
                type   : 'input',
                name   : 'description',
                message: 'Enter your application description',
                default: ''
            },
            {
                type   : 'input',
                name   : 'authorName',
                message: 'Author name?',
                default: ''
            },
            {
                type: 'input',
                name: 'authorEmail',
                message: 'Author\'s email?',
                default: ''
            },
            {
                type   : 'confirm',
                name   : 'npmInstall',
                message: 'Would you like to install dependencies?',
                default: true
            }
        ];

        return this.prompt(prompts).then(props => {
            this.props.appname = cleanAppname(props.appname);

            this.props = props;
        });
    },

    writing: function () {
        // templated files
        this.fs.copyTpl(
            this.templatePath('package.json'),
            this.destinationPath('package.json'),
            this.props
        );

        this.fs.copyTpl(
            this.templatePath('index.js'),
            this.destinationPath('index.js'),
            this.props
        );

        // root files
        this.fs.copy(this.templatePath('.eslintrc'), this.destinationPath('.eslintrc'));
        this.fs.copy(this.templatePath('.babelrc'), this.destinationPath('.babelrc'));
        this.fs.copy(this.templatePath('webpack.config.js'), this.destinationPath('webpack.config.js'));

        // directories
        this.fs.copy(this.templatePath('config/'), this.destinationPath('config/'));
        this.fs.copy(this.templatePath('src'), this.destinationPath('src'));
    },

    install: function () {
        if (!this.props.npmInstall) {
            return;
        }

        this.npmInstall();
    }
});
<|endoftext|>


<commit_before>var
	DEFAULTS = require('./constants/defaults'),
	MESSAGES = require('./constants/messages'),
	PATTERNS = require('./constants/ignorePatterns')
;

module.exports = function(grunt) {

	grunt.registerMultiTask('lintspaces', 'Checking spaces', function() {
		var
			options = this.options(DEFAULTS),
			output = ''
		;

		// replace ingnore strings with buildin patterns:
		options.ignores = updateIgnores(options);

		this.files.forEach(function(file) {
			file.src.forEach(function(path) {
				var
					data = grunt.file.read(path, options.encoding),
					ignoredLines = indexIgnoreLines(options, data),
					lines = data.split('\n'),
					warnings = []
				;

				lines.forEach(function(line, index) {
					if(!ignoredLines[index]) {
						// check indentation:
						pushWarning(warnings, checkIndentation(options, line, index));
					}

					// check trailingspaces:
					pushWarning(warnings, checkTrailingspaces(options, line, index));
				});

				// check newline at end of file:
				pushWarning(warnings, checkNewline(options, lines));

				// print found warning for file
				output += formatWarnings(options, path, warnings);
			});
		});

		printOutput(output);
	});

	/* Validation functions. */
	function checkIndentation(options, line, index) {
		if(typeof options.indentation === 'string' && typeof line === 'string') {
			var
				tabsRegExp = /^\t*(?!\s).*$/, // leading tabs without leading spaces
				spacesRegExp = /^ *(?!\s).*$/, // leading spaces without leading tabs
				spacesLeadingRegExp = /^( *).*$/
			;

			switch(options.indentation) {
				case 'tabs':
					if(!tabsRegExp.test(line)) {
						// indentation failed...
						return formatMessage(index + 1, MESSAGES.INDENTATION_TABS);
					}
					break;

				case 'spaces':
					if(!spacesRegExp.test(line)) {
						// indentation failed...
						return formatMessage(index + 1, MESSAGES.INDENTATION_SPACES);
					} else {
						// indentation correct, is amount of spaces correct?
						if(typeof options.spaces === 'number') {
							if(line.match(spacesLeadingRegExp)[1].length % options.spaces !== 0) {
								return formatMessage(index + 1, MESSAGES.INDENTATION_SPACES_AMOUNT);
							}
						}
					}
					break;
			}
		}
	}

	function checkTrailingspaces(options, line, index) {
		if(options.trailingspaces && typeof line === 'string') {
			var matchSpaces = line.match(/\s*$/);
			if( matchSpaces.length > 0 && matchSpaces[0].length > 0) {
				return formatMessage(index + 1, MESSAGES.TRAILINGSPACES);
			}
		}
	}

	function checkNewline(options, lines) {
		if(options.newline && lines.length > 1) {
			var
				index = lines.length - 1
			;

			// check last line:
			if(lines[index].length > 0) {
				return formatMessage(index + 1, MESSAGES.NEWLINE);
			}

			// check line before last line:
			if(lines[index - 1].length === 0) {
				return formatMessage(index, MESSAGES.NEWLINE_AMOUNT);
			}
		}
	}

	function updateIgnores(options) {
		var ignores = [];
		if(Array.isArray(options.ignores)) {
			options.ignores.forEach(function(ignore) {
				if(typeof ignore === 'string' && typeof PATTERNS[ignore] === 'object') {
					ignores.push(PATTERNS[ignore]);
				} else if(typeof ignore === 'object' && typeof ignore.test === 'function') {
					ignores.push(ignore);
				}
			});
		}

		if(ignores.length === 0) {
			ignores = false;
		}

		return ignores;
	}

	function indexIgnoreLines(options, data) {
		var ignoredLines = {};

		if(Array.isArray(options.ignores)) {

			/* Loop all given regular expressions: */
			options.ignores.forEach(function(expression) {
				var
					lines = data,
					matches = data.match(expression),
					expressionIgnores = {},
					expressionIgnoresCount = 0
				;

				matches.forEach(function(match) {

					/* Only perform an action when match has more
					/* than one line */
					if(match.indexOf('\n') > -1) {
						var
							index = 0,
							removedAt = 0,
							removedLines = 0,
							oldLines = lines.split('\n'),
							newLines
						;

						/* remove match from 'lines' so it can't match for
						/* any other 'match' from this expression: */
						lines = lines.replace(match, '');
						newLines = lines.split('\n');

						/* Find the first line which isn't equal to the
						/* original lines to get starting line of match: */
						while(index < newLines.length && newLines[index] === oldLines[index]) {
							index++;
						}

						/* when a starting line was found, loop as long as
						/* possible over irregular lines to find all lines to
						/* ignore and list them: */
						removedAt = index + 1;
						while(	removedAt < oldLines.length &&
								removedAt < newLines.length &&
								oldLines[removedAt] !== newLines[index + 1]) {
							expressionIgnores[removedAt + expressionIgnoresCount] = true;
							removedLines++;
							removedAt++;
						}

						expressionIgnoresCount += removedLines;
					}
				});

				ignoredLines = extend(ignoredLines, expressionIgnores);
			});
		}

		return ignoredLines;
	}

	/* Helper functions for formating output. */
	function formatMessage(linenumber, message) {
		return 'L'+ linenumber +': '+ message;
	}

	function pushWarning(warnings, warning) {
		if(typeof warning === 'string') {
			warnings.push(warning);
		}
	}

	function formatWarnings(options, path, warnings) {
		var
			msg = ''
		;

		if(warnings.length > 0) {
			msg = '\nErrors found at '+ path;
			warnings.forEach(function(warning) {
				msg += '\n\t'+ warning;
			});
		}

		return msg;
	}

	function printOutput(output) {
		if(output.length > 0) {
			grunt.fail.warn(output +'\n');
		} else {
			grunt.log.ok('All spaces are correct.');
		}
	}

	function extend(target) {
		var sources = [].slice.call(arguments, 1);
		sources.forEach(function (source) {
			for (var prop in source) {
				target[prop] = source[prop];
			}
		});
		return target;
	}
};
<commit_msg>Refactor comments<commit_after>var
	DEFAULTS = require('./constants/defaults'),
	MESSAGES = require('./constants/messages'),
	PATTERNS = require('./constants/ignorePatterns')
;

module.exports = function(grunt) {

	grunt.registerMultiTask('lintspaces', 'Checking spaces', function() {
		var
			options = this.options(DEFAULTS),
			output = ''
		;

		// replace ingnore strings with buildin patterns:
		options.ignores = updateIgnores(options);

		this.files.forEach(function(file) {
			file.src.forEach(function(path) {
				var
					data = grunt.file.read(path, options.encoding),
					ignoredLines = indexIgnoreLines(options, data),
					lines = data.split('\n'),
					warnings = []
				;

				lines.forEach(function(line, index) {
					if(!ignoredLines[index]) {
						// check indentation:
						pushWarning(warnings, checkIndentation(options, line, index));
					}

					// check trailingspaces:
					pushWarning(warnings, checkTrailingspaces(options, line, index));
				});

				// check newline at end of file:
				pushWarning(warnings, checkNewline(options, lines));

				// print found warning for file
				output += formatWarnings(options, path, warnings);
			});
		});

		printOutput(output);
	});

	/* Validation functions.
	/* ---------------------------------------------------------------------- */
	function checkIndentation(options, line, index) {
		if(typeof options.indentation === 'string' && typeof line === 'string') {
			var
				tabsRegExp = /^\t*(?!\s).*$/, // leading tabs without leading spaces
				spacesRegExp = /^ *(?!\s).*$/, // leading spaces without leading tabs
				spacesLeadingRegExp = /^( *).*$/
			;

			switch(options.indentation) {
				case 'tabs':
					if(!tabsRegExp.test(line)) {
						// indentation failed...
						return formatMessage(index + 1, MESSAGES.INDENTATION_TABS);
					}
					break;

				case 'spaces':
					if(!spacesRegExp.test(line)) {
						// indentation failed...
						return formatMessage(index + 1, MESSAGES.INDENTATION_SPACES);
					} else {
						// indentation correct, is amount of spaces correct?
						if(typeof options.spaces === 'number') {
							if(line.match(spacesLeadingRegExp)[1].length % options.spaces !== 0) {
								return formatMessage(index + 1, MESSAGES.INDENTATION_SPACES_AMOUNT);
							}
						}
					}
					break;
			}
		}
	}

	function checkTrailingspaces(options, line, index) {
		if(options.trailingspaces && typeof line === 'string') {
			var matchSpaces = line.match(/\s*$/);
			if( matchSpaces.length > 0 && matchSpaces[0].length > 0) {
				return formatMessage(index + 1, MESSAGES.TRAILINGSPACES);
			}
		}
	}

	function checkNewline(options, lines) {
		if(options.newline && lines.length > 1) {
			var
				index = lines.length - 1
			;

			// check last line:
			if(lines[index].length > 0) {
				return formatMessage(index + 1, MESSAGES.NEWLINE);
			}

			// check line before last line:
			if(lines[index - 1].length === 0) {
				return formatMessage(index, MESSAGES.NEWLINE_AMOUNT);
			}
		}
	}

	/* Ignores functions.
	/* ---------------------------------------------------------------------- */
	function updateIgnores(options) {
		var ignores = [];
		if(Array.isArray(options.ignores)) {
			options.ignores.forEach(function(ignore) {
				if(typeof ignore === 'string' && typeof PATTERNS[ignore] === 'object') {
					ignores.push(PATTERNS[ignore]);
				} else if(typeof ignore === 'object' && typeof ignore.test === 'function') {
					ignores.push(ignore);
				}
			});
		}

		if(ignores.length === 0) {
			ignores = false;
		}

		return ignores;
	}

	function indexIgnoreLines(options, data) {
		var ignoredLines = {};

		if(Array.isArray(options.ignores)) {

			/* Loop all given regular expressions: */
			options.ignores.forEach(function(expression) {
				var
					lines = data,
					matches = data.match(expression),
					expressionIgnores = {},
					expressionIgnoresCount = 0
				;

				matches.forEach(function(match) {

					/* Only perform an action when match has more
					/* than one line */
					if(match.indexOf('\n') > -1) {
						var
							index = 0,
							removedAt = 0,
							removedLines = 0,
							oldLines = lines.split('\n'),
							newLines
						;

						/* remove match from 'lines' so it can't match for
						/* any other 'match' from this expression: */
						lines = lines.replace(match, '');
						newLines = lines.split('\n');

						/* Find the first line which isn't equal to the
						/* original lines to get starting line of match: */
						while(index < newLines.length && newLines[index] === oldLines[index]) {
							index++;
						}

						/* when a starting line was found, loop as long as
						/* possible over irregular lines to find all lines to
						/* ignore and list them: */
						removedAt = index + 1;
						while(	removedAt < oldLines.length &&
								removedAt < newLines.length &&
								oldLines[removedAt] !== newLines[index + 1]) {
							expressionIgnores[removedAt + expressionIgnoresCount] = true;
							removedLines++;
							removedAt++;
						}

						expressionIgnoresCount += removedLines;
					}
				});

				ignoredLines = extend(ignoredLines, expressionIgnores);
			});
		}

		return ignoredLines;
	}

	/* Formating output.
	/* ---------------------------------------------------------------------- */
	function formatMessage(linenumber, message) {
		return 'L'+ linenumber +': '+ message;
	}

	function pushWarning(warnings, warning) {
		if(typeof warning === 'string') {
			warnings.push(warning);
		}
	}

	function formatWarnings(options, path, warnings) {
		var
			msg = ''
		;

		if(warnings.length > 0) {
			msg = '\nErrors found at '+ path;
			warnings.forEach(function(warning) {
				msg += '\n\t'+ warning;
			});
		}

		return msg;
	}

	function printOutput(output) {
		if(output.length > 0) {
			grunt.fail.warn(output +'\n');
		} else {
			grunt.log.ok('All spaces are correct.');
		}
	}

	/* Helper functions.
	/* ---------------------------------------------------------------------- */
	function extend(target) {
		var sources = [].slice.call(arguments, 1);
		sources.forEach(function (source) {
			for (var prop in source) {
				target[prop] = source[prop];
			}
		});
		return target;
	}
};
<|endoftext|>


<commit_before>'use strict';

var elasticsearch = require('elasticsearch');

module.exports = new elasticsearch.Client({
  host: process.env.ES_HOST || 'localhost:9200',

  // Note that this doesn't abort the query.
  requestTimeout: 10000  // milliseconds
});
<commit_msg>decrease request timeout<commit_after>'use strict';

var elasticsearch = require('elasticsearch');

module.exports = new elasticsearch.Client({
  host: process.env.ES_HOST || 'localhost:9200',

  // Note that this doesn't abort the query.
  requestTimeout: 5000  // milliseconds
});
<|endoftext|>


<commit_before>// This is the main ShelfDB javascript framework namespace
var ShelfDB = (function(sdb, $) {

  // The Parts submodule
  var partsModule = (function() {

    var getListViewModel = function(opts) {

      defaults = {
        imageFormatter: null,
        footprintFilterString: "undefined",
        storeLocationFilterString: "undefined",
        categoryFilterString: "undefined"
      };

      opts = $.extend(defaults, opts)

      var _linkFormatterFactory = function(parameter, dataFieldName) {
        return function (cellvalue, options, rowObject) {

  				var retstr = '';

  				retstr = ''
  									+ cellvalue + '';

  				return retstr;
  			}
      }

      return [
          {
            name: 'image',
            label: Lang.get('image'),
            index: 'mainpicfile',
            fixed: true,
            width: 32+5 /*2+2+1 padding + border*/,
            sortable: false,
            editable: false,
            align: 'center',
            formatter: opts.imageFormatter,
            search: false,
          },
          {
            name: 'name',
            label: Lang.get('name'),
            index: 'name',
            sortable: true,
            align: 'left',
            editrules: {
              required: true
            },
            formatter: 'showlink',
            formatoptions: {
              idName: 'partid',
              baseLinkUrl: sdb.Core.basePath + 'pages/page-showpartdetail.php',
            },
            width: 40
          },
          {
            name: 'instock',
            label: 'Lager',
            index: 'instock',
            sortable: true,
            align: 'right',
            template: 'integer',
            width: 40,
            fixed: true,
            editable: function(opts) {
              return (opts.mode == 'edit' ? false : true);
            },
            editrules: {
              integer: true,
              minValue: 0,
              edithidden: true
            }
          },
          {
            name: 'totalstock',
            label: 'Vorh.',
            index: 'totalstock',
            sortable: true,
            align: 'right',
            template: 'integer',
            width: 40,
            fixed: true,
            editable: function(opts) {
              return (opts.mode == 'edit' ? false : true);
            },
            editrules: {
              integer: true,
              minValue: 0,
              edithidden: true
            }
          },
          {
            name: 'mininstock',
            label: 'Min.',
            index: 'mininstock',
            sortable: true,
            align: 'right',
            template: 'integer',
            width: 40,
            fixed: true,
            editrules: {
              required: true,
              minValue: 0,
              integer: true
            }
          },
          {
            name: 'footprint',
            label: Lang.get('footprint'),
            index: 'footprint',
            sortable: true,
            align: 'right',
            edittype: 'select',
            formatter: _linkFormatterFactory('footprintId', 'id_footprint'),
            stype: 'select',
            searchoptions: {
              sopt: ['eq','ne'],
              value: ":Any;"+opts.footprintFilterString
            },
            editoptions: {
              value: opts.footprintFilterString
            },
            width: 10
          },
          {
            name: 'storeloc',
            label: 'Lagerort',
            index: 'storelocid',
            sortable: true,
            align: 'right',
            edittype: 'select',
            //formatter: 'select',
            formatter: _linkFormatterFactory('storageLocationId', 'id_storeloc'),
            stype: 'select',
            searchoptions: {
              sopt: ['eq','ne'],
              value: ":Any;"+opts.storeLocationFilterString
            },
            editoptions: {
              value: opts.storeLocationFilterString
            },
            width: 10,
          },
          /*
          {

            name: 'datasheet',
            label: 'Datenblätter',
            template: 'datasheet',
            sortable: false,
            align: 'left',
            width: 80,
            fixed: true,
            editable: function(opts) {
              return (opts.mode == 'edit' ? false : true);
            },
            search: false,
          },
          */
          {
            name: 'actions',
            label: 'Aktionen',
            template: 'actions',
            align: 'center',
            formatter: 'actions',
            formatoptions: {
              keys: true
            }
          },
          {
            label: 'Kategorie',
            name: 'category_name',
            index: 'category_name',
            hidden: true,
            sortable: true,
            editable: true,
            edittype: 'select',
            formatter: 'select',
            stype: 'select',
            searchoptions: {
              sopt: ['eq','ne'],
              value: ":Any;"+opts.categoryFilterString,
              searchhidden: true
            },
            editrules: {
              edithidden: true
            },
            editoptions: {
              value: opts.categoryFilterString
            }
          }
      ]
    };

    var editPartFieldData = function( id, fieldName, fieldData, success ) {
  		$.mobile.referencedLoading('show');
  		$.ajax({
  			url: sdb.Core.basePath + 'lib/edit-part.php',
  			data: {
  				id: id,
  				field: fieldName,
  				data: fieldData,
  				method: 'editDetail'
  			},
  			type: 'POST',
  			dataType: 'json'
  		}).done(function(data) {
  			if( data && data.success && success) {
  				success(data);
  			}
  			$.mobile.referencedLoading('hide');
  		});
  	}

    var getPartFieldData = function( id, fieldName, success ) {
  		$.mobile.referencedLoading('show');
  		$.ajax({
  			url: sdb.Core.basePath + 'lib/json.parts.php',
  			data: {
  				partid: id,
  				getDetailed: true,
  			},
  			type: 'POST',
  			dataType: 'json'
  		}).done(function(data) {
  			if( data  && success && data.hasOwnProperty(fieldName)) {
			    success(data[fieldName]);
  			}
  			$.mobile.referencedLoading('hide');
  		});
  	}

    var _addPartCount = function(opts) {
      var defaults = {
        id: null,
        type: "",
        inc: 0,
        success: null
      };

      opts = $.extend(defaults,opts);
      opts.type = opts.type.toLowerCase()

      if( opts.id === null ) return false;

      switch( opts.type ) {
        case 'totalstock':
        case 'instock':
        case 'mininstock':
          getPartFieldData(opts.id, opts.type, function(oldData) {
              var newData = parseInt(oldData) + parseInt(opts.inc);
              editPartFieldData(opts.id, opts.type, newData, function() {
                if( opts.success )
                  opts.success(newData);
              } );
          });
        default:
          return false;
      }

      return newval;
    }

    // Return the column model for jqGrid for the parts view
    return  {
      getListViewModel: getListViewModel,
      incrementTotal: function(id, success) { return _addPartCount({id:id, type: "totalstock", inc:1, success:success})},
      decrementTotal: function(id, success) { return _addPartCount({id:id, type: "totalstock", inc:-1, success:success})},
      incrementStock: function(id, success) { return _addPartCount({id:id, type: "instock", inc:1, success:success})},
      decrementStock: function(id, success) { return _addPartCount({id:id, type: "instock", inc:-1, success:success})},
      editPartFieldData: editPartFieldData
    };
  })();

  $.extend(sdb, {
    Parts: partsModule,
  });

  return sdb;
})(typeof ShelfDB !== 'undefined' ? ShelfDB : {}, jQuery);
<commit_msg>Added localization support for column header model<commit_after>// This is the main ShelfDB javascript framework namespace
var ShelfDB = (function(sdb, $, Lang) {

  // The Parts submodule
  var partsModule = (function() {

    var getListViewModel = function(opts) {

      defaults = {
        imageFormatter: null,
        footprintFilterString: "undefined",
        storeLocationFilterString: "undefined",
        categoryFilterString: "undefined"
      };

      opts = $.extend(defaults, opts)

      var _linkFormatterFactory = function(parameter, dataFieldName) {
        return function (cellvalue, options, rowObject) {

  				var retstr = '';

  				retstr = ''
  									+ cellvalue + '';

  				return retstr;
  			}
      }

      return [
          {
            name: 'image',
            label: Lang.get('image'),
            index: 'mainpicfile',
            fixed: true,
            width: 32+5 /*2+2+1 padding + border*/,
            sortable: false,
            editable: false,
            align: 'center',
            formatter: opts.imageFormatter,
            search: false,
          },
          {
            name: 'name',
            label: Lang.get('name'),
            index: 'name',
            sortable: true,
            align: 'left',
            editrules: {
              required: true
            },
            formatter: 'showlink',
            formatoptions: {
              idName: 'partid',
              baseLinkUrl: sdb.Core.basePath + 'pages/page-showpartdetail.php',
            },
            width: 40
          },
          {
            name: 'instock',
            label: Lang.get('inStockColumnHeader'),
            index: 'instock',
            sortable: true,
            align: 'right',
            template: 'integer',
            width: 40,
            fixed: true,
            editable: function(opts) {
              return (opts.mode == 'edit' ? false : true);
            },
            editrules: {
              integer: true,
              minValue: 0,
              edithidden: true
            }
          },
          {
            name: 'totalstock',
            label: Lang.get('totalStockColumnHeader'),
            index: 'totalstock',
            sortable: true,
            align: 'right',
            template: 'integer',
            width: 40,
            fixed: true,
            editable: function(opts) {
              return (opts.mode == 'edit' ? false : true);
            },
            editrules: {
              integer: true,
              minValue: 0,
              edithidden: true
            }
          },
          {
            name: 'mininstock',
            label: Lang.get('minStockColumnHeader'),
            index: 'mininstock',
            sortable: true,
            align: 'right',
            template: 'integer',
            width: 40,
            fixed: true,
            editrules: {
              required: true,
              minValue: 0,
              integer: true
            }
          },
          {
            name: 'footprint',
            label: Lang.get('footprint'),
            index: 'footprint',
            sortable: true,
            align: 'right',
            edittype: 'select',
            formatter: _linkFormatterFactory('footprintId', 'id_footprint'),
            stype: 'select',
            searchoptions: {
              sopt: ['eq','ne'],
              value: ":Any;"+opts.footprintFilterString
            },
            editoptions: {
              value: opts.footprintFilterString
            },
            width: 10
          },
          {
            name: 'storeloc',
            label: Lang.get('storageLocation'),
            index: 'storelocid',
            sortable: true,
            align: 'right',
            edittype: 'select',
            //formatter: 'select',
            formatter: _linkFormatterFactory('storageLocationId', 'id_storeloc'),
            stype: 'select',
            searchoptions: {
              sopt: ['eq','ne'],
              value: ":Any;"+opts.storeLocationFilterString
            },
            editoptions: {
              value: opts.storeLocationFilterString
            },
            width: 10,
          },
          /*
          {

            name: 'datasheet',
            label: 'Datenblätter',
            template: 'datasheet',
            sortable: false,
            align: 'left',
            width: 80,
            fixed: true,
            editable: function(opts) {
              return (opts.mode == 'edit' ? false : true);
            },
            search: false,
          },
          */
          {
            name: 'actions',
            label: Lang.get('actions'),
            template: 'actions',
            align: 'center',
            formatter: 'actions',
            formatoptions: {
              keys: true
            }
          },
          {
            label: Lang.get('category'),
            name: 'category_name',
            index: 'category_name',
            hidden: true,
            sortable: true,
            editable: true,
            edittype: 'select',
            formatter: 'select',
            stype: 'select',
            searchoptions: {
              sopt: ['eq','ne'],
              value: ":Any;"+opts.categoryFilterString,
              searchhidden: true
            },
            editrules: {
              edithidden: true
            },
            editoptions: {
              value: opts.categoryFilterString
            }
          }
      ]
    };

    var editPartFieldData = function( id, fieldName, fieldData, success ) {
  		$.mobile.referencedLoading('show');
  		$.ajax({
  			url: sdb.Core.basePath + 'lib/edit-part.php',
  			data: {
  				id: id,
  				field: fieldName,
  				data: fieldData,
  				method: 'editDetail'
  			},
  			type: 'POST',
  			dataType: 'json'
  		}).done(function(data) {
  			if( data && data.success && success) {
  				success(data);
  			}
  			$.mobile.referencedLoading('hide');
  		});
  	}

    var getPartFieldData = function( id, fieldName, success ) {
  		$.mobile.referencedLoading('show');
  		$.ajax({
  			url: sdb.Core.basePath + 'lib/json.parts.php',
  			data: {
  				partid: id,
  				getDetailed: true,
  			},
  			type: 'POST',
  			dataType: 'json'
  		}).done(function(data) {
  			if( data  && success && data.hasOwnProperty(fieldName)) {
			    success(data[fieldName]);
  			}
  			$.mobile.referencedLoading('hide');
  		});
  	}

    var _addPartCount = function(opts) {
      var defaults = {
        id: null,
        type: "",
        inc: 0,
        success: null
      };

      opts = $.extend(defaults,opts);
      opts.type = opts.type.toLowerCase()

      if( opts.id === null ) return false;

      switch( opts.type ) {
        case 'totalstock':
        case 'instock':
        case 'mininstock':
          getPartFieldData(opts.id, opts.type, function(oldData) {
              var newData = parseInt(oldData) + parseInt(opts.inc);
              editPartFieldData(opts.id, opts.type, newData, function() {
                if( opts.success )
                  opts.success(newData);
              } );
          });
        default:
          return false;
      }

      return newval;
    }

    // Return the column model for jqGrid for the parts view
    return  {
      getListViewModel: getListViewModel,
      incrementTotal: function(id, success) { return _addPartCount({id:id, type: "totalstock", inc:1, success:success})},
      decrementTotal: function(id, success) { return _addPartCount({id:id, type: "totalstock", inc:-1, success:success})},
      incrementStock: function(id, success) { return _addPartCount({id:id, type: "instock", inc:1, success:success})},
      decrementStock: function(id, success) { return _addPartCount({id:id, type: "instock", inc:-1, success:success})},
      editPartFieldData: editPartFieldData
    };
  })();

  $.extend(sdb, {
    Parts: partsModule,
  });

  return sdb;
})(typeof ShelfDB !== 'undefined' ? ShelfDB : {}, jQuery, Lang);
<|endoftext|>


<commit_before>var gridWidth = 22;
var gridHeight = 12;

var values=[], positions=[];//arrays for values and edges
var verticalEdges=[], horizontalEdges=[];
//values are currently 0 for empty and 1 for material
//TODO add more materials

function initializeArrays(){
   var i,j;
   for(i=0;i<gridWidth;i++){
      values[i] = [];
      positions[i] = [];
      for(j=0;j<gridHeight;j++){
         values[i][j]=0;//init to air
         positions[i][j]={x:0.5,y:0.5};
      }
   }
   for(i=0;i<gridWidth;i++){
      verticalEdges[i] = [];
      horizontalEdges[i] = [];
      for(j=0;j<gridHeight;j++){
         verticalEdges[i][j]={p:0,nx:1,ny:1};//no intersection
         horizontalEdges[i][j]={p:0,nx:1,ny:1};//no intersection
      }
   }
}
function getValue(x,y){
   if(x<0||x>=gridWidth||y<0||y>=gridHeight) return 0;//default to air
   return values[x][y];
}

function gridHasSignChange(x,y){
   var sgn = getValue(x,y);
   for(var i=0;i<2;i++){
      for(var j=0;j<2;j++){
         if(sgn!=getValue(x+i,y+j)) return true;//TODO more materials
      }
   }
   return false;
}
function edgeHasSignChange(x,y,isVertical){
   if(isVertical){
      return (getValue(x,y)!=getValue(x,y+1));
   }else{
      return (getValue(x,y)!=getValue(x+1,y));
   }
}

function getIntersectionPoint(x,y,isVertical,dx,dy){
   if(x<0||x>=gridWidth||y<0||y>=gridHeight) return {x:dx+0.5,y:dy+0.5};
   if(isVertical){
      return {x:dx, y:dy+verticalEdges[x][y].p};
   }else{
      return {x:dx+horizontalEdges[x][y].p, y:dy};
   }
}

function updateSquare(x,y){
   if(x<0||y<0) return;
   //recompute current gridposition
   var px=0.0,py=0.0,sx=0.0,sy=0.0;
   if(gridHasSignChange(x,y)){
      var p,n,nx,ny;
      if(edgeHasSignChange(x,y,true)){
         p = getIntersectionPoint(x,y,true,0,0);
         n = verticalEdges[x][y];
         nx=n.nx*n.nx;ny=n.ny*n.ny;
         //if(nx+ny<0.01){nx=0.5;ny=0.5;}
         px+=p.x*nx;
         sx+=nx;
         py+=p.y*ny;
         sy+=ny;
      }
      if(edgeHasSignChange(x,y,false)){
         p = getIntersectionPoint(x,y,false,0,0);
         n = horizontalEdges[x][y];
         nx=n.nx*n.nx;ny=n.ny*n.ny;
         //if(nx+ny<0.01){nx=0.5;ny=0.5;}
         px+=p.x*nx;
         sx+=nx;
         py+=p.y*ny;
         sy+=ny;
      }
      if(edgeHasSignChange(x+1,y,true)){
         p = getIntersectionPoint(x+1,y,true,1,0);
         n = verticalEdges[x+1][y];
         nx=n.nx*n.nx;ny=n.ny*n.ny;
         //if(nx+ny<0.01){nx=0.5;ny=0.5;}
         px+=p.x*nx;
         sx+=nx;
         py+=p.y*ny;
         sy+=ny;
      }
      if(edgeHasSignChange(x,y+1,false)){
         p = getIntersectionPoint(x,y+1,false,0,1);
         n = horizontalEdges[x][y+1];
         nx=n.nx*n.nx;ny=n.ny*n.ny;
         //if(nx+ny<0.01){nx=0.5;ny=0.5;}
         px+=p.x*nx;
         sx+=nx;
         py+=p.y*ny;
         sy+=ny;
      }
      px/=sx;
      py/=sy;
      //px = clamp(px,0,1);//it doesn't seem to be needed?
      //py = clamp(py,0,1);
      positions[x][y] = {x:px,y:py};
      renderer_updatePosition(x,y,px,py);
      //console.log(x,y,px,py,sx,sy);
   }else{
      positions[x][y].x=0.5;//reset
      positions[x][y].y=0.5;//reset
   }
   //rerender edges
   rerenderEdge(x,y,true);
   rerenderEdge(x,y,false);
   rerenderEdge(x+1,y,true);
   rerenderEdge(x,y+1,false);
}

function updateEdge(x,y,isVertical){
   //update neighbouring grids
   updateSquare(x,y);
   if(isVertical){
      updateSquare(x-1,y);
   }
   else{
      updateSquare(x,y-1);
   }
}

function getGridPos(x,y){
   if(x<0||x>=gridWidth||y<0||y>=gridHeight)
      return {x:x*64+32,y:y*64+32};
   return {x:x*64+(positions[x][y].x*64),y:y*64+(positions[x][y].y*64)};
}

function rerenderEdge(x,y,isVertical){
   var a,b;
   if(edgeHasSignChange(x,y,isVertical)){
      if(isVertical){
         a=getGridPos(x-1,y);
         b=getGridPos(x,y);
         renderer_updateEdge(x,y,isVertical, a.x+10,a.y+10,b.x+10,b.y+10);
      }else{
         a=getGridPos(x,y-1);
         b=getGridPos(x,y);
         renderer_updateEdge(x,y,isVertical, a.x+10,a.y+10,b.x+10,b.y+10);
      }
   }else{
      renderer_removeEdge(x,y,isVertical);
   }
}
<commit_msg>Refactored the intersection algorithm for greater readability and easier changing.<commit_after>var gridWidth = 22;
var gridHeight = 12;

var values=[], positions=[];//arrays for values and edges
var verticalEdges=[], horizontalEdges=[];
//values are currently 0 for empty and 1 for material
//TODO add more materials

function initializeArrays(){
   var i,j;
   for(i=0;i<gridWidth;i++){
      values[i] = [];
      positions[i] = [];
      for(j=0;j<gridHeight;j++){
         values[i][j]=0;//init to air
         positions[i][j]={x:0.5,y:0.5};
      }
   }
   for(i=0;i<gridWidth;i++){
      verticalEdges[i] = [];
      horizontalEdges[i] = [];
      for(j=0;j<gridHeight;j++){
         verticalEdges[i][j]={p:0,nx:1,ny:1};//no intersection
         horizontalEdges[i][j]={p:0,nx:1,ny:1};//no intersection
      }
   }
}
function getValue(x,y){
   if(x<0||x>=gridWidth||y<0||y>=gridHeight) return 0;//default to air
   return values[x][y];
}

function gridHasSignChange(x,y){
   var sgn = getValue(x,y);
   for(var i=0;i<2;i++){
      for(var j=0;j<2;j++){
         if(sgn!=getValue(x+i,y+j)) return true;//TODO more materials
      }
   }
   return false;
}
function edgeHasSignChange(x,y,isVertical){
   if(isVertical){
      return (getValue(x,y)!=getValue(x,y+1));
   }else{
      return (getValue(x,y)!=getValue(x+1,y));
   }
}

function getIntersectionPoint(x,y,isVertical,dx,dy){
   if(x<0||x>=gridWidth||y<0||y>=gridHeight) return {x:dx+0.5,y:dy+0.5};
   if(isVertical){
      return {x:dx, y:dy+verticalEdges[x][y].p};
   }else{
      return {x:dx+horizontalEdges[x][y].p, y:dy};
   }
}
///QEF

function mul(v,x){
   return {x:v.x*x,y:v.y*x};
}

function dot(a,b){
   return a.x*b.x+a.y*b.y;
}

function normalToRightVector(normal){
   return {x:-normal.y,y:normal.x};
}

function projection(planeNormal, point){
   var plane = normalToRightVector(planeNormal);
   return mul(plane, dot(point,plane));
}

function updateSquare(x,y){
   if(x<0||y<0) return;
   //recompute current gridposition
   var px=0.0,py=0.0;
   if(gridHasSignChange(x,y)){
      var intersections = [];
      if(edgeHasSignChange(x,y,true)){
         intersections.push({p:getIntersectionPoint(x,y,true,0,0),n:verticalEdges[x][y]});
      }
      if(edgeHasSignChange(x,y,false)){
         intersections.push({p:getIntersectionPoint(x,y,false,0,0),n:horizontalEdges[x][y]});
      }
      if(edgeHasSignChange(x+1,y,true)){
         intersections.push({p:getIntersectionPoint(x+1,y,true,1,0),n:verticalEdges[x+1][y]});
      }
      if(edgeHasSignChange(x,y+1,false)){
         intersections.push({p:getIntersectionPoint(x,y+1,false,0,1),n:horizontalEdges[x][y+1]});
      }

      var sx=0.0,sy=0.0;
      for(var i=0;i<intersections.length;i++){
         var p = intersections[i].p;
         var n = intersections[i].n;
         px+=p.x*n.nx*n.nx;
         sx+=n.nx*n.nx;
         py+=p.y*n.ny*n.ny;
         sy+=n.ny*n.ny;
      }
      px/=sx;
      py/=sy;

      //px = clamp(px,0,1);//it doesn't seem to be needed?
      //py = clamp(py,0,1);
      positions[x][y] = {x:px,y:py};
      renderer_updatePosition(x,y,px,py);
      //console.log(x,y,px,py,sx,sy);
   }else{
      positions[x][y].x=0.5;//reset
      positions[x][y].y=0.5;//reset
   }
   //rerender edges
   rerenderEdge(x,y,true);
   rerenderEdge(x,y,false);
   rerenderEdge(x+1,y,true);
   rerenderEdge(x,y+1,false);
}

function updateEdge(x,y,isVertical){
   //update neighbouring grids
   updateSquare(x,y);
   if(isVertical){
      updateSquare(x-1,y);
   }
   else{
      updateSquare(x,y-1);
   }
}

function getGridPos(x,y){
   if(x<0||x>=gridWidth||y<0||y>=gridHeight)
      return {x:x*64+32,y:y*64+32};
   return {x:x*64+(positions[x][y].x*64),y:y*64+(positions[x][y].y*64)};
}

function rerenderEdge(x,y,isVertical){
   var a,b;
   if(edgeHasSignChange(x,y,isVertical)){
      if(isVertical){
         a=getGridPos(x-1,y);
         b=getGridPos(x,y);
         renderer_updateEdge(x,y,isVertical, a.x+10,a.y+10,b.x+10,b.y+10);
      }else{
         a=getGridPos(x,y-1);
         b=getGridPos(x,y);
         renderer_updateEdge(x,y,isVertical, a.x+10,a.y+10,b.x+10,b.y+10);
      }
   }else{
      renderer_removeEdge(x,y,isVertical);
   }
}
<|endoftext|>


<commit_before>/**
 * Class for storing relevant data from the font file.
 * @class me.BitmapFontData
 * @memberOf me
 * @param data {String} - The bitmap font data pulled from the resource loader using me.loader.getBinary()
 * @constructor
 */
me.BitmapFontData = me.Object.extend({
    init: function (data) {
        this.padTop = 0;
        this.padRight = 0;
        this.padBottom = 0;
        this.padLeft = 0;
        this.lineHeight = 0;
        // The distance from the top of most uppercase characters to the baseline. Since the drawing position is the cap height of
        // the first line, the cap height can be used to get the location of the baseline.
        this.capHeight = 1;
        // The distance from the bottom of the glyph that extends the lowest to the baseline. This number is negative.
        this.descent = 0;
        this.down = 0;
        this.scale = new me.Vector2d();

        /**
         * The map of glyphs, each key is a char code.
         * @name glyphs
         * @type {Object}
         * @memberOf me.BitmapFontData
         */
        this.glyphs = {};

        /**
         * The width of the space glyph
         * @name spaceWidth
         * @type {Number}
         * @memberOf me.BitmapFontData
         */
        this.spaceWidth = 0;

        this.xChars = ["x", "e", "a", "o", "n", "s", "r", "c", "u", "m", "v", "w", "z"];
        this.capChars = ["M", "N", "B", "D", "C", "E", "F", "K", "A", "G", "H", "I", "J", "L", "O", "P", "Q", "R", "S",
            "T", "U", "V", "W", "X", "Y", "Z"];
        this.parse(data);
    },

    /**
     * Creates a glyph to use for the space character
     * @private
     * @name _createSpaceGlyph
     * @memberOf me.BitmapFontData
     * @function
     */
    _createSpaceGlyph: function () {
        var spaceCharCode = " ".charCodeAt(0);
        var glyph = this.glyphs[spaceCharCode];
        if (!this.glyphs[spaceCharCode]) {
            glyph = me.pool.pull("me.Glyph");
            glyph.id = spaceCharCode;
            glyph.xadvance = this._getFirstGlyph().xadvance;
            this.glyphs[spaceCharCode] = glyph;
        }

        if (glyph.width === 0) {
            glyph.width = ~~(this.padLeft + glyph.xadvance + this.padRight);
            glyph.offset.set(-this.padLeft, 0);
        }

        if (glyph.height === 0) {
            glyph.height = this._getFirstGlyph().height;
        }

        this.spaceWidth = glyph.width;
    },

    /**
     * Gets the first glyph in the map that is not a space character
     * @private
     * @name _getFirstGlyph
     * @memberOf me.BitmapFontData
     * @function
     * @returns {me.Glyph}
     */
    _getFirstGlyph: function () {
        var keys = Object.keys(this.glyphs);
        for (var i = 0; i < keys.length; i++) {
            if (keys[i] > 32) {
                return this.glyphs[keys[i]];
            }
        }
        return null;
    },

    /**
     * Gets the value from a string of pairs. For example: one=1 two=2 something=hi. Can accept the regex of /one={d}/
     * and returns the value of d
     * @private
     * @name _getValueFromPair
     * @memberOf me.BitmapFontData
     * @function
     * @returns {String}
     */
    _getValueFromPair: function (string, pattern) {
        var value = string.match(pattern);
        if (!value) {
            throw "Could not find pattern " + pattern + " in string: " + string;
        }

        return value[0].split("=")[1];
    },

    /**
     * This parses the font data text and builds a map of glyphs containing the data for each character
     * @name parse
     * @memberOf me.BitmapFontData
     * @function
     * @param {String} fontData
     */
    parse: function (fontData) {
        if (!fontData) {
            throw "File containing font data was empty, cannot load the bitmap font.";
        }
        var lines = fontData.split(/\r\n|\n/);
        var padding = fontData.match(/padding\=\d+,\d+,\d+,\d+/g);
        if (!padding) {
            throw "Padding not found in first line";
        }
        var paddingValues = padding[0].split("=")[1].split(",");
        this.padTop = parseFloat(paddingValues[0]);
        this.padLeft = parseFloat(paddingValues[1]);
        this.padBottom = parseFloat(paddingValues[2]);
        this.padRight = parseFloat(paddingValues[3]);

        this.lineHeight = parseFloat(this._getValueFromPair(lines[1], /lineHeight\=\d+/g));

        var baseLine = parseFloat(this._getValueFromPair(lines[1], /base\=\d+/g));

        var padY = this.padTop + this.padBottom;

        var glyph = null;

        for (var i = 4; i < lines.length; i++) {
            var line = lines[i];
            var characterValues = line.split(/=|\s+/);
            if (!line || /^kernings/.test(line)) {
                continue;
            }
            if (/^kerning\s/.test(line)) {
                var first = parseFloat(characterValues[2]);
                var second = parseFloat(characterValues[4]);
                var amount = parseFloat(characterValues[6]);

                glyph = this.glyphs[first];
                if (glyph !== null && typeof glyph !== "undefined") {
                    glyph.setKerning(second, amount);
                }
            } else {
                glyph = me.pool.pull("me.Glyph");

                var ch = parseFloat(characterValues[2]);
                glyph.id = ch;
                glyph.src.set(parseFloat(characterValues[4]), parseFloat(characterValues[6]));
                glyph.width = parseFloat(characterValues[8]);
                glyph.height = parseFloat(characterValues[10]);
                var y = parseFloat(characterValues[14]);
                glyph.offset.set(parseFloat(characterValues[12]), y);

                glyph.xadvance = parseFloat(characterValues[16]);

                if (glyph.width > 0 && glyph.height > 0) {
                    this.descent = Math.min(baseLine + glyph.yoffset, this.descent);
                }

                this.glyphs[ch] = glyph;
            }
        }

        this.descent += this.padBottom;

        this._createSpaceGlyph();

        var xGlyph = null;
        for (i = 0; i < this.xChars.length; i++) {
            var xChar = this.xChars[i];
            xGlyph = this.glyphs[xChar.charCodeAt(0)];
            if (xGlyph) {
                break;
            }
        }
        if (!xGlyph) {
            xGlyph = this._getFirstGlyph();
        }

        var capGlyph = null;
        for (i = 0; i < this.capChars.length; i++) {
            var capChar = this.capChars[i];
            capGlyph = this.glyphs[capChar.charCodeAt(0)];
            if (capGlyph) {
                break;
            }
        }
        if (!capGlyph) {
            for (var charCode in this.glyphs) {
                if (this.glyphs.hasOwnProperty(charCode)) {
                    glyph = this.glyphs[charCode];
                    if (glyph.height === 0 || glyph.width === 0) {
                        continue;
                    }
                    this.capHeight = Math.max(this.capHeight, glyph.height);
                }
            }
        } else {
            this.capHeight = capGlyph.height;
        }

        this.capHeight -= padY;

        this.down = -this.lineHeight;
    }
});
<commit_msg>use local var<commit_after>/**
 * Class for storing relevant data from the font file.
 * @class me.BitmapFontData
 * @memberOf me
 * @param data {String} - The bitmap font data pulled from the resource loader using me.loader.getBinary()
 * @constructor
 */
me.BitmapFontData = me.Object.extend({
    init: function (data) {
        this.padTop = 0;
        this.padRight = 0;
        this.padBottom = 0;
        this.padLeft = 0;
        this.lineHeight = 0;
        // The distance from the top of most uppercase characters to the baseline. Since the drawing position is the cap height of
        // the first line, the cap height can be used to get the location of the baseline.
        this.capHeight = 1;
        // The distance from the bottom of the glyph that extends the lowest to the baseline. This number is negative.
        this.descent = 0;
        this.down = 0;
        this.scale = new me.Vector2d();

        /**
         * The map of glyphs, each key is a char code.
         * @name glyphs
         * @type {Object}
         * @memberOf me.BitmapFontData
         */
        this.glyphs = {};

        /**
         * The width of the space glyph
         * @name spaceWidth
         * @type {Number}
         * @memberOf me.BitmapFontData
         */
        this.spaceWidth = 0;

        this.xChars = ["x", "e", "a", "o", "n", "s", "r", "c", "u", "m", "v", "w", "z"];
        this.capChars = ["M", "N", "B", "D", "C", "E", "F", "K", "A", "G", "H", "I", "J", "L", "O", "P", "Q", "R", "S",
            "T", "U", "V", "W", "X", "Y", "Z"];
        this.parse(data);
    },

    /**
     * Creates a glyph to use for the space character
     * @private
     * @name _createSpaceGlyph
     * @memberOf me.BitmapFontData
     * @function
     */
    _createSpaceGlyph: function () {
        var spaceCharCode = " ".charCodeAt(0);
        var glyph = this.glyphs[spaceCharCode];
        if (!glyph) {
            glyph = me.pool.pull("me.Glyph");
            glyph.id = spaceCharCode;
            glyph.xadvance = this._getFirstGlyph().xadvance;
            this.glyphs[spaceCharCode] = glyph;
        }

        if (glyph.width === 0) {
            glyph.width = ~~(this.padLeft + glyph.xadvance + this.padRight);
            glyph.offset.set(-this.padLeft, 0);
        }

        if (glyph.height === 0) {
            glyph.height = this._getFirstGlyph().height;
        }

        this.spaceWidth = glyph.width;
    },

    /**
     * Gets the first glyph in the map that is not a space character
     * @private
     * @name _getFirstGlyph
     * @memberOf me.BitmapFontData
     * @function
     * @returns {me.Glyph}
     */
    _getFirstGlyph: function () {
        var keys = Object.keys(this.glyphs);
        for (var i = 0; i < keys.length; i++) {
            if (keys[i] > 32) {
                return this.glyphs[keys[i]];
            }
        }
        return null;
    },

    /**
     * Gets the value from a string of pairs. For example: one=1 two=2 something=hi. Can accept the regex of /one={d}/
     * and returns the value of d
     * @private
     * @name _getValueFromPair
     * @memberOf me.BitmapFontData
     * @function
     * @returns {String}
     */
    _getValueFromPair: function (string, pattern) {
        var value = string.match(pattern);
        if (!value) {
            throw "Could not find pattern " + pattern + " in string: " + string;
        }

        return value[0].split("=")[1];
    },

    /**
     * This parses the font data text and builds a map of glyphs containing the data for each character
     * @name parse
     * @memberOf me.BitmapFontData
     * @function
     * @param {String} fontData
     */
    parse: function (fontData) {
        if (!fontData) {
            throw "File containing font data was empty, cannot load the bitmap font.";
        }
        var lines = fontData.split(/\r\n|\n/);
        var padding = fontData.match(/padding\=\d+,\d+,\d+,\d+/g);
        if (!padding) {
            throw "Padding not found in first line";
        }
        var paddingValues = padding[0].split("=")[1].split(",");
        this.padTop = parseFloat(paddingValues[0]);
        this.padLeft = parseFloat(paddingValues[1]);
        this.padBottom = parseFloat(paddingValues[2]);
        this.padRight = parseFloat(paddingValues[3]);

        this.lineHeight = parseFloat(this._getValueFromPair(lines[1], /lineHeight\=\d+/g));

        var baseLine = parseFloat(this._getValueFromPair(lines[1], /base\=\d+/g));

        var padY = this.padTop + this.padBottom;

        var glyph = null;

        for (var i = 4; i < lines.length; i++) {
            var line = lines[i];
            var characterValues = line.split(/=|\s+/);
            if (!line || /^kernings/.test(line)) {
                continue;
            }
            if (/^kerning\s/.test(line)) {
                var first = parseFloat(characterValues[2]);
                var second = parseFloat(characterValues[4]);
                var amount = parseFloat(characterValues[6]);

                glyph = this.glyphs[first];
                if (glyph !== null && typeof glyph !== "undefined") {
                    glyph.setKerning(second, amount);
                }
            } else {
                glyph = me.pool.pull("me.Glyph");

                var ch = parseFloat(characterValues[2]);
                glyph.id = ch;
                glyph.src.set(parseFloat(characterValues[4]), parseFloat(characterValues[6]));
                glyph.width = parseFloat(characterValues[8]);
                glyph.height = parseFloat(characterValues[10]);
                var y = parseFloat(characterValues[14]);
                glyph.offset.set(parseFloat(characterValues[12]), y);

                glyph.xadvance = parseFloat(characterValues[16]);

                if (glyph.width > 0 && glyph.height > 0) {
                    this.descent = Math.min(baseLine + glyph.yoffset, this.descent);
                }

                this.glyphs[ch] = glyph;
            }
        }

        this.descent += this.padBottom;

        this._createSpaceGlyph();

        var xGlyph = null;
        for (i = 0; i < this.xChars.length; i++) {
            var xChar = this.xChars[i];
            xGlyph = this.glyphs[xChar.charCodeAt(0)];
            if (xGlyph) {
                break;
            }
        }
        if (!xGlyph) {
            xGlyph = this._getFirstGlyph();
        }

        var capGlyph = null;
        for (i = 0; i < this.capChars.length; i++) {
            var capChar = this.capChars[i];
            capGlyph = this.glyphs[capChar.charCodeAt(0)];
            if (capGlyph) {
                break;
            }
        }
        if (!capGlyph) {
            for (var charCode in this.glyphs) {
                if (this.glyphs.hasOwnProperty(charCode)) {
                    glyph = this.glyphs[charCode];
                    if (glyph.height === 0 || glyph.width === 0) {
                        continue;
                    }
                    this.capHeight = Math.max(this.capHeight, glyph.height);
                }
            }
        } else {
            this.capHeight = capGlyph.height;
        }

        this.capHeight -= padY;

        this.down = -this.lineHeight;
    }
});
<|endoftext|>


<commit_before>var XHR = JCX.xhr = function(cfg) {
    return XHR.main(cfg);
},
htmlClass = D.documentElement.classList;

XHR.ctor = XMLHttpRequest;
XHR.main = function(cfg) {
    var xhr,
        promise;

    if (cfg.cache) {
        xhr = store(XHR.key(cfg));
        if (xhr) {
            promise = Promise.resolve(xhr);
        }
    }
    if (!promise) {
        xhr = new XHR.ctor();
        XHR.config(xhr, cfg);
        promise = XHR.promise(xhr, cfg);
        if (cfg.cache) {
            promise = promise.then(XHR.cache);
        }
    }

    var always = XHR.chain(cfg.always);
    promise = promise
        .then(always, always)
        .then(XHR.chain(cfg.then), XHR.chain(cfg.catch));

    promise.xhr = xhr;
    return promise;
};

XHR.config = function(xhr, cfg) {
    xhr.open(XHR.method(cfg),
             XHR.url(cfg),
             'async' in cfg ? cfg.async : true,
             cfg.username, cfg.password);
    xhr.cfg = cfg;
    for (var prop in cfg) {
        if (prop in xhr) {
            xhr[prop] = cfg[prop];
        }
    }
    if (cfg.mimeType) {
        xhr.overrideMimeType(cfg.mimeType);
    }
    if (cfg.requestedWith !== false) {
        xhr.setRequestHeader('X-Requested-With', cfg.requestedWith || 'XMLHttpRequest');
    }
    if (cfg.json) {
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.setRequestHeader('Content-Type', 'application/json');
    }
    if (cfg.headers) {
        for (var header in cfg.headers) {
            xhr.setRequestHeader(header, cfg.headers[header]);
        }
    }
};

XHR.method = function(cfg) {
    return XHR.methodMap[cfg.method] || cfg.method || 'GET';
};
XHR.methodMap = {
    PATCH: 'POST'
};

XHR.url = function(cfg) {
    var url = cfg.url,
        was;
    while (was !== url) {
        was = url;
        url = url.replace(/([\/\?\&]|^)[^\/\.\?\&]+[\/\?\&]?\.\.([\/\?\&]?)/, '$1');
    }
    return url;
};

XHR.promise = function(xhr, cfg) {
    var promise = new Promise(function(resolve, reject) {
        var error = function(e) {
            xhr.error = e;
            reject(xhr);
        };
        xhr.onerror = xhr.ontimeout = error;
        xhr.onloadstart = XHR.start;
        xhr.onload = function() {
            try {
                // cfg status code handling (e.g. {0: 200} for file://)
                var status = cfg[xhr.status] || xhr.status;
                if (typeof status === "function") {
                    status = status(xhr) || xhr.status;
                }
                if (status >= 200 && status < 300) {
                    if (cfg.json && typeof xhr.response !== "object") {
                        XHR.forceJSONResponse(xhr);
                    }
                    resolve(xhr);
                } else {
                    error(status);
                }
            } catch (e) {
                error(e);
            }
        };
        xhr.onloadend = XHR.end;

        try {
            xhr.send(XHR.data(cfg));
        } catch (e) {
            error(e);
        }
    });
    return cfg.retry ? promise.catch(XHR.chain(XHR.retry)) : promise;
};

XHR.forceJSONResponse = function(xhr) {
    try {
        delete xhr.response;
        Object.defineProperty(xhr, 'response', { value: xhr.responseObject, configurable: true });
    } catch (e) {}
};

XHR.data = function(cfg) {
    var data = cfg.data;
    if (cfg.serialize) {
        data = cfg.serialize(data);
    }
    if (data !== undefined && typeof data !== "string") {
        data = JSON.stringify(data);
    }
    return data || '';
};

XHR.properties = {
    responseObject: {
        get: function() {
            var response = null;
            try {
                if (this.responseText) {
                    response = JSON.parse(this.responseText);
                }
            } catch (e) {}
            Object.defineProperty(this, 'responseObject', {value:response});
            return response;
        },
        enumerable: true,
        configurable: true
    },
    responseHeaders: {
        get: function() {
            var headers = {},
                all = this.getAllResponseHeaders().trim().split('\n');
            for (var i=0,m=all.length, header; i<m; i++) {
                if ((header = all[i])) {
                    var parts = header.match(/^([\w\-]+):(.*)/);
                    if (parts.length === 3) {
                        headers[parts[1]] = parts[2].trim();
                    }
                }
            }
            Object.defineProperty(this, 'responseHeaders', {value:headers});
            return headers;
        },
        enumerable: true,
        configurable: true
    }
};
Object.defineProperties(XMLHttpRequest.prototype, XHR.properties);

XHR.active = 0;
XHR.activeClass = 'xhr-active';
XHR.start = function() {
    XHR.active++;
    htmlClass.add(XHR.activeClass);
};
XHR.end = function() {
    if (!--XHR.active) {
        htmlClass.remove(XHR.activeClass);
    }
};

XHR.key = function(cfg) {
    return XHR.url(cfg)+'|'+XHR.method(cfg)+'|'+XHR.data(cfg);
};
XHR.cache = function(xhr) {
    var cfg = xhr.cfg;
    store(XHR.key(cfg), XHR.safeCopy(xhr), cfg.cache);
    return xhr;
};
XHR.safeCopy = function(object, copied) {
    var copy = {};
    copied = copied || [];
    if (copied.indexOf(object) < 0) {
        copied.push(object);
        for (var name in object) {
            var value = object[name],
                type = typeof value;
            if (type === 'function') {
                value = undefined;
            } else if (type === 'object') {
                value = XHR.safeCopy(value, copied);
            }
            if (value !== undefined) {
                copy[name] = value;
            }
        }
        return copy;
    }
};

XHR.chain = function(fn) {
    if (fn) {
        return function chain(xhr) {
            var ret = fn(xhr);
            return ret !== xhr && ret !== undefined ? ret :
                   xhr.error ? Promise.reject(xhr) :
                   xhr;
        };
    }
};

XHR.retry = function(xhr) {
    var retry = xhr.cfg.retry;
    if (retry && (retry.limit || 3) > retry.count) {
        if (typeof retry === 'number') {
            retry = { wait: retry };
        }
        return new Promise(function(resolve) {
            setTimeout(function() {
                retry.count = (retry.count || 0) + 1;
                retry.wait = (retry.wait || 1000) * 2;
                resolve(XHR(xhr.cfg));
            }, retry.wait || 1000);
        });
    }
    return xhr;
};
<commit_msg>chrome wipes responseText when responseType is 'json'<commit_after>var XHR = JCX.xhr = function(cfg) {
    return XHR.main(cfg);
},
htmlClass = D.documentElement.classList;

XHR.ctor = XMLHttpRequest;
XHR.main = function(cfg) {
    var xhr,
        promise;

    if (cfg.cache) {
        xhr = store(XHR.key(cfg));
        if (xhr) {
            promise = Promise.resolve(xhr);
        }
    }
    if (!promise) {
        xhr = new XHR.ctor();
        XHR.config(xhr, cfg);
        promise = XHR.promise(xhr, cfg);
        if (cfg.cache) {
            promise = promise.then(XHR.cache);
        }
    }

    var always = XHR.chain(cfg.always);
    promise = promise
        .then(always, always)
        .then(XHR.chain(cfg.then), XHR.chain(cfg.catch));

    promise.xhr = xhr;
    return promise;
};

XHR.config = function(xhr, cfg) {
    xhr.open(XHR.method(cfg),
             XHR.url(cfg),
             'async' in cfg ? cfg.async : true,
             cfg.username, cfg.password);
    xhr.cfg = cfg;
    for (var prop in cfg) {
        if (prop in xhr) {
            xhr[prop] = cfg[prop];
        }
    }
    if (cfg.mimeType) {
        xhr.overrideMimeType(cfg.mimeType);
    }
    if (cfg.requestedWith !== false) {
        xhr.setRequestHeader('X-Requested-With', cfg.requestedWith || 'XMLHttpRequest');
    }
    if (cfg.json) {
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.setRequestHeader('Content-Type', 'application/json');
    }
    if (cfg.headers) {
        for (var header in cfg.headers) {
            xhr.setRequestHeader(header, cfg.headers[header]);
        }
    }
};

XHR.method = function(cfg) {
    return XHR.methodMap[cfg.method] || cfg.method || 'GET';
};
XHR.methodMap = {
    PATCH: 'POST'
};

XHR.url = function(cfg) {
    var url = cfg.url,
        was;
    while (was !== url) {
        was = url;
        url = url.replace(/([\/\?\&]|^)[^\/\.\?\&]+[\/\?\&]?\.\.([\/\?\&]?)/, '$1');
    }
    return url;
};

XHR.promise = function(xhr, cfg) {
    var promise = new Promise(function(resolve, reject) {
        var error = function(e) {
            xhr.error = e;
            reject(xhr);
        };
        xhr.onerror = xhr.ontimeout = error;
        xhr.onloadstart = XHR.start;
        xhr.onload = function() {
            try {
                // cfg status code handling (e.g. {0: 200} for file://)
                var status = cfg[xhr.status] || xhr.status;
                if (typeof status === "function") {
                    status = status(xhr) || xhr.status;
                }
                if (status >= 200 && status < 300) {
                    if (cfg.json && typeof xhr.response !== "object") {
                        XHR.forceJSONResponse(xhr);
                    }
                    resolve(xhr);
                } else {
                    error(status);
                }
            } catch (e) {
                error(e);
            }
        };
        xhr.onloadend = XHR.end;

        try {
            xhr.send(XHR.data(cfg));
        } catch (e) {
            error(e);
        }
    });
    return cfg.retry ? promise.catch(XHR.chain(XHR.retry)) : promise;
};

XHR.forceJSONResponse = function(xhr) {
    try {
        delete xhr.response;
        Object.defineProperty(xhr, 'response', { value: xhr.responseObject, configurable: true });
    } catch (e) {}
};

XHR.data = function(cfg) {
    var data = cfg.data;
    if (cfg.serialize) {
        data = cfg.serialize(data);
    }
    if (data !== undefined && typeof data !== "string") {
        data = JSON.stringify(data);
    }
    return data || '';
};

XHR.properties = {
    responseObject: {
        get: function() {
            var response = null;
            try {
                if (this.responseText) {
                    response = JSON.parse(this.responseText);
                } else if (typeof response === 'object') {
                    response = this.response;
                }
            } catch (e) {}
            Object.defineProperty(this, 'responseObject', {value:response});
            return response;
        },
        enumerable: true,
        configurable: true
    },
    responseHeaders: {
        get: function() {
            var headers = {},
                all = this.getAllResponseHeaders().trim().split('\n');
            for (var i=0,m=all.length, header; i<m; i++) {
                if ((header = all[i])) {
                    var parts = header.match(/^([\w\-]+):(.*)/);
                    if (parts.length === 3) {
                        headers[parts[1]] = parts[2].trim();
                    }
                }
            }
            Object.defineProperty(this, 'responseHeaders', {value:headers});
            return headers;
        },
        enumerable: true,
        configurable: true
    }
};
Object.defineProperties(XMLHttpRequest.prototype, XHR.properties);

XHR.active = 0;
XHR.activeClass = 'xhr-active';
XHR.start = function() {
    XHR.active++;
    htmlClass.add(XHR.activeClass);
};
XHR.end = function() {
    if (!--XHR.active) {
        htmlClass.remove(XHR.activeClass);
    }
};

XHR.key = function(cfg) {
    return XHR.url(cfg)+'|'+XHR.method(cfg)+'|'+XHR.data(cfg);
};
XHR.cache = function(xhr) {
    var cfg = xhr.cfg;
    store(XHR.key(cfg), XHR.safeCopy(xhr), cfg.cache);
    return xhr;
};
XHR.safeCopy = function(object, copied) {
    var copy = {};
    copied = copied || [];
    if (copied.indexOf(object) < 0) {
        copied.push(object);
        for (var name in object) {
            var value = object[name],
                type = typeof value;
            if (type === 'function') {
                value = undefined;
            } else if (type === 'object') {
                value = XHR.safeCopy(value, copied);
            }
            if (value !== undefined) {
                copy[name] = value;
            }
        }
        return copy;
    }
};

XHR.chain = function(fn) {
    if (fn) {
        return function chain(xhr) {
            var ret = fn(xhr);
            return ret !== xhr && ret !== undefined ? ret :
                   xhr.error ? Promise.reject(xhr) :
                   xhr;
        };
    }
};

XHR.retry = function(xhr) {
    var retry = xhr.cfg.retry;
    if (retry && (retry.limit || 3) > retry.count) {
        if (typeof retry === 'number') {
            retry = { wait: retry };
        }
        return new Promise(function(resolve) {
            setTimeout(function() {
                retry.count = (retry.count || 0) + 1;
                retry.wait = (retry.wait || 1000) * 2;
                resolve(XHR(xhr.cfg));
            }, retry.wait || 1000);
        });
    }
    return xhr;
};
<|endoftext|>