<commit_before>'use strict';

/*
  fb-menu.js

  Menu process
*/

const FBProcess = require('./fb-process');
const requestGlobal = require('request');
const util = require('util');

// States
const STATE = {
  INITIAL: FBProcess.CONST.STATE.INITIAL,
  MENU: 'state_menu'
};

// Commands
const CMD = {
  REPORT: {
    REPLY: 'Signaler',
    POSTBACK: 'MENU_REPORT'
  },
  MY_REPORTS: {
    REPLY: 'Mes signalements',
    POSTBACK: 'MENU_MY_REPORTS'
  },
  MAP: {
    REPLY: 'Carte signalements',
    URL: 'http://alfred-grand-lyon.herokuapp.com/api/map'
  }
};

function FBMenu(options) {
  if (!(this instanceof FBMenu)) {
    return new FBMenu(options);
  }

  options = options || {};
  options.name = FBProcess.CONST.PROCESS.MENU;
  FBProcess.call(this, options);
}

util.inherits(FBMenu, FBProcess);

FBMenu.prototype.handleMessageState = function(options) {
  options = options || {};

  switch (options.state) {
    case STATE.INITIAL:
      this.sendMenu(options);
      break;
    case STATE.MENU:
      switch (options.type) {
        case 'postback':
          this.handlePostback(options);
          break;
        default:
          this.unknownCommand(options);
      }
      break;
    default:
      this.unknownCommand(options);
  }
};

// Send the menu form to the user
FBMenu.prototype.sendMenu = function(options) {
  options = options || {};

  const buttons = [];
  buttons.push(this.bot.botly.createPostbackButton(CMD.REPORT.REPLY, CMD.REPORT.POSTBACK));
  buttons.push(this.bot.botly.createPostbackButton(CMD.MY_REPORTS.REPLY, CMD.MY_REPORTS.POSTBACK));
  buttons.push(this.bot.botly.createWebURLButton(CMD.MAP.REPLY, CMD.MAP.URL));

  this.bot.botly.sendGeneric({
    id: options.user_id,
    elements: [{
      title:"Bienvenue au menu",
      buttons: buttons
    }]
  });

  options.state = STATE.MENU;
  this.transitionState(options);
};

FBMenu.prototype.handlePostback = function(options) {
  options = options || {};

  switch(options.postback) {
    case CMD.REPORT.POSTBACK:
      this.reportCommand(options);
      break;
    case CMD.MY_REPORTS.POSTBACK:
      this.myReportsCommand(options);
      break;
    default:
      this.unknownCommand(options);
  }
};

// Report command => transition to report process
FBMenu.prototype.reportCommand = function(options) {
  options = options || {};

  options.proc = FBProcess.CONST.PROCESS.REPORT;
  this.transitionProcess(options);
};

// My reports command => Display user's reports
FBMenu.prototype.myReportsCommand = function(options) {
  options = options || {};

  // Fetch user reports from ES
  requestGlobal.post(
  {
    url: `${this.bot.api_url}/api/reports`,
    form: {
      "filters": [
        {
          "type": "user_id",
          "user_id": options.user_id
        }
      ]
    },
    json: true
  }, (err, res, body) => {
    if(err || res.statusCode != 200) {
      throw (err);
    } else {
      console.log(`Fetched reports for user ${options.user_id}`);

      console.log(`Nb of reports : ${body.features.length}`);

      let listElements = [];

      for (let i = 0; i < 4 && i < body.features.length; ++i) {
        let props = body.features[i].properties;

        let date = new Date(props.date);
        date = [
          date.getDate().padLeft(),
          (date.getMonth() + 1).padLeft(),
          date.getFullYear()
        ].join('/');
        console.log(`date ${date}`);

        let title = `Signalé le ${date}`;
        let image = props.image;
        let status = props.state;

        switch (status) {
          case "Untreated":
            title += '- En attente';
            break;
          case "In progress":
            title += '- En cours';
            break;
          case "Done":
            title += '- Résolu';

            if (props.date_final) {
              let date_final = new Date(props.date_final);
              date_final = [
                date_final.getDate().padLeft(),
                (date_final.getMonth() + 1).padLeft(),
                date_final.getFullYear()
              ].join('/');

              title += ` le ${date_final}`;
            }

            if (props.image_final) {
              image = props.image_final;
            }
            break;
        }

        console.log(`title : ${title}`);

        let subtitle = '';
        for (let j = 0; j < props.hashtags.length; ++j) {
          let hashtag = props.hashtags[j];
          subtitle += `#${hashtag} `;
        }

        console.log(`subtitle: ${subtitle}`);

        let listElement = this.bot.botly.createListElement({
          title: title,
          image_url: image,
          subtitle: subtitle
        });

        listElements.push(listElement);
      }

      this.bot.botly.sendList({
        id: options.user_id,
        elements: listElements
      });
    }
  });
};

// Unknown/Unexpected command
FBMenu.prototype.unknownCommand = function(options) {
  options = options || {};

  options.proc = FBProcess.CONST.PROCESS.MENU;
  this.transitionProcess(options);
};

Number.prototype.padLeft = function(base,chr){
  var  len = (String(base || 10).length - String(this).length)+1;
  return len > 0? new Array(len).join(chr || '0')+this : this;
};

module.exports = FBMenu;<commit_msg>Debug #3<commit_after>'use strict';

/*
  fb-menu.js

  Menu process
*/

const FBProcess = require('./fb-process');
const requestGlobal = require('request');
const util = require('util');

// States
const STATE = {
  INITIAL: FBProcess.CONST.STATE.INITIAL,
  MENU: 'state_menu'
};

// Commands
const CMD = {
  REPORT: {
    REPLY: 'Signaler',
    POSTBACK: 'MENU_REPORT'
  },
  MY_REPORTS: {
    REPLY: 'Mes signalements',
    POSTBACK: 'MENU_MY_REPORTS'
  },
  MAP: {
    REPLY: 'Carte signalements',
    URL: 'http://alfred-grand-lyon.herokuapp.com/api/map'
  }
};

function FBMenu(options) {
  if (!(this instanceof FBMenu)) {
    return new FBMenu(options);
  }

  options = options || {};
  options.name = FBProcess.CONST.PROCESS.MENU;
  FBProcess.call(this, options);
}

util.inherits(FBMenu, FBProcess);

FBMenu.prototype.handleMessageState = function(options) {
  options = options || {};

  switch (options.state) {
    case STATE.INITIAL:
      this.sendMenu(options);
      break;
    case STATE.MENU:
      switch (options.type) {
        case 'postback':
          this.handlePostback(options);
          break;
        default:
          this.unknownCommand(options);
      }
      break;
    default:
      this.unknownCommand(options);
  }
};

// Send the menu form to the user
FBMenu.prototype.sendMenu = function(options) {
  options = options || {};

  const buttons = [];
  buttons.push(this.bot.botly.createPostbackButton(CMD.REPORT.REPLY, CMD.REPORT.POSTBACK));
  buttons.push(this.bot.botly.createPostbackButton(CMD.MY_REPORTS.REPLY, CMD.MY_REPORTS.POSTBACK));
  buttons.push(this.bot.botly.createWebURLButton(CMD.MAP.REPLY, CMD.MAP.URL));

  this.bot.botly.sendGeneric({
    id: options.user_id,
    elements: [{
      title:"Bienvenue au menu",
      buttons: buttons
    }]
  });

  options.state = STATE.MENU;
  this.transitionState(options);
};

FBMenu.prototype.handlePostback = function(options) {
  options = options || {};

  switch(options.postback) {
    case CMD.REPORT.POSTBACK:
      this.reportCommand(options);
      break;
    case CMD.MY_REPORTS.POSTBACK:
      this.myReportsCommand(options);
      break;
    default:
      this.unknownCommand(options);
  }
};

// Report command => transition to report process
FBMenu.prototype.reportCommand = function(options) {
  options = options || {};

  options.proc = FBProcess.CONST.PROCESS.REPORT;
  this.transitionProcess(options);
};

// My reports command => Display user's reports
FBMenu.prototype.myReportsCommand = function(options) {
  options = options || {};

  // Fetch user reports from ES
  requestGlobal.post(
  {
    url: `${this.bot.api_url}/api/reports`,
    form: {
      "filters": [
        {
          "type": "user_id",
          "user_id": options.user_id
        }
      ]
    },
    json: true
  }, (err, res, body) => {
    if(err || res.statusCode != 200) {
      throw (err);
    } else {
      console.log(`Fetched reports for user ${options.user_id}`);

      console.log(`Nb of reports : ${body.features.length}`);

      let listElements = [];

      for (let i = 0; i < 4 && i < body.features.length; ++i) {
        let props = body.features[i].properties;

        let date = new Date(props.date);
        date = [
          date.getDate().padLeft(),
          (date.getMonth() + 1).padLeft(),
          date.getFullYear()
        ].join('/');
        console.log(`date ${date}`);

        let title = `Signalé le ${date}`;
        let image = props.image;
        let status = props.state;

        switch (status) {
          case "Untreated":
            title += '- En attente';
            break;
          case "In progress":
            title += '- En cours';
            break;
          case "Done":
            title += '- Résolu';

            if (props.date_final) {
              let date_final = new Date(props.date_final);
              date_final = [
                date_final.getDate().padLeft(),
                (date_final.getMonth() + 1).padLeft(),
                date_final.getFullYear()
              ].join('/');

              title += ` le ${date_final}`;
            }

            if (props.image_final) {
              image = props.image_final;
            }
            break;
        }

        console.log(`title : ${title}`);

        let subtitle = '';
        for (let j = 0; j < props.hashtags.length; ++j) {
          let hashtag = props.hashtags[j];
          subtitle += `#${hashtag} `;
        }

        console.log(`subtitle: ${subtitle}`);

        let listElement = this.bot.botly.createListElement({
          title: title,
          // image_url: image,
          subtitle: subtitle
        });

        listElements.push(listElement);
      }

      this.bot.botly.sendList({
        id: options.user_id,
        elements: listElements
      });
    }
  });
};

// Unknown/Unexpected command
FBMenu.prototype.unknownCommand = function(options) {
  options = options || {};

  options.proc = FBProcess.CONST.PROCESS.MENU;
  this.transitionProcess(options);
};

Number.prototype.padLeft = function(base,chr){
  var  len = (String(base || 10).length - String(this).length)+1;
  return len > 0? new Array(len).join(chr || '0')+this : this;
};

module.exports = FBMenu;<|endoftext|>


<commit_before>/* --------------------
 * Sequelize hierarchy
 * Hooks on individual models
 * ------------------*/

'use strict';

// Imports
const utils = require('./utils'),
	patchesFn = require('./patches');

// Exports

module.exports = function(Sequelize) {
	const patches = patchesFn(Sequelize),
		{Promise} = Sequelize;

	return {
		beforeCreate(item, options) {
			const {hierarchy} = this,
				values = item.dataValues,
				parentId = utils.valueFilteredByFields(hierarchy.foreignKey, item, options),
				{levelFieldName} = hierarchy;

			// If no parent, set level and exit - no ancestor records to create
			if (!parentId) {
				values[levelFieldName] = 1;
				return undefined;
			}

			// Check that not trying to make item a child of itself
			const itemId = utils.valueFilteredByFields(hierarchy.primaryKey, item, options);
			if (parentId === itemId) return Promise.reject(new Sequelize.HierarchyError('Parent cannot be a child of itself'));

			// Set level based on parent
			const queryOptions = utils.addOptions({where: {}, attributes: [levelFieldName]}, options);
			queryOptions.where[hierarchy.primaryKey] = parentId;

			return patches.findOne(this, queryOptions).then((parent) => {
				if (!parent) throw new Sequelize.HierarchyError('Parent does not exist');

				// Set hierarchy level
				values[levelFieldName] = parent[levelFieldName] + 1;
				utils.addToFields(levelFieldName, options);
			});
		},

		afterCreate(item, options) {
			const {hierarchy} = this,
				values = item.dataValues,
				parentId = utils.valueFilteredByFields(hierarchy.foreignKey, item, options);

			// If no parent, exit - no hierarchy to create
			if (!parentId) return undefined;

			// Create row in hierarchy table for parent
			const itemId = values[hierarchy.primaryKey],
				{through} = hierarchy;

			return Promise.try(() => {
				// Get ancestors

				// If parent is at top level, has no ancestors
				if (values[hierarchy.levelFieldName] === 2) return [];

				// Get parent's ancestors
				const queryOptions = utils.addOptions({
					where: {},
					attributes: [hierarchy.throughForeignKey]
				}, options);
				queryOptions.where[hierarchy.throughKey] = parentId;

				return patches.findAll(through, queryOptions);
			}).then((ancestors) => {
				// Add parent as ancestor
				const parentValues = {};
				parentValues[hierarchy.throughForeignKey] = parentId;
				ancestors.push(parentValues);
				return ancestors;
			}).then((ancestors) => {
				// Save ancestors
				ancestors = ancestors.map((_ancestor) => {
					const ancestor = {};
					ancestor[hierarchy.throughForeignKey] = _ancestor[hierarchy.throughForeignKey];
					ancestor[hierarchy.throughKey] = itemId;
					return ancestor;
				});

				return through.bulkCreate(ancestors, utils.addOptions({}, options));
			}).return();
		},

		beforeUpdate(item, options) {
			const model = this,
				{sequelize} = model,
				{hierarchy} = model,
				values = item.dataValues;

			// NB This presumes item has not been updated since it was originally retrieved
			const itemId = values[hierarchy.primaryKey],
				parentId = values[hierarchy.foreignKey],
				oldParentId = item._previousDataValues[hierarchy.foreignKey];

			// If parent not changing, exit - no change to make
			if (
				parentId === oldParentId
				|| !utils.inFields(hierarchy.foreignKey, options)
			) return undefined;

			return Promise.try(() => {
				if (parentId === null) return undefined;

				// Check that not trying to make item a child of itself
				if (parentId === itemId) {
					throw new Sequelize.HierarchyError('Parent cannot be a child of itself');
				}

				// Check that not trying to make item a child of one of its own descendents
				const where = {};
				where[hierarchy.throughKey] = parentId;
				where[hierarchy.throughForeignKey] = itemId;

				return patches.findOne(
					hierarchy.through,
					utils.addOptions({where}, options)
				).then((illegalItem) => {
					if (illegalItem) throw new Sequelize.HierarchyError('Parent cannot be a child of itself');
				});
			}).then(() => {
				// Get parent's level
				if (parentId === null) return 0;

				const where = {};
				where[hierarchy.primaryKey] = parentId;

				return patches.findOne(
					model,
					utils.addOptions({where, attributes: [hierarchy.levelFieldName]}, options)
				).then((parent) => {
					if (!parent) throw new Sequelize.HierarchyError('Parent does not exist');

					return parent[hierarchy.levelFieldName];
				});
			}).then((parentLevel) => {
				// Set hierarchy level
				const newLevel = parentLevel + 1,
					levelChange = newLevel - item._previousDataValues[hierarchy.levelFieldName];

				values[hierarchy.levelFieldName] = newLevel;
				utils.addToFields(hierarchy.levelFieldName, options);

				// Update level and hierarchy table
				return Promise.try(() => {
					if (!levelChange) return undefined;

					// Update hierarchy level for all descendents
					let sql = 'UPDATE *item '
							+ 'SET *level = *level + :levelChange '
							+ 'WHERE *id IN ('
							+ '  SELECT *itemId '
							+ '  FROM *through AS ancestors '
							+ '  WHERE ancestors.*ancestorId = :id'
							+ ')';

					sql = utils.replaceTableNames(sql, {
						item: model,
						through: hierarchy.through
					}, sequelize);

					sql = utils.replaceFieldNames(sql, {
						level: hierarchy.levelFieldName,
						id: hierarchy.primaryKey
					}, model);

					sql = utils.replaceFieldNames(sql, {
						itemId: hierarchy.throughKey,
						ancestorId: hierarchy.throughForeignKey
					}, hierarchy.through);

					return patches.query(
						sequelize,
						sql,
						utils.addOptions({replacements: {id: itemId, levelChange}}, options)
					);
				}).then(() => {
					// Delete ancestors from hierarchy table for item and all descendents
					if (oldParentId === null) return undefined;

					let sql;
					if (sequelize.options.dialect === 'postgres') {
						sql = 'DELETE FROM *through '
							+ 'USING *through AS descendents, *through AS ancestors '
							+ 'WHERE descendents.*itemId = *through.*itemId '
							+ '  AND ancestors.*ancestorId = *through.*ancestorId '
							+ '  AND ancestors.*itemId = :id '
							+ '  AND ('
							+ '    descendents.*ancestorId = :id '
							+ '    OR descendents.*itemId = :id'
							+ '  )';
					} else if (sequelize.options.dialect === 'sqlite') {
						sql = 'DELETE FROM *through '
							+ 'WHERE EXISTS ('
							+ '  SELECT * '
							+ '  FROM *through AS deleters '
							+ '    INNER JOIN *through AS descendents ON descendents.*itemId = deleters.*itemId '
							+ '    INNER JOIN *through AS ancestors ON ancestors.*ancestorId = deleters.*ancestorId '
							+ '  WHERE deleters.*itemId = *through.*itemId '
							+ '    AND deleters.*ancestorId = *through.*ancestorId '
							+ '    AND ancestors.*ancestorId = *through.*ancestorId '
							+ '    AND ancestors.*itemId = :id '
							+ '    AND ('
							+ '      descendents.*ancestorId = :id '
							+ '      OR descendents.*itemId = :id'
							+ '    )'
							+ ')';
					} else {
						// mySQL
						sql = 'DELETE deleters '
							+ 'FROM *through AS deleters '
							+ '  INNER JOIN *through AS descendents ON descendents.*itemId = deleters.*itemId '
							+ '  INNER JOIN *through AS ancestors ON ancestors.*ancestorId = deleters.*ancestorId '
							+ 'WHERE ancestors.*itemId = :id '
							+ '  AND ('
							+ '    descendents.*ancestorId = :id '
							+ '    OR descendents.*itemId = :id'
							+ '  )';
					}

					sql = utils.replaceTableNames(sql, {through: hierarchy.through}, sequelize);

					sql = utils.replaceFieldNames(sql, {
						itemId: hierarchy.throughKey,
						ancestorId: hierarchy.throughForeignKey
					}, hierarchy.through);

					return patches.query(
						sequelize,
						sql,
						utils.addOptions({replacements: {id: itemId}}, options)
					);
				}).then(() => {
					// Insert ancestors into hierarchy table for item and all descendents
					if (parentId === null) return undefined;

					let sql = 'INSERT INTO *through (*itemId, *ancestorId) '
						+ 'SELECT descendents.*itemId, ancestors.*ancestorId '
						+ 'FROM ( '
						+ '    SELECT *itemId '
						+ '    FROM *through '
						+ '    WHERE *ancestorId = :id '
						+ '    UNION ALL '
						+ '    SELECT :id '
						+ '  ) AS descendents, '
						+ '  ('
						+ '    SELECT *ancestorId '
						+ '    FROM *through '
						+ '    WHERE *itemId = :parentId '
						+ '    UNION ALL '
						+ '    SELECT :parentId'
						+ '  ) AS ancestors';

					sql = utils.replaceTableNames(sql, {through: hierarchy.through}, sequelize);

					sql = utils.replaceFieldNames(sql, {
						itemId: hierarchy.throughKey,
						ancestorId: hierarchy.throughForeignKey
					}, hierarchy.through);

					return patches.query(
						sequelize,
						sql,
						utils.addOptions({replacements: {id: itemId, parentId}}, options)
					);
				});
			}).return();
		},

		beforeBulkCreate(daos, options) {
			// Set individualHooks = true so that beforeCreate and afterCreate hooks run
			options.individualHooks = true;
		},
		beforeBulkUpdate(options) {
			// Set individualHooks = true so that beforeUpdate and afterUpdate hooks run
			options.individualHooks = true;
		}
	};
};
<commit_msg>Add line spacing [refactor]<commit_after>/* --------------------
 * Sequelize hierarchy
 * Hooks on individual models
 * ------------------*/

'use strict';

// Imports
const utils = require('./utils'),
	patchesFn = require('./patches');

// Exports

module.exports = function(Sequelize) {
	const patches = patchesFn(Sequelize),
		{Promise} = Sequelize;

	return {
		beforeCreate(item, options) {
			const {hierarchy} = this,
				values = item.dataValues,
				parentId = utils.valueFilteredByFields(hierarchy.foreignKey, item, options),
				{levelFieldName} = hierarchy;

			// If no parent, set level and exit - no ancestor records to create
			if (!parentId) {
				values[levelFieldName] = 1;
				return undefined;
			}

			// Check that not trying to make item a child of itself
			const itemId = utils.valueFilteredByFields(hierarchy.primaryKey, item, options);
			if (parentId === itemId) return Promise.reject(new Sequelize.HierarchyError('Parent cannot be a child of itself'));

			// Set level based on parent
			const queryOptions = utils.addOptions({where: {}, attributes: [levelFieldName]}, options);
			queryOptions.where[hierarchy.primaryKey] = parentId;

			return patches.findOne(this, queryOptions).then((parent) => {
				if (!parent) throw new Sequelize.HierarchyError('Parent does not exist');

				// Set hierarchy level
				values[levelFieldName] = parent[levelFieldName] + 1;
				utils.addToFields(levelFieldName, options);
			});
		},

		afterCreate(item, options) {
			const {hierarchy} = this,
				values = item.dataValues,
				parentId = utils.valueFilteredByFields(hierarchy.foreignKey, item, options);

			// If no parent, exit - no hierarchy to create
			if (!parentId) return undefined;

			// Create row in hierarchy table for parent
			const itemId = values[hierarchy.primaryKey],
				{through} = hierarchy;

			return Promise.try(() => {
				// Get ancestors

				// If parent is at top level, has no ancestors
				if (values[hierarchy.levelFieldName] === 2) return [];

				// Get parent's ancestors
				const queryOptions = utils.addOptions({
					where: {},
					attributes: [hierarchy.throughForeignKey]
				}, options);
				queryOptions.where[hierarchy.throughKey] = parentId;

				return patches.findAll(through, queryOptions);
			}).then((ancestors) => {
				// Add parent as ancestor
				const parentValues = {};
				parentValues[hierarchy.throughForeignKey] = parentId;
				ancestors.push(parentValues);
				return ancestors;
			}).then((ancestors) => {
				// Save ancestors
				ancestors = ancestors.map((_ancestor) => {
					const ancestor = {};
					ancestor[hierarchy.throughForeignKey] = _ancestor[hierarchy.throughForeignKey];
					ancestor[hierarchy.throughKey] = itemId;
					return ancestor;
				});

				return through.bulkCreate(ancestors, utils.addOptions({}, options));
			}).return();
		},

		beforeUpdate(item, options) {
			const model = this,
				{sequelize} = model,
				{hierarchy} = model,
				values = item.dataValues;

			// NB This presumes item has not been updated since it was originally retrieved
			const itemId = values[hierarchy.primaryKey],
				parentId = values[hierarchy.foreignKey],
				oldParentId = item._previousDataValues[hierarchy.foreignKey];

			// If parent not changing, exit - no change to make
			if (
				parentId === oldParentId
				|| !utils.inFields(hierarchy.foreignKey, options)
			) return undefined;

			return Promise.try(() => {
				if (parentId === null) return undefined;

				// Check that not trying to make item a child of itself
				if (parentId === itemId) {
					throw new Sequelize.HierarchyError('Parent cannot be a child of itself');
				}

				// Check that not trying to make item a child of one of its own descendents
				const where = {};
				where[hierarchy.throughKey] = parentId;
				where[hierarchy.throughForeignKey] = itemId;

				return patches.findOne(
					hierarchy.through,
					utils.addOptions({where}, options)
				).then((illegalItem) => {
					if (illegalItem) throw new Sequelize.HierarchyError('Parent cannot be a child of itself');
				});
			}).then(() => {
				// Get parent's level
				if (parentId === null) return 0;

				const where = {};
				where[hierarchy.primaryKey] = parentId;

				return patches.findOne(
					model,
					utils.addOptions({where, attributes: [hierarchy.levelFieldName]}, options)
				).then((parent) => {
					if (!parent) throw new Sequelize.HierarchyError('Parent does not exist');

					return parent[hierarchy.levelFieldName];
				});
			}).then((parentLevel) => {
				// Set hierarchy level
				const newLevel = parentLevel + 1,
					levelChange = newLevel - item._previousDataValues[hierarchy.levelFieldName];

				values[hierarchy.levelFieldName] = newLevel;
				utils.addToFields(hierarchy.levelFieldName, options);

				// Update level and hierarchy table
				return Promise.try(() => {
					if (!levelChange) return undefined;

					// Update hierarchy level for all descendents
					let sql = 'UPDATE *item '
							+ 'SET *level = *level + :levelChange '
							+ 'WHERE *id IN ('
							+ '  SELECT *itemId '
							+ '  FROM *through AS ancestors '
							+ '  WHERE ancestors.*ancestorId = :id'
							+ ')';

					sql = utils.replaceTableNames(sql, {
						item: model,
						through: hierarchy.through
					}, sequelize);

					sql = utils.replaceFieldNames(sql, {
						level: hierarchy.levelFieldName,
						id: hierarchy.primaryKey
					}, model);

					sql = utils.replaceFieldNames(sql, {
						itemId: hierarchy.throughKey,
						ancestorId: hierarchy.throughForeignKey
					}, hierarchy.through);

					return patches.query(
						sequelize,
						sql,
						utils.addOptions({replacements: {id: itemId, levelChange}}, options)
					);
				}).then(() => {
					// Delete ancestors from hierarchy table for item and all descendents
					if (oldParentId === null) return undefined;

					let sql;
					if (sequelize.options.dialect === 'postgres') {
						sql = 'DELETE FROM *through '
							+ 'USING *through AS descendents, *through AS ancestors '
							+ 'WHERE descendents.*itemId = *through.*itemId '
							+ '  AND ancestors.*ancestorId = *through.*ancestorId '
							+ '  AND ancestors.*itemId = :id '
							+ '  AND ('
							+ '    descendents.*ancestorId = :id '
							+ '    OR descendents.*itemId = :id'
							+ '  )';
					} else if (sequelize.options.dialect === 'sqlite') {
						sql = 'DELETE FROM *through '
							+ 'WHERE EXISTS ('
							+ '  SELECT * '
							+ '  FROM *through AS deleters '
							+ '    INNER JOIN *through AS descendents ON descendents.*itemId = deleters.*itemId '
							+ '    INNER JOIN *through AS ancestors ON ancestors.*ancestorId = deleters.*ancestorId '
							+ '  WHERE deleters.*itemId = *through.*itemId '
							+ '    AND deleters.*ancestorId = *through.*ancestorId '
							+ '    AND ancestors.*ancestorId = *through.*ancestorId '
							+ '    AND ancestors.*itemId = :id '
							+ '    AND ('
							+ '      descendents.*ancestorId = :id '
							+ '      OR descendents.*itemId = :id'
							+ '    )'
							+ ')';
					} else {
						// mySQL
						sql = 'DELETE deleters '
							+ 'FROM *through AS deleters '
							+ '  INNER JOIN *through AS descendents ON descendents.*itemId = deleters.*itemId '
							+ '  INNER JOIN *through AS ancestors ON ancestors.*ancestorId = deleters.*ancestorId '
							+ 'WHERE ancestors.*itemId = :id '
							+ '  AND ('
							+ '    descendents.*ancestorId = :id '
							+ '    OR descendents.*itemId = :id'
							+ '  )';
					}

					sql = utils.replaceTableNames(sql, {through: hierarchy.through}, sequelize);

					sql = utils.replaceFieldNames(sql, {
						itemId: hierarchy.throughKey,
						ancestorId: hierarchy.throughForeignKey
					}, hierarchy.through);

					return patches.query(
						sequelize,
						sql,
						utils.addOptions({replacements: {id: itemId}}, options)
					);
				}).then(() => {
					// Insert ancestors into hierarchy table for item and all descendents
					if (parentId === null) return undefined;

					let sql = 'INSERT INTO *through (*itemId, *ancestorId) '
						+ 'SELECT descendents.*itemId, ancestors.*ancestorId '
						+ 'FROM ( '
						+ '    SELECT *itemId '
						+ '    FROM *through '
						+ '    WHERE *ancestorId = :id '
						+ '    UNION ALL '
						+ '    SELECT :id '
						+ '  ) AS descendents, '
						+ '  ('
						+ '    SELECT *ancestorId '
						+ '    FROM *through '
						+ '    WHERE *itemId = :parentId '
						+ '    UNION ALL '
						+ '    SELECT :parentId'
						+ '  ) AS ancestors';

					sql = utils.replaceTableNames(sql, {through: hierarchy.through}, sequelize);

					sql = utils.replaceFieldNames(sql, {
						itemId: hierarchy.throughKey,
						ancestorId: hierarchy.throughForeignKey
					}, hierarchy.through);

					return patches.query(
						sequelize,
						sql,
						utils.addOptions({replacements: {id: itemId, parentId}}, options)
					);
				});
			}).return();
		},

		beforeBulkCreate(daos, options) {
			// Set individualHooks = true so that beforeCreate and afterCreate hooks run
			options.individualHooks = true;
		},

		beforeBulkUpdate(options) {
			// Set individualHooks = true so that beforeUpdate and afterUpdate hooks run
			options.individualHooks = true;
		}
	};
};
<|endoftext|>


<commit_before>function $ (selector, el) {
    if (!el) {el = document;}
    return el.querySelector(selector);
}
function $$ (selector, el) {
    if (!el) {el = document;}
    return Array.prototype.slice.call(el.querySelectorAll(selector));
}
Element.prototype.toggleClass = function (className) {
    if (this.className.indexOf(className) > -1) {
        this.className = this.className.replace(className, '');
    }
    else {
        this.className += ' ' + className;
    }
};
(function(){
    function Send(url, method, data, sync) {
        return new Promise(function (resolve, reject) {
            var request = new XMLHttpRequest();
            request.open(method, url, !sync);
            request.onreadystatechange = function () {
                console.log(request);
                if (request.readyState === 4 && request.status === 200) {
                    resolve(request.responseText);
                }
                else {
                    reject(request.responseText);
                }
            };
            if (method == 'POST') {
                request.setRequestHeader('Content-type', 'application/json; charset=utf-8');
            }
            request.send(JSON.stringify(data));
        });
    }
    function BuildUrl(base, params) {
        if (params==null||params=={}||params==[])
            return base;
        var query = [];
        for (var key in params) {
            query.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
        }
        return base + '?' + query.join('&');
    }
    $.Post = function (url, params, data, sync) {
        return this.Send(BuildUrl(url, params), 'POST', data, sync);
    }
    $.Get = function (url, params, sync) {
        return this.Send(BuildUrl(url, params), 'GET', null, sync);
    }
})();<commit_msg>added isEmpty function, fixed ajax methods<commit_after>function $ (selector, el) {
    if (!el) {el = document;}
    return el.querySelector(selector);
}
function $$ (selector, el) {
    if (!el) {el = document;}
    return Array.prototype.slice.call(el.querySelectorAll(selector));
}
Element.prototype.toggleClass = function (className) {
    if (this.className.indexOf(className) > -1) {
        this.className = this.className.replace(className, '');
    }
    else {
        this.className += ' ' + className;
    }
};
(function(){
    function send(url, method, data) {
        return new Promise(function (resolve, reject) {
            var request = new XMLHttpRequest();
            request.open(method, url, true);
            request.onreadystatechange = function () {
                if (request.readyState === 4) {
                    if (request.status === 200)
                        resolve(request.responseText);
                    else
                        reject(request.responseText);
                }
            };
            if (method == 'POST') {
                request.setRequestHeader('Content-type', 'application/json; charset=utf-8');
            }
            request.send(JSON.stringify(data));
        });
    }
    function buildUrl(base, params) {
        if ($.isEmpty(params))
            return base;
        var query = [];
        for (var key in params) {
            query.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
        }
        return base + '?' + query.join('&');
    }
    $.isEmpty = function (value) {
        return value == null
        || (value.length && value.length == 0)
        || (Object.keys(value).length === 0);
    }
    $.post = function (url, params, data) {
        return send(buildUrl(url, params), 'POST', data);
    }
    $.get = function (url, params) {
        return send(buildUrl(url, params), 'GET', null);
    }
})();<|endoftext|>


<commit_before>/*
* numeric.ly
* author: steve kaliski
* last modified: sep 2012
*-----------------------------------------------------------------------------*/

var numeric = {

  //basic addition of vals in an array
  addition: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = 0;
      for (var i = 0 ; i < arr.length ; i++) {
        total = total + arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //subtract items in an array (descending)
  subtraction: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[arr.length - 1];
      for (var i = arr.length - 2; i >= 0; i--) {
        total -= arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //product of items in array
  product: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[0];
      for (var i = 1; i < arr.length; i++) {
        total = total * arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //greatest common denominator
  gcd: function(num1, num2) {
    var result;
    if (num1 > num2) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num2 % i === 0) {
          if (num1 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else if (num2 > num1) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num1 % i === 0) {
          if (num2 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else {
      result = num1 * num2 / num1;
      return result;
    }
  },

  //least common multiple
  lcm: function(num1, num2) {
    var result = Math.abs(num1 * num2) / gcd(num1,num2);
    return result;
  },

  //evaluate function at val (func passed as a string)
  evaluate: function(func, val) {
    return parseFloat(eval("with(Math){var x = " + val + ";" + func+'};'));
  },

/*-----------------------------------------------------------------------------*/

  //a variety of calculus tools
  calculus: {

    //function, point at which differentiation occurs (func passed as string)
    pointDiff: function(func, point) {
      var a = evaluate(func, point - .00001);
      var b = evaluate(func, point + .00001);

      return (b - a) / (.00002);
    },

    //calculate riemann integral (left hand) (func passed as string)
    riemann: function(func, start, finish, n) {
      var inc = (finish - start) / n;
      var result = 0;
      for (var i = start; i < finish; i += inc) {
        result += (evaluate(func, i) * inc);
      }
      return result;
    },

    //estimate integral with adaptive simpson quadrature
    simpsonDef: function(func, a, b) {
      var c = (a + b) / 2;
      var d = Math.abs(b - a) / 6;
      return d * (evaluate(func, a) + 4 * evaluate(func, c) + evaluate(func, b));
    },
    simpsonRecursive: function(func, a, b, eps, whole) {
      var c = a + b;
      var left = simpsonDef(func, a, c);
      var right = simpsonDef(func, c, b);
      if (Math.abs(left + right - whole) <= 15 * eps) {
        return left + right + (left + right - whole) / 15;
      } else {
        return simpsonRecursive(func, a, c, eps/2, left) + simpsonRecursive(func, c, b, eps / 2, right);
      }
    },
    //execute this
    adaptiveSimpson: function(func, a, b, eps) {
      return simpsonRecursive(func, a, b, eps, simpsonDef(func, a, b));
    },

    //take the limit of a function (left, middle, or right)
    limit: function(func, point, approach) {
      if (approach === 'left') {
        return evaluate(func, point - .001);
      } else if (approach === 'right') {
        return evaluate(func, point + .001);
      } else if (approach === 'middle') {
        return (limit(func, point, 'left') + limit(func, point, 'right')) / 2;
      } else {
        throw new Error('Approach not provided');
      }
    },

    //return taylor polynomial for function (func) at point (point) to degree (degree: 0, 1 and 2 for now)
    taylor: function(func, point, degree) {
      if (degree == 0) {

      } else if (degree == 1) {

      } else if (degree == 2) {

      }
    },

    //integrate taylor polynomial for some func
    polyIntegrate: function(func) {
      var taylor = taylor(func, 0, 8);
    }
  },

/*-----------------------------------------------------------------------------*/

  /*
  a variety of matrix analysis tools

  let's consider the matrix A:

  [1 2 3]
  [4 5 6]

  As input, set arg = [[1,2,3],[4,5,6]];

  Note: The "structure" of matrices may be neglected in some calculations,
  however in and transformation, mapping, etc, we recognize the proper
  format.
  */
  matrix: {

    //add two arrays (arrA and arrB)
    addition: function(arrA, arrB) {
      if ((arrA.length === arrB.length) && (arrA[0].length === arrB[0].length)) {
        var result = new Array(arrA.length);
        for (var i = 0; i < arrA.length; i++) {
          result[i] = new Array(arrA[i].length);
          for (var j = 0; j < arrA[i].length; j++) {
            result[i][j] = arrA[i][j] + arrB[i][j];
          }
        }
        return result;
      } else {
        throw new Error('Array mismatch');
      }
    },

    //multiple array (arr) by a scalar (val)
    scalar: function(arr,val) {
      for (var i = 0; i < arr.length; i++) {
        for (var j = 0; j < arr[i].length; j++) {
          arr[i][j] = val * arr[i][j];
        }
      }
      return arr;
    },

    //transpose array
    transpose: function(arr) {
      var result = new Array(arr[0].length);
      for (var i = 0; i < arr[0].length; i++) {
        result[i] = new Array(arr.length);
        for (var j = 0; j < arr.length; j++){
          result[i][j] = arr[j][i];
        }
      }
      return result;
    },

    //return identity matrix of dimension n x n
    identity: function(n) {
      var result = new Array(n);
      for (var i = 0 ; i < n ; i++) {
        result[i] = new Array(n);
        for (var j = 0 ; j < n ; j++) {
          result[i][j] = (i === j) ? 1 : 0;
        }
      }
      return result;
    },

    //dot product
    dotproduct: function(vectorA, vectorB) {
      if (vectorA.length === vectorB.length) {
        var result = 0;
        for (var i = 0 ; i < vectorA.length ; i++) {
          result += vectorA[i]*vectorB[i];
        }
        return result;
      } else {
        throw new Error("Vector mismatch");
      }
    },

    //multiply two matrices
    multiply: function(arrA, arrB) {
      if (arrA[0].length === arrB.length) {
        var result = new Array(arrA.length);

        for (var i = 0 ; i < arrA.length ; i++) {
          result[i] = new Array(arrB[0].length);
        }

        var arrB_T = transpose(arrB);

        for (var i = 0 ; i < result.length ; i++) {
          for (var j = 0 ; j < result[i].length ; j++) {
            result[i][j] = dotproduct(arrA[i],arrB_T[j]);
          }
        }
        return result;
      } else {
        throw new Error("Array mismatch");
      }
    },

    //determinant, only for n x n -> 2 and 3
    determinant: function(m) {
      if ((m.length === 2) && (m[0].length === 2)) {
        return m[0][0] * m[1][1] - m[0][1] * m[1][0];
      } else if ((m.length === 3) && (m[0].length === 3)) {
        return m[0][0] * m[1][1] * m[2][2]
          + m[0][1] * m[1][2] * m[2][0]
          + m[0][2] * m[1][0] * m[2][1]
          - m[0][2] * m[1][1] * m[2][0]
          - m[0][1] * m[1][0] * m[2][2]
          - m[0][0] * m[1][2] * m[2][1];
      }
    }
  },

/*-----------------------------------------------------------------------------*/

  //collection of prime associated tools
  prime: {

    //standard prime evaluation (no consideration towards efficiency)
    simple: function(val) {
      if (val == 1) {
        return false;
      } else if (val == 2) {
        return true;
      } else if (val != null) {
        var start = 2;
        var result = true;
        while (start < val) {
          if (val % start === 0) {
            result = false;
            break;
          } else {
            start++;
          }
        }
        return result;
      }
    },

    //determine primality using elliptic curve testing
    elliptic: function() {
      return null;
    }
  },

/*-----------------------------------------------------------------------------*/

  //statistic oriented tools
  statistic: {

    //get mean value of the numbers in an array
    mean: function(arr) {
      var count = arr.length;
      var sum = addition(arr);
      return sum/count;
    },

    //get median value of the numbers in an array
    median: function(arr) {
      var count = arr.length;
      var middle;
      if (count % 2 === 0) {
        return (arr[count/2] + arr[(count/2 - 1)])/2;
      } else {
        return arr[Math.floor(count / 2)];
      }
    },

    //get mode value (most common value) of the numbers in an array
    mode: function(arr) {
      //sort array
      var maxIndex = 0, maxOccurence = 0, tempIndex = 0, tempOccurence = 0;
      arr = arr.sort();
      while (tempIndex < arr.length) {
        for (var j = tempIndex; j < arr.length; j++) {
          if (arr[j] == arr[tempIndex]) {
            tempOccurence++;
          } else {
            break;
          }
        }
        if (tempOccurence > maxOccurence) {
          maxOccurence = tempOccurence;
          maxIndex = tempIndex;
        }

        tempIndex = j;
        tempOccurence = 0;
      }
      return arr[maxIndex];
    },

    //generate a random sample of n-values within lower/upper bounds
    randomSample: function(lower,upper,n) {
      var sample = new Array();
      var temp;
      for (var i = 0 ; i < n ; i++) {
        temp = Math.random()*upper;
        if (temp > lower)
          sample[i] = temp;
      }
      return sample;
    },

    //standard deviation
    standardDev: function(arr) {
      var count = arr.length;
      var mean = mean(arr);
      var squaredArr = new Array();
      for (var i = 0; i < arr.length; i++) {
        squaredArr[i] = Math.pow((arr[i] - mean),2);
      }
      return Math.sqrt((1/count) * addition(squaredArr));
    },

    //correlation of two arrays
    correlation: function(arrX,arrY) {
      if (arrX.length == arrY.length) {
        var numerator = 0;
        var denominator = (arrX.length) * (standardDev(arrX)) * (standardDev(arrY));
        var xMean = mean(arrX);
        var yMean = mean(arrY);
        for (var i = 0 ; i < arrX.length ; i++) {
          numerator += (arrX[i] - xMean) * (arrY[i] - yMean);
        }
        return numerator / denominator;
      } else {
        throw new Error('Array mismatch');
      }
    }
  }
};<commit_msg>More robust, but still backwards-compatible, evaluate()<commit_after>/*
* numeric.ly
* author: steve kaliski
* last modified: sep 2012
*-----------------------------------------------------------------------------*/

var numeric = {

  //basic addition of vals in an array
  addition: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = 0;
      for (var i = 0 ; i < arr.length ; i++) {
        total = total + arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //subtract items in an array (descending)
  subtraction: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[arr.length - 1];
      for (var i = arr.length - 2; i >= 0; i--) {
        total -= arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //product of items in array
  product: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[0];
      for (var i = 1; i < arr.length; i++) {
        total = total * arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //greatest common denominator
  gcd: function(num1, num2) {
    var result;
    if (num1 > num2) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num2 % i === 0) {
          if (num1 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else if (num2 > num1) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num1 % i === 0) {
          if (num2 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else {
      result = num1 * num2 / num1;
      return result;
    }
  },

  //least common multiple
  lcm: function(num1, num2) {
    var result = Math.abs(num1 * num2) / gcd(num1,num2);
    return result;
  },

  //evaluate function at val (func passed as a string)
  evaluate: function(func, val) {
    if(typeof func == 'string') {
      return Math[func.substring(0,func.indexOf('('))](val);
    }
    return func(val);
  },

/*-----------------------------------------------------------------------------*/

  //a variety of calculus tools
  calculus: {

    //function, point at which differentiation occurs (func passed as string)
    pointDiff: function(func, point) {
      var a = evaluate(func, point - .00001);
      var b = evaluate(func, point + .00001);

      return (b - a) / (.00002);
    },

    //calculate riemann integral (left hand) (func passed as string)
    riemann: function(func, start, finish, n) {
      var inc = (finish - start) / n;
      var result = 0;
      for (var i = start; i < finish; i += inc) {
        result += (evaluate(func, i) * inc);
      }
      return result;
    },

    //estimate integral with adaptive simpson quadrature
    simpsonDef: function(func, a, b) {
      var c = (a + b) / 2;
      var d = Math.abs(b - a) / 6;
      return d * (evaluate(func, a) + 4 * evaluate(func, c) + evaluate(func, b));
    },
    simpsonRecursive: function(func, a, b, eps, whole) {
      var c = a + b;
      var left = simpsonDef(func, a, c);
      var right = simpsonDef(func, c, b);
      if (Math.abs(left + right - whole) <= 15 * eps) {
        return left + right + (left + right - whole) / 15;
      } else {
        return simpsonRecursive(func, a, c, eps/2, left) + simpsonRecursive(func, c, b, eps / 2, right);
      }
    },
    //execute this
    adaptiveSimpson: function(func, a, b, eps) {
      return simpsonRecursive(func, a, b, eps, simpsonDef(func, a, b));
    },

    //take the limit of a function (left, middle, or right)
    limit: function(func, point, approach) {
      if (approach === 'left') {
        return evaluate(func, point - .001);
      } else if (approach === 'right') {
        return evaluate(func, point + .001);
      } else if (approach === 'middle') {
        return (limit(func, point, 'left') + limit(func, point, 'right')) / 2;
      } else {
        throw new Error('Approach not provided');
      }
    },

    //return taylor polynomial for function (func) at point (point) to degree (degree: 0, 1 and 2 for now)
    taylor: function(func, point, degree) {
      if (degree == 0) {

      } else if (degree == 1) {

      } else if (degree == 2) {

      }
    },

    //integrate taylor polynomial for some func
    polyIntegrate: function(func) {
      var taylor = taylor(func, 0, 8);
    }
  },

/*-----------------------------------------------------------------------------*/

  /*
  a variety of matrix analysis tools

  let's consider the matrix A:

  [1 2 3]
  [4 5 6]

  As input, set arg = [[1,2,3],[4,5,6]];

  Note: The "structure" of matrices may be neglected in some calculations,
  however in and transformation, mapping, etc, we recognize the proper
  format.
  */
  matrix: {

    //add two arrays (arrA and arrB)
    addition: function(arrA, arrB) {
      if ((arrA.length === arrB.length) && (arrA[0].length === arrB[0].length)) {
        var result = new Array(arrA.length);
        for (var i = 0; i < arrA.length; i++) {
          result[i] = new Array(arrA[i].length);
          for (var j = 0; j < arrA[i].length; j++) {
            result[i][j] = arrA[i][j] + arrB[i][j];
          }
        }
        return result;
      } else {
        throw new Error('Array mismatch');
      }
    },

    //multiple array (arr) by a scalar (val)
    scalar: function(arr,val) {
      for (var i = 0; i < arr.length; i++) {
        for (var j = 0; j < arr[i].length; j++) {
          arr[i][j] = val * arr[i][j];
        }
      }
      return arr;
    },

    //transpose array
    transpose: function(arr) {
      var result = new Array(arr[0].length);
      for (var i = 0; i < arr[0].length; i++) {
        result[i] = new Array(arr.length);
        for (var j = 0; j < arr.length; j++){
          result[i][j] = arr[j][i];
        }
      }
      return result;
    },

    //return identity matrix of dimension n x n
    identity: function(n) {
      var result = new Array(n);
      for (var i = 0 ; i < n ; i++) {
        result[i] = new Array(n);
        for (var j = 0 ; j < n ; j++) {
          result[i][j] = (i === j) ? 1 : 0;
        }
      }
      return result;
    },

    //dot product
    dotproduct: function(vectorA, vectorB) {
      if (vectorA.length === vectorB.length) {
        var result = 0;
        for (var i = 0 ; i < vectorA.length ; i++) {
          result += vectorA[i]*vectorB[i];
        }
        return result;
      } else {
        throw new Error("Vector mismatch");
      }
    },

    //multiply two matrices
    multiply: function(arrA, arrB) {
      if (arrA[0].length === arrB.length) {
        var result = new Array(arrA.length);

        for (var i = 0 ; i < arrA.length ; i++) {
          result[i] = new Array(arrB[0].length);
        }

        var arrB_T = transpose(arrB);

        for (var i = 0 ; i < result.length ; i++) {
          for (var j = 0 ; j < result[i].length ; j++) {
            result[i][j] = dotproduct(arrA[i],arrB_T[j]);
          }
        }
        return result;
      } else {
        throw new Error("Array mismatch");
      }
    },

    //determinant, only for n x n -> 2 and 3
    determinant: function(m) {
      if ((m.length === 2) && (m[0].length === 2)) {
        return m[0][0] * m[1][1] - m[0][1] * m[1][0];
      } else if ((m.length === 3) && (m[0].length === 3)) {
        return m[0][0] * m[1][1] * m[2][2]
          + m[0][1] * m[1][2] * m[2][0]
          + m[0][2] * m[1][0] * m[2][1]
          - m[0][2] * m[1][1] * m[2][0]
          - m[0][1] * m[1][0] * m[2][2]
          - m[0][0] * m[1][2] * m[2][1];
      }
    }
  },

/*-----------------------------------------------------------------------------*/

  //collection of prime associated tools
  prime: {

    //standard prime evaluation (no consideration towards efficiency)
    simple: function(val) {
      if (val == 1) {
        return false;
      } else if (val == 2) {
        return true;
      } else if (val != null) {
        var start = 2;
        var result = true;
        while (start < val) {
          if (val % start === 0) {
            result = false;
            break;
          } else {
            start++;
          }
        }
        return result;
      }
    },

    //determine primality using elliptic curve testing
    elliptic: function() {
      return null;
    }
  },

/*-----------------------------------------------------------------------------*/

  //statistic oriented tools
  statistic: {

    //get mean value of the numbers in an array
    mean: function(arr) {
      var count = arr.length;
      var sum = addition(arr);
      return sum/count;
    },

    //get median value of the numbers in an array
    median: function(arr) {
      var count = arr.length;
      var middle;
      if (count % 2 === 0) {
        return (arr[count/2] + arr[(count/2 - 1)])/2;
      } else {
        return arr[Math.floor(count / 2)];
      }
    },

    //get mode value (most common value) of the numbers in an array
    mode: function(arr) {
      //sort array
      var maxIndex = 0, maxOccurence = 0, tempIndex = 0, tempOccurence = 0;
      arr = arr.sort();
      while (tempIndex < arr.length) {
        for (var j = tempIndex; j < arr.length; j++) {
          if (arr[j] == arr[tempIndex]) {
            tempOccurence++;
          } else {
            break;
          }
        }
        if (tempOccurence > maxOccurence) {
          maxOccurence = tempOccurence;
          maxIndex = tempIndex;
        }

        tempIndex = j;
        tempOccurence = 0;
      }
      return arr[maxIndex];
    },

    //generate a random sample of n-values within lower/upper bounds
    randomSample: function(lower,upper,n) {
      var sample = new Array();
      var temp;
      for (var i = 0 ; i < n ; i++) {
        temp = Math.random()*upper;
        if (temp > lower)
          sample[i] = temp;
      }
      return sample;
    },

    //standard deviation
    standardDev: function(arr) {
      var count = arr.length;
      var mean = mean(arr);
      var squaredArr = new Array();
      for (var i = 0; i < arr.length; i++) {
        squaredArr[i] = Math.pow((arr[i] - mean),2);
      }
      return Math.sqrt((1/count) * addition(squaredArr));
    },

    //correlation of two arrays
    correlation: function(arrX,arrY) {
      if (arrX.length == arrY.length) {
        var numerator = 0;
        var denominator = (arrX.length) * (standardDev(arrX)) * (standardDev(arrY));
        var xMean = mean(arrX);
        var yMean = mean(arrY);
        for (var i = 0 ; i < arrX.length ; i++) {
          numerator += (arrX[i] - xMean) * (arrY[i] - yMean);
        }
        return numerator / denominator;
      } else {
        throw new Error('Array mismatch');
      }
    }
  }
};<|endoftext|>


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

    var path        = require('path'),
        mime        = require('mime'),
        files       = require('files-io'),

        status      = require('taus'),

        OK          = 200,
        MOVED       = [301, 302],
        DIR         = path.normalize(__dirname + '/../'),
        DIR_IMG     = DIR + 'img/',
        EXT         = '.png',
        IMG_OK      = DIR_IMG + 'ok'    + EXT,
        IMG_ERROR   = DIR_IMG + 'error' + EXT,
        IMG_MOVED   = DIR_IMG + 'moved' + EXT,
        TYPE        = mime.lookup(IMG_OK),

        TIME        = 1000;

    module.exports = function(addr, res) {
        var sended;

        setTimeout(function() {
            if (!sended) {
                sended = true;
                sendFile(res, IMG_MOVED);
            }
        }, TIME);

        status(addr, function(error, status) {
            if (!sended) {
                sended = true;

                res.contentType(TYPE);

                if (status === OK)
                    sendFile(res, IMG_OK);
                else if(status === MOVED[0] || status === MOVED[1])
                    sendFile(res, IMG_MOVED);
                else
                    sendFile(res, IMG_ERROR);
            }
        });
    };

    function sendFile(res, name) {
        files.pipe(name, res, function(error) {
            if (error)
                res.send(error.message);
        });
    }
})();
<commit_msg>chore(status-img) rm iife<commit_after>'use strict';

var path        = require('path'),
    mime        = require('mime'),
    files       = require('files-io'),

    status      = require('taus'),

    OK          = 200,
    MOVED       = [301, 302],
    DIR         = path.normalize(__dirname + '/../'),
    DIR_IMG     = DIR + 'img/',
    EXT         = '.png',
    IMG_OK      = DIR_IMG + 'ok'    + EXT,
    IMG_ERROR   = DIR_IMG + 'error' + EXT,
    IMG_MOVED   = DIR_IMG + 'moved' + EXT,
    TYPE        = mime.lookup(IMG_OK),

    TIME        = 1000;

module.exports = function(addr, res) {
    var sended;

    setTimeout(function() {
        if (!sended) {
            sended = true;
            sendFile(res, IMG_MOVED);
        }
    }, TIME);

    status(addr, function(error, status) {
        if (!sended) {
            sended = true;

            res.contentType(TYPE);

            if (status === OK)
                sendFile(res, IMG_OK);
            else if(status === MOVED[0] || status === MOVED[1])
                sendFile(res, IMG_MOVED);
            else
                sendFile(res, IMG_ERROR);
        }
    });
};

function sendFile(res, name) {
    files.pipe(name, res, function(error) {
        if (error)
            res.send(error.message);
    });
}
<|endoftext|>


<commit_before>require(window.APT_OPTIONS.configObject,
	['js/quickvm_sup',
	 'js/lib/text!template/cluster-graphs.html',
	 'js/bilevel', 'js/liquidFillGauge'],
function (sup, clusterString)
{
    'use strict';

    function initialize()
    {
	window.APT_OPTIONS.initialize(sup);

	$('#cluster-graphs').html(clusterString);

	bilevelAsterGraph("/cloudlab-nofed.json",
			  "#status-nofed","auto","large");
	bilevelAsterGraph("/cloudlab-fedonly.json",
			  "#status-fedonly","auto","large");
    }

    $(document).ready(initialize);
});
<commit_msg>Add 30 second refresh.<commit_after>require(window.APT_OPTIONS.configObject,
	['js/quickvm_sup',
	 'js/lib/text!template/cluster-graphs.html',
	 'js/bilevel', 'js/liquidFillGauge'],
function (sup, clusterString)
{
    'use strict';

    function initialize()
    {
	window.APT_OPTIONS.initialize(sup);

	$('#cluster-graphs').html(clusterString);

	bilevelAsterGraph("/cloudlab-nofed.json",
			  "#status-nofed","auto","large");
	bilevelAsterGraph("/cloudlab-fedonly.json",
			  "#status-fedonly","auto","large");

	setTimeout(function f() { Refresh() }, 30000);
    }

    /*
     * Refresh the graphs.
     */
    function Refresh()
    {
	$('#status-fedonly').html("");
	$('#status-nofed').html("");
	$("div").remove(".d3-tip");

	bilevelAsterGraph("/cloudlab-nofed.json",
			  "#status-nofed","auto","large");
	bilevelAsterGraph("/cloudlab-fedonly.json",
			  "#status-fedonly","auto","large");

	setTimeout(function f() { Refresh() }, 30000);
    }

    $(document).ready(initialize);
});
<|endoftext|>


<commit_before>	'use strict';

window.onload = function init (){

		$("#H1C").fadeIn("slow");
		$("#H2C").fadeIn("slow");
		$("#H3C").fadeIn("slow");

		$("#H1PC").fadeOut("slow");
		$("#H2PC").fadeOut("slow");
		$("#H3PC").fadeOut("slow");

		$(".BateauG1").fadeOut("slow");
		$(".BateauP1").fadeOut("slow");
		$(".BateauM1").fadeOut("slow");
		$(".BateauM2").fadeOut("slow");
		$(".BateauP2").fadeOut("slow");
		$(".BateauG2").fadeOut("slow");

		$(".Homard1").fadeIn("slow");
		$(".Homard2").fadeOut("slow");
		$(".Homard3").fadeIn("slow");
		$(".Homard4").fadeOut("slow");

		$(".Merlu1").fadeIn("slow");
		$(".Merlu2").fadeOut("slow");
		$(".Merlu3").fadeIn("slow");
		$(".Merlu4").fadeOut("slow");

		$(".Sole1").fadeIn("slow");
		$(".Sole2").fadeOut("slow");
		$(".Sole3").fadeOut("slow");
		$(".Sole4").fadeIn("slow");

		$(".Touriste1").fadeOut("slow");
		$(".Touriste2").fadeOut("slow");
		$(".Touriste3").fadeOut("slow");
		$(".Touriste4").fadeOut("slow");

		$(".Agriculteur").fadeOut("slow");
		$(".PORC").fadeOut("slow");
		//caca
		$(".").fadeOut("slow");

		$(".Scientifique").fadeOut("slow");
		$(".LogoScientifique1").fadeOut("slow");
		$(".LogoScientifique2").fadeOut("slow");
		$(".LogoScientifique3").fadeOut("slow");
		$(".LogoScientifique4").fadeOut("slow");
		$(".LogoScientifique5").fadeOut("slow");

		$(".Monstre4").fadeIn("slow");
		$(".Monstre3").fadeOut("slow");
		$(".Monstre2").fadeOut("slow");
		$(".Monstre1").fadeOut("slow");
		document.getElementById("Budget").value = 200000-document.getElementById("barreJ4-1").value*80000+document.getElementById("barreJ4-2").value*50000;
	}<commit_msg>Avancement onlaod J3<commit_after>	'use strict';

window.onload = function init (){

		$("#H1C").fadeIn("slow");
		$("#H2C").fadeIn("slow");
		$("#H3C").fadeIn("slow");

		$("#H1PC").fadeOut("slow");
		$("#H2PC").fadeOut("slow");
		$("#H3PC").fadeOut("slow");

		$(".BateauG1").fadeOut("slow");
		$(".BateauP1").fadeOut("slow");
		$(".BateauM1").fadeOut("slow");
		$(".BateauM2").fadeOut("slow");
		$(".BateauP2").fadeOut("slow");
		$(".BateauG2").fadeOut("slow");

		$(".Homard1").fadeIn("slow");
		$(".Homard2").fadeOut("slow");
		$(".Homard3").fadeIn("slow");
		$(".Homard4").fadeOut("slow");

		$(".Merlu1").fadeIn("slow");
		$(".Merlu2").fadeOut("slow");
		$(".Merlu3").fadeIn("slow");
		$(".Merlu4").fadeOut("slow");

		$(".Sole1").fadeIn("slow");
		$(".Sole2").fadeOut("slow");
		$(".Sole3").fadeOut("slow");
		$(".Sole4").fadeIn("slow");

		$(".Touriste1").fadeOut("slow");
		$(".Touriste2").fadeOut("slow");
		$(".Touriste3").fadeOut("slow");
		$(".Touriste4").fadeOut("slow");

		$(".Agriculteur").fadeOut("slow");
		$(".PORC").fadeOut("slow");
		//caca
		$(".").fadeOut("slow");

		$(".Scientifique").fadeOut("slow");
		//Scientifique victoire
		$(".").fadeOut("slow");

		$(".LogoScientifique1").fadeOut("slow");
		$(".LogoScientifique2").fadeOut("slow");
		$(".LogoScientifique3").fadeOut("slow");
		$(".LogoScientifique4").fadeOut("slow");
		$(".LogoScientifique5").fadeOut("slow");

		$(".Monstre4").fadeIn("slow");
		$(".Monstre3").fadeOut("slow");
		$(".Monstre2").fadeOut("slow");
		$(".Monstre1").fadeOut("slow");

		document.getElementById("Budget").value = 200000-document.getElementById("barreJ4-1").value*80000+document.getElementById("barreJ4-2").value*50000;
	}<|endoftext|>


<commit_before>// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

angular.module('mm.core')
/**
 * Common synchronization service.
 *
 * @module mm.core
 * @ngdoc service
 * @name $mmWsRequestSync
 */
.factory('$mmWsRequestSync', function($q, $log, $mmSitesFactory, $mmSitesManager, $mmSite, $mmSync, $mmWsRequestOffline) {
    var self = $mmSync.createChild(mmaModWikiComponent, mmaModWikiSyncTime);
    $log = $log.getInstance('$mmWsRequestSync');

    self.syncRequest = function(request){
        var retrying = true;
        console.log("Syncing request: "+JSON.stringify(request));
        return $mmSitesFactory.request(request.method, request.data, request.preSets, retrying);
    }

    self.syncRequests = function(){
        if (!$mmApp.isOnline()) {
            $log.debug('Cannot sync all requests because device is offline.');
            return $q.reject();
        }
        console.log("Syncing requests");
        var promise = $mmSitesManager.getSitesIds();
        return promise.then(function(siteIds) {
            var sitePromises = [];
            angular.forEach(siteIds, function(siteId) {
                if($mmWsRequestOffline.hasSavedRequests(siteId)){
                    sitePromises.push($mmWsRequestOffline.getRequests(siteId).then(function(requests) {
                        angular.forEach(requests, function(request) {
                            self.syncRequest(request).then(function(response) {
                                if(!!response.status){
                                    $mmWsRequestOffline.deleteRequest(request.id).then(function(result){
                                        console.log("Deleted request with ID "+requestId + " Result: "+JSON.stringify(result));
                                    })
                                } else {
                                    console.log("Something went wrong syncing request. Response: "+JSON.stringify(response));
                                }
                            });
                        });

                    }));
                } else {
                    console.log("Site has no requests to sync");
                }
            });
            return $q.all(sitePromises);
        });
    }

    self.syncHandler = function() {

        var handlerself = {};
        handlerself.execute = function(siteId) {
            return self.syncRequests();
        };
        handlerself.getInterval = function() {
            return 300000; // 5 minutes.
        };
        handlerself.isSync = function() {
            return true;
        };
        handlerself.usesNetwork = function() {
            return true;
        };

        return handlerself;
    };

    return self;
});
<commit_msg>fix wrong assignments<commit_after>// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

angular.module('mm.core')
/**
 * Common synchronization service.
 *
 * @module mm.core
 * @ngdoc service
 * @name $mmWsRequestSync
 */
.factory('$mmWsRequestSync', function($q, $log, $mmSitesFactory, $mmSitesManager, $mmSite, $mmSync, $mmWsRequestOffline) {
    var self = $mmSync.createChild('mm.core', 300000);
    $log = $log.getInstance('$mmWsRequestSync');

    self.syncRequest = function(request){
        var retrying = true;
        console.log("Syncing request: "+JSON.stringify(request));
        return $mmSitesFactory.request(request.method, request.data, request.preSets, retrying);
    }

    self.syncRequests = function(){
        if (!$mmApp.isOnline()) {
            $log.debug('Cannot sync all requests because device is offline.');
            return $q.reject();
        }
        console.log("Syncing requests");
        var promise = $mmSitesManager.getSitesIds();
        return promise.then(function(siteIds) {
            var sitePromises = [];
            angular.forEach(siteIds, function(siteId) {
                if($mmWsRequestOffline.hasSavedRequests(siteId)){
                    sitePromises.push($mmWsRequestOffline.getRequests(siteId).then(function(requests) {
                        angular.forEach(requests, function(request) {
                            self.syncRequest(request).then(function(response) {
                                if(!!response.status){
                                    $mmWsRequestOffline.deleteRequest(request.id).then(function(result){
                                        console.log("Deleted request with ID "+requestId + " Result: "+JSON.stringify(result));
                                    })
                                } else {
                                    console.log("Something went wrong syncing request. Response: "+JSON.stringify(response));
                                }
                            });
                        });

                    }));
                } else {
                    console.log("Site has no requests to sync");
                }
            });
            return $q.all(sitePromises);
        });
    }

    self.syncHandler = function() {

        var handlerself = {};
        handlerself.execute = function(siteId) {
            return self.syncRequests();
        };
        handlerself.getInterval = function() {
            return 300000; // 5 minutes.
        };
        handlerself.isSync = function() {
            return true;
        };
        handlerself.usesNetwork = function() {
            return true;
        };

        return handlerself;
    };

    return self;
});
<|endoftext|>


<commit_before>/*jslint node: true */
/*global console */
"use strict";

// ================================================================
//                    Helpers
// ================================================================

var SPACES          = /\ +/g;
var ALL_UNDERSCORES =/_/g;
var STACK_ABLES     = [String, Boolean, Number];
var quote           = function (str) { return '"' + str + '"'; };
var standard_key    = function (s) { return trim(s).toUpperCase(); };
var trim            = function (str) {
  if (str.trim) {
    return str.trim();
  }
  return String(str).replace(new RegExp('^\\s+|\\s+$', 'g'), '');
};

var is_string         = function (s) { return typeof s === 'string'; };
var is_function       = function (o) { return o && o.constructor === Function; };
var is_empty          = function (arr) { return arr.length ===  0; };
var is_array          = function (o) { return o && o.constructor === Array; };
var is_object         = function (o) { return o && is_array(o.IS) && o.constructor === Object; };
var is_applet_object  = function (o) { return is_object(o) && is_array(o.IS); };
var last              = function (arr) { return arr[arr.length-1]; };

var is_applet_command = function (val) {
  return is_applet_object(val) && is_included(val.IS, "APPLET COMMAND");
};

var is_stack_able = function (o) {
  if (o && is_included(STACK_ABLES, o.constructor)) {
    return true;
  }

  if (is_applet_object(o) && !is_applet_command(o)) {
    return true;
  }
  return false;

};

var is_included       = function (arr, val) {
  var curr  = 0;
  var stop  = arr.length;

  while (curr < stop) {
    if (arr[curr] === val) {
      return true;
    }
    curr = curr + 1;
  }
  return false;
};

var for_each = function (arr, func) {

  for (var i = 0; i < arr.length; i++) {

    var props = {
      is_start : i===0,
      is_end   : i===(arr.length-1),
      next_ele : arr[i+1]
    };

    func(arr[i], i, props);
  }

  return arr;
};

var puts = function () {
  if (typeof console === "undefined") {
    for_each(arguments, function (o) {
      puts.output.push(o);
    });
  } else {
    console.log.apply(console, arguments);
  }
};

puts.output = [];

// ================================================================
//                    Define Container
// ================================================================

//
// Possible:
//
//   new                         "[..JSON..]"
//   new            "__main__",  "[..JSON..] "
//   new                          [...tokens...]
//   new            "__main__",   [...tokens...]
//   new   applet , "my func" ,   [...tokens...]
//   new   applet , "my func" ,   [...tokens...], [..args..]
//
var WWW_Applet = function () {

  this.parent     = null;
  this.name       = null;
  this.tokens     = [];
  this.args       = [];
  this.computers  = {};
  this.values     = {};
  this.stack      = [];
  this.is_fork    = false;
  this.is_done    = false;
  this.is_running = false;

  switch (arguments.length) {

    case 1:
      this.tokens = arguments[0];
    break;

    case 2:
      this.name   = arguments[0];
      this.tokens = arguments[1];
      break;

    case 3:
      this.parent = arguments[0];
      this.name   = arguments[1];
      this.tokens = arguments[2];
      break;

    case 4:
      this.parent = arguments[0];
      this.name   = arguments[1];
      this.tokens = arguments[2];
      this.args   = arguments[3];
      break;

    default:
      if (arguments.length === 0) {
        throw "At least one argument required.";
      }
      throw "Too many extra arguments: " + JSON.encode(arguments);
  } // switch

  if (!this.name) {
    this.name = "[UNKNOWN]";
  }

  if (!is_array(this.args)) {
    throw "Invalid value: for args: " + JSON.encode(this.args);
  }

  if (is_string(this.tokens)) {
    this.tokens = JSON.parse(this.tokens);
  }

  if (!is_array(this.tokens)) {
    throw "Invalid: JS object must be an array";
  }

  if (!this.parent) {
    this.extend(WWW_Applet.Computers);
  }

  return this;
};

WWW_Applet.STOP_APPLET       = {"IS":  ["APPLET COMMAND"], "VALUE": "STOP APPLET" };
WWW_Applet.IGNORE_RETURN     = {"IS": "APPLET COMMAND", "VALUE": "IGNORE RETURN"};

WWW_Applet.prototype.extend = function (o) {
  for (var raw_name in o) {
    if (o.hasOwnProperty(raw_name)) {
      var name = standard_key(raw_name);
      this[name] = o[raw_name];
      this.computers[name.replace(ALL_UNDERSCORES, " ")] = [name];
    }
  }
  return this;
};

WWW_Applet.prototype.is_fork = function (answer) {
  if (arguments.length > 0) {
    this.is_fork = answer;
  }
  return this.is_fork;
};

WWW_Applet.prototype.fork_and_run = function (name, tokens) {
  var c = new WWW_Applet(this, name, tokens);
  c.is_fork(true);
  c.run();
  return c;
};

WWW_Applet.prototype.top = function () {
  var p = this.parent;
  var curr = p;
  while (curr) {
    curr = p.parent;
    if (curr) {
      p = curr;
    }
  }

  return p || this;
};

WWW_Applet.prototype.run = function () {

  if (this.is_running) {
    throw "Invalid state: Already running.";
  }

  this.is_running = true;

  if (this.is_done) {
    throw "Invalid state: Already finished running.";
  }

  var stop     = this.tokens.length;
  var curr     = 0;

  while (curr < stop && !this.is_done) {

    var val      = this.tokens[curr];
    if (is_array(val)) {
      throw "Invalid syntax: Computer name not specified: " + JSON.encode(val);
    }
    var next_val    = this.tokens[curr + 1];
    var is_end      = (curr + 1) === stop;
    var should_send = is_array(next_val);

    curr = curr + 1;

    if (is_end || !should_send) {
      if (!is_stack_able(val)) {
        throw "Invalid value: " + JSON.encode(val);
      }
      this.stack.push(val);
      continue;
    }

    // ===================================================
    // SEND TO COMPUTER
    // ===================================================
    curr = curr + 1; // move past the tokens array
    var from                = this;
    var to                  = standard_key(val);
    var raw_args            = next_val;
    var should_compile_args = (to !== standard_key("IS A COMPUTER"));
    var args                = null;
    var resp                = null;
    var box                 = this;
    var found               = null;
    var c                   = null;
    var computers           = null;
    var computers_box       = null;

    if (should_compile_args) {
      args = from.fork_and_run("arg run for " + JSON.encode(to), raw_args).stack;
    } else {
      args = raw_args;
    }

    // === Find the computer. ============================
    // === Send to computer. =============================
    // === Re-send to next computer if requested. ========
    // === Process final result. =========================
    while (box && !found) { // === computer as box with array of computers

      computers     = box.computers[to];
      computers_box = box;

      box = box.parent;
      if (!computers) {
        continue;
      }

      for ( var i_computer = 0; !found && i_computer < computers.length; ++i_computer) {

        c = computers[i_computer];
        if (is_function(c)) {
          resp = c(from, to, args);
        } else {
          resp = computers_box[c](from, to, args);
        }

        if (is_stack_able(resp)) { // === push value to stack
          this.stack.push(resp);
          found = true;

        } else { // === run applet command

          switch (resp.VALUE) {

            case "STOP APPLET":
              this.is_done = true;
            found = true;
            break;

            case "IGNORE RETURN": // don't put anything on the stack
              found = true;
            break;

            case "CONTINUE":
              found = false;
            break;

            default:
              throw("Invalid: Unknown operation: " + JSON.encode(resp.VALUE) );

          } // === switch

        } // === if/else

      } // === for
    } // === while box && !found

    if (!found) {
      throw "Computer not found: " + JSON.encode(val);
    }

    // ===================================================
    // END OF SEND TO COMPUTER
    // ===================================================

  } // === while

  this.is_done = true;
  return this;
};

// ================================================================
//                    Computers
// ================================================================

WWW_Applet.Computers = {

  "get" : function (raw_name) {
    return this.values[WWW_Applet.standard_key(raw_name)];
  },

  "is": function (raw_name, v) {
    var name = WWW_Applet.standard_key(raw_name);
    if (this.hasOwnProperty(name)) {
      throw new WWW_Applet.Value_Already_Created(name);
    }
    this.values[name] = v;
    return v;
  },

  "is a computer" : function (raw_name, f) {
    var name = WWW_Applet.standard_key(raw_name);
    if (!this.computers[name]) {
      this.computers[name] = [];
    }
    this.computers[name].push(f);

    return f;
  }

}; // === Computers

exports.WWW_Applet = WWW_Applet;

<commit_msg>Fixed: errors are thrown instead of strings.<commit_after>/*jslint node: true */
/*global console */
"use strict";

// ================================================================
//                    Helpers
// ================================================================

var SPACES          = /\ +/g;
var ALL_UNDERSCORES =/_/g;
var STACK_ABLES     = [String, Boolean, Number];
var quote           = function (str) { return '"' + str + '"'; };
var standard_key    = function (s) { return trim(s).toUpperCase(); };
var trim            = function (str) {
  if (str.trim) {
    return str.trim();
  }
  return String(str).replace(new RegExp('^\\s+|\\s+$', 'g'), '');
};

var inspect           = function (o) { return JSON.stringify(o); };
var is_string         = function (s) { return typeof s === 'string'; };
var is_function       = function (o) { return o && o.constructor === Function; };
var is_empty          = function (arr) { return arr.length ===  0; };
var is_array          = function (o) { return o && o.constructor === Array; };
var is_object         = function (o) { return o && is_array(o.IS) && o.constructor === Object; };
var is_applet_object  = function (o) { return is_object(o) && is_array(o.IS); };
var last              = function (arr) { return arr[arr.length-1]; };

var is_applet_command = function (val) {
  return is_applet_object(val) && is_included(val.IS, "APPLET COMMAND");
};

var is_stack_able = function (o) {
  if (o && is_included(STACK_ABLES, o.constructor)) {
    return true;
  }

  if (is_applet_object(o) && !is_applet_command(o)) {
    return true;
  }

  return false;
};

var is_included       = function (arr, val) {
  var curr  = 0;
  var stop  = arr.length;

  while (curr < stop) {
    if (arr[curr] === val) {
      return true;
    }
    curr = curr + 1;
  }
  return false;
};

var for_each = function (arr, func) {

  for (var i = 0; i < arr.length; i++) {

    var props = {
      is_start : i===0,
      is_end   : i===(arr.length-1),
      next_ele : arr[i+1]
    };

    func(arr[i], i, props);
  }

  return arr;
};

var puts = function () {
  if (typeof console === "undefined") {
    for_each(arguments, function (o) {
      puts.output.push(o);
    });
  } else {
    console.log.apply(console, arguments);
  }
};

puts.output = [];

// ================================================================
//                    Define Container
// ================================================================

//
// Possible:
//
//   new                         "[..JSON..]"
//   new            "__main__",  "[..JSON..] "
//   new                          [...tokens...]
//   new            "__main__",   [...tokens...]
//   new   applet , "my func" ,   [...tokens...]
//   new   applet , "my func" ,   [...tokens...], [..args..]
//
var WWW_Applet = function () {

  this.parent     = null;
  this.name       = null;
  this.tokens     = [];
  this.args       = [];
  this.computers  = {};
  this.values     = {};
  this.stack      = [];
  this.is_fork    = false;
  this.is_done    = false;
  this.is_running = false;

  switch (arguments.length) {

    case 1:
      this.tokens = arguments[0];
    break;

    case 2:
      this.name   = arguments[0];
      this.tokens = arguments[1];
      break;

    case 3:
      this.parent = arguments[0];
      this.name   = arguments[1];
      this.tokens = arguments[2];
      break;

    case 4:
      this.parent = arguments[0];
      this.name   = arguments[1];
      this.tokens = arguments[2];
      this.args   = arguments[3];
      break;

    default:
      if (arguments.length === 0) {
        throw new Error("At least one argument required.");
      }
      throw new Error("Too many extra arguments: " + inspect(arguments));
  } // switch

  if (!this.name) {
    this.name = "[UNKNOWN]";
  }

  if (!is_array(this.args)) {
    throw new Error("Invalid value: for args: " + inspect(this.args));
  }

  if (is_string(this.tokens)) {
    this.tokens = JSON.parse(this.tokens);
  }

  if (!is_array(this.tokens)) {
    throw new Error("Invalid: JS object must be an array");
  }

  if (!this.parent) {
    this.extend(WWW_Applet.Computers);
  }

  return this;
};

WWW_Applet.STOP_APPLET       = {"IS":  ["APPLET COMMAND"], "VALUE": "STOP APPLET" };
WWW_Applet.IGNORE_RETURN     = {"IS": "APPLET COMMAND", "VALUE": "IGNORE RETURN"};

WWW_Applet.prototype.extend = function (o) {
  for (var raw_name in o) {
    if (o.hasOwnProperty(raw_name)) {
      var name = standard_key(raw_name);
      this[name] = o[raw_name];
      this.computers[name.replace(ALL_UNDERSCORES, " ")] = [name];
    }
  }
  return this;
};

WWW_Applet.prototype.fork_and_run = function (name, tokens) {
  var c = new WWW_Applet(this, name, tokens);
  c.is_fork = true;
  c.run();
  return c;
};

WWW_Applet.prototype.top = function () {
  var p = this.parent;
  var curr = p;
  while (curr) {
    curr = p.parent;
    if (curr) {
      p = curr;
    }
  }

  return p || this;
};

WWW_Applet.prototype.run = function () {

  if (this.is_running) {
    throw new Error("Invalid state: Already running.");
  }

  this.is_running = true;

  if (this.is_done) {
    throw new Error("Invalid state: Already finished running.");
  }

  var stop     = this.tokens.length;
  var curr     = 0;

  while (curr < stop && !this.is_done) {

    var val      = this.tokens[curr];
    if (is_array(val)) {
      throw new Error("Invalid syntax: Computer name not specified: " + inspect(val));
    }
    var next_val    = this.tokens[curr + 1];
    var is_end      = (curr + 1) === stop;
    var should_send = is_array(next_val);

    curr = curr + 1;

    if (is_end || !should_send) {
      if (!is_stack_able(val)) {
        throw new Error("Invalid value: " + inspect(val));
      }
      this.stack.push(val);
      continue;
    }

    // ===================================================
    // SEND TO COMPUTER
    // ===================================================
    curr = curr + 1; // move past the tokens array
    var from                = this;
    var to                  = standard_key(val);
    var raw_args            = next_val;
    var should_compile_args = (to !== standard_key("IS A COMPUTER"));
    var args                = null;
    var resp                = null;
    var box                 = this;
    var found               = null;
    var c                   = null;
    var computers           = null;
    var computers_box       = null;

    if (should_compile_args) {
      args = from.fork_and_run("arg run for " + inspect(to), raw_args).stack;
    } else {
      args = raw_args;
    }

    // === Find the computer. ============================
    // === Send to computer. =============================
    // === Re-send to next computer if requested. ========
    // === Process final result. =========================
    while (box && !found) { // === computer as box with array of computers

      computers     = box.computers[to];
      computers_box = box;

      box = box.parent;
      if (!computers) {
        continue;
      }

      for ( var i_computer = 0; !found && i_computer < computers.length; ++i_computer) {

        c = computers[i_computer];
        if (is_function(c)) {
          resp = c(from, to, args);
        } else {
          resp = computers_box[c](from, to, args);
        }

        if (is_stack_able(resp)) { // === push value to stack
          this.stack.push(resp);
          found = true;

        } else { // === run applet command

          console.log(to, args, resp)
          switch (resp.VALUE) {

            case "STOP APPLET":
              this.is_done = true;
            found = true;
            break;

            case "IGNORE RETURN": // don't put anything on the stack
              found = true;
            break;

            case "CONTINUE":
              found = false;
            break;

            default:
              throw new Error("Invalid: Unknown operation: " + inspect(resp.VALUE) );

          } // === switch

        } // === if/else

      } // === for
    } // === while box && !found

    if (!found) {
      throw new Error("Computer not found: " + inspect(val));
    }

    // ===================================================
    // END OF SEND TO COMPUTER
    // ===================================================

  } // === while

  this.is_done = true;
  return this;
};

// ================================================================
//                    Computers
// ================================================================

WWW_Applet.Computers = {

  "get" : function (sender, to, args) {
    return this.values[standard_key(to)];
  },

  "is": function (sender, to, args) {
    var name = standard_key(last(sender.stack));
    if (this.hasOwnProperty(name)) {
      throw new Error("Value already created: " + inspect(name));
    }
    this.values[name] = last(args);
    return last(args);
  },

  "is a computer" : function (sender, to, tokens) {
    var name = standard_key(last(sender.stack));
    if (!this.computers[name]) {
      this.computers[name] = [];
    }
    this.computers[name].push(tokens);

    return {"IS": ["COMPUTER"], "VALUE": name};
  }

}; // === Computers

exports.WWW_Applet = WWW_Applet;

<|endoftext|>