<commit_before>export { NeuralWorker_Proxies as Proxies };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import * as GSheets from "../../til/GSheets.js";
//import * as ValueMax from "../../util/ValueMax.js";
import * as NeuralNet from "../../Conv/NeuralNet.js";
import { Proxy as NeuralWorker_Proxy } from "./NeuralWorker_Proxy.js";
import { Mode as NeuralWorker_Mode } from "./NeuralWorker_Mode.js";

//!!! ...unfinished... (2022/05/25)
// Perhaps, Using SharedArrayBuffer to pass input image between different web worker.
//

/**
 * The container of WorkerProxy. It orchestrates these WorkerProxy. Especially, it
 * transfers (scaled) source image data to and from web worker. This could maximize
 * parallel computing under the restriction transferring source image data to every
 * web worker serially.
 *
 *
 * 1. For NeuralWorker_Mode.Singleton.Ids.ONE_WORKER__Xxx
 *
 * Since it is slow to transfer data between CPU and GPU (for WebGL), it seems not
 * feasible to use multiple workers (which will transfer data between CPU and GPU
 * multiple times) to process both competition side of an diffential evolution
 * iteration.
 *
 * So these ONE_WORKER__Xxx mode combine two neural networks of both competition
 * sides in one web worker. Although they compute serially (not parallelly), they
 * still may be faster than compute them in two worker because the reduced memory
 * transferring between CPU and GPU.
 *
 *
 * 2. For NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__Xxx
 *
 * Every worker handles one neural network. When .ImageData_process_async() is called,
 * the input (usually a large memory block) will be transffered to the 1st worker to
 * start computing, and then transffered to the 2nd worker to start computing, ... etc.
 *
 * When passing large data by Worker.postMessage(), it is preferred by transferring
 * (not by copying). If the large data wants to be transferred (not copied) to many
 * workers, the only possible way is to transferring them serially.
 *
 * However, serially transferring hurts the performance. Workers are better to compute
 * parallelly. So every worker should transfer the (possible scaled) source image data
 * back to this WorkerProxies, and keep computing neural network at the same time. And
 * then, this WorkerProxies will transfer the source image data to the next worker
 * as soon as possible.
 *
 * Finally, this WorkerProxies collects all web workers' results in a promise. The
 * promise will resolve with an array of Float32Array. Every Float32Array is the
 * output of one neural network.
 *
 *
 *
 * @member {number} nNeuralWorker_ModeId
 *   The numeric identifier of neural worker mode (i.e.
 * NeuralWorker.Mode.Singleton.Ids.Xxx).
 *
 * @member {number} neuralNetCount
 *   There are how many neural networks created. It is always 2 (because of differential
 * evolution) no matter how totalWorkerCount is.
 *
 * @member {number} totalWorkerCount
 *   There are how many web worker(s) created.
 *
 * @member {function} ImageData_process_async
 *   This is a data member which is a pointer to a function. The function accepts
 * ImageData as input. It returns a promise resolved to an array
 * [ Float32Array, Float32Array ] representing the neural networks' results.
 */
class NeuralWorker_Proxies extends Recyclable.Root {

  /**
   * Used as default NeuralWorker.Proxies provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "NeuralWorker.Proxies.Pool",
    NeuralWorker_Proxies, NeuralWorker_Proxies.setAsConstructor );

  /** */
  constructor() {
    super();
    NeuralWorker_Proxies.setAsConstructor_self.call( this );
  }

  /** @override */
  static setAsConstructor() {
    super.setAsConstructor();
    NeuralWorker_Proxies.setAsConstructor_self.call( this );
    return this;
  }

  /** @override */
  static setAsConstructor_self() {
  }

  /** @override */
  disposeResources() {
    this.ImageData_process_async = undefined;

    this.workerProxyArray_dispose();

    this.hardwareConcurrency = undefined;
    this.neuralNetCount = undefined;

    this.nNeuralWorker_ModeId = undefined;

    super.disposeResources();
  }

  /**
   * Initialize this worker proxy controller. It will create two neural networks in
   * one or two web worker(s).
   *
   *
   * @param {string} backendName
   *   Specify which backend should be used by tensorflow.js library.
   *
   * @return {Promise}
   *   Return a promise:
   *   - Resolved to true, if success.
   *   - Resolved to false, if failed.
   */
  async init_async( nNeuralWorker_ModeId, backendName = "webgl" ) {

    // 0.
    this.nNeuralWorker_ModeId = nNeuralWorker_ModeId;

    this.neuralNetCount = 2; // Always two neural network (for differential evolution).
    this.hardwareConcurrency = navigator.hardwareConcurrency; // logical CPU count.

    // Two web workers are sufficient.
    //
    // Although we might want create as many web worker as logical CPU count, it might
    // not need because our neural networks are learning by differential evolution.
    // Differential evolution evaluates just two entities every time.
    //
    // Note1: How could the two neural networks determine all the actions of so many
    //        game objects? The method is to let the output of one neural network
    //        contains all actions of all game objects.
    //
    // Note2: For NeuralWorker_Mode whose ( bFill == false ), only half of the output
    //        actions (i.e. actions of one alignment in the game world) will be used
    //        in one time.
    //
    let totalWorkerCount = NeuralWorker_Mode.workerCount_get( nNeuralWorker_ModeId );

    // 1. Web workers.
    let initOkArray;
    {
      // 1.0 Prepare container of all worker proxy.
      {
        if ( this.workerProxyArray )
          this.workerProxyArray.clear(); // Release old worker proxy.
        else
          this.workerProxyArray = Recyclable.OwnerArray.Pool.get_or_create_by();

        this.workerProxyArray.length = totalWorkerCount;
      }

      // 1.1 Create workers.
      let initPromiseArray = new Array( totalWorkerCount );
      for ( let i = 0; i < totalWorkerCount; ++i ) {
        this.workerProxyArray[ i ] = NeuralWorker_Proxy.Pool.get_or_create_by();
        initPromiseArray[ i ] = this.workerProxyArray[ i ].initWorker_async(
          i, backendName );
      }

      initOkArray = await Promise.all( initPromiseArray );
    }

    // 1.2 Summary workers.
    let initOk = initOkArray.reduce(
      ( previousValue, currentValue ) => ( previousValue && currentValue ),
      true
    );

    // 2. Determine .ImageData_process_async
    NeuralWorker_Proxies.setup_ImageData_process.call( this );

    return initOk;
  }

  /** */
  workerProxyArray_dispose() {
    if ( this.workerProxyArray ) {
      this.workerProxyArray.disposeResources_and_recycleToPool();
      this.workerProxyArray = null;
    }
  }

  /**
   * Create neural networks in the web worker body.
   *
   * @param {NeuralNet.ParamsBase[]} neuralNetParamsBaseArray
   *   An array of configurations for the neural network to be created. These
   * configurations (exclude the array) will be owned (i.e. kept and destroyed)
   * by this NeuralWorker.Proxy.
   *
   * @param {ArrayBuffer[]} weightArrayBufferArray
   *   An array of every neural network's weights. Every element  will be interpreted
   * as Float32Array.
   *
   * @return {Promise}
   *   Return a promise:
   *   - Resolved to true, if success.
   *   - Resolved to false, if failed.
   */
  async NeuralNetArray_create_async( neuralNetParamsBaseArray, weightArrayBufferArray ) {

    if ( neuralNetParamsBaseArray.length != this.neuralNetCount )
      throw Error( `NeuralWorker.Proxies.NeuralNetArray_create_async(): `
        + `neuralNetParamsBaseArray.length ( ${neuralNetParamsBaseArray.length} ) `
        + `should be ${this.neuralNetCount}.`
      );

    if ( weightArrayBufferArray.length != this.neuralNetCount )
      throw Error( `NeuralWorker.Proxies.NeuralNetArray_create_async(): `
        + `weightArrayBufferArray.length ( ${weightArrayBufferArray.length} ) `
        + `should be ${this.neuralNetCount}.`
      );

    let createOk;

    // 1. Every worker create one neural network.
    if ( this.workerProxyArray.length > 1 ) { // (i.e. two workers)

      let createPromiseArray = new Array( this.workerProxyArray.length );
      for ( let i = 0; i < this.workerProxyArray.length; ++i ) {
        createPromiseArray[ i ] = this.workerProxyArray[ i ].NeuralNetArray_create_async(
          [ neuralNetParamsBaseArray[ i ] ], [ weightArrayBufferArray[ i ] ] );
      }

      let createOkArray = await Promise.all( createPromiseArray );

      createOk = createOkArray.reduce(
        ( previousValue, currentValue ) => ( previousValue && currentValue ),
        true
      );

    // 2. The only worker creates all neural networks.
    } else {
      createOk = await this.workerProxyArray[ 0 ].NeuralNetArray_create_async(
        neuralNetParamsBaseArray, weightArrayBufferArray );
    }

    return createOk;
  }

  /**
   * @param {integer[]} markValueArray
   *   An array of values representing every neural network playing which alignment.
   *
   * @return {Promise}
   *   Return a promise:
   *   - Resolved to true, if success.
   *   - Resolved to false, if failed.
   */
  async alignmentMarkArray_setValue_async( markValueArray ) {

    if ( markValueArray.length != this.neuralNetCount )
      throw Error( `NeuralWorker.Proxies.alignmentMarkArray_setValue_async(): `
        + `markValueArray.length ( ${markValueArray.length} ) `
        + `should be ${this.neuralNetCount}.`
      );

    let resultOk;

    // 1. Every worker set one alignment mark value.
    if ( this.workerProxyArray.length > 1 ) { // (i.e. two workers)

      let resultPromiseArray = new Array( this.workerProxyArray.length );
      for ( let i = 0; i < this.workerProxyArray.length; ++i ) {
        resultPromiseArray[ i ]
          = this.workerProxyArray[ i ].alignmentMarkArray_setValue_async(
            [ markValueArray[ i ] ] );
      }

      let resultOkArray = await Promise.all( resultPromiseArray );

      resultOk = resultOkArray.reduce(
        ( previousValue, currentValue ) => ( previousValue && currentValue ),
        true
      );

    // 2. The only worker sets all alignment mark values.
    } else {
      resultOk = await this.workerProxyArray[ 0 ].alignmentMarkArray_setValue_async(
        markValueArray );
    }

    return resultOk;
  }

  /**
   * Setup .ImageData_process_async according to .nNeuralWorker_ModeId.
   *
   * @param {NeuralWorker_Proxies} this
   */
  static setup_ImageData_process() {
    switch ( this.nNeuralWorker_ModeId ) {
      case NeuralWorker_Mode.Singleton.Ids.ONE_WORKER__ONE_SCALE__FILL: // (0)
      case NeuralWorker_Mode.Singleton.Ids.ONE_WORKER__ONE_SCALE__NO_FILL: // (1)
        this.ImageData_process_async
          = NeuralWorker_Proxies.apply__ONE_WORKER__ONE_SCALE__FILL__OR__NO_FILL;
        break;

      case NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__ONE_SCALE__FILL: // (2)
      case NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__ONE_SCALE__NO_FILL: // (3)
        this.ImageData_process_async
          = NeuralWorker_Proxies.apply__TWO_WORKER__ONE_SCALE__FILL__OR__NO_FILL;
        break;

      case NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__TWO_SCALE__NO_FILL: // (4)
        this.ImageData_process_async
          = NeuralWorker_Proxies.apply__TWO_WORKER__TWO_SCALE__NO_FILL;
        break;

      default:
        throw Error( `NeuralWorker_Proxies.setup_apply(): `
          + `Unknown nNeuralWorker_ModeId ( ${nNeuralWorker_ModeId} ).`
        );
        break;
    }
  }

  /** */
  static async apply__ONE_WORKER__ONE_SCALE__FILL__OR__NO_FILL( sourceImageData ) {
    let bFill = NeuralWorker_Mode.bFill_get( this.nNeuralWorker_ModeId );

    let worker0_promise = this.workerProxyArray[ 0 ]
      .ImageData_scale_once_process_multiple_async( sourceImageData, bFill );

    let worker0_value_Float32ArrayArray = await worker0_promise;
    return worker0_value_Float32ArrayArray;
  }

  /** */
  static async apply__TWO_WORKER__ONE_SCALE__FILL__OR__NO_FILL( sourceImageData ) {
    let bFill = NeuralWorker_Mode.bFill_get( this.nNeuralWorker_ModeId );

!!!???    bApply_or_Applier

    let worker0_resulter = this.workerProxyArray[ 0 ]
      .ImageData_scale_fork_fillable_process_asyncGenerator( sourceImageData, bFill );

    let { done: worker0_done_false, value: worker0_value_Int32Array }
      = await worker0_resulter.next();

    let worker1_promise = this.workerProxyArray[ 1 ]
      .Int32Array_fillable_process_async( worker0_value_Int32Array, bFill );

    let [
      { done: worker0_done_true, value: worker0_value_Float32Array },
      worker1_value_Float32Array
    ] = await Promise.all( [ worker0_resulter.next(), worker1_promise ] );

    return [ worker0_value_Float32Array, worker1_value_Float32Array ];
  }

  /** */
  static async apply__TWO_WORKER__TWO_SCALE__NO_FILL( sourceImageData ) {
    const worker0_bFork = true;
    const worker1_bFork = false;

    let worker0_resulter = this.workerProxyArray[ 0 ]
      .ImageData_scale_forkable_process_asyncGenerator(
        sourceImageData, worker0_bFork );

    let { done: worker0_done_false, value: worker0_value_ImageData }
      = await worker0_resulter.next();

    let worker1_resulter = this.workerProxyArray[ 1 ]
      .ImageData_scale_forkable_process_asyncGenerator(
        worker0_value_ImageData, worker1_bFork );

    let [
      { done: worker0_done_true, value: worker0_value_Float32Array },
      { done: worker1_done_true, value: worker1_value_Float32Array },
    ] = await Promise.all( [ worker0_resulter.next(), worker1_resulter.next() ] );

    return [ worker0_value_Float32Array, worker1_value_Float32Array ];
  }

  get totalWorkerCount() {
    return this.workerProxyArray.length;
  }

}

<commit_msg>setup_ImageData_process<commit_after>export { NeuralWorker_Proxies as Proxies };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import * as GSheets from "../../til/GSheets.js";
//import * as ValueMax from "../../util/ValueMax.js";
import * as NeuralNet from "../../Conv/NeuralNet.js";
import { Proxy as NeuralWorker_Proxy } from "./NeuralWorker_Proxy.js";
import { Mode as NeuralWorker_Mode } from "./NeuralWorker_Mode.js";

//!!! ...unfinished... (2022/05/25)
// Perhaps, Using SharedArrayBuffer to pass input image between different web worker.
//

/**
 * The container of WorkerProxy. It orchestrates these WorkerProxy. Especially, it
 * transfers (scaled) source image data to and from web worker. This could maximize
 * parallel computing under the restriction transferring source image data to every
 * web worker serially.
 *
 *
 * 1. For NeuralWorker_Mode.Singleton.Ids.ONE_WORKER__Xxx
 *
 * Since it is slow to transfer data between CPU and GPU (for WebGL), it seems not
 * feasible to use multiple workers (which will transfer data between CPU and GPU
 * multiple times) to process both competition side of an diffential evolution
 * iteration.
 *
 * So these ONE_WORKER__Xxx mode combine two neural networks of both competition
 * sides in one web worker. Although they compute serially (not parallelly), they
 * still may be faster than compute them in two worker because the reduced memory
 * transferring between CPU and GPU.
 *
 *
 * 2. For NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__Xxx
 *
 * Every worker handles one neural network. When .ImageData_process_async() is called,
 * the input (usually a large memory block) will be transffered to the 1st worker to
 * start computing, and then transffered to the 2nd worker to start computing, ... etc.
 *
 * When passing large data by Worker.postMessage(), it is preferred by transferring
 * (not by copying). If the large data wants to be transferred (not copied) to many
 * workers, the only possible way is to transferring them serially.
 *
 * However, serially transferring hurts the performance. Workers are better to compute
 * parallelly. So every worker should transfer the (possible scaled) source image data
 * back to this WorkerProxies, and keep computing neural network at the same time. And
 * then, this WorkerProxies will transfer the source image data to the next worker
 * as soon as possible.
 *
 * Finally, this WorkerProxies collects all web workers' results in a promise. The
 * promise will resolve with an array of Float32Array. Every Float32Array is the
 * output of one neural network.
 *
 *
 *
 * @member {number} nNeuralWorker_ModeId
 *   The numeric identifier of neural worker mode (i.e.
 * NeuralWorker.Mode.Singleton.Ids.Xxx).
 *
 * @member {number} neuralNetCount
 *   There are how many neural networks created. It is always 2 (because of differential
 * evolution) no matter how totalWorkerCount is.
 *
 * @member {number} totalWorkerCount
 *   There are how many web worker(s) created.
 *
 * @member {function} ImageData_process_async
 *   This is a data member which is a pointer to a function. The function accepts
 * ImageData as input. It returns a promise resolved to an array
 * [ Float32Array, Float32Array ] representing the neural networks' results.
 */
class NeuralWorker_Proxies extends Recyclable.Root {

  /**
   * Used as default NeuralWorker.Proxies provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "NeuralWorker.Proxies.Pool",
    NeuralWorker_Proxies, NeuralWorker_Proxies.setAsConstructor );

  /** */
  constructor() {
    super();
    NeuralWorker_Proxies.setAsConstructor_self.call( this );
  }

  /** @override */
  static setAsConstructor() {
    super.setAsConstructor();
    NeuralWorker_Proxies.setAsConstructor_self.call( this );
    return this;
  }

  /** @override */
  static setAsConstructor_self() {
  }

  /** @override */
  disposeResources() {
    this.ImageData_process_async = undefined;

    this.workerProxyArray_dispose();

    this.hardwareConcurrency = undefined;
    this.neuralNetCount = undefined;

    this.nNeuralWorker_ModeId = undefined;

    super.disposeResources();
  }

  /**
   * Initialize this worker proxy controller. It will create two neural networks in
   * one or two web worker(s).
   *
   *
   * @param {string} backendName
   *   Specify which backend should be used by tensorflow.js library.
   *
   * @return {Promise}
   *   Return a promise:
   *   - Resolved to true, if success.
   *   - Resolved to false, if failed.
   */
  async init_async( nNeuralWorker_ModeId, backendName = "webgl" ) {

    // 0.
    this.nNeuralWorker_ModeId = nNeuralWorker_ModeId;

    this.neuralNetCount = 2; // Always two neural network (for differential evolution).
    this.hardwareConcurrency = navigator.hardwareConcurrency; // logical CPU count.

    // Two web workers are sufficient.
    //
    // Although we might want create as many web worker as logical CPU count, it might
    // not need because our neural networks are learning by differential evolution.
    // Differential evolution evaluates just two entities every time.
    //
    // Note1: How could the two neural networks determine all the actions of so many
    //        game objects? The method is to let the output of one neural network
    //        contains all actions of all game objects.
    //
    // Note2: For NeuralWorker_Mode whose ( bFill == false ), only half of the output
    //        actions (i.e. actions of one alignment in the game world) will be used
    //        in one time.
    //
    let totalWorkerCount = NeuralWorker_Mode.workerCount_get( nNeuralWorker_ModeId );

    // 1. Web workers.
    let initOkArray;
    {
      // 1.0 Prepare container of all worker proxy.
      {
        if ( this.workerProxyArray )
          this.workerProxyArray.clear(); // Release old worker proxy.
        else
          this.workerProxyArray = Recyclable.OwnerArray.Pool.get_or_create_by();

        this.workerProxyArray.length = totalWorkerCount;
      }

      // 1.1 Create workers.
      let initPromiseArray = new Array( totalWorkerCount );
      for ( let i = 0; i < totalWorkerCount; ++i ) {
        this.workerProxyArray[ i ] = NeuralWorker_Proxy.Pool.get_or_create_by();
        initPromiseArray[ i ] = this.workerProxyArray[ i ].initWorker_async(
          i, backendName );
      }

      initOkArray = await Promise.all( initPromiseArray );
    }

    // 1.2 Summary workers.
    let initOk = initOkArray.reduce(
      ( previousValue, currentValue ) => ( previousValue && currentValue ),
      true
    );

    // 2. Determine .ImageData_process_async
    NeuralWorker_Proxies.setup_ImageData_process.call( this );

    return initOk;
  }

  /** */
  workerProxyArray_dispose() {
    if ( this.workerProxyArray ) {
      this.workerProxyArray.disposeResources_and_recycleToPool();
      this.workerProxyArray = null;
    }
  }

  /**
   * Create neural networks in the web worker body.
   *
   * @param {NeuralNet.ParamsBase[]} neuralNetParamsBaseArray
   *   An array of configurations for the neural network to be created. These
   * configurations (exclude the array) will be owned (i.e. kept and destroyed)
   * by this NeuralWorker.Proxy.
   *
   * @param {ArrayBuffer[]} weightArrayBufferArray
   *   An array of every neural network's weights. Every element  will be interpreted
   * as Float32Array.
   *
   * @return {Promise}
   *   Return a promise:
   *   - Resolved to true, if success.
   *   - Resolved to false, if failed.
   */
  async NeuralNetArray_create_async( neuralNetParamsBaseArray, weightArrayBufferArray ) {

    if ( neuralNetParamsBaseArray.length != this.neuralNetCount )
      throw Error( `NeuralWorker.Proxies.NeuralNetArray_create_async(): `
        + `neuralNetParamsBaseArray.length ( ${neuralNetParamsBaseArray.length} ) `
        + `should be ${this.neuralNetCount}.`
      );

    if ( weightArrayBufferArray.length != this.neuralNetCount )
      throw Error( `NeuralWorker.Proxies.NeuralNetArray_create_async(): `
        + `weightArrayBufferArray.length ( ${weightArrayBufferArray.length} ) `
        + `should be ${this.neuralNetCount}.`
      );

    let createOk;

    // 1. Every worker create one neural network.
    if ( this.workerProxyArray.length > 1 ) { // (i.e. two workers)

      let createPromiseArray = new Array( this.workerProxyArray.length );
      for ( let i = 0; i < this.workerProxyArray.length; ++i ) {
        createPromiseArray[ i ] = this.workerProxyArray[ i ].NeuralNetArray_create_async(
          [ neuralNetParamsBaseArray[ i ] ], [ weightArrayBufferArray[ i ] ] );
      }

      let createOkArray = await Promise.all( createPromiseArray );

      createOk = createOkArray.reduce(
        ( previousValue, currentValue ) => ( previousValue && currentValue ),
        true
      );

    // 2. The only worker creates all neural networks.
    } else {
      createOk = await this.workerProxyArray[ 0 ].NeuralNetArray_create_async(
        neuralNetParamsBaseArray, weightArrayBufferArray );
    }

    return createOk;
  }

  /**
   * @param {integer[]} markValueArray
   *   An array of values representing every neural network playing which alignment.
   *
   * @return {Promise}
   *   Return a promise:
   *   - Resolved to true, if success.
   *   - Resolved to false, if failed.
   */
  async alignmentMarkArray_setValue_async( markValueArray ) {

    if ( markValueArray.length != this.neuralNetCount )
      throw Error( `NeuralWorker.Proxies.alignmentMarkArray_setValue_async(): `
        + `markValueArray.length ( ${markValueArray.length} ) `
        + `should be ${this.neuralNetCount}.`
      );

    let resultOk;

    // 1. Every worker set one alignment mark value.
    if ( this.workerProxyArray.length > 1 ) { // (i.e. two workers)

      let resultPromiseArray = new Array( this.workerProxyArray.length );
      for ( let i = 0; i < this.workerProxyArray.length; ++i ) {
        resultPromiseArray[ i ]
          = this.workerProxyArray[ i ].alignmentMarkArray_setValue_async(
            [ markValueArray[ i ] ] );
      }

      let resultOkArray = await Promise.all( resultPromiseArray );

      resultOk = resultOkArray.reduce(
        ( previousValue, currentValue ) => ( previousValue && currentValue ),
        true
      );

    // 2. The only worker sets all alignment mark values.
    } else {
      resultOk = await this.workerProxyArray[ 0 ].alignmentMarkArray_setValue_async(
        markValueArray );
    }

    return resultOk;
  }

  /**
   * Setup .ImageData_process_async according to .nNeuralWorker_ModeId.
   *
   * @param {NeuralWorker_Proxies} this
   */
  static setup_ImageData_process() {

//!!! ...unfinished... (2022/09/22)
    // *   -  0: ONE_WORKER__ONE_SCALE__FILL
    // *   -  1: ONE_WORKER__ONE_SCALE__NO_FILL
    // *
    // *   -  2: TWO_WORKER__ONE_SCALE__FILL__APPLY
    // *   -  3: TWO_WORKER__ONE_SCALE__FILL__APPLIER
    // *
    // *   -  4: TWO_WORKER__ONE_SCALE__NO_FILL__APPLY
    // *   -  5: TWO_WORKER__ONE_SCALE__NO_FILL__APPLIER
    //
    // *   -  6: TWO_WORKER__TWO_SCALE__NO_FILL

    switch ( this.nNeuralWorker_ModeId ) {
      case NeuralWorker_Mode.Singleton.Ids.ONE_WORKER__ONE_SCALE__FILL: // (0)
      case NeuralWorker_Mode.Singleton.Ids.ONE_WORKER__ONE_SCALE__NO_FILL: // (1)
        this.ImageData_process_async
          = NeuralWorker_Proxies.apply__ONE_WORKER__ONE_SCALE__FILL__OR__NO_FILL;
        break;

      case NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__ONE_SCALE__FILL: // (2)
      case NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__ONE_SCALE__NO_FILL: // (3)
        this.ImageData_process_async
          = NeuralWorker_Proxies.apply__TWO_WORKER__ONE_SCALE__FILL__OR__NO_FILL;
        break;

      case NeuralWorker_Mode.Singleton.Ids.TWO_WORKER__TWO_SCALE__NO_FILL: // (4)
        this.ImageData_process_async
          = NeuralWorker_Proxies.apply__TWO_WORKER__TWO_SCALE__NO_FILL;
        break;

      default:
        throw Error( `NeuralWorker_Proxies.setup_apply(): `
          + `Unknown nNeuralWorker_ModeId ( ${nNeuralWorker_ModeId} ).`
        );
        break;
    }
  }

  /** */
  static async apply__ONE_WORKER__ONE_SCALE__FILL__OR__NO_FILL( sourceImageData ) {
    let bFill = NeuralWorker_Mode.bFill_get( this.nNeuralWorker_ModeId );

    let worker0_promise = this.workerProxyArray[ 0 ]
      .ImageData_scale_once_process_multiple_async( sourceImageData, bFill );

    let worker0_value_Float32ArrayArray = await worker0_promise;
    return worker0_value_Float32ArrayArray;
  }

  /** */
  static async apply__TWO_WORKER__ONE_SCALE__FILL__OR__NO_FILL( sourceImageData ) {
    let bFill = NeuralWorker_Mode.bFill_get( this.nNeuralWorker_ModeId );

!!!???    bApply_or_Applier

    let worker0_resulter = this.workerProxyArray[ 0 ]
      .ImageData_scale_fork_fillable_process_asyncGenerator( sourceImageData, bFill );

    let { done: worker0_done_false, value: worker0_value_Int32Array }
      = await worker0_resulter.next();

    let worker1_promise = this.workerProxyArray[ 1 ]
      .Int32Array_fillable_process_async( worker0_value_Int32Array, bFill );

    let [
      { done: worker0_done_true, value: worker0_value_Float32Array },
      worker1_value_Float32Array
    ] = await Promise.all( [ worker0_resulter.next(), worker1_promise ] );

    return [ worker0_value_Float32Array, worker1_value_Float32Array ];
  }

  /** */
  static async apply__TWO_WORKER__TWO_SCALE__NO_FILL( sourceImageData ) {
    const worker0_bFork = true;
    const worker1_bFork = false;

    let worker0_resulter = this.workerProxyArray[ 0 ]
      .ImageData_scale_forkable_process_asyncGenerator(
        sourceImageData, worker0_bFork );

    let { done: worker0_done_false, value: worker0_value_ImageData }
      = await worker0_resulter.next();

    let worker1_resulter = this.workerProxyArray[ 1 ]
      .ImageData_scale_forkable_process_asyncGenerator(
        worker0_value_ImageData, worker1_bFork );

    let [
      { done: worker0_done_true, value: worker0_value_Float32Array },
      { done: worker1_done_true, value: worker1_value_Float32Array },
    ] = await Promise.all( [ worker0_resulter.next(), worker1_resulter.next() ] );

    return [ worker0_value_Float32Array, worker1_value_Float32Array ];
  }

  get totalWorkerCount() {
    return this.workerProxyArray.length;
  }

}

<|endoftext|>


<commit_before>var Plugins = function(bot){
	this.bot = bot;
	this.hooks = {};
	this.plugins = {};
};
Plugins.prototype = {
	load: function(plugins){
		for(plugin in plugins){
			var tempPlugin = require('./plugins/'+plugin);
			if(typeof tempPlugin == 'object'){
				if(plugins[plugin]){
					tempPlugin.name = plugin;
					tempPlugin.config = plugins[plugin];
				}
				tempPlugin.init(this, this.bot);
			}
			this.plugins[plugin] = tempPlugin;
		}
	},
	isPluginFunction: function(plugin, func){
		return !!(plugin && this.plugins[plugin] && this.plugins[plugin][func] && typeof this.plugins[plugin][func] == 'function');
	},
	listen: function(plugin, event, func){
		if(typeof this.hooks[plugin.name] == 'undefined'){
			this.hooks[plugin.name] = [];
		}
		this.hooks[plugin.name][event] = func;
	},
	fire: function(event, passedVars){
		var hooks = this.hooks;
		var self = this;
		for (plugin in hooks){
			if(hooks[plugin]){
				if(typeof hooks[plugin][event] == 'function'){
					hooks[plugin][event].apply(self, [passedVars]);
				}
			}
		}
	}
};
exports.Plugins = Plugins;
<commit_msg>tplugins<commit_after>var Plugins = function(bot){
	this.bot = bot;
	this.hooks = {};
	this.sets = {};
	this.plugins = {};
};
Plugins.prototype = {
	load: function(plugins){
		for(plugin in plugins){
			var tempPlugin = require('./plugins/'+plugin);
			if(typeof tempPlugin == 'object'){
				if(plugins[plugin]){
					tempPlugin.name = plugin;
					tempPlugin.config = plugins[plugin];
				}
				tempPlugin.init(this, this.bot);
			}
			this.plugins[plugin] = tempPlugin;
		}
	},
	isPluginFunction: function(plugin, func){
		return !!(plugin && this.plugins[plugin] && this.plugins[plugin][func] && typeof this.plugins[plugin][func] == 'function');
	},
	listen: function(plugin, event, func){
		if(this.hooks[plugin.name] == undefined){
			this.hooks[plugin.name] = [];
		}
		this.hooks[plugin.name][event] = func;
	},
	registerSet: function(plugin, name){
		if(this.sets[name] == undefined){
			this.sets[name] = [];
		}
		this.sets[name][plugin.name] = plugin;
	},
	handleSet: function(){
		for(set in sets){
			if(sets[set]){
			}
		}
	},
	fire: function(event, passedVars){
		var hooks = this.hooks;
		var self = this;
		for (plugin in hooks){
			if(hooks[plugin]){
				if(typeof hooks[plugin][event] == 'function'){
					hooks[plugin][event].apply(self, [passedVars]);
				}
			}
		}
	}
};
exports.Plugins = Plugins;
<|endoftext|>


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

  console.log('preload');
  const electron = require('electron');

  const Attachment = require('./js/modules/types/attachment');
  const Attachments = require('./app/attachments');
  const Message = require('./js/modules/types/message');

  const { app } = electron.remote;

  window.PROTO_ROOT = 'protos';
  window.config = require('url').parse(window.location.toString(), true).query;
  window.wrapDeferred = function(deferred) {
    return new Promise(function(resolve, reject) {
      deferred.then(resolve, reject);
    });
  };

  const ipc = electron.ipcRenderer;
  window.config.localeMessages = ipc.sendSync('locale-data');

  window.setBadgeCount = function(count) {
    ipc.send('set-badge-count', count);
  };
  window.drawAttention = function() {
    console.log('draw attention');
    ipc.send('draw-attention');
  };
  window.showWindow = function() {
    console.log('show window');
    ipc.send('show-window');
  };
  window.setAutoHideMenuBar = function(autoHide) {
    ipc.send('set-auto-hide-menu-bar', autoHide);
  };
  window.setMenuBarVisibility = function(visibility) {
    ipc.send('set-menu-bar-visibility', visibility);
  };
  window.restart = function() {
    console.log('restart');
    ipc.send('restart');
  };
  window.closeAbout = function() {
    ipc.send('close-about');
  };
  window.updateTrayIcon = function(unreadCount) {
    ipc.send('update-tray-icon', unreadCount);
  };

  ipc.on('debug-log', function() {
    Whisper.events.trigger('showDebugLog');
  });

  ipc.on('set-up-with-import', function() {
    Whisper.events.trigger('setupWithImport');
  });

  ipc.on('set-up-as-new-device', function() {
    Whisper.events.trigger('setupAsNewDevice');
  });

  ipc.on('set-up-as-standalone', function() {
    Whisper.events.trigger('setupAsStandalone');
  });

  ipc.on('show-settings', function() {
    Whisper.events.trigger('showSettings');
  });

  window.addSetupMenuItems = function() {
    ipc.send('add-setup-menu-items');
  }

  window.removeSetupMenuItems = function() {
    ipc.send('remove-setup-menu-items');
  }

  // We pull these dependencies in now, from here, because they have Node.js dependencies

  require('./js/logging');

  if (window.config.proxyUrl) {
    console.log('using proxy url', window.config.proxyUrl);
  }

  window.nodeSetImmediate = setImmediate;
  window.nodeWebSocket = require("websocket").w3cwebsocket;

  // Linux seems to periodically let the event loop stop, so this is a global workaround
  setInterval(function() {
    window.nodeSetImmediate(function() {});
  }, 1000);

  window.dataURLToBlobSync = require('blueimp-canvas-to-blob');
  window.loadImage = require('blueimp-load-image');
  window.ProxyAgent = require('proxy-agent');
  window.EmojiConvertor = require('emoji-js');
  window.emojiData = require('emoji-datasource');
  window.nodeFetch = require('node-fetch');
  window.nodeBuffer = Buffer;
  window.EmojiPanel = require('emoji-panel');
  window.libphonenumber = require('google-libphonenumber').PhoneNumberUtil.getInstance();
  window.libphonenumber.PhoneNumberFormat = require('google-libphonenumber').PhoneNumberFormat;
  window.nodeNotifier = require('node-notifier');

  const { autoOrientImage } = require('./js/modules/auto_orient_image');
  window.autoOrientImage = autoOrientImage;

  // ES2015+ modules
  const attachmentsPath = Attachments.getPath(app.getPath('userData'));
  const deleteAttachmentData = Attachments.deleteData(attachmentsPath);
  const readAttachmentData = Attachments.readData(attachmentsPath);
  const writeAttachmentData = Attachments.writeData(attachmentsPath);

  // Injected context functions to keep `Message` agnostic from Electron:
  const upgradeSchemaContext = {
    writeAttachmentData,
  };
  const upgradeMessageSchema = message =>
    Message.upgradeSchema(message, upgradeSchemaContext);

  const { IdleDetector} = require('./js/modules/idle_detector');

  window.Signal = window.Signal || {};
  window.Signal.Backup = require('./js/modules/backup');
  window.Signal.Crypto = require('./js/modules/crypto');
  window.Signal.Logs = require('./js/modules/logs');
  window.Signal.Migrations = {};
  window.Signal.Migrations.loadAttachmentData = Attachment.loadData(readAttachmentData);
  window.Signal.Migrations.deleteAttachmentData = Attachment.deleteData(deleteAttachmentData);
  window.Signal.Migrations.upgradeMessageSchema = upgradeMessageSchema;
  window.Signal.Migrations.V17 = require('./js/modules/migrations/17');
  window.Signal.OS = require('./js/modules/os');
  window.Signal.Types = window.Signal.Types || {};
  window.Signal.Types.Attachment = Attachment;
  window.Signal.Types.Errors = require('./js/modules/types/errors');
  window.Signal.Types.Message = Message;
  window.Signal.Types.MIME = require('./js/modules/types/mime');
  window.Signal.Types.Settings = require('./js/modules/types/settings');
  window.Signal.Workflow = {};
  window.Signal.Workflow.IdleDetector = IdleDetector;
  window.Signal.Workflow.MessageDataMigrator =
    require('./js/modules/messages_data_migrator');

  // We pull this in last, because the native module involved appears to be sensitive to
  //   /tmp mounted as noexec on Linux.
  require('./js/spell_check');
})();
<commit_msg>Make namespace generation clearer<commit_after>(function () {
  'use strict';

  console.log('preload');
  const electron = require('electron');

  const Attachment = require('./js/modules/types/attachment');
  const Attachments = require('./app/attachments');
  const Message = require('./js/modules/types/message');

  const { app } = electron.remote;

  window.PROTO_ROOT = 'protos';
  window.config = require('url').parse(window.location.toString(), true).query;
  window.wrapDeferred = function(deferred) {
    return new Promise(function(resolve, reject) {
      deferred.then(resolve, reject);
    });
  };

  const ipc = electron.ipcRenderer;
  window.config.localeMessages = ipc.sendSync('locale-data');

  window.setBadgeCount = function(count) {
    ipc.send('set-badge-count', count);
  };
  window.drawAttention = function() {
    console.log('draw attention');
    ipc.send('draw-attention');
  };
  window.showWindow = function() {
    console.log('show window');
    ipc.send('show-window');
  };
  window.setAutoHideMenuBar = function(autoHide) {
    ipc.send('set-auto-hide-menu-bar', autoHide);
  };
  window.setMenuBarVisibility = function(visibility) {
    ipc.send('set-menu-bar-visibility', visibility);
  };
  window.restart = function() {
    console.log('restart');
    ipc.send('restart');
  };
  window.closeAbout = function() {
    ipc.send('close-about');
  };
  window.updateTrayIcon = function(unreadCount) {
    ipc.send('update-tray-icon', unreadCount);
  };

  ipc.on('debug-log', function() {
    Whisper.events.trigger('showDebugLog');
  });

  ipc.on('set-up-with-import', function() {
    Whisper.events.trigger('setupWithImport');
  });

  ipc.on('set-up-as-new-device', function() {
    Whisper.events.trigger('setupAsNewDevice');
  });

  ipc.on('set-up-as-standalone', function() {
    Whisper.events.trigger('setupAsStandalone');
  });

  ipc.on('show-settings', function() {
    Whisper.events.trigger('showSettings');
  });

  window.addSetupMenuItems = function() {
    ipc.send('add-setup-menu-items');
  }

  window.removeSetupMenuItems = function() {
    ipc.send('remove-setup-menu-items');
  }

  // We pull these dependencies in now, from here, because they have Node.js dependencies

  require('./js/logging');

  if (window.config.proxyUrl) {
    console.log('using proxy url', window.config.proxyUrl);
  }

  window.nodeSetImmediate = setImmediate;
  window.nodeWebSocket = require("websocket").w3cwebsocket;

  // Linux seems to periodically let the event loop stop, so this is a global workaround
  setInterval(function() {
    window.nodeSetImmediate(function() {});
  }, 1000);

  window.dataURLToBlobSync = require('blueimp-canvas-to-blob');
  window.loadImage = require('blueimp-load-image');
  window.ProxyAgent = require('proxy-agent');
  window.EmojiConvertor = require('emoji-js');
  window.emojiData = require('emoji-datasource');
  window.nodeFetch = require('node-fetch');
  window.nodeBuffer = Buffer;
  window.EmojiPanel = require('emoji-panel');
  window.libphonenumber = require('google-libphonenumber').PhoneNumberUtil.getInstance();
  window.libphonenumber.PhoneNumberFormat = require('google-libphonenumber').PhoneNumberFormat;
  window.nodeNotifier = require('node-notifier');

  const { autoOrientImage } = require('./js/modules/auto_orient_image');
  window.autoOrientImage = autoOrientImage;

  // ES2015+ modules
  const attachmentsPath = Attachments.getPath(app.getPath('userData'));
  const deleteAttachmentData = Attachments.deleteData(attachmentsPath);
  const readAttachmentData = Attachments.readData(attachmentsPath);
  const writeAttachmentData = Attachments.writeData(attachmentsPath);

  // Injected context functions to keep `Message` agnostic from Electron:
  const upgradeSchemaContext = {
    writeAttachmentData,
  };
  const upgradeMessageSchema = message =>
    Message.upgradeSchema(message, upgradeSchemaContext);

  const { IdleDetector} = require('./js/modules/idle_detector');

  window.Signal = {};
  window.Signal.Backup = require('./js/modules/backup');
  window.Signal.Crypto = require('./js/modules/crypto');
  window.Signal.Logs = require('./js/modules/logs');
  window.Signal.Migrations = {};
  window.Signal.Migrations.loadAttachmentData = Attachment.loadData(readAttachmentData);
  window.Signal.Migrations.deleteAttachmentData = Attachment.deleteData(deleteAttachmentData);
  window.Signal.Migrations.upgradeMessageSchema = upgradeMessageSchema;
  window.Signal.Migrations.V17 = require('./js/modules/migrations/17');
  window.Signal.OS = require('./js/modules/os');
  window.Signal.Types = {};
  window.Signal.Types.Attachment = Attachment;
  window.Signal.Types.Errors = require('./js/modules/types/errors');
  window.Signal.Types.Message = Message;
  window.Signal.Types.MIME = require('./js/modules/types/mime');
  window.Signal.Types.Settings = require('./js/modules/types/settings');
  window.Signal.Workflow = {};
  window.Signal.Workflow.IdleDetector = IdleDetector;
  window.Signal.Workflow.MessageDataMigrator =
    require('./js/modules/messages_data_migrator');

  // We pull this in last, because the native module involved appears to be sensitive to
  //   /tmp mounted as noexec on Linux.
  require('./js/spell_check');
})();
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

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.
*/

Function.prototype.bind = function (obj) {
  var fun = this;
  return function() {
      return fun.apply(obj, arguments);
    };
};

Function.bind = function(obj, name) {
  return obj[name].bind(obj);
}

print = Function.bind(IO.stdout, 'print');
<commit_msg>Prelude: add functions for creating arrays<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

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.
*/

Array.from = function(iterable) {
  if (!iterable)
    return [];
  if (iterable.toArray)
    return iterable.toArray();
  return Array.slice(iterable, 0);
}

String.prototype.toArray = function () {
  return this.split(/\s+/);
};

Function.prototype.bind = function (obj) {
  var fun = this;
  return function() {
      return fun.apply(obj, arguments);
    };
};

Function.bind = function(obj, name) {
  return obj[name].bind(obj);
}

print = Function.bind(IO.stdout, 'print');
<|endoftext|>


<commit_before>var _param = require('./param.json');

var sys = require('sys')
var exec = require('child_process').exec;
var child;

var pollInterval = _param.pollInterval || 3000;
var processes = _param.processes;

var _os = require('os');
var _source = _os.hostname();

function numProcessRunning(processName){
	child = exec("ps -ef | grep splunk | wc -l", function (error, stdout, stderr) {
        var proc = stdout - 2;
	var host = processName + "-" + _source;
        console.log('BOUNDARY_PROCESS_RUNNING %d %s', proc, host);
	});
}

function poll()
{
	for(var i = 0; i < processes.length; i++)
	{
		numProcessRunning(processes[i]);
	}
}

setInterval(poll, pollInterval);
<commit_msg>testing some ways of splitting processes<commit_after>var _param = require('./param.json');

var sys = require('sys')
var exec = require('child_process').exec;
var child;

var pollInterval = _param.pollInterval || 3000;
var processes = _param.processes;

var _os = require('os');
var _source = _os.hostname();

function numProcessRunning(processName){
	child = exec("ps -ef | grep splunk | wc -l", function (error, stdout, stderr) {
        var proc = stdout - 2;
	var host = processName + "-" + _source;
        console.log('BOUNDARY_PROCESS_RUNNING %d %s %s', proc, host, processName);
	});
}

function poll()
{
	for(var i = 0; i < processes.length; i++)
	{
		numProcessRunning(processes[i]);
	}
}

setInterval(poll, pollInterval);
<|endoftext|>


<commit_before>define([
  'client/preprocessors/visualisation_fallback'
], function (visualisationFallback) {
  describe('Module actions', function () {

    var originalModernizr = visualisationFallback.Modernizr;

    var el;
    beforeEach(function () {
      visualisationFallback.Modernizr = {};
      el = $('
original content
');
      $('body').append(el);
    });

    afterEach(function () {
      visualisationFallback.Modernizr = originalModernizr;
      $('.visualisation-inner').remove();
    });

    it('does nothing when the browser supports SVG', function () {
      visualisationFallback.Modernizr.inlinesvg = true;
      visualisationFallback();
      expect(el.html()).toEqual('original content');
    });

    it('replaces the fallback container content with a fallback image', function () {
      visualisationFallback.Modernizr.inlinesvg = false;
      visualisationFallback();

      waitsFor(function () {
        return (el.html() !== 'original content');
      });

      runs(function () {
        expect(el.html()).toEqual('');
      });
    });
  });
});
<commit_msg>Fix tests for image fallbacks<commit_after>define([
  'client/preprocessors/visualisation_fallback',
  'modernizr'
], function (visualisationFallback, Modernizr) {
  describe('Module actions', function () {

    var el;
    beforeEach(function () {
      el = $('
original content
');
      $('body').append(el);
    });

    afterEach(function () {
      $('.visualisation-inner').remove();
    });

    it('does nothing when the browser supports SVG', function () {
      Modernizr.inlinesvg = true;
      visualisationFallback();
      expect(el.html()).toEqual('original content');
    });

    it('replaces the fallback container content with a fallback image', function () {
      Modernizr.inlinesvg = false;
      visualisationFallback();

      waitsFor(function () {
        return (el.html() !== 'original content');
      });

      runs(function () {
        expect(el.html()).toEqual('');
      });
    });
  });
});
<|endoftext|>


<commit_before>var async = require('async');
var utility = require('./utility');
var convert64to32 = utility.convert64to32;
var queueReq = utility.queueReq;
var computePlayerMatchData = require('./compute').computePlayerMatchData;
var zlib = require('zlib');
var aggregator = require('./aggregator');
var reduceMatch = utility.reduceMatch;
var config = require('./config');

function getSets(redis, cb) {
    async.parallel({
        "bots": function(cb) {
            redis.get("bots", function(err, bots) {
                bots = JSON.parse(bots || "[]");
                //sort list of bots descending, but full bots go to end (concentrates load)
                /*
                bots.sort(function(a, b) {
                    var threshold = 50;
                    if (a.friends > threshold) {
                        return 1;
                    }
                    if (b.friends > threshold) {
                        return -1;
                    }
                    return (b.friends - a.friends);
                });
                */
                //sort ascending (distributes load)
                bots.sort(function(a, b) {
                    return a.friends - b.friends;
                });
                cb(err, bots);
            });
        },
        "ratingPlayers": function(cb) {
            redis.get("ratingPlayers", function(err, rps) {
                cb(err, JSON.parse(rps || "{}"));
            });
        },
        "trackedPlayers": function(cb) {
            redis.get("trackedPlayers", function(err, tps) {
                cb(err, JSON.parse(tps || "{}"));
            });
        },
        "userPlayers": function(cb) {
            redis.get("userPlayers", function(err, ups) {
                cb(err, JSON.parse(ups || "{}"));
            });
        },
        "donators": function(cb) {
            redis.get("donators", function(err, ds) {
                cb(err, JSON.parse(ds || "{}"));
            });
        }
    }, function(err, results) {
        cb(err, results);
    });
}

function insertMatch(db, redis, queue, match, options, cb) {
    var players = match.players ? JSON.parse(JSON.stringify(match.players)) : undefined;
    delete match.players;
    //options specify api, parse, or skill
    //we want to insert into matches, then insert into player_matches for each entry in players
    async.series([insertMatchTable, insertPlayerMatchesTable, ensurePlayers, updatePlayerCaches, clearMatchCache], decideParse);

    function insertMatchTable(cb) {
        var row = match;
        //TODO support upsert
        if (options.type === "api") {
            db('matches').insert(row).where({
                match_id: row.match_id
            }).asCallback(cb);
        }
        else {
            db('matches').update(row).where({
                match_id: row.match_id
            }).asCallback(cb);
        }
    }

    function insertPlayerMatchesTable(cb) {
        //we can skip this if we have no players (skill case)
        async.each(players || [], function(pm, cb) {
            var row = pm;
            row.match_id = match.match_id;
            //TODO support upsert
            if (options.type === "api") {
                db('player_matches').insert(row).where({
                    match_id: row.match_id,
                    player_slot: row.player_slot
                }).asCallback(cb);
            }
            else {
                db('player_matches').update(row).where({
                    match_id: row.match_id,
                    player_slot: row.player_slot
                }).asCallback(cb);
            }
        }, cb);
    }

    function ensurePlayers(cb) {
        async.each(players || [], function(p, cb) {
            insertPlayer(db, p, cb);
        }, cb);
    }

    function updatePlayerCaches(cb) {
        async.each(players || options.players, function(player_match, cb) {
            //put match fields into each player to form player_match
            for (var key in match) {
                player_match[key] = match[key];
            }
            redis.get("player:" + player_match.account_id, function(err, result) {
                if (err) {
                    return cb(err);
                }
                //if player cache doesn't exist, skip
                var cache = result ? JSON.parse(zlib.inflateSync(new Buffer(result, 'base64'))) : null;
                if (cache) {
                    if (options.type !== "skill") {
                        var reInsert = player_match.match_id in cache.aggData.match_ids && options.type === "api";
                        var reParse = player_match.match_id in cache.aggData.parsed_match_ids && options.type === "parsed";
                        if (!reInsert && !reParse) {
                            computePlayerMatchData(player_match);
                            var group = {};
                            group[player_match.match_id] = players;
                            cache.aggData = aggregator([player_match], group, options.type, cache.aggData);
                        }
                    }
                    //reduce match to save cache space--we only need basic data per match for matches tab
                    player_match = reduceMatch(player_match);
                    var identifier = [player_match.match_id, player_match.player_slot].join(':');
                    var orig = cache.data[identifier];
                    if (!orig) {
                        cache.data[player_match.match_id] = player_match;
                    }
                    else {
                        //iterate instead of setting directly to avoid clobbering existing data
                        for (var key in player_match) {
                            orig[key] = player_match[key];
                        }
                    }
                    redis.ttl("player:" + player_match.account_id, function(err, ttl) {
                        if (err) {
                            return cb(err);
                        }
                        redis.setex("player:" + player_match.account_id, Number(ttl) > 0 ? Number(ttl) : 24 * 60 * 60 * config.UNTRACK_DAYS, zlib.deflateSync(JSON.stringify(cache)).toString('base64'));
                    });
                }
                return cb();
            });
        }, cb);
    }

    function clearMatchCache(cb) {
        redis.del("match:" + match.match_id, cb);
    }

    function decideParse(err) {
        if (err) {
            return cb(err);
        }
        if (match.parse_status !== 0) {
            //not parsing this match
            //this isn't a error, although we want to report that we refused to parse back to user if it was a request
            return cb();
        }
        else {
            var options = match.request ? {
                priority: "high",
                attempts: 1,
                ttl: 120 * 1000
            } : {
                ttl: 120 * 1000
            };
            //queue it and finish
            return queueReq(queue, "parse", match, options, function(err, job2) {
                cb(err, job2);
            });
        }
    }
}

function insertMatchProgress(db, redis, queue, match, options, cb) {
    //pass job in options to match API of insertMatch
    var job = options.job;
    insertMatch(db, redis, queue, match, options, function(err, job2) {
        if (err) {
            return cb(err);
        }
        if (!job2) {
            //succeeded in API, but decided not to parse this replay
            job.progress(100, 100, "This replay is unavailable.");
            cb();
        }
        else {
            //wait for parse to finish
            job.progress(0, 100, "Parsing replay...");
            //request, parse and log the progress
            job2.on('progress', function(prog) {
                job.progress(prog, 100);
            });
            job2.on('failed', function(err) {
                cb(err);
            });
            job2.on('complete', function() {
                job.progress(100, 100, "Parse complete!");
                redis.setex("requested_match:" + match.match_id, 60 * 60 * 24, "1");
                cb();
            });
        }
    });
}

function insertPlayer(db, player, cb) {
    player.account_id = player.account_id || Number(convert64to32(player.steamid));
    db('players').columnInfo().asCallback(function(err, info) {
        if (err) {
            return cb(err);
        }
        var row = {};
        for (var key in info) {
            row[key] = player[key];
        }
        //TODO support upsert to avoid crashing on relogs
        db('players').insert(row).asCallback(function(err) {
            return cb(err, row);
        });
    });
}

function insertPlayerRating(db, rating, cb) {
    db('player_ratings').columnInfo().asCallback(function(err, info) {
        if (err) {
            return cb(err);
        }
        var row = {};
        for (var key in row) {
            row[key] = rating[key];
        }
        db('player_ratings').insert(row).asCallback(cb);
    });
}
module.exports = {
    getSets: getSets,
    insertPlayer: insertPlayer,
    insertMatch: insertMatch,
    insertMatchProgress: insertMatchProgress,
    insertPlayerRating: insertPlayerRating
};
<commit_msg>removed kue ttl<commit_after>var async = require('async');
var utility = require('./utility');
var convert64to32 = utility.convert64to32;
var queueReq = utility.queueReq;
var computePlayerMatchData = require('./compute').computePlayerMatchData;
var zlib = require('zlib');
var aggregator = require('./aggregator');
var reduceMatch = utility.reduceMatch;
var config = require('./config');

function getSets(redis, cb) {
    async.parallel({
        "bots": function(cb) {
            redis.get("bots", function(err, bots) {
                bots = JSON.parse(bots || "[]");
                //sort list of bots descending, but full bots go to end (concentrates load)
                /*
                bots.sort(function(a, b) {
                    var threshold = 50;
                    if (a.friends > threshold) {
                        return 1;
                    }
                    if (b.friends > threshold) {
                        return -1;
                    }
                    return (b.friends - a.friends);
                });
                */
                //sort ascending (distributes load)
                bots.sort(function(a, b) {
                    return a.friends - b.friends;
                });
                cb(err, bots);
            });
        },
        "ratingPlayers": function(cb) {
            redis.get("ratingPlayers", function(err, rps) {
                cb(err, JSON.parse(rps || "{}"));
            });
        },
        "trackedPlayers": function(cb) {
            redis.get("trackedPlayers", function(err, tps) {
                cb(err, JSON.parse(tps || "{}"));
            });
        },
        "userPlayers": function(cb) {
            redis.get("userPlayers", function(err, ups) {
                cb(err, JSON.parse(ups || "{}"));
            });
        },
        "donators": function(cb) {
            redis.get("donators", function(err, ds) {
                cb(err, JSON.parse(ds || "{}"));
            });
        }
    }, function(err, results) {
        cb(err, results);
    });
}

function insertMatch(db, redis, queue, match, options, cb) {
    var players = match.players ? JSON.parse(JSON.stringify(match.players)) : undefined;
    delete match.players;
    //options specify api, parse, or skill
    //we want to insert into matches, then insert into player_matches for each entry in players
    async.series([insertMatchTable, insertPlayerMatchesTable, ensurePlayers, updatePlayerCaches, clearMatchCache], decideParse);

    function insertMatchTable(cb) {
        var row = match;
        //TODO support upsert
        if (options.type === "api") {
            db('matches').insert(row).where({
                match_id: row.match_id
            }).asCallback(cb);
        }
        else {
            db('matches').update(row).where({
                match_id: row.match_id
            }).asCallback(cb);
        }
    }

    function insertPlayerMatchesTable(cb) {
        //we can skip this if we have no players (skill case)
        async.each(players || [], function(pm, cb) {
            var row = pm;
            row.match_id = match.match_id;
            //TODO support upsert
            if (options.type === "api") {
                db('player_matches').insert(row).where({
                    match_id: row.match_id,
                    player_slot: row.player_slot
                }).asCallback(cb);
            }
            else {
                db('player_matches').update(row).where({
                    match_id: row.match_id,
                    player_slot: row.player_slot
                }).asCallback(cb);
            }
        }, cb);
    }

    function ensurePlayers(cb) {
        async.each(players || [], function(p, cb) {
            insertPlayer(db, p, cb);
        }, cb);
    }

    function updatePlayerCaches(cb) {
        async.each(players || options.players, function(player_match, cb) {
            //put match fields into each player to form player_match
            for (var key in match) {
                player_match[key] = match[key];
            }
            redis.get("player:" + player_match.account_id, function(err, result) {
                if (err) {
                    return cb(err);
                }
                //if player cache doesn't exist, skip
                var cache = result ? JSON.parse(zlib.inflateSync(new Buffer(result, 'base64'))) : null;
                if (cache) {
                    if (options.type !== "skill") {
                        var reInsert = player_match.match_id in cache.aggData.match_ids && options.type === "api";
                        var reParse = player_match.match_id in cache.aggData.parsed_match_ids && options.type === "parsed";
                        if (!reInsert && !reParse) {
                            computePlayerMatchData(player_match);
                            var group = {};
                            group[player_match.match_id] = players;
                            cache.aggData = aggregator([player_match], group, options.type, cache.aggData);
                        }
                    }
                    //reduce match to save cache space--we only need basic data per match for matches tab
                    player_match = reduceMatch(player_match);
                    var identifier = [player_match.match_id, player_match.player_slot].join(':');
                    var orig = cache.data[identifier];
                    if (!orig) {
                        cache.data[player_match.match_id] = player_match;
                    }
                    else {
                        //iterate instead of setting directly to avoid clobbering existing data
                        for (var key in player_match) {
                            orig[key] = player_match[key];
                        }
                    }
                    redis.ttl("player:" + player_match.account_id, function(err, ttl) {
                        if (err) {
                            return cb(err);
                        }
                        redis.setex("player:" + player_match.account_id, Number(ttl) > 0 ? Number(ttl) : 24 * 60 * 60 * config.UNTRACK_DAYS, zlib.deflateSync(JSON.stringify(cache)).toString('base64'));
                    });
                }
                return cb();
            });
        }, cb);
    }

    function clearMatchCache(cb) {
        redis.del("match:" + match.match_id, cb);
    }

    function decideParse(err) {
        if (err) {
            return cb(err);
        }
        if (match.parse_status !== 0) {
            //not parsing this match
            //this isn't a error, although we want to report that we refused to parse back to user if it was a request
            return cb();
        }
        else {
            var options = match.request ? {
                priority: "high",
                attempts: 1
            } : {};
            //queue it and finish
            return queueReq(queue, "parse", match, options, function(err, job2) {
                cb(err, job2);
            });
        }
    }
}

function insertMatchProgress(db, redis, queue, match, options, cb) {
    //pass job in options to match API of insertMatch
    var job = options.job;
    insertMatch(db, redis, queue, match, options, function(err, job2) {
        if (err) {
            return cb(err);
        }
        if (!job2) {
            //succeeded in API, but decided not to parse this replay
            job.progress(100, 100, "This replay is unavailable.");
            cb();
        }
        else {
            //wait for parse to finish
            job.progress(0, 100, "Parsing replay...");
            //request, parse and log the progress
            job2.on('progress', function(prog) {
                job.progress(prog, 100);
            });
            job2.on('failed', function(err) {
                cb(err);
            });
            job2.on('complete', function() {
                job.progress(100, 100, "Parse complete!");
                redis.setex("requested_match:" + match.match_id, 60 * 60 * 24, "1");
                cb();
            });
        }
    });
}

function insertPlayer(db, player, cb) {
    player.account_id = player.account_id || Number(convert64to32(player.steamid));
    db('players').columnInfo().asCallback(function(err, info) {
        if (err) {
            return cb(err);
        }
        var row = {};
        for (var key in info) {
            row[key] = player[key];
        }
        //TODO support upsert to avoid crashing on relogs
        db('players').insert(row).asCallback(function(err) {
            return cb(err, row);
        });
    });
}

function insertPlayerRating(db, rating, cb) {
    db('player_ratings').columnInfo().asCallback(function(err, info) {
        if (err) {
            return cb(err);
        }
        var row = {};
        for (var key in row) {
            row[key] = rating[key];
        }
        db('player_ratings').insert(row).asCallback(cb);
    });
}
module.exports = {
    getSets: getSets,
    insertPlayer: insertPlayer,
    insertMatch: insertMatch,
    insertMatchProgress: insertMatchProgress,
    insertPlayerRating: insertPlayerRating
};
<|endoftext|>


<commit_before>/* globals Promise */

'use strict';

const logger = require('../../config/logger');

module.exports = function (organizationsData, userData) {
  function index(req, res) {
    const page = +req.query.page || 0;
    const size = +req.query.size || 5;

    organizationsData.findPage(page, size)
      .then(([organizations, pageCount]) => {
        const pagination = {
          active: +pageCount > 1,
          pageSize: size,
          previous: {
            active: +page > 0,
            value: +page - 1
          },
          next: {
            active: +page < +pageCount - 1,
            value: +page + 1
          }
        };

        res.render('./organizations/index', {
          isAuthenticated: req.isAuthenticated(),
          result: {
            user: req.user,
            organizations,
            pagination
          }
        });
      })
      .catch((err) => {
        res.redirect('/error');
      });
  }

  function search(req, res) {
    const isAuthenticated = req.isAuthenticated();

    organizationsData.getOrganizationsWhichContains(req.query.search)
      .then((organizations) => {
        return res
          .status(200)
          .render('./organizations/organizations-list', {
            isAuthenticated,
            result: {
              data: organizations,
              user: req.user
            }
          });
      });
  }

  function details(req, res) {
    const organizationId = req.params.organizationId;
    const isAuthenticated = req.isAuthenticated();

    organizationsData.findById(organizationId)
      .then((organization) => {
        if (!organization) {
          res.redirect('/organizations/not-found');
        }

        const user = req.user;

        let isMember;
        if (user) {
          isMember = user.organization.name === organization.name;
        }

        res.render('./organizations/details', {
          result: {
            user,
            isMember,
            organization
          },
          isAuthenticated
        });
      })
      .catch((err) => {
        // TODO: Log error.
        res.send(err.message);
      });
  }

  function createOrganizationForm(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.redirect('/account/login');
    }

    return res.render('./organizations/create', {
      isAuthenticated,
      result: {
        user: req.user
      }
    });
  }

  function createOrganization(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.redirect('/account/login');
    }

    const inputOrganization = req.body;
    const owners = [{
      username: req.user.username,
      ownerId: req.user._id
    }];

    inputOrganization.owners = owners;

    return organizationsData.createOrganization(inputOrganization)
      .then((organization) => {
        const user = req.user;
        user.organization = {
          name: organization.name,
          organizationId: organization._id
        };

        return userData.updateUser(user);
      })
      .then((user) => {
        const redirectUrl = `/organizations/${user.organization.organizationId}`;
        res.redirect(redirectUrl);
      })
      .catch((err) => {
        // TODO: Log errors.
        res.send(err.message);
      });
  }

  function applyForm(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER!');
    return organizationsData.findById(organizationId)
      .then((organization) => {
        res.status(200)
          .render('./organizations/apply', {
            isAuthenticated,
            result: {
              user: req.user,
              organization
            }
          });
      })
      .catch(() => {
        res.status(500).redirect('/error');
      });
  }

  function addApplication(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    const newApplication = req.body;
    if (!newApplication) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER!');
    const user = req.user;
    return organizationsData.findById(organizationId)
      .then((organization) => {
        organization.applications = organization.applications || [];
        const userHasAlreadyApplied = organization.applications.some(a => a.username === user.username);
        if (userHasAlreadyApplied) {
          return res.status(200)
            .render('./organizations/apply-fail', {
              isAuthenticated,
              result: {
                user
              }
            });
        }

        organization.applications.push({
          username: user.username,
          userId: user._id,
          comment: newApplication.comment
        });

        return organizationsData.updateOrganization(organization);
      })
      .then(() => {
        res.status(200)
          .render('./organizations/apply-success', {
            isAuthenticated,
            result: {
              user
            }
          });
      })
      .catch((err) => {
        logger.info(err.message);
        res.status(500).redirect('/error');
      });
  }

  function listApplications(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER');
    return organizationsData.findById(organizationId)
      .then((organization) => {
        if (!organization) {
          logger.info('No organization with this ID found.');
          return res.status(500).redirect('/account/login');
        }

        return res.status(200)
          .render('./organizations/applications-list', {
            isAuthenticated,
            result: {
              organization
            }
          });
      })
      .catch((err) => {
        logger.info(err.message);
        return res.status(500).redirect('/account/login');
      });
  }

  function approveApplication(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    const userId = req.params.userId;
    if (!userId) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER');
    return Promise.all([
      organizationsData.findById(organizationId),
      userData.getUserById(userId)
    ])
      .then(([organization, user]) => {

      })
      .catch((err) => {
        logger.info(err.message);
        res.status(500).redirect('/error');
      });
  }

  return {
    index,
    search,
    details,
    createOrganizationForm,
    createOrganization,
    applyForm,
    addApplication,
    listApplications,
    approveApplication
  };
};<commit_msg>organizationsController.approveApplication()<commit_after>/* globals Promise */

'use strict';

const logger = require('../../config/logger');

module.exports = function (organizationsData, userData) {
  function index(req, res) {
    const page = +req.query.page || 0;
    const size = +req.query.size || 5;

    organizationsData.findPage(page, size)
      .then(([organizations, pageCount]) => {
        const pagination = {
          active: +pageCount > 1,
          pageSize: size,
          previous: {
            active: +page > 0,
            value: +page - 1
          },
          next: {
            active: +page < +pageCount - 1,
            value: +page + 1
          }
        };

        res.render('./organizations/index', {
          isAuthenticated: req.isAuthenticated(),
          result: {
            user: req.user,
            organizations,
            pagination
          }
        });
      })
      .catch((err) => {
        res.redirect('/error');
      });
  }

  function search(req, res) {
    const isAuthenticated = req.isAuthenticated();

    organizationsData.getOrganizationsWhichContains(req.query.search)
      .then((organizations) => {
        return res
          .status(200)
          .render('./organizations/organizations-list', {
            isAuthenticated,
            result: {
              data: organizations,
              user: req.user
            }
          });
      });
  }

  function details(req, res) {
    const organizationId = req.params.organizationId;
    const isAuthenticated = req.isAuthenticated();

    organizationsData.findById(organizationId)
      .then((organization) => {
        if (!organization) {
          res.redirect('/organizations/not-found');
        }

        const user = req.user;

        let isMember;
        if (user) {
          isMember = user.organization.name === organization.name;
        }

        res.render('./organizations/details', {
          result: {
            user,
            isMember,
            organization
          },
          isAuthenticated
        });
      })
      .catch((err) => {
        // TODO: Log error.
        res.send(err.message);
      });
  }

  function createOrganizationForm(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.redirect('/account/login');
    }

    return res.render('./organizations/create', {
      isAuthenticated,
      result: {
        user: req.user
      }
    });
  }

  function createOrganization(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.redirect('/account/login');
    }

    const inputOrganization = req.body;
    const owners = [{
      username: req.user.username,
      ownerId: req.user._id
    }];

    inputOrganization.owners = owners;

    return organizationsData.createOrganization(inputOrganization)
      .then((organization) => {
        const user = req.user;
        user.organization = {
          name: organization.name,
          organizationId: organization._id
        };

        return userData.updateUser(user);
      })
      .then((user) => {
        const redirectUrl = `/organizations/${user.organization.organizationId}`;
        res.redirect(redirectUrl);
      })
      .catch((err) => {
        // TODO: Log errors.
        res.send(err.message);
      });
  }

  function applyForm(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER!');
    return organizationsData.findById(organizationId)
      .then((organization) => {
        res.status(200)
          .render('./organizations/apply', {
            isAuthenticated,
            result: {
              user: req.user,
              organization
            }
          });
      })
      .catch(() => {
        res.status(500).redirect('/error');
      });
  }

  function addApplication(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    const newApplication = req.body;
    if (!newApplication) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER!');
    const user = req.user;
    return organizationsData.findById(organizationId)
      .then((organization) => {
        organization.applications = organization.applications || [];
        const userHasAlreadyApplied = organization.applications.some(a => a.username === user.username);
        if (userHasAlreadyApplied) {
          return res.status(200)
            .render('./organizations/apply-fail', {
              isAuthenticated,
              result: {
                user
              }
            });
        }

        organization.applications.push({
          username: user.username,
          userId: user._id,
          comment: newApplication.comment
        });

        return organizationsData.updateOrganization(organization);
      })
      .then(() => {
        res.status(200)
          .render('./organizations/apply-success', {
            isAuthenticated,
            result: {
              user
            }
          });
      })
      .catch((err) => {
        logger.info(err.message);
        res.status(500).redirect('/error');
      });
  }

  function listApplications(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER');
    return organizationsData.findById(organizationId)
      .then((organization) => {
        if (!organization) {
          logger.info('No organization with this ID found.');
          return res.status(500).redirect('/account/login');
        }

        return res.status(200)
          .render('./organizations/applications-list', {
            isAuthenticated,
            result: {
              organization
            }
          });
      })
      .catch((err) => {
        logger.info(err.message);
        return res.status(500).redirect('/account/login');
      });
  }

  function approveApplication(req, res) {
    const isAuthenticated = req.isAuthenticated();
    if (!isAuthenticated) {
      return res.status(401).redirect('/account/login');
    }

    const organizationId = req.params.organizationId;
    if (!organizationId) {
      return res.status(500).redirect('/account/login');
    }

    const userId = req.params.userId;
    if (!userId) {
      return res.status(500).redirect('/account/login');
    }

    // return res.send('I WUZ HEER');
    return Promise.all([
      organizationsData.findById(organizationId),
      userData.getUserById(userId)
    ])
      .then(([organization, user]) => {
        const userAlreadyAssigned = organization.unassigned.some(u => u.username === user.username);
        if (userAlreadyAssigned) {
          return res.status(400).redirect('/error');
        }

        if (user.organization) {
          return Promise.all([
            new Promise(resolve => resolve(organization)),
            new Promise(resolve => resolve(user)),
            organizationsData.findByName(user.organization.name)
          ]);
        }

        return Promise.all([
          new Promise(resolve => resolve(organization)),
          new Promise(resolve => resolve(user))
        ]);
      })
      .then(([organization, user, previousOrganization]) => {
        organization.unassigned.push({
          username: user.username,
          unassignedId: user._id
        });

        if (previousOrganization !== null) {
          return Promise.all([
            organizationsData.updateOrganization(organization),
            organizationsData.updateOrganization(previousOrganization),
            userData.updateUser(user)
          ]);
        }

        return Promise.all([
          organizationsData.updateOrganization(organization),
          organizationsData.updateOrganization(previousOrganization)
        ]);
      })
      .then(() => {
        res.status(200).redirect(`/organizations/${organizationId}/employees`);
      })
      .catch((err) => {
        logger.info(err.message);
        res.status(500).redirect('/error');
      });
  }

  return {
    index,
    search,
    details,
    createOrganizationForm,
    createOrganization,
    applyForm,
    addApplication,
    listApplications,
    approveApplication
  };
};<|endoftext|>


<commit_before>const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const WebpackNotifierPlugin = require('webpack-notifier');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const chalk = require('chalk');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CheckerPlugin, ForkCheckerPlugin } = require('awesome-typescript-loader');

const commonConfig = require('./webpack.common');
const { ENV, dir } = require('./helpers');

module.exports = function(config) {
  return webpackMerge(commonConfig({ env: ENV }), {
    devtool: 'cheap-module-eval-source-map',
    devServer: {
      port: 9999,
      hot: config.HMR,
      stats: {
        modules: false,
        cached: false,
        chunk: false
      }
    },
    entry: {
      'app': './demo/index.ts',
      'libs': './demo/libs.ts'
    },
    module: {
      exprContextCritical: false,
      rules: [
        {
          enforce: 'pre',
          test: /\.js$/,
          loader: 'source-map-loader',
          exclude: /(node_modules)/
        },
        {
          enforce: 'pre',
          test: /\.ts$/,
          loader: 'tslint-loader',
          exclude: /(node_modules|release|dist)/
        },
        {
          test: /\.ts$/,
          loaders: [
            'awesome-typescript-loader',
            'angular2-template-loader',
            '@angularclass/hmr-loader'
          ],
          exclude: [/\.(spec|e2e|d)\.ts$/]
        }
      ]
    },
    plugins: [
      // new ForkCheckerPlugin(),
      // new webpack.HotModuleReplacementPlugin()
      new CheckerPlugin(),
      new webpack.optimize.CommonsChunkPlugin({
        name: ['libs'],
        minChunks: Infinity
      }),
      new HtmlWebpackPlugin({
        template: 'demo/index.ejs',
        chunksSortMode: 'dependency',
        title: 'ngx-ui'
      }),
      new WebpackNotifierPlugin({
        excludeWarnings: true
      }),
      new ProgressBarPlugin({
        format: chalk.yellow.bold('Webpack Building...') +
          ' [:bar] ' + chalk.green.bold(':percent') + ' (:elapsed seconds)'
      })
    ]
  });

};
<commit_msg>(chore): sourcemaps don't work right<commit_after>const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const WebpackNotifierPlugin = require('webpack-notifier');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const chalk = require('chalk');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CheckerPlugin, ForkCheckerPlugin } = require('awesome-typescript-loader');

const commonConfig = require('./webpack.common');
const { ENV, dir } = require('./helpers');

module.exports = function(config) {
  return webpackMerge(commonConfig({ env: ENV }), {
    devtool: 'source-map',
    devServer: {
      port: 9999,
      hot: config.HMR,
      stats: {
        modules: false,
        cached: false,
        chunk: false
      }
    },
    entry: {
      'app': './demo/index.ts',
      'libs': './demo/libs.ts'
    },
    module: {
      exprContextCritical: false,
      rules: [
        {
          enforce: 'pre',
          test: /\.js$/,
          loader: 'source-map-loader',
          exclude: /(node_modules)/
        },
        {
          enforce: 'pre',
          test: /\.ts$/,
          loader: 'tslint-loader',
          exclude: /(node_modules|release|dist)/
        },
        {
          test: /\.ts$/,
          loaders: [
            'awesome-typescript-loader',
            'angular2-template-loader',
            '@angularclass/hmr-loader'
          ],
          exclude: [/\.(spec|e2e|d)\.ts$/]
        }
      ]
    },
    plugins: [
      // new ForkCheckerPlugin(),
      // new webpack.HotModuleReplacementPlugin()
      new CheckerPlugin(),
      new webpack.optimize.CommonsChunkPlugin({
        name: ['libs'],
        minChunks: Infinity
      }),
      new HtmlWebpackPlugin({
        template: 'demo/index.ejs',
        chunksSortMode: 'dependency',
        title: 'ngx-ui'
      }),
      new WebpackNotifierPlugin({
        excludeWarnings: true
      }),
      new ProgressBarPlugin({
        format: chalk.yellow.bold('Webpack Building...') +
          ' [:bar] ' + chalk.green.bold(':percent') + ' (:elapsed seconds)'
      })
    ]
  });

};
<|endoftext|>