<commit_before>import { push } from 'react-router-redux';
import {
  mapValues,
  merge,
  omit,
  omitBy,
  isNil,
  forEach,
  zipObject,
  pickBy,
  size,
} from 'lodash';

import { DEACTIVATE_SIDEBAR_EDIT } from 'store/actions/sidebar-edit.actions';
import { releaseSyncLock } from 'store/actions/sector.actions';
import {
  configurationSelector,
  currentSectorSelector,
  currentEntitySelector,
  currentEntityTypeSelector,
  entitySelector,
  sidebarEditSelector,
  holdKeySelector,
  hoverKeySelector,
  syncLockSelector,
} from 'store/selectors/base.selectors';
import {
  getCurrentTopLevelEntities,
  getCurrentEntityType,
  getCurrentEntityId,
  getCurrentEntity,
} from 'store/selectors/entity.selectors';

import {
  generateEntity as generateEntityUtil,
  deleteEntity as deleteEntityUtil,
  getTopLevelEntity,
} from 'utils/entity';
import { coordinatesFromKey } from 'utils/common';
import { saveEntities, deleteEntities } from 'store/api/shared';
import Entities from 'constants/entities';

export const UPDATE_ENTITIES = 'UPDATE_ENTITIES';
export const DELETE_ENTITIES = 'DELETE_ENTITIES';
export const SAVE_SECTOR = 'SAVE_SECTOR';
export const UPDATE_ID_MAPPING = 'UPDATE_ID_MAPPING';

const updateHandler = (state, dispatch) => ({ action, mapping }) => {
  const dispatches = [dispatch(releaseSyncLock())];
  if (action) {
    dispatches.push(dispatch(action));
  }
  if (!mapping) {
    return Promise.all(dispatches);
  }
  const currentEntity = currentEntitySelector(state);
  const currentEntityType = currentEntityTypeSelector(state);
  const entityUrl = currentEntity
    ? `/${currentEntityType}/${mapping[currentEntity] || currentEntity}`
    : '';
  return Promise.all([
    ...dispatches,
    dispatch({ type: UPDATE_ID_MAPPING, mapping }),
  ]).then(() => {
    const currentSector = currentSectorSelector(state);
    return dispatch(
      push(`/sector/${mapping[currentSector] || currentSector}${entityUrl}`),
    );
  });
};

export const generateEntity = (entity, parameters) => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const entities = generateEntityUtil({
    entity,
    currentSector: currentSectorSelector(state),
    configuration: configurationSelector(state),
    parameters,
  });
  dispatch({
    type: UPDATE_ENTITIES,
    entities,
  });

  const existingSector = state.entity.sector[state.sector.currentSector];
  const newSectorKeys = Object.keys(entities.sector || {});
  if (
    (!state.sector.currentSector || !existingSector) &&
    newSectorKeys.length
  ) {
    dispatch(push(`/sector/${newSectorKeys[0]}`));
  }

  if (entity.entityType !== Entities.sector.key) {
    return saveEntities({ state, created: entities, entities }).then(
      updateHandler(state, dispatch),
    );
  }
  return dispatch(releaseSyncLock());
};

export const moveTopLevelEntity = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const topLevelEntities = getCurrentTopLevelEntities(state);
  const holdEntity = getTopLevelEntity(
    topLevelEntities,
    holdKeySelector(state),
  );
  const hoverKey = hoverKeySelector(state);
  const hoverEntity = getTopLevelEntity(topLevelEntities, hoverKey);
  const holdUpdate = { ...holdEntity.entity, ...coordinatesFromKey(hoverKey) };
  let entities = {
    [holdEntity.entityType]: {
      [holdEntity.entityId]: omit(holdUpdate, ['numChildren', 'type']),
    },
  };
  if (hoverEntity.entity) {
    const hoverUpdate = {
      ...omit(hoverEntity.entity, ['numChildren', 'type']),
      x: holdEntity.entity.x,
      y: holdEntity.entity.y,
    };
    entities = {
      ...entities,
      [hoverEntity.entityType]: {
        ...(entities[hoverEntity.entityType] || {}),
        [hoverEntity.entityId]: hoverUpdate,
      },
    };
  }
  dispatch({ type: UPDATE_ENTITIES, entities });
  return saveEntities({ state, updated: entities, entities }).then(
    updateHandler(state, dispatch),
  );
};

export const deleteEntity = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const entity = getCurrentEntity(state);
  const currentSector = currentSectorSelector(state);
  if (!entity.parent) {
    dispatch(push('/'));
  } else if (entity.parent === currentSector) {
    dispatch(push(`/sector/${entity.parent}`));
  } else {
    dispatch(
      push(`/sector/${currentSector}/${entity.parentEntity}/${entity.parent}`),
    );
  }
  const deleted = deleteEntityUtil({
    entityType: getCurrentEntityType(state),
    entityId: getCurrentEntityId(state),
    entities: entitySelector(state),
  });
  dispatch({
    type: DELETE_ENTITIES,
    entities: deleted,
  });
  return deleteEntities({ state, deleted }).then(
    updateHandler(state, dispatch),
  );
};

export const saveSector = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  dispatch({ type: SAVE_SECTOR });
  return saveEntities({ state }).then(updateHandler(state, dispatch));
};

export const saveEntityEdit = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const currentEntityType = getCurrentEntityType(state);
  const currentEntityId = getCurrentEntityId(state);
  const { entity, children } = sidebarEditSelector(state);

  let createdEntities = {};
  const deletedEntities = {};
  let updatedEntities = mapValues(children, (entities, thisEntityType) =>
    omitBy(
      mapValues(
        entities,
        ({ isCreated, isDeleted, isUpdated, ...thisEntity }, thisEntityId) => {
          if (isCreated) {
            createdEntities = merge(
              createdEntities,
              generateEntityUtil({
                entity: { entityType: thisEntityType },
                currentSector: currentSectorSelector(state),
                configuration: configurationSelector(state),
                parameters: {
                  ...thisEntity,
                  parentEntity: currentEntityType,
                  parent: currentEntityId,
                },
              }),
            );
          } else if (isDeleted) {
            forEach(
              deleteEntityUtil({
                entityType: thisEntityType,
                entityId: thisEntityId,
                entities: entitySelector(state),
              }),
              (entityIdArray, deletedType) => {
                deletedEntities[deletedType] = [
                  ...(deletedEntities[deletedType] || []),
                  ...entityIdArray,
                ];
              },
            );
          }
          return isDeleted || isCreated || !isUpdated ? undefined : thisEntity;
        },
      ),
      isNil,
    ),
  );

  if (entity.isUpdated) {
    updatedEntities = merge(updatedEntities, {
      [currentEntityType]: { [currentEntityId]: entity },
    });
  }

  let allEntities = {
    ...updatedEntities,
    ...mapValues(createdEntities, (entityList, entityType) => ({
      ...entityList,
      ...(updatedEntities[entityType] || {}),
    })),
  };
  allEntities = merge(
    allEntities,
    mapValues(deletedEntities, deletedIds =>
      zipObject(deletedIds, deletedIds.map(() => null)),
    ),
  );

  const filteredUpdatedEntities = pickBy(allEntities, size);
  if (size(filteredUpdatedEntities)) {
    dispatch({
      type: UPDATE_ENTITIES,
      entities: filteredUpdatedEntities,
    });
    return saveEntities({
      state,
      entities: filteredUpdatedEntities,
      updated: updatedEntities,
      created: createdEntities,
      deleted: deletedEntities,
    }).then(updateHandler(state, dispatch));
  }
  return Promise.all([
    dispatch({ type: DEACTIVATE_SIDEBAR_EDIT }),
    dispatch(releaseSyncLock()),
  ]);
};
<commit_msg>When updating the current entity merge with existing state<commit_after>import { push } from 'react-router-redux';
import {
  mapValues,
  merge,
  omit,
  omitBy,
  isNil,
  forEach,
  zipObject,
  pickBy,
  size,
} from 'lodash';

import { DEACTIVATE_SIDEBAR_EDIT } from 'store/actions/sidebar-edit.actions';
import { releaseSyncLock } from 'store/actions/sector.actions';
import {
  configurationSelector,
  currentSectorSelector,
  currentEntitySelector,
  currentEntityTypeSelector,
  entitySelector,
  sidebarEditSelector,
  holdKeySelector,
  hoverKeySelector,
  syncLockSelector,
} from 'store/selectors/base.selectors';
import {
  getCurrentTopLevelEntities,
  getCurrentEntityType,
  getCurrentEntityId,
  getCurrentEntity,
} from 'store/selectors/entity.selectors';

import {
  generateEntity as generateEntityUtil,
  deleteEntity as deleteEntityUtil,
  getTopLevelEntity,
} from 'utils/entity';
import { coordinatesFromKey } from 'utils/common';
import { saveEntities, deleteEntities } from 'store/api/shared';
import Entities from 'constants/entities';

export const UPDATE_ENTITIES = 'UPDATE_ENTITIES';
export const DELETE_ENTITIES = 'DELETE_ENTITIES';
export const SAVE_SECTOR = 'SAVE_SECTOR';
export const UPDATE_ID_MAPPING = 'UPDATE_ID_MAPPING';

const updateHandler = (state, dispatch) => ({ action, mapping }) => {
  const dispatches = [dispatch(releaseSyncLock())];
  if (action) {
    dispatches.push(dispatch(action));
  }
  if (!mapping) {
    return Promise.all(dispatches);
  }
  const currentEntity = currentEntitySelector(state);
  const currentEntityType = currentEntityTypeSelector(state);
  const entityUrl = currentEntity
    ? `/${currentEntityType}/${mapping[currentEntity] || currentEntity}`
    : '';
  return Promise.all([
    ...dispatches,
    dispatch({ type: UPDATE_ID_MAPPING, mapping }),
  ]).then(() => {
    const currentSector = currentSectorSelector(state);
    return dispatch(
      push(`/sector/${mapping[currentSector] || currentSector}${entityUrl}`),
    );
  });
};

export const generateEntity = (entity, parameters) => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const entities = generateEntityUtil({
    entity,
    currentSector: currentSectorSelector(state),
    configuration: configurationSelector(state),
    parameters,
  });
  dispatch({
    type: UPDATE_ENTITIES,
    entities,
  });

  const existingSector = state.entity.sector[state.sector.currentSector];
  const newSectorKeys = Object.keys(entities.sector || {});
  if (
    (!state.sector.currentSector || !existingSector) &&
    newSectorKeys.length
  ) {
    dispatch(push(`/sector/${newSectorKeys[0]}`));
  }

  if (entity.entityType !== Entities.sector.key) {
    return saveEntities({ state, created: entities, entities }).then(
      updateHandler(state, dispatch),
    );
  }
  return dispatch(releaseSyncLock());
};

export const moveTopLevelEntity = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const topLevelEntities = getCurrentTopLevelEntities(state);
  const holdEntity = getTopLevelEntity(
    topLevelEntities,
    holdKeySelector(state),
  );
  const hoverKey = hoverKeySelector(state);
  const hoverEntity = getTopLevelEntity(topLevelEntities, hoverKey);
  const holdUpdate = { ...holdEntity.entity, ...coordinatesFromKey(hoverKey) };
  let entities = {
    [holdEntity.entityType]: {
      [holdEntity.entityId]: omit(holdUpdate, ['numChildren', 'type']),
    },
  };
  if (hoverEntity.entity) {
    const hoverUpdate = {
      ...omit(hoverEntity.entity, ['numChildren', 'type']),
      x: holdEntity.entity.x,
      y: holdEntity.entity.y,
    };
    entities = {
      ...entities,
      [hoverEntity.entityType]: {
        ...(entities[hoverEntity.entityType] || {}),
        [hoverEntity.entityId]: hoverUpdate,
      },
    };
  }
  dispatch({ type: UPDATE_ENTITIES, entities });
  return saveEntities({ state, updated: entities, entities }).then(
    updateHandler(state, dispatch),
  );
};

export const deleteEntity = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const entity = getCurrentEntity(state);
  const currentSector = currentSectorSelector(state);
  if (!entity.parent) {
    dispatch(push('/'));
  } else if (entity.parent === currentSector) {
    dispatch(push(`/sector/${entity.parent}`));
  } else {
    dispatch(
      push(`/sector/${currentSector}/${entity.parentEntity}/${entity.parent}`),
    );
  }
  const deleted = deleteEntityUtil({
    entityType: getCurrentEntityType(state),
    entityId: getCurrentEntityId(state),
    entities: entitySelector(state),
  });
  dispatch({
    type: DELETE_ENTITIES,
    entities: deleted,
  });
  return deleteEntities({ state, deleted }).then(
    updateHandler(state, dispatch),
  );
};

export const saveSector = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  dispatch({ type: SAVE_SECTOR });
  return saveEntities({ state }).then(updateHandler(state, dispatch));
};

export const saveEntityEdit = () => (dispatch, getState) => {
  const state = getState();
  if (syncLockSelector(state)) {
    return Promise.resolve();
  }
  const currentEntityType = getCurrentEntityType(state);
  const currentEntityId = getCurrentEntityId(state);
  const { entity, children } = sidebarEditSelector(state);

  let createdEntities = {};
  const deletedEntities = {};
  let updatedEntities = mapValues(children, (entities, thisEntityType) =>
    omitBy(
      mapValues(
        entities,
        ({ isCreated, isDeleted, isUpdated, ...thisEntity }, thisEntityId) => {
          if (isCreated) {
            createdEntities = merge(
              createdEntities,
              generateEntityUtil({
                entity: { entityType: thisEntityType },
                currentSector: currentSectorSelector(state),
                configuration: configurationSelector(state),
                parameters: {
                  ...thisEntity,
                  parentEntity: currentEntityType,
                  parent: currentEntityId,
                },
              }),
            );
          } else if (isDeleted) {
            forEach(
              deleteEntityUtil({
                entityType: thisEntityType,
                entityId: thisEntityId,
                entities: entitySelector(state),
              }),
              (entityIdArray, deletedType) => {
                deletedEntities[deletedType] = [
                  ...(deletedEntities[deletedType] || []),
                  ...entityIdArray,
                ];
              },
            );
          }
          return isDeleted || isCreated || !isUpdated ? undefined : thisEntity;
        },
      ),
      isNil,
    ),
  );

  if (entity.isUpdated) {
    const entities = entitySelector(state);
    updatedEntities = merge(updatedEntities, {
      [currentEntityType]: {
        [currentEntityId]: {
          ...entities[currentEntityType][currentEntityId],
          ...entity,
        },
      },
    });
  }

  let allEntities = {
    ...updatedEntities,
    ...mapValues(createdEntities, (entityList, entityType) => ({
      ...entityList,
      ...(updatedEntities[entityType] || {}),
    })),
  };
  allEntities = merge(
    allEntities,
    mapValues(deletedEntities, deletedIds =>
      zipObject(deletedIds, deletedIds.map(() => null)),
    ),
  );

  const filteredUpdatedEntities = pickBy(allEntities, size);
  if (size(filteredUpdatedEntities)) {
    dispatch({
      type: UPDATE_ENTITIES,
      entities: filteredUpdatedEntities,
    });
    return saveEntities({
      state,
      entities: filteredUpdatedEntities,
      updated: updatedEntities,
      created: createdEntities,
      deleted: deletedEntities,
    }).then(updateHandler(state, dispatch));
  }
  return Promise.all([
    dispatch({ type: DEACTIVATE_SIDEBAR_EDIT }),
    dispatch(releaseSyncLock()),
  ]);
};
<|endoftext|>


<commit_before>"use strict";

const Promise = require("bluebird");
const { fork } = require("child_process");
const EventEmitter = require("events");
const path = require("path");
const fs = require("fs");
const uuid = require("uuid");

const FORK_OPTIONS = {
    detached: true,
    stdio: "ignore"
};

class Process extends EventEmitter {

    constructor(logger) {
        super();
        this.logger = logger;
        this.child = null;
        this.data = null;
        this.isConnected = false;
        this.stack = {};
        this.forkId = uuid.v4();
    }

    spawn(sourceFile, data = {}) {
        this.data = data;

        if (!path.isAbsolute(sourceFile)) {
            sourceFile = path.join(path.dirname(process.argv[1]), sourceFile);
        }

        const exists = fs.existsSync(sourceFile);
        if (!exists) {
            this.logger.error(`module ${sourceFile} does not exist, cannot start process for job as fork: ${this.forkId}.`);
            process.nextTick(() => {
                super.emit("close", true); //ends running queue-job
            });
            return;
        }

        this.logger.info(`spawning process ${this.forkId} with module: ${sourceFile}.`);
        this.child = fork(sourceFile, [this.forkId], FORK_OPTIONS);

        this.child.on("error", error => {
            this.logger.error(`${this.forkId} child error ${error}.`);
        });

        this.child.on("disconnect", () => {
            this.logger.warn(`${this.forkId} child disconnected.`);
        });

        this.child.on("exit", () => {
            this.logger.warn(`${this.forkId} child exited.`);
        });

        this.child.on("close", () => {
            this.logger.warn(`${this.forkId} child closed.`);
            this.emit("close", true);
        });

        this.child.on("message", message => {
            this.emit("message", message);
            this._handleMessage(message);
        });

        this.child.unref();
    }

    _handleMessage(message) {

        if (typeof message !== "object") {
            return;
        }

        if (typeof message.type === "undefined" ||
            typeof message.content === "undefined") {
            return;
        }

        switch (message.type) {

            case "id":
                if (this.forkId === message.content) {
                    this.logger.info(`forked process ${message.content} is connected.`);
                    this.isConnected = true;
                    this.send("data", this.data);
                    this.emit("ready", true);
                } else {
                    this.logger.error(`forked process ${this.forkId} send bad forkId: ${message.content}.`);
                }
                break;

            case "log":
                this.logger.info(`f-ipc-log:${this.forkId}: ${message.content}.`);
                break;

            case "metrics":
                super.emit("metrics", message.content);
                break;

            case "error":
                this.logger.error(`error in fork process: ${this.forkId}, ${message.content}.`);
                break;

            case "task":
                this._handleTaskResult(message.content);
                break;

            default:
                this.logger.warn(`received unknown message type: ${message.type} from f-ipc: ${this.forkId}.`);
                break;
        }
    }

    send(type, content) {

        if (this.child) {
            this.child.send({ type, content });
        }
    }

    pullMetrics(description = {}, timeout = 2000) {
        return new Promise((resolve, reject) => {

            let received = false;

            const _t = setTimeout(() => {
                if (!received) {
                    received = true;
                    reject(new Error(`took to long to retrieve metrics for fork ${this.forkId}.`));
                }
            }, timeout);

            this.send("metrics", description);
            super.once("metrics", metrics => {
                if (!received) {
                    received = true;
                    clearTimeout(_t);
                    this.logger.debug(`received metrics for fork ${this.forkId}.`);
                    resolve(metrics);
                }
            });
        });
    }

    runTask(name, args = {}){
        return new Promise((resolve, reject) => {

            const task = {
                task: name,
                identifier: uuid.v4(),
                args
            };

            //TODO additional timeout

            this.stack[task.identifier] = (error, result) => {

                //clear timeout

                if(error){
                    return reject(error);
                }

                resolve(result);
            };

            this.send("task", task);
        });
    }

    _handleTaskResult(data){
        //TODO
    }

    kill() {

        if (this.child) {
            this.logger.warn(`killing fork process ${this.forkId}.`);
            this.child.kill("SIGINT");
        }
    }
}

module.exports = Process;<commit_msg>Update Process.js<commit_after>"use strict";

const Promise = require("bluebird");
const { fork } = require("child_process");
const EventEmitter = require("events");
const path = require("path");
const fs = require("fs");
const uuid = require("uuid");

const FORK_OPTIONS = {
    detached: true,
    stdio: "ignore"
};

class Process extends EventEmitter {

    constructor(logger) {
        super();
        this.logger = logger;
        this.child = null;
        this.data = null;
        this.isConnected = false;
        this.stack = {};
        this.forkId = uuid.v4();
    }

    spawn(sourceFile, data = {}) {
        this.data = data;

        if (!path.isAbsolute(sourceFile)) {
            sourceFile = path.join(path.dirname(process.argv[1]), sourceFile);
        }

        const exists = fs.existsSync(sourceFile);
        if (!exists) {
            this.logger.error(`module ${sourceFile} does not exist, cannot start process for job as fork: ${this.forkId}.`);
            process.nextTick(() => {
                super.emit("close", true); //ends running queue-job
            });
            return;
        }

        this.logger.info(`spawning process ${this.forkId} with module: ${sourceFile}.`);
        this.child = fork(sourceFile, [this.forkId], FORK_OPTIONS);

        this.child.on("error", error => {
            this.logger.error(`${this.forkId} child error ${error}.`);
        });

        this.child.on("disconnect", () => {
            this.logger.warn(`${this.forkId} child disconnected.`);
        });

        this.child.on("exit", () => {
            this.logger.warn(`${this.forkId} child exited.`);
        });

        this.child.on("close", () => {
            this.logger.warn(`${this.forkId} child closed.`);
            this.emit("close", true);
        });

        this.child.on("message", message => {
            this.emit("message", message);
            this._handleMessage(message);
        });

        this.child.unref();
    }

    _handleMessage(message) {

        if (typeof message !== "object") {
            return;
        }

        if (typeof message.type === "undefined" ||
            typeof message.content === "undefined") {
            return;
        }

        switch (message.type) {

            case "id":
                if (this.forkId === message.content) {
                    this.logger.info(`forked process ${message.content} is connected.`);
                    this.isConnected = true;
                    this.send("data", this.data);
                    this.emit("ready", true);
                } else {
                    this.logger.error(`forked process ${this.forkId} send bad forkId: ${message.content}.`);
                }
                break;

            case "log":
                this.logger.info(`f-ipc-log:${this.forkId}: ${message.content}.`);
                break;

            case "metrics":
                super.emit("metrics", message.content);
                break;

            case "error":
                this.logger.error(`error in fork process: ${this.forkId}, ${message.content}.`);
                break;

            case "task":
                this._handleTaskResult(message.content);
                break;

            default:
                this.logger.warn(`received unknown message type: ${message.type} from f-ipc: ${this.forkId}.`);
                break;
        }
    }

    send(type, content) {

        if (this.child) {
            this.child.send({ type, content });
        }
    }

    pullMetrics(description = {}, timeout = 2000) {
        return new Promise((resolve, reject) => {

            let received = false;
            const _t = setTimeout(() => {
                if (!received) {
                    received = true;
                    reject(new Error(`took to long to retrieve metrics for fork ${this.forkId}.`));
                }
            }, timeout);

            this.send("metrics", description);
            super.once("metrics", metrics => {
                if (!received) {
                    received = true;
                    clearTimeout(_t);
                    this.logger.debug(`received metrics for fork ${this.forkId}.`);
                    resolve(metrics);
                }
            });
        });
    }

    runTask(name, args = {}){
        return new Promise((resolve, reject) => {

            const task = {
                task: name,
                identifier: uuid.v4(),
                args
            };

            let received = false;
            const _t = setTimeout(() => {
                if (!received) {
                    received = true;
                    reject(new Error(`took to long to run task for fork ${this.forkId}.`));
                }
            }, timeout);

            this.stack[task.identifier] = (error, result) => {

                if (!received) {
                    received = true;
                    clearTimeout(_t);
                    this.logger.debug(`received task result for fork ${this.forkId} and task ${task.identifier}.`);

                    if(error){
                        return reject(error);
                    }

                    resolve(result);
                }
            };

            this.logger.debug(`sending task for fork ${this.forkId} and task ${task.identifier}.`);
            this.send("task", task);
        });
    }

    _handleTaskResult(data){

        if(!this.stack[data.identifier]){
            return this.logger.error(`received task result ${data.identifier}, but task is not in stack.`);
        }

        this.stack[data.identifier](data.error, data.result);
        delete this.stack[data.identifier];
    }

    kill() {

        if (this.child) {
            this.logger.warn(`killing fork process ${this.forkId}.`);
            this.child.kill("SIGINT");
        }
    }
}

module.exports = Process;
<|endoftext|>


<commit_before>/**
 * Copyright 2014-2015 Francesco Camarlinghi
 *
 * 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.
 */

module.exports = function (grunt)
{
    'use strict';
    var path = require('path');
    var _ = require('lodash');
    var cep = require('../lib/cep.js')(grunt);

    /**
     * Creates a CSXS manifest file from template.
     */
    var manifest = function (callback, build)
    {
        var bundle = build.bundle;

        // Validate manifest
        grunt.verbose.or.write('Generating bundle manifest...');

        if (!bundle.manifest)
        {
            grunt.verbose.or.error();
            grunt.fatal('No bundle manifest file specified.');
        }
        else if (!grunt.file.exists(bundle.manifest))
        {
            grunt.verbose.or.error();
            grunt.fatal('Unable to read bundle manifest file template at ' + bundle.manifest.cyan + '.');
        }

        // Generate manifest data for each extension
        var extension_list_manifest = [],
            extensions_manifest = [];

        build.extensions.forEach(function (extension)
        {
            var data = _.extend({}, { 'extension': extension, 'build': build, });

            // <ExtensionList>
            extension_list_manifest.push(grunt.template.process('<Extension Id="<%= extension.id %>" Version="<%= extension.version %>" />', { data: data }));

            // <Extensions>
            if (!extension.manifest)
            {
                grunt.verbose.or.error();
                grunt.fatal('No extension manifest file specified for ' + extension.id + '.');
            }
            else if (!grunt.file.exists(extension.manifest))
            {
                grunt.verbose.or.error();
                grunt.fatal('Unable to read extension manifest file template at ' + extension.manifest.cyan + ' for ' + extension.id + '.');
            }

            extensions_manifest.push(grunt.template.process(grunt.file.read(extension.manifest), { data: data }));
        });

        // Generate bundle manifest
        // <Host> list
        var list_hosts = [],
            products = build.products,
            families = build.families;

        if (products)
        {
            for (var i = 0, n = products.length; i < n; i++)
            {
                var host = cep.hosts.getProduct(products[i]);
                var range = cep.hosts.getVersionRange(products[i], families);

                for (var j = 0; j < host.ids.length; j++)
                {
                    list_hosts.push('<Host Name="' + host.ids[j] + '" Version="[' + range.min + ',' + range.max + ']" />');
                }
            }
        }

        // Templating
        var dest = path.join(build.staging, '/CSXS/manifest.xml');

        var data = _.extend({},
            {
                'bundle': bundle,
                'extension_list': extension_list_manifest.join('\n\t\t\t'),
                'extensions': extensions_manifest.join('\n\t\t\t'),
                'hosts': list_hosts.join('\n\t\t\t'),
            });

        var processed = grunt.template.process(grunt.file.read(bundle.manifest), { data: data });
        grunt.file.write(dest, processed);

        grunt.verbose.or.ok();
        callback();
    };

    /**
     * Populates extension MXI file template.
     */
    var mxi = function (callback, options)
    {
        var builds = options.builds,
            product_versions = {},
            data = {
                files: [],
                products: []
            },
            mxi_filename = options.bundle.basename + '.mxi';

        grunt.log.write('Generating ' + mxi_filename.cyan + ' file from template...');

        function get_version_range(product, families)
        {
            var range = cep.hosts.getVersionRange(product, families);

            // Store version range
            if (!product_versions.hasOwnProperty(product))
                product_versions[product] = {};

            // If current range values are higher or lower than
            // the stored ones, save them
            if (!product_versions[product].min || parseFloat(range.min) < parseFloat(product_versions[product].min))
                product_versions[product].min = range.min;

            if (!product_versions[product].max || parseFloat(range.max) > parseFloat(product_versions[product].max))
                product_versions[product].max = range.max;

            return range;
        };

        // Create <files> list
        for (var i = 0, n = builds.length; i < n; i++)
        {
            // Parse CC products
            builds[i].products.forEach(function (product)
            {
                var version_range = get_version_range(product, builds[i].families);
                data.files.push('<file destination="" file-type="CSXS" products="' + cep.hosts.get_cc_family_name(cep.hosts.getProduct(product).familyname) + '" maxVersion="' + version_range.max + '" minVersion="' + version_range.min + '" source="' + path.basename(builds[i].output_file) + '" />');
            });
        }

        // Create <product> list
        for (var product in product_versions)
        {
            data.products.push('<product familyname="' + cep.hosts.getProduct(product).familyname + '" maxversion="' + product_versions[product].max + '" primary="true" version="' + product_versions[product].min + '" />');
        }

        // Fill in .mxi template
        data.files = data.files.join('\n\t\t');
        data.products = data.products.join('\n\t\t');
        data = _.merge(_.extend({}, data), options);

        // Setup 'update.xml', if needed
        if (options['package'].update.enabled)
            data.bundle.update_url += 'update.xml';

        // Process template
        var processed = grunt.template.process(grunt.file.read(options['package'].mxi), { data: data });
        grunt.file.write(path.resolve(options.staging, mxi_filename), processed);

        grunt.log.ok();
        callback();
    };

    /**
     * Populates extension "update.xml" file template.
     */
    var update = function (callback, options)
    {
        grunt.log.write('Generating ' + 'update.xml'.cyan + ' file...');

        var changes_path = path.join(options['package'].update.changelog_folder, options.bundle.version + options['package'].update.changelog_extension),
            description;

        if (grunt.file.exists(changes_path))
        {
            // Parse changelog txt and generate description in update.xml file
            description = '
';
            description += '
' + path.basename(changes_path, '.txt') + '
';
            description += '
' + grunt.file.read(changes_path).replace(/\r?\n/g, '
') + '
';
            description += '
';
        }

        // Put templating data together
        var update_data = _.extend({}, options, {
            'download_url': options.bundle.update_url + options.bundle.name.replace(/[\s]+/g, '_').toLowerCase() + '_' + options.bundle.version + '.zxp',
            'update_description': description,
        });

        // Process template and save result
        var processed = grunt.template.process(grunt.file.read(options['package'].update.file), { data: update_data });
        grunt.file.write(path.join(options.staging, '../', 'update.xml'), processed);
        grunt.log.ok();

        callback();
    };

    // Public interface
    var xml = {};
    xml.manifest = manifest;
    xml.mxi = mxi;
    xml.update = update;
    return xml;
};
<commit_msg>added CEF commandline support<commit_after>/**
 * Copyright 2014-2015 Francesco Camarlinghi
 *
 * 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.
 */

module.exports = function (grunt)
{
    'use strict';
    var path = require('path');
    var _ = require('lodash');
    var cep = require('../lib/cep.js')(grunt);

    /**
     * Creates a CSXS manifest file from template.
     */
    var manifest = function (callback, build)
    {
        var bundle = build.bundle;

        // Validate manifest
        grunt.verbose.or.write('Generating bundle manifest...');

        if (!bundle.manifest)
        {
            grunt.verbose.or.error();
            grunt.fatal('No bundle manifest file specified.');
        }
        else if (!grunt.file.exists(bundle.manifest))
        {
            grunt.verbose.or.error();
            grunt.fatal('Unable to read bundle manifest file template at ' + bundle.manifest.cyan + '.');
        }

        // Generate manifest data for each extension
        var extension_list_manifest = [],
            extensions_manifest = [];

        build.extensions.forEach(function (extension)
        {
            //<CEFCommandLine>
            var cef_params = [];
            extension.cef_params.forEach(function(cef_param)
            {
                cef_params.push('<Parameter>'+ cef_param +'</Parameter>')
            });
            extension.cef_params = cef_params.join('\n\t\t\t\t\t');

            var data = _.extend({}, { 'extension': extension, 'build': build, });

            // <ExtensionList>
            extension_list_manifest.push(grunt.template.process('<Extension Id="<%= extension.id %>" Version="<%= extension.version %>" />', { data: data }));

            // <Extensions>
            if (!extension.manifest)
            {
                grunt.verbose.or.error();
                grunt.fatal('No extension manifest file specified for ' + extension.id + '.');
            }
            else if (!grunt.file.exists(extension.manifest))
            {
                grunt.verbose.or.error();
                grunt.fatal('Unable to read extension manifest file template at ' + extension.manifest.cyan + ' for ' + extension.id + '.');
            }

            extensions_manifest.push(grunt.template.process(grunt.file.read(extension.manifest), { data: data }));
        });

        // Generate bundle manifest
        // <Host> list
        var list_hosts = [],
            products = build.products,
            families = build.families;

        if (products)
        {
            for (var i = 0, n = products.length; i < n; i++)
            {
                var host = cep.hosts.getProduct(products[i]);
                var range = cep.hosts.getVersionRange(products[i], families);

                for (var j = 0; j < host.ids.length; j++)
                {
                    list_hosts.push('<Host Name="' + host.ids[j] + '" Version="[' + range.min + ',' + range.max + ']" />');
                }
            }
        }

        // Templating
        var dest = path.join(build.staging, '/CSXS/manifest.xml');

        var data = _.extend({},
            {
                'bundle': bundle,
                'extension_list': extension_list_manifest.join('\n\t\t\t'),
                'extensions': extensions_manifest.join('\n\t\t\t'),
                'hosts': list_hosts.join('\n\t\t\t'),
            });

        var processed = grunt.template.process(grunt.file.read(bundle.manifest), { data: data });
        grunt.file.write(dest, processed);

        grunt.verbose.or.ok();
        callback();
    };

    /**
     * Populates extension MXI file template.
     */
    var mxi = function (callback, options)
    {
        var builds = options.builds,
            product_versions = {},
            data = {
                files: [],
                products: []
            },
            mxi_filename = options.bundle.basename + '.mxi';

        grunt.log.write('Generating ' + mxi_filename.cyan + ' file from template...');

        function get_version_range(product, families)
        {
            var range = cep.hosts.getVersionRange(product, families);

            // Store version range
            if (!product_versions.hasOwnProperty(product))
                product_versions[product] = {};

            // If current range values are higher or lower than
            // the stored ones, save them
            if (!product_versions[product].min || parseFloat(range.min) < parseFloat(product_versions[product].min))
                product_versions[product].min = range.min;

            if (!product_versions[product].max || parseFloat(range.max) > parseFloat(product_versions[product].max))
                product_versions[product].max = range.max;

            return range;
        };

        // Create <files> list
        for (var i = 0, n = builds.length; i < n; i++)
        {
            // Parse CC products
            builds[i].products.forEach(function (product)
            {
                var version_range = get_version_range(product, builds[i].families);
                data.files.push('<file destination="" file-type="CSXS" products="' + cep.hosts.get_cc_family_name(cep.hosts.getProduct(product).familyname) + '" maxVersion="' + version_range.max + '" minVersion="' + version_range.min + '" source="' + path.basename(builds[i].output_file) + '" />');
            });
        }

        // Create <product> list
        for (var product in product_versions)
        {
            data.products.push('<product familyname="' + cep.hosts.getProduct(product).familyname + '" maxversion="' + product_versions[product].max + '" primary="true" version="' + product_versions[product].min + '" />');
        }

        // Fill in .mxi template
        data.files = data.files.join('\n\t\t');
        data.products = data.products.join('\n\t\t');
        data = _.merge(_.extend({}, data), options);

        // Setup 'update.xml', if needed
        if (options['package'].update.enabled)
            data.bundle.update_url += 'update.xml';

        // Process template
        var processed = grunt.template.process(grunt.file.read(options['package'].mxi), { data: data });
        grunt.file.write(path.resolve(options.staging, mxi_filename), processed);

        grunt.log.ok();
        callback();
    };

    /**
     * Populates extension "update.xml" file template.
     */
    var update = function (callback, options)
    {
        grunt.log.write('Generating ' + 'update.xml'.cyan + ' file...');

        var changes_path = path.join(options['package'].update.changelog_folder, options.bundle.version + options['package'].update.changelog_extension),
            description;

        if (grunt.file.exists(changes_path))
        {
            // Parse changelog txt and generate description in update.xml file
            description = '
';
            description += '
' + path.basename(changes_path, '.txt') + '
';
            description += '
' + grunt.file.read(changes_path).replace(/\r?\n/g, '
') + '
';
            description += '
';
        }

        // Put templating data together
        var update_data = _.extend({}, options, {
            'download_url': options.bundle.update_url + options.bundle.name.replace(/[\s]+/g, '_').toLowerCase() + '_' + options.bundle.version + '.zxp',
            'update_description': description,
        });

        // Process template and save result
        var processed = grunt.template.process(grunt.file.read(options['package'].update.file), { data: update_data });
        grunt.file.write(path.join(options.staging, '../', 'update.xml'), processed);
        grunt.log.ok();

        callback();
    };

    // Public interface
    var xml = {};
    xml.manifest = manifest;
    xml.mxi = mxi;
    xml.update = update;
    return xml;
};
<|endoftext|>


<commit_before>import { expect } from "chai";
import sinon from "sinon";
import fs from "fs";
import temp from "temp";
import rimraf from "rimraf";
import logger from "../../src/lib/logger";
import { isGluestickProject, quitUnlessGluestickProject } from "../../src/lib/utils";

describe("utils", function () {

  let originalCwd, tmpDir;

  beforeEach(() => {
    originalCwd = process.cwd();
    tmpDir = temp.mkdirSync("gluestick-generate");
    process.chdir(tmpDir);
  });

  afterEach(done => {
    process.chdir(originalCwd);
    rimraf(tmpDir, done);
  });

  describe("isGluestickProject", function () {

    it("should return false if a .gluestick file is not found in the current directory", done => {
      expect(isGluestickProject()).to.be.false;
      done();
    });

    it("should return true if a .gluestick file is not found in the current directory", done => {
      fs.closeSync(fs.openSync(".gluestick", "w"));
      expect(isGluestickProject()).to.be.true;
      done();
    });

  });

  describe("quitUnlessGluestickProject", function () {

    let sandbox;

    beforeEach(() => {
      sandbox = sinon.sandbox.create();
      sandbox.stub(process, "exit");
      sandbox.spy(logger, "error");
    });

    afterEach(() => {
      sandbox.restore();
    });

    it("should quit the program if run outside of a gluestick project", done => {
      quitUnlessGluestickProject("test");
      expect(process.exit.called).to.be.true;
      done();
    });

    it("should not quit the program if run inside of a gluestick project", done => {
      fs.closeSync(fs.openSync(".gluestick", "w"));
      quitUnlessGluestickProject("test");
      expect(process.exit.called).to.be.false;
      done();
    });

    it("should display an error if run outside of a gluestick project", done => {
      quitUnlessGluestickProject("test");
      expect(logger.error.calledWithMatch("commands must be run from the root of a gluestick project")).to.be.true;
      done();
    });

    it("should not display an error if run inside of a gluestick project", done => {
      fs.closeSync(fs.openSync(".gluestick", "w"));
      quitUnlessGluestickProject("test");
      expect(logger.error.calledWithMatch("commands must be run from the root of a gluestick project")).to.be.false;
      done();
    });

  });

});

<commit_msg>Fix name for test directory<commit_after>import { expect } from "chai";
import sinon from "sinon";
import fs from "fs";
import temp from "temp";
import rimraf from "rimraf";
import logger from "../../src/lib/logger";
import { isGluestickProject, quitUnlessGluestickProject } from "../../src/lib/utils";

describe("utils", function () {

  let originalCwd, tmpDir;

  beforeEach(() => {
    originalCwd = process.cwd();
    tmpDir = temp.mkdirSync("gluestick-utils");
    process.chdir(tmpDir);
  });

  afterEach(done => {
    process.chdir(originalCwd);
    rimraf(tmpDir, done);
  });

  describe("isGluestickProject", function () {

    it("should return false if a .gluestick file is not found in the current directory", done => {
      expect(isGluestickProject()).to.be.false;
      done();
    });

    it("should return true if a .gluestick file is not found in the current directory", done => {
      fs.closeSync(fs.openSync(".gluestick", "w"));
      expect(isGluestickProject()).to.be.true;
      done();
    });

  });

  describe("quitUnlessGluestickProject", function () {

    let sandbox;

    beforeEach(() => {
      sandbox = sinon.sandbox.create();
      sandbox.stub(process, "exit");
      sandbox.spy(logger, "error");
    });

    afterEach(() => {
      sandbox.restore();
    });

    it("should quit the program if run outside of a gluestick project", done => {
      quitUnlessGluestickProject("test");
      expect(process.exit.called).to.be.true;
      done();
    });

    it("should not quit the program if run inside of a gluestick project", done => {
      fs.closeSync(fs.openSync(".gluestick", "w"));
      quitUnlessGluestickProject("test");
      expect(process.exit.called).to.be.false;
      done();
    });

    it("should display an error if run outside of a gluestick project", done => {
      quitUnlessGluestickProject("test");
      expect(logger.error.calledWithMatch("commands must be run from the root of a gluestick project")).to.be.true;
      done();
    });

    it("should not display an error if run inside of a gluestick project", done => {
      fs.closeSync(fs.openSync(".gluestick", "w"));
      quitUnlessGluestickProject("test");
      expect(logger.error.calledWithMatch("commands must be run from the root of a gluestick project")).to.be.false;
      done();
    });

  });

});

<|endoftext|>


<commit_before>var editor = ace.edit('game-rb-editor');
editor.setTheme('ace/theme/monokai');
editor.getSession().setFoldStyle('manual');
editor.getSession().setMode("ace/mode/ruby");
editor.getSession().setTabSize(2);
editor.getSession().setUseSoftTabs(true);
editor.getSession().setUseWrapMode(true);
editor.setDisplayIndentGuides(false);
editor.setHighlightActiveLine(true);
editor.setShowPrintMargin(false);
editor.setShowInvisibles(true);

var addToTerminal = function(value, type) {
    if (type === 'output' && value.indexOf('()') > -1) return;
    var classes = 'outputs outputs-' + type;
    value = value.replace(/&/g, '&')
                 .replace(/>/g, '>')
                 .replace(/</g, '<')
                 .replace(/"/g, '"')
                 .replace(/'/g, ''')
                 .replace(/\n/g, '
');
    terminalOutputs.innerHTML += '
' + value + '
';
    terminalInput.scrollIntoView();
};

var handleterminalInput = function(event) {
    var key = event.which || event.keyCode;
    if (key == 13) {
        event.preventDefault();
        socket.emit('terminalInput', { input: terminalInput.value });
        addToTerminal(terminalInput.value, 'input');
        terminalInput.value = '';
    }
};

var handleFileBuild = function() {
    handleFileSave();
    addToTerminal('Build started...', 'status');
};

var handleFileSave = function() {
    var currentFileContent = editor.getValue();
    socket.emit('fileSave', { fileContent: currentFileContent });
};

var handleFileLoad = function() {
    var currentFileContent = editor.getValue();
    socket.emit('fileLoad', { input: currentFileContent });
};

// Set socket URL based on environment
var socketURL = 'http://wotf-cyoa.herokuapp.com:80/ruby';
if (window.location.origin === 'http://localhost:3333')
    socketURL = 'http://localhost:8888/ruby';

var socket = io(socketURL),
    terminal = document.getElementById('terminal'),
    terminalOutputs = document.getElementById('terminal-outputs'),
    terminalInput = document.getElementById('terminal-input'),
    sourceActionBuild = document.getElementById('source-action-build');

terminal.addEventListener('click', function(e) { terminalInput.focus() }, false);

socket.on('connect', function() {
    addToTerminal('Server connected.', 'status');
    terminalInput.addEventListener('keypress', handleterminalInput, false);
    sourceActionBuild.addEventListener('click', handleFileBuild, false);
});

socket.on('disconnect', function() {
    addToTerminal('Server disconnected.', 'error');
    terminalInput.removeEventListener('keypress', handleterminalInput, false);
    sourceActionBuild.removeEventListener('click', handleFileBuild, false);
});

socket.on('ready', function(data) {
    addToTerminal(data.output, 'status');
    editor.setValue(data.fileContent);
    editor.gotoLine(0);
});

socket.on('terminalOutput', function(data) {
    //if (data.output.indexOf('Error') > -1 || data.output.indexOf('undefined') > -1)
    //    addToTerminal(data.output, 'error');
    //else addToTerminal(data.output, 'output');
    addToTerminal(data.output, 'output');
});

socket.on('terminalError', function(data) {
    addToTerminal(data.output, 'error');
});

socket.on('fileSaved', function(data) {
    addToTerminal(data.output, 'status');
    handleFileLoad();
});

socket.on('fileLoaded', function(data) {
    addToTerminal(data.output, 'status');
    addToTerminal('Build successful!', 'status');
});
<commit_msg>Cleanly put build into a single socket event<commit_after>var editor = ace.edit('game-rb-editor');
editor.setTheme('ace/theme/monokai');
editor.getSession().setFoldStyle('manual');
editor.getSession().setMode("ace/mode/ruby");
editor.getSession().setTabSize(2);
editor.getSession().setUseSoftTabs(true);
editor.getSession().setUseWrapMode(true);
editor.setDisplayIndentGuides(false);
editor.setHighlightActiveLine(true);
editor.setShowPrintMargin(false);
editor.setShowInvisibles(true);

var addToTerminal = function(value, type) {
    if (type === 'output' && value.indexOf('()') > -1) return;
    var classes = 'outputs outputs-' + type;
    value = value.replace(/&/g, '&')
                 .replace(/>/g, '>')
                 .replace(/</g, '<')
                 .replace(/"/g, '"')
                 .replace(/'/g, ''')
                 .replace(/\n/g, '
');
    terminalOutputs.innerHTML += '
' + value + '
';
    terminalInput.scrollIntoView();
};

var handleterminalInput = function(event) {
    var key = event.which || event.keyCode;
    if (key == 13) {
        event.preventDefault();
        socket.emit('terminalInput', { input: terminalInput.value });
        addToTerminal(terminalInput.value, 'input');
        terminalInput.value = '';
    }
};

var handleCodeBuild = function() {
    var currentFileContent = editor.getValue();
    addToTerminal('Build started...', 'status');
    socket.emit('codeBuild', { fileContent: currentFileContent });
};

// Set socket URL based on environment
var socketURL = 'http://wotf-cyoa.herokuapp.com:80/ruby';
if (window.location.origin === 'http://localhost:3333')
    socketURL = 'http://localhost:8888/ruby';

var socket = io(socketURL),
    terminal = document.getElementById('terminal'),
    terminalOutputs = document.getElementById('terminal-outputs'),
    terminalInput = document.getElementById('terminal-input'),
    sourceActionBuild = document.getElementById('source-action-build');

terminal.addEventListener('click', function(e) { terminalInput.focus() }, false);

socket.on('connect', function() {
    addToTerminal('Server connected.', 'status');
    terminalInput.addEventListener('keypress', handleterminalInput, false);
    sourceActionBuild.addEventListener('click', handleCodeBuild, false);
});

socket.on('disconnect', function() {
    addToTerminal('Server disconnected.', 'error');
    terminalInput.removeEventListener('keypress', handleterminalInput, false);
    sourceActionBuild.removeEventListener('click', handleCodeBuild, false);
});

socket.on('ready', function(data) {
    addToTerminal(data.output, 'status');
    editor.setValue(data.fileContent);
    editor.gotoLine(0);
});

socket.on('terminalOutput', function(data) {
    //if (data.output.indexOf('Error') > -1 || data.output.indexOf('undefined') > -1)
    //    addToTerminal(data.output, 'error');
    //else addToTerminal(data.output, 'output');
    addToTerminal(data.output, 'output');
});

socket.on('terminalError', function(data) {
    addToTerminal(data.output, 'error');
});

socket.on('buildStatus', function(data) {
    addToTerminal(data.output, 'status');
});

<|endoftext|>


<commit_before>// @flow

import { chTest, randomString } from './helper';

const ch = chTest();

// FIXME: creating new events takes a few seconds, so we rely on a known
// customerId already having some associated events
const cid = '689ef20e-e37a-4b8e-8d3f-2494ec901bc5';

describe('ContactHub', () => {

  describe('addEvent', () => {
    it('creates a new event', async () => {
      const res = await ch.addEvent({
        customerId: cid,
        context: 'WEB',
        type: 'viewedPage',
        properties: {}
      });

      expect(res).toBe(true);
    });

    it('creates an anonymous event', async () => {
      const res = await ch.addEvent({
        sessionId: randomString(),
        context: 'WEB',
        type: 'viewedPage',
        properties: {}
      });

      expect(res).toBe(true);
    });
  });

  describe('getEvent', () => {
    it('retrieves an Event by id', async () => {
      const events = await ch.getEvents(cid);

      const event = await ch.getEvent(events[0].id);
      expect(event.id).toBe(events[0].id);
    });
  });

  describe('getEvents', () => {
    it('retrieves all Events for a Customer', async () => {
      const events = await ch.getEvents(cid);
      expect(events.length).toBe(10);
      expect(events[0].customerId).toBe(cid);
    });
  });

  describe('getEvents', () => {
    it('retrieves all Events for a Customer using filters', async () => {
      const dateFrom = new Date('2017-02-28');
      const filters = {
        mode: 'ACTIVE',
        context: 'WEB',
        dateFrom
      };
      const events = await ch.getEvents(cid, filters);
      const areWebEvents = events.reduce((acc, v) => acc && v.context === 'WEB', true);
      expect(areWebEvents).toBe(true);
      const haveRightDate = events.reduce((acc, v) => acc && new Date(v.date) >= dateFrom, true);
      expect(haveRightDate).toBe(true);
    });
  });

});
<commit_msg>Specified a date range, replaced '.reduce' with '.every'.<commit_after>// @flow

import { chTest, randomString } from './helper';

const ch = chTest();

// FIXME: creating new events takes a few seconds, so we rely on a known
// customerId already having some associated events
const cid = '689ef20e-e37a-4b8e-8d3f-2494ec901bc5';

describe('ContactHub', () => {

  describe('addEvent', () => {
    it('creates a new event', async () => {
      const res = await ch.addEvent({
        customerId: cid,
        context: 'WEB',
        type: 'viewedPage',
        properties: {}
      });

      expect(res).toBe(true);
    });

    it('creates an anonymous event', async () => {
      const res = await ch.addEvent({
        sessionId: randomString(),
        context: 'WEB',
        type: 'viewedPage',
        properties: {}
      });

      expect(res).toBe(true);
    });
  });

  describe('getEvent', () => {
    it('retrieves an Event by id', async () => {
      const events = await ch.getEvents(cid);

      const event = await ch.getEvent(events[0].id);
      expect(event.id).toBe(events[0].id);
    });
  });

  describe('getEvents', () => {
    it('retrieves all Events for a Customer', async () => {
      const events = await ch.getEvents(cid);
      expect(events.length).toBe(10);
      expect(events[0].customerId).toBe(cid);
    });
  });

  describe('getEvents', () => {
    it('retrieves all Events for a Customer using filters', async () => {
      const dateFrom = new Date('2017-02-10');
      const dateTo = new Date('2017-02-20');
      const filters = {
        mode: 'ACTIVE',
        context: 'WEB',
        dateFrom,
        dateTo
      };

      const events = await ch.getEvents(cid, filters);
      expect(events.length > 0).toBe(true);

      const areWebEvents = events.every((v) => v.context === 'WEB');
      expect(areWebEvents).toBe(true);

      const haveRightDate = events.every((v) => {
        const eventDate = new Date(v.date);
        return dateTo >= eventDate && eventDate >= dateFrom;
      });
      expect(haveRightDate).toBe(true);
    });
  });

});
<|endoftext|>


<commit_before>module.exports = function(grunt) {

    'use strict';

    var spawn = require('child_process').spawn,
        path = require('path'),
        async = require('async'),
        fs = require('fs');

    var _ = grunt.util._;

    var versions = {
        1.0: '1.0.3705',
        1.1: '1.1.4322',
        2.0: '2.0.50727',
        3.5: '3.5',
        4.0: '4.0.30319',
        12.0: '12.0',
        14.0: '14.0'
    };

    grunt.registerMultiTask('msbuild', 'Run MSBuild tasks', function() {

        var asyncCallback = this.async();

        var options = this.options({
            targets: ['Build'],
            buildParameters: {},
            failOnError: true,
            verbosity: 'normal',
            processor: '',
            nologo: true
        });

        if (!options.projectConfiguration) {
            options.projectConfiguration = 'Release';
        }

        grunt.verbose.writeln('Using Options: ' + JSON.stringify(options, null, 4).cyan);

        var projectFunctions = [];
        var files = this.files;

        if (files.length == 0) {
            files.push({src: ['']});
        }

        files.forEach(function(filePair) {
            filePair.src.forEach(function(src) {
                projectFunctions.push(function(cb) {
                    build(src, options, cb);
                });

                projectFunctions.push(function(cb) {
                    cb();
                });
            });
        });

        async.series(projectFunctions, function() {
            asyncCallback();
        });

    });

    function build(src, options, cb) {

        var projName = src || path.basename(process.cwd());

        grunt.log.writeln('Building ' + projName.cyan);

        var cmd = createCommand(options.version || null, options.processor);
        var args = createCommandArgs(src, options);

        grunt.verbose.writeln('Using cmd:', cmd);
        grunt.verbose.writeln('Using args:', args);

        if (!cmd) {
            return;
        }

        var cp = spawn(cmd, args, {
            stdio: 'inherit'
        });

        cp.on('close', function(code) {
            var success = code === 0;
            grunt.verbose.writeln('close received - code: ', success);

            if (code === 0) {
                grunt.log.writeln('Build complete ' + projName.cyan);
                cb();
            } else {
                grunt.log.writeln(('MSBuild failed with code: ' + code).cyan + projName);
                if (options.failOnError) {
                    grunt.warn('MSBuild exited with a failure code: ' + code);
                }
            }

        });

    }

    function createCommandArgs(src, options) {

        var args = [];

        if (src) {
            var projectPath = path.normalize(path.resolve() + '/' + src);

            args.push(projectPath);
        }

        args.push('/target:' + options.targets);
        args.push('/verbosity:' + options.verbosity);

        if (options.nologo) {
            args.push('/nologo');
        }

        if (options.maxCpuCount) {
            grunt.verbose.writeln('Using maxcpucount:', +options.maxCpuCount);
            args.push('/maxcpucount:' + options.maxCpuCount);
        }

	if (options.consoleLoggerParameters) {
            grunt.verbose.writeln('Using clp:' + options.consoleLoggerParameters);
	    args.push('/clp:' + options.consoleLoggerParameters);
	}

        args.push('/property:Configuration=' + options.projectConfiguration);

        if (options.platform) {
            args.push('/p:Platform=' + options.platform);
        }

        for (var buildArg in options.buildParameters) {
            args.push('/property:' + buildArg + '=' + options.buildParameters[buildArg]);
        }

        return args;
    }

    function createCommand(version, processor) {

        // temp mono xbuild usage for linux / osx - assumes xbuild is in the path, works on my machine...
        if (process.platform === 'linux' || process.platform === 'darwin') {
            return 'xbuild';
        }

        // convert to numbers if correct strings
        version = isNaN(version) ? version : parseFloat(version);
        processor = isNaN(processor) ? processor : parseFloat(processor);

        var programFiles = process.env['ProgramFiles(x86)'] || process.env.PROGRAMFILES;

        if (!version) {
            version = 4.0; // default fallback to version 4.0

            var msbuildDir = path.join(programFiles, 'MSBuild');

            if (fs.existsSync(msbuildDir)) {
                var msbuildVersions = fs.readdirSync(msbuildDir)
                    .filter(function(entryName) {
                        return entryName.indexOf('1') === 0;
                    });

                if (msbuildVersions.length > 0) {
                    // set latest installed msbuild version
                    version = parseFloat(msbuildVersions[msbuildVersions.length - 1]);
                }
            }
        }

        var specificVersion = versions[version];

        if (!specificVersion) {
            grunt.fatal('Unrecognised MSBuild version "' + version + '"');
        }

        if (version < 12) {
            var frameworkDir = 'Framework' + (processor === 64 ? processor : '');
            var buildExecutablePath = path.join(process.env.WINDIR, 'Microsoft.Net', frameworkDir, 'v' + specificVersion, 'MSBuild.exe');
        } else {
            var x64Dir = processor === 64 ? 'amd64' : '';
            var buildExecutablePath = path.join(programFiles, 'MSBuild', specificVersion, 'Bin', x64Dir, 'MSBuild.exe');
        }

        grunt.verbose.writeln('Using MSBuild at:' + buildExecutablePath.cyan);

        if (!fs.existsSync(buildExecutablePath)) {
            grunt.fatal('Unable to find MSBuild executable');
        }

        return path.normalize(buildExecutablePath);

    }

};
<commit_msg>grunt warning when no project or solution files found<commit_after>module.exports = function(grunt) {

    'use strict';

    var spawn = require('child_process').spawn,
        path = require('path'),
        async = require('async'),
        fs = require('fs');

    var _ = grunt.util._;

    var versions = {
        1.0: '1.0.3705',
        1.1: '1.1.4322',
        2.0: '2.0.50727',
        3.5: '3.5',
        4.0: '4.0.30319',
        12.0: '12.0',
        14.0: '14.0'
    };

    grunt.registerMultiTask('msbuild', 'Run MSBuild tasks', function() {

        var asyncCallback = this.async();

        var options = this.options({
            targets: ['Build'],
            buildParameters: {},
            failOnError: true,
            verbosity: 'normal',
            processor: '',
            nologo: true
        });

        if (!options.projectConfiguration) {
            options.projectConfiguration = 'Release';
        }

        grunt.verbose.writeln('Using Options: ' + JSON.stringify(options, null, 4).cyan);

        var projectFunctions = [];
        var files = this.files;
        var fileExists = false;

        if (files.length == 0) {
            files.push({src: ['']});
        }

        files.forEach(function(filePair) {
            filePair.src.forEach(function(src) {
                fileExists = true;
                projectFunctions.push(function(cb) {
                    build(src, options, cb);
                });

                projectFunctions.push(function(cb) {
                    cb();
                });
            });
        });

        if(!fileExists){
            grunt.warn('No project or solution files found');
        }

        async.series(projectFunctions, function() {
            asyncCallback();
        });

    });

    function build(src, options, cb) {

        var projName = src || path.basename(process.cwd());

        grunt.log.writeln('Building ' + projName.cyan);

        var cmd = createCommand(options.version || null, options.processor);
        var args = createCommandArgs(src, options);

        grunt.verbose.writeln('Using cmd:', cmd);
        grunt.verbose.writeln('Using args:', args);

        if (!cmd) {
            return;
        }

        var cp = spawn(cmd, args, {
            stdio: 'inherit'
        });

        cp.on('close', function(code) {
            var success = code === 0;
            grunt.verbose.writeln('close received - code: ', success);

            if (code === 0) {
                grunt.log.writeln('Build complete ' + projName.cyan);
                cb();
            } else {
                grunt.log.writeln(('MSBuild failed with code: ' + code).cyan + projName);
                if (options.failOnError) {
                    grunt.warn('MSBuild exited with a failure code: ' + code);
                }
            }

        });

    }

    function createCommandArgs(src, options) {

        var args = [];

        if (src) {
            var projectPath = path.normalize(path.resolve() + '/' + src);

            args.push(projectPath);
        }

        args.push('/target:' + options.targets);
        args.push('/verbosity:' + options.verbosity);

        if (options.nologo) {
            args.push('/nologo');
        }

        if (options.maxCpuCount) {
            grunt.verbose.writeln('Using maxcpucount:', +options.maxCpuCount);
            args.push('/maxcpucount:' + options.maxCpuCount);
        }

	if (options.consoleLoggerParameters) {
            grunt.verbose.writeln('Using clp:' + options.consoleLoggerParameters);
	    args.push('/clp:' + options.consoleLoggerParameters);
	}

        args.push('/property:Configuration=' + options.projectConfiguration);

        if (options.platform) {
            args.push('/p:Platform=' + options.platform);
        }

        for (var buildArg in options.buildParameters) {
            args.push('/property:' + buildArg + '=' + options.buildParameters[buildArg]);
        }

        return args;
    }

    function createCommand(version, processor) {

        // temp mono xbuild usage for linux / osx - assumes xbuild is in the path, works on my machine...
        if (process.platform === 'linux' || process.platform === 'darwin') {
            return 'xbuild';
        }

        // convert to numbers if correct strings
        version = isNaN(version) ? version : parseFloat(version);
        processor = isNaN(processor) ? processor : parseFloat(processor);

        var programFiles = process.env['ProgramFiles(x86)'] || process.env.PROGRAMFILES;

        if (!version) {
            version = 4.0; // default fallback to version 4.0

            var msbuildDir = path.join(programFiles, 'MSBuild');

            if (fs.existsSync(msbuildDir)) {
                var msbuildVersions = fs.readdirSync(msbuildDir)
                    .filter(function(entryName) {
                        return entryName.indexOf('1') === 0;
                    });

                if (msbuildVersions.length > 0) {
                    // set latest installed msbuild version
                    version = parseFloat(msbuildVersions[msbuildVersions.length - 1]);
                }
            }
        }

        var specificVersion = versions[version];

        if (!specificVersion) {
            grunt.fatal('Unrecognised MSBuild version "' + version + '"');
        }

        if (version < 12) {
            var frameworkDir = 'Framework' + (processor === 64 ? processor : '');
            var buildExecutablePath = path.join(process.env.WINDIR, 'Microsoft.Net', frameworkDir, 'v' + specificVersion, 'MSBuild.exe');
        } else {
            var x64Dir = processor === 64 ? 'amd64' : '';
            var buildExecutablePath = path.join(programFiles, 'MSBuild', specificVersion, 'Bin', x64Dir, 'MSBuild.exe');
        }

        grunt.verbose.writeln('Using MSBuild at:' + buildExecutablePath.cyan);

        if (!fs.existsSync(buildExecutablePath)) {
            grunt.fatal('Unable to find MSBuild executable');
        }

        return path.normalize(buildExecutablePath);

    }

};
<|endoftext|>


<commit_before>(function($) {

  $(document).ready(function(){
    module('Objectify.convert');

    var form = $('form').get(0),
        formObj = Objectify.convert(form);

    test('Object definitions', function() {
      ok(formObj.person, 'Person object exists');
      ok(formObj.person.name, 'Person has a name');
      ok(formObj.person.email, 'Person has an email');
      ok(formObj.person.address, 'Person has an Address');
      ok(formObj.person.address.street_address, 'Address has a street_address');
      ok(formObj.person.address.city, 'Address has a city');
      ok(formObj.person.address.state, 'Address has a state');
      ok(formObj.person.address.zip, 'Address has a zip');
      ok(formObj.person.authorizations, 'Authorizations object exists');
      ok(Object.isArray(formObj.person.authorizations), 'Authorizations is an array');
    });

    test('Object structure', function() {
      same(
        formObj,
        {
          "person": {
            "id": "1",
            "name": "Joe Blow",
            "email": "joe.blow@test.com",
            "address": {
              "street_address": "123 Somewhere St",
              "city": "Omaha",
              "state": "NE",
              "zip": "68144"
            },
            "authorizations": ["1", "2", "3"]
          }
        }
      );
    });
  });

})(jQuery);<commit_msg>Adding multiple forms test<commit_after>(function($) {

  $(document).ready(function(){
    module('Objectify.convert');

    var form = $('form').get(0),
        formObj = Objectify.convert(form);

    test('Object definitions', function() {
      ok(formObj.person, 'Person object exists');
      ok(formObj.person.name, 'Person has a name');
      ok(formObj.person.email, 'Person has an email');
      ok(formObj.person.address, 'Person has an Address');
      ok(formObj.person.address.street_address, 'Address has a street_address');
      ok(formObj.person.address.city, 'Address has a city');
      ok(formObj.person.address.state, 'Address has a state');
      ok(formObj.person.address.zip, 'Address has a zip');
      ok(formObj.person.authorizations, 'Authorizations object exists');
      ok(Object.isArray(formObj.person.authorizations), 'Authorizations is an array');
    });

    test('Object structure', function() {
      same(
        formObj,
        {
          "person": {
            "id": "1",
            "name": "Joe Blow",
            "email": "joe.blow@test.com",
            "address": {
              "street_address": "123 Somewhere St",
              "city": "Omaha",
              "state": "NE",
              "zip": "68144"
            },
            "authorizations": ["1", "2", "3"]
          }
        },
        "Object structure is generated as expected"
      );
    });

    test('Multiple forms', function() {
      same(Objectify.convert([form, form]), [formObj, formObj], "Multiple forms are processed correctly");
    });
  });

})(jQuery);<|endoftext|>


<commit_before>/*

Copyright (c) 2015 Hexagon <robinnilsson@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

var	Index = require("./index.js"),
	processors = require("./processors.js"),
	rankers = require("./rankers.js"),
	utils = require("./utils.js");

function processWord (word, opts) {
	var result,
		i;

	// Check if the word is too short
	if (!word || word.length < opts.minWordLen) {
		return;
	}

	// Check if the word is too long
	if (word.length > opts.maxWordLen) {
		word = word.substring(0, opts.maxWordLen);
	}

	// Always convert everything to lowercase if not case sensitive
	if (!opts.caseSensitive) {
		word = word.toLowerCase();
	}

	// Prepare object
	result = { original: word /*, processed: undefined*/ };

	// Apply all wordProcessors
	for (i = 0; i < opts.wordProcessors.length; i++) {
		if (!word) {
			break;
		}

		word = opts.wordProcessors[i](word);
	}

	// Check if the preprocessor disabled this word
	if (!word) {
		return;
	}

	// Save processed word
	result.processed = word;

	return result;
};

function Thinker (opts) {
	var self = this;

	// Optional `new` keyword
	if (!(self instanceof Thinker)) {
		return new Thinker(opts);
	}

	self.ranker = function() {};

	// All these options must be set before indexing and
	// cannot change afterwards (the object will also be frozen).
	self.options = utils.defaults({
		characters: /([a-zA-Z0-9]*)/g,
		caseSensitive: false,
		minWildcardWordLen: 4,
		maxWildcardWordLen: 32,
		minWordLen: 2,
		maxWordLen: 32,
		wordProcessors: [],
		fieldProcessors: [],
		suggestionMinWordCount: 6,
		enableSuggestions: false
	}, opts );

	// Changing settings after initializing the index would break things, we will try to prevent that
	Object.freeze(self.options);

	// Index backend
	self.index = new Index(self.options);

};

Thinker.prototype.feed = function (texts) {
	var self = this,
		opts = self.options,
		currentDocument,
		currentField,
		currentWord,
		i,j,k;

	// Helper function adding a single word to the index
	function addWord (word, docid, fieldIdx) {
		var wIndex,
			i, j;

		// Add original
		wIndex = self.index.populate(word, docid, fieldIdx);

		// Add processed
		self.index.populateProcessed(word.processed, wIndex);

		// Add partials
		for (i = opts.minWildcardWordLen; i < word.original.length && i < opts.maxWildcardWordLen; i++) {
			for (j = 0; j < (word.original.length - i) + 1; j++) {
				// Do not input partial if equals processed or equals original
				if( word.original.substr(j,i) !== word.processed && word.original.substr(j,i) !== word.original ) {
					self.index.populatePartial(word.original.substr(j, i), wIndex);
				}
			}
		}
	}

	/* Stage 1, query index for each individual word */
	while (currentDocument = texts.pop()) {

		// split text into separate words, removing empty results
		// Loop through all textfields (index > 0)
		for (j = 1 ; j < currentDocument.length; j++) {

			// Extract current field
			if ( (currentField = currentDocument[j]) ) {

				// Apply all fieldProcessors
				for (i = 0; i < opts.fieldProcessors.length; i++) {
					if (currentField) {
						currentField = opts.fieldProcessors[i](currentField);
					}
				}

				// Split field into separate words
				currentField = currentField.match(opts.characters);

				// Extract unique words
				for (k = 0; k < currentField.length; k++) {
					if (currentWord !== "" && (currentWord = processWord(currentField[k], opts))) {
						addWord(currentWord, currentDocument[0], j);
					}
				}
			}
		}
	}
};

Thinker.prototype.addFieldProcessor = function (fn) {
	return (this.options.fieldProcessors.push(fn), this);
};

Thinker.prototype.addWordProcessor = function (fn) {
	return (this.options.wordProcessors.push(fn), this);
};

Thinker.prototype.find = function (string) {

	utils.time("findTime");

	var self = this,

		// Extract valid parts of the expression
		words = string.split(" "),
		word,

		// Find matching texts
		resultSet = { expressions: [] },

		queryResult,
		suggestion,
		i;

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

		var modifier=undefined, exact=false;

		// Find modifiers, set flags, and remove their textual representation
		if ( ["+","-"].indexOf(words[i][0]) !== -1) {
			modifier = words[i][0];
			words[i] = words[i].substring(1,words[i].length);
		}

		// Trigger exact mode
		if ( words[i][0] == "\"" ) {
			exact = true;
		}
		words[i] = words[i].replace(/\"/g,"");

		// Normalize and validate word
		if (!(word = words[i]) || !(word = processWord(words[i], self.options))) {
			continue;
		}

		//
		queryResult = self.index.query(word, exact);

		// Enable suggestions if self.options.enableSuggestions is true
		suggestion = undefined;
		if (!queryResult.direct.length && self.options.enableSuggestions) {
			suggestion = self.index.findClosestWord(word.original);
		}

		// Push this expression to result array
		resultSet.expressions.push({
			interpretation: exact ? word.original : word.processed,
			original: word.original,
			suggestion: suggestion,
			modifier: modifier,
			exactMode: exact,
			hits: queryResult
		});

	}

	// Done finding
	resultSet.findTime = utils.time("findTime");

	// Start ranking
	utils.time("rankTime")
	resultSet.documents = self.ranker(resultSet,self.index.getWordCount());

	// Remove expression[m].hits from resultset, not needed anymore
	for (i = 0; i < resultSet.expressions.length; i++) {
		delete resultSet.expressions[i].hits;
	}

	// Done fanking
	resultSet.rankTime = utils.time("rankTime");

	return resultSet;
};

Thinker.processors = processors;
Thinker.rankers = rankers;

module.exports = Thinker;<commit_msg>Update Thinker.js<commit_after>/*

Copyright (c) 2015 Hexagon <robinnilsson@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

var	Index = require("./index.js"),
	processors = require("./processors.js"),
	rankers = require("./rankers.js"),
	utils = require("./utils.js");

function processWord (word, opts) {
	var result,
		i;

	// Check if the word is too short
	if (!word || word.length < opts.minWordLen) {
		return;
	}

	// Check if the word is too long
	if (word.length > opts.maxWordLen) {
		word = word.substring(0, opts.maxWordLen);
	}

	// Always convert everything to lowercase if not case sensitive
	if (!opts.caseSensitive) {
		word = word.toLowerCase();
	}

	// Prepare object
	result = { original: word, processed: undefined };

	// Apply all wordProcessors
	for (i = 0; i < opts.wordProcessors.length; i++) {
		if (!word) {
			break;
		}

		word = opts.wordProcessors[i](word);
	}

	// Check if the preprocessor disabled this word
	if (!word) {
		return;
	}

	// Save processed word
	result.processed = word;

	return result;
};

function Thinker (opts) {
	var self = this;

	// Optional `new` keyword
	if (!(self instanceof Thinker)) {
		return new Thinker(opts);
	}

	self.ranker = function() {};

	// All these options must be set before indexing and
	// cannot change afterwards (the object will also be frozen).
	self.options = utils.defaults({
		characters: /([a-zA-Z0-9]*)/g,
		caseSensitive: false,
		minWildcardWordLen: 4,
		maxWildcardWordLen: 32,
		minWordLen: 2,
		maxWordLen: 32,
		wordProcessors: [],
		fieldProcessors: [],
		suggestionMinWordCount: 6,
		enableSuggestions: false
	}, opts );

	// Changing settings after initializing the index would break things, we will try to prevent that
	Object.freeze(self.options);

	// Index backend
	self.index = new Index(self.options);

};

Thinker.prototype.feed = function (texts) {
	var self = this,
		opts = self.options,
		currentDocument,
		currentField,
		currentWord,
		i,j,k;

	// Helper function adding a single word to the index
	function addWord (word, docid, fieldIdx) {
		var wIndex,
			i, j;

		// Add original
		wIndex = self.index.populate(word, docid, fieldIdx);

		// Add processed
		self.index.populateProcessed(word.processed, wIndex);

		// Add partials
		for (i = opts.minWildcardWordLen; i < word.original.length && i < opts.maxWildcardWordLen; i++) {
			for (j = 0; j < (word.original.length - i) + 1; j++) {
				// Do not input partial if equals processed or equals original
				if( word.original.substr(j,i) !== word.processed && word.original.substr(j,i) !== word.original ) {
					self.index.populatePartial(word.original.substr(j, i), wIndex);
				}
			}
		}
	}

	/* Stage 1, query index for each individual word */
	while (currentDocument = texts.pop()) {

		// split text into separate words, removing empty results
		// Loop through all textfields (index > 0)
		for (j = 1 ; j < currentDocument.length; j++) {

			// Extract current field
			if ( (currentField = currentDocument[j]) ) {

				// Apply all fieldProcessors
				for (i = 0; i < opts.fieldProcessors.length; i++) {
					if (currentField) {
						currentField = opts.fieldProcessors[i](currentField);
					}
				}

				// Split field into separate words
				currentField = currentField.match(opts.characters);

				// Extract unique words
				for (k = 0; k < currentField.length; k++) {
					if (currentWord !== "" && (currentWord = processWord(currentField[k], opts))) {
						addWord(currentWord, currentDocument[0], j);
					}
				}
			}
		}
	}
};

Thinker.prototype.addFieldProcessor = function (fn) {
	return (this.options.fieldProcessors.push(fn), this);
};

Thinker.prototype.addWordProcessor = function (fn) {
	return (this.options.wordProcessors.push(fn), this);
};

Thinker.prototype.find = function (string) {

	utils.time("findTime");

	var self = this,

		// Extract valid parts of the expression
		words = string.split(" "),
		word,

		// Find matching texts
		resultSet = { expressions: [] },

		queryResult,
		suggestion,
		i;

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

		var modifier=undefined, exact=false;

		// Find modifiers, set flags, and remove their textual representation
		if ( ["+","-"].indexOf(words[i][0]) !== -1) {
			modifier = words[i][0];
			words[i] = words[i].substring(1,words[i].length);
		}

		// Trigger exact mode
		if ( words[i][0] == "\"" ) {
			exact = true;
		}
		words[i] = words[i].replace(/\"/g,"");

		// Normalize and validate word
		if (!(word = words[i]) || !(word = processWord(words[i], self.options))) {
			continue;
		}

		//
		queryResult = self.index.query(word, exact);

		// Enable suggestions if self.options.enableSuggestions is true
		suggestion = undefined;
		if (!queryResult.direct.length && self.options.enableSuggestions) {
			suggestion = self.index.findClosestWord(word.original);
		}

		// Push this expression to result array
		resultSet.expressions.push({
			interpretation: exact ? word.original : word.processed,
			original: word.original,
			suggestion: suggestion,
			modifier: modifier,
			exactMode: exact,
			hits: queryResult
		});

	}

	// Done finding
	resultSet.findTime = utils.time("findTime");

	// Start ranking
	utils.time("rankTime")
	resultSet.documents = self.ranker(resultSet,self.index.getWordCount());

	// Remove expression[m].hits from resultset, not needed anymore
	for (i = 0; i < resultSet.expressions.length; i++) {
		delete resultSet.expressions[i].hits;
	}

	// Done fanking
	resultSet.rankTime = utils.time("rankTime");

	return resultSet;
};

Thinker.processors = processors;
Thinker.rankers = rankers;

module.exports = Thinker;
<|endoftext|>


<commit_before>import { app, ipcMain } from 'electron'
import sqlite3 from 'sqlite3'
import path from 'path'
import url from 'url'
import rpc from 'pauls-electron-rpc'
import manifest from '../lib/rpc-manifests/bookmarks'
import { setupDatabase } from '../lib/bg/sqlite-tools'
import log from '../log'

// globals
// =
var db
var migrations
var waitForSetup

// exported methods
// =

export function setup () {
  // open database
  var dbPath = path.join(app.getPath('userData'), 'Bookmarks')
  db = new sqlite3.Database(dbPath)
  waitForSetup = setupDatabase(db, migrations, '[BOOKMARKS]')

  // wire up RPC
  rpc.exportAPI('bookmarks', manifest, { add, changeTitle, changeUrl, addVisit, remove, get, list })
}

export function add (url, title, cb) {
  waitForSetup(() => {
    db.run(`
      INSERT OR REPLACE
        INTO bookmarks (url, title, num_visits)
        VALUES (?, ?, 0)
    `, [url, title], cb)
  })
}

export function changeTitle (url, title, cb) {
  waitForSetup(() => {
    db.run(`UPDATE bookmarks SET title = ? WHERE url = ?`, [title, url], cb)
  })
}

export function changeUrl (oldUrl, newUrl, cb) {
  waitForSetup(() => {
    db.run(`UPDATE bookmarks SET url = ? WHERE url = ?`, [newUrl, oldUrl], cb)
  })
}

export function addVisit (url, cb) {
  waitForSetup(() => {
    db.run(`UPDATE bookmarks SET num_visits = num_visits + 1 WHERE url = ?`, url, cb)
  })
}

export function remove (url, cb) {
  waitForSetup(() => {
    db.run(`DELETE FROM bookmarks WHERE url = ?`, [url], cb)
  })
}

export function get (url, cb) {
  waitForSetup(() => {
    db.get(`SELECT url, title FROM bookmarks WHERE url = ?`, [url], cb)
  })
}

export function list (cb) {
  waitForSetup(() => {
    db.all(`SELECT url, title FROM bookmarks ORDER BY num_visits DESC`, cb)
  })
}

// internal methods
// =

migrations = [
  // version 1
  function (cb) {
    db.exec(`
      CREATE TABLE bookmarks(
        url NOT NULL,
        title
      );
      CREATE INDEX bookmarks_url ON bookmarks (url);
      INSERT INTO bookmarks (title, url) VALUES ('Beaker Browser', 'https://github.com/pfraze/beaker');
      INSERT INTO bookmarks (title, url) VALUES ('@pfrazee (ask for support!)', 'https://twitter.com/pfrazee');
      INSERT INTO bookmarks (title, url) VALUES ('Dat Protocol', 'http://dat-data.com/');
      INSERT INTO bookmarks (title, url) VALUES ('IPFS Protocol', 'https://ipfs.io/');
      INSERT INTO bookmarks (title, url) VALUES ('SQLite3', 'https://www.sqlite.org/');
      INSERT INTO bookmarks (title, url) VALUES ('DuckDuckGo (the default search engine)', 'https://duckduckgo.com');
      PRAGMA user_version = 1;
    `, cb)
  },
  // version 2
  function (cb) {
    db.exec(`
      ALTER TABLE bookmarks ADD COLUMN num_visits;
      UPDATE bookmarks SET num_visits = 0;
      PRAGMA user_version = 2;
    `, cb)
  },
]<commit_msg>update bookmarks<commit_after>import { app, ipcMain } from 'electron'
import sqlite3 from 'sqlite3'
import path from 'path'
import url from 'url'
import rpc from 'pauls-electron-rpc'
import manifest from '../lib/rpc-manifests/bookmarks'
import { setupDatabase } from '../lib/bg/sqlite-tools'
import log from '../log'

// globals
// =
var db
var migrations
var waitForSetup

// exported methods
// =

export function setup () {
  // open database
  var dbPath = path.join(app.getPath('userData'), 'Bookmarks')
  db = new sqlite3.Database(dbPath)
  waitForSetup = setupDatabase(db, migrations, '[BOOKMARKS]')

  // wire up RPC
  rpc.exportAPI('bookmarks', manifest, { add, changeTitle, changeUrl, addVisit, remove, get, list })
}

export function add (url, title, cb) {
  waitForSetup(() => {
    db.run(`
      INSERT OR REPLACE
        INTO bookmarks (url, title, num_visits)
        VALUES (?, ?, 0)
    `, [url, title], cb)
  })
}

export function changeTitle (url, title, cb) {
  waitForSetup(() => {
    db.run(`UPDATE bookmarks SET title = ? WHERE url = ?`, [title, url], cb)
  })
}

export function changeUrl (oldUrl, newUrl, cb) {
  waitForSetup(() => {
    db.run(`UPDATE bookmarks SET url = ? WHERE url = ?`, [newUrl, oldUrl], cb)
  })
}

export function addVisit (url, cb) {
  waitForSetup(() => {
    db.run(`UPDATE bookmarks SET num_visits = num_visits + 1 WHERE url = ?`, url, cb)
  })
}

export function remove (url, cb) {
  waitForSetup(() => {
    db.run(`DELETE FROM bookmarks WHERE url = ?`, [url], cb)
  })
}

export function get (url, cb) {
  waitForSetup(() => {
    db.get(`SELECT url, title FROM bookmarks WHERE url = ?`, [url], cb)
  })
}

export function list (cb) {
  waitForSetup(() => {
    db.all(`SELECT url, title FROM bookmarks ORDER BY num_visits DESC`, cb)
  })
}

// internal methods
// =

migrations = [
  // version 1
  function (cb) {
    db.exec(`
      CREATE TABLE bookmarks(
        url NOT NULL,
        title
      );
      CREATE INDEX bookmarks_url ON bookmarks (url);
      INSERT INTO bookmarks (title, url) VALUES ('Hostless.Website', 'dat://hostless.website');
      INSERT INTO bookmarks (title, url) VALUES ('Beaker Browser', 'https://github.com/pfrazee/beaker');
      INSERT INTO bookmarks (title, url) VALUES ('@pfrazee (ask for support!)', 'https://twitter.com/pfrazee');
      INSERT INTO bookmarks (title, url) VALUES ('Dat Protocol', 'http://dat-data.com/');
      INSERT INTO bookmarks (title, url) VALUES ('DuckDuckGo (the default search engine)', 'https://duckduckgo.com');
      PRAGMA user_version = 1;
    `, cb)
  },
  // version 2
  function (cb) {
    db.exec(`
      ALTER TABLE bookmarks ADD COLUMN num_visits;
      UPDATE bookmarks SET num_visits = 0;
      PRAGMA user_version = 2;
    `, cb)
  }
]<|endoftext|>


<commit_before>console.log("Starting pt-flow server");

require("./modules/helpers.js"); // no return
var     express = require("express"),
           http = require("http"),
      xmlParser = require("./modules/xml-parser.js"),
         routes = require("./modules/routes.js"),
          mongo = require("./modules/mongo-helper.js");

// Set to global so we can call useToken once (below)
global.pivotal = require("pivotal");

var app = express();

// Config and middleware
app.configure(function () {
    process.env["NODE_ENV"] = (process.env["NODE_ENV"] || "production");

    app.set("port", process.env.PORT || 5000);
    app.set("views", __dirname + "/views");
    app.set("view engine", "jade");
    app.use(express.logger("dev"));
    app.use(xmlParser);
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser("huADnaQnwJXbh3A49VFA"));
    app.use(express.session());
    app.use(app.router);
    app.use(express.static(__dirname + "/public"));
});

// Error handling
app.configure("dev", function () {
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure("production", function () {
    app.use(express.errorHandler());
});

// Pivotal Tracker API token
if (!process.env["PT_TOKEN"] || !process.env["PT_TOKEN"].length) {
    throw Error("No Pivotal Tracker token is set in the env var: \"PT_TOKEN\". This is required to process activity web hooks!");
}

// Mongo DB connection info
var mongoInfo = mongo.parseConnectionURI(process.env["MONGO_DB_URL"]);
if (!mongoInfo) {
    throw Error("Either no MongoDB connection URL was provided or it was invalid. Please place one in an environment variable (\"MONGO_DB_URL\") with the format: [protocol][username:password@]host[:port]/database");
}

// GETs
app.get("/", routes.index);
//app.get("/stats/:id", routes.hasToken, routes.getStatsForProject);

// POSTs
app.post("/projects", routes.getProjects);
//app.post("/activity-hook", routes.hasToken, routes.activityHook);

http.createServer(app).listen(app.get("port"), function () {
  console.log("pt-flow server listening on port " + app.get("port"));
});
<commit_msg>Added POST index route (same as GET) and GET for /projects Also changed the "server lsitening" console message<commit_after>console.log("Starting pt-flow server");

require("./modules/helpers.js"); // no return
var     express = require("express"),
           http = require("http"),
      xmlParser = require("./modules/xml-parser.js"),
         routes = require("./modules/routes.js"),
          mongo = require("./modules/mongo-helper.js");

// Set to global so we can call useToken once (below)
global.pivotal = require("pivotal");

var app = express();

// Config and middleware
app.configure(function () {
    process.env["NODE_ENV"] = (process.env["NODE_ENV"] || "production");

    app.set("port", process.env.PORT || 5000);
    app.set("views", __dirname + "/views");
    app.set("view engine", "jade");
    app.use(express.logger("dev"));
    app.use(xmlParser);
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser("huADnaQnwJXbh3A49VFA"));
    app.use(express.session());
    app.use(app.router);
    app.use(express.static(__dirname + "/public"));
});

// Error handling
app.configure("dev", function () {
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure("production", function () {
    app.use(express.errorHandler());
});

// Pivotal Tracker API token
if (!process.env["PT_TOKEN"] || !process.env["PT_TOKEN"].length) {
    throw Error("No Pivotal Tracker token is set in the env var: \"PT_TOKEN\". This is required to process activity web hooks!");
}

// Mongo DB connection info
var mongoInfo = mongo.parseConnectionURI(process.env["MONGO_DB_URL"]);
if (!mongoInfo) {
    throw Error("Either no MongoDB connection URL was provided or it was invalid. Please place one in an environment variable (\"MONGO_DB_URL\") with the format: [protocol][username:password@]host[:port]/database");
}

// GETs
app.get("/", routes.index);
app.get("/projects", routes.hasToken, routes.listProjects);
//app.get("/stats/:id", routes.hasToken, routes.getStatsForProject);

// POSTs
app.post("/", routes.index);
app.post("/projects", routes.getProjects);
//app.post("/activity-hook", routes.hasToken, routes.activityHook);

http.createServer(app).listen(app.get("port"), function () {
  console.log("pt-cfd server listening on port " + app.get("port"));
});
<|endoftext|>


<commit_before>describe('Login Form', function () {
    beforeEach(function () {
        browser.get('/app');
    });

    describe('basics', function () {
        it('should display the correct page title', function () {
            expect(browser.getTitle()).toBe('Log in');
        });

        it('should display the forgot password link', function () {
            var forgotLink = element(by.linkText('Forgot your password?'));
            expect(forgotLink.isPresent()).toBe(true);
        });
    });
});
<commit_msg>Exercise 1 Answer Code<commit_after>describe('Login Form', function () {
    beforeEach(function () {
        browser.get('/app');
    });

    describe('basics', function () {
        it('should display the correct page title', function () {
            expect(browser.getTitle()).toBe('Log in');
        });

        it('should display the forgot password link', function () {
            var forgotLink = element(by.linkText('Forgot your password?'));
            expect(forgotLink.isPresent()).toBe(true);
        });

        it('should display the expected submit button text', function () {
            var submitBtn = element(by.buttonText('Log in'));
            expect(submitBtn.isPresent()).toBe(true);
        });

        it('should go to /forgot when clicking the forgot link', function () {
            element(by.linkText('Forgot your password?')).click();
            expect(browser.getLocationAbsUrl()).toBe('/forgot');
        });
    });
});
<|endoftext|>