<commit_before>export { TwinArray };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
import * as TensorPlaceholder from "../TensorPlaceholder.js";
import * as ActivationEscaping from "../ActivationEscaping.js";
import { Root } from "./Operation_Base.js";

/**
 * An array of operations. Every time appending operation, one or parallel twin operations could be appended.
 *
 * No matter how many sub operations (even no sub operation) are appended, this TwinArray's .output0 and .output1 (tensor
 * placeholder) are always .endingDummyOperation.output0 and .endingDummyOperation.output1 in fact. The .endingInput0
 * and endingInput1 are always .endingDummyOperation.input0 and .endingDummyOperation.input1 in fact. This could
 * simplify the decision of what tensor placeholders should be used as the next (appended) operation's input.
 *
 *
 * Note: The .outputTensorCount is determined when constructor is called. No matter what kind of operation is appended
 * (even if the is no operation is appended), the outputTensorCount will not be changed.
 *
 *
 *
 * @member {TensorPlaceholder.Base} endingInput0
 *   The last sub operation's output0 (also .endingDummyOperation.input0). It could be used as input of next appended sub operation.
 *
 * @member {TensorPlaceholder.Base} endingInput1
 *   The last sub operation's output1 (also .endingDummyOperation.input1). It could be used as input of next appended sub operation.
 *
 * @member {number} tensorWeightCountExtracted
 *   The sum of all sub operations' tensorWeightCountExtracted.
 *
 * @member {number} tensorWeightCountTotal
 *   The sum of all sub operations' tensorWeightCountTotal.
 *
 * @member {function} apply
 *   This is a data member pointer to a function. It processes this.input0.realTensor (and this.input1.realTensor) as inputTensors. It
 * puts to this.output0.realTensor (and this.output1.realTensor) as outputTensor. In fact, its calls .apply of every sub operation
 * and .endingDummyOperation.
 *
 * @see Operation.Root
 */
class TwinArray extends Root {

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

  /**
   *
   */
  constructor( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {

    // Note: The real output TensorPlacehoder will be created later as final operation outputs.
    super( inputTensorPlaceholder0, inputTensorPlaceholder1, 0, ...restArgs );

    TwinArray.setAsConstructor_self.call( this, inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );
  }

  /** @override */
  static setAsConstructor( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {
    super.setAsConstructor( inputTensorPlaceholder0, inputTensorPlaceholder1, 0, ...restArgs );
    TwinArray.setAsConstructor_self.call( this, inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );
    return this;
  }

  /** @override */
  static setAsConstructor_self( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {

    // In order to handle keep-input-flag correctly (even if no sub operation at all), an ending dummy operation is used.
    {
      this.endingDummyOperation = Root.Pool.get_or_create_by( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );

      // The ending dummy operation's output will be the output of this operation array.
      {
        if ( this.endingDummyOperation.output0 )
          this.output0 = this.endingDummyOperation.output0;
        if ( this.endingDummyOperation.output1 )
          this.output1 = this.endingDummyOperation.output1;
      }
    }

    this.operationArray = Recyclable.OwnerArray.Pool.get_or_create_by();

    TwinArray.setup_apply_loop.call( this );

    // For reducing memory re-allocation.
    //
    // When one or twin operations are appended, the newly appende operations' output tensor placeholders will be collected here
    // temporarily. And then they will be assigned as endingDummyOperation's input tensor placeholder.
    //
    this.tempLastOutputTensorPlaceholderArray = Recyclable.Array.Pool.get_or_create_by( 0 );
    return this;
  }

  /** @override */
  disposeResources() {

    if ( this.tempLastOutputTensorPlaceholderArray ) {
      this.tempLastOutputTensorPlaceholderArray.disposeResources_and_recycleToPool();
      this.tempLastOutputTensorPlaceholderArray = null;
    }

    // Because outputs are not created by this operation, they should not be released by this operation.
    //
    // Note: The this.output0 and this.output1 are created by .endingDummyOperation (i.e. not by this), they should be released
    // by .endingDummyOperation.
    //
    // Q: Why not just use read-only property to return .endingDummyOperation.outputX?
    // A: Because the parent class (i.e. Operation.Root) has read-write .output0 and .output1 property, they can not become
    //    read-only in here (i.e. in sub-class).
    {
      if ( this.output1 )
        this.output1 = null;

      if ( this.output0 )
        this.output0 = null;
    }

!!! ...unfinished... (2022/07/03)
// Where does .endingDummyOperation.outputX's scaleBoundsArray come from?
// What about .dispose_intermediate_ScaleBoundsArray() will do for that?

    // Because outputs are created by .endingDummyOperation, they should be released by it.
    if ( this.endingDummyOperation ) {
      this.endingDummyOperation.disposeResources_and_recycleToPool();
      this.endingDummyOperation = null;
    }

    // Release every sub operation in reverse order.
    if ( this.operationArray ) {
      this.operationArray.disposeResources_and_recycleToPool();
      this.operationArray = null;
    }

    // Because inputs are not created by this operation, they should not be released by this operation.
    {
      if ( this.input1 )
        this.input1 = null;

      if ( this.input0 )
        this.input0 = null;
    }

    super.disposeResources();
  }

  /**
   * Release all ScaleBoundsArray (inside tensor placeholder) except this.input0, this.input1, this.output0, this.output1
   *
   * This could reduce memory footprint by releasing unused scale bounds array.
   */
  dispose_intermediate_ScaleBoundsArray() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];

      if ( ( operation.input0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input0 ) ) )
        operation.input0.ScaleBoundsArray_dispose();

      if ( ( operation.input1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input1 ) ) )
        operation.input1.ScaleBoundsArray_dispose();

      if ( ( operation.output0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output0 ) ) )
        operation.output0.ScaleBoundsArray_dispose();

      if ( ( operation.output1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output1 ) ) )
        operation.output1.ScaleBoundsArray_dispose();
    }
  }

  /**
   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to bKeepInputTensor0 and bKeepInputTensor1.
   *
   * Note: After all .operation_append() are called and  before .apply() is called, this .setKeepInputTensor() should be called to
   *       configure all sub operation's .apply correctly.
   *
   * @override
   */
  setKeepInputTensor( bKeepInputTensor0, bKeepInputTensor1 ) {

    // Q: Why not recorded bKeepInputTensor0 and bKeepInputTensor1 as data members.
    // A: The operation appending is complex so that the keep-input state will be changed in complicated way. Recording
    //    them is not helpful.

    TwinArray.alwaysKeepSet_collect.call( this, bKeepInputTensor0, bKeepInputTensor1 );
    TwinArray.setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet.call( this );
  }

  /**
   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to this.alwaysKeepSet.
   */
  static setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet() {

    // 2. Every input tensors' final operation is responsible for releasing the tensor (except the input tensors which are requested
    //    to be kept (i.e. inside alwaysKeepSet)).
    //
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
    }

    // 3.
    this.endingDummyOperation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
  }

  /**
   * Append one or twin (i.e. two operation in parallel) operation(s) into this.operationArray[].
   *
   * All of the newly appended operations' .outputX TensorPlaceholders will be assigned as .endingDummyOperation.inputX (i.e.
   * .endingInputX) with some rules:
   *
   *   - If a .endingDummyOperation is no longer the final operation of .endingDummyOperation.inputX, the .endingDummyOperation.inputX
   *       will be viewed as empty solt which could be assigned by newly appended operations' .outputX.
   *
   *   - However, because there are only two slots (i.e. .endingDummyOperation.input0 and .endingDummyOperation.input1) at most,
   *       there are only two operationX.outputY could be assigned to them.
   *
   *   - If there too many operationX.outputY needs to be handled, it will be asserted failed.
   *
   *
   * Note: After all .operation_append() are called, the .setKeepInputTensor() should be called to configure correctly before
   *       .apply() is called.
   *
   *
   * @param {Operation.Base} operation0  The 1st operation object to be appended into this.operationArray[].
   * @param {Operation.Base} operation1  The 2nd operation object. If null, there will be no 2nd operation.
   */
  operation_append( operation0, operation1 ) {

    // 1. Put into queue.
    if ( operation0 ) {
      this.operationArray.push( operation0 );
    }

    if ( operation1 ) {
      this.operationArray.push( operation1 );
    }

    // 2. Determine whether give up or keep current .endingInputX
    //
    // No matter ( .endingInputX does not exist ) or ( .endingInputX exists but .endingDummyOperation is no longer its final
    // operation ), .endingInputX will become an empty slot which could handle newly generated output tensor placeholders from
    // newly appended operations.
    //
    // Q: Why .endingDummyOperation should give it up when .endingDummyOperation is no longer its input tensor placeholder's
    //    final operation (i.e. the newly created and appended operation becomes its final operation)?
    // A: So that .endingDummyOperation will not use a disposed tensor.
    //
    let endingInput0_new, endingInput1_new;
    {
      if ( this.endingDummyOperation.input0?.finalOperation == this.endingDummyOperation )
        endingInput0_new = this.endingDummyOperation.input0; // Continue to handle it Since it still is its final operation.
      else
        endingInput0_new = null;

      if ( this.endingDummyOperation.input1?.finalOperation == this.endingDummyOperation )
        endingInput1_new = this.endingDummyOperation.input1; // Continue to handle it Since it still is its final operation.
      else
        endingInput1_new = null;
    }

    // 3. Adjust .endingInputX

    // 3.1 Collect output tensor placeholders in reverse order (so that they will be popped in forward order).
    {
      this.tempLastOutputTensorPlaceholderArray.length = 0;

      if ( operation1 ) {
        if ( operation1.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output1 );
        if ( operation1.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output0 );
      }

      if ( operation0 ) {
        if ( operation0.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output1 );
        if ( operation0.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output0 );
      }
    }

    // 3.2 Assign newly generated output tensor placeholders (from newly appended operations) to empty input slot of .endingDummyOperation.
    {
      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput0_new == null ) )
        endingInput0_new = this.tempLastOutputTensorPlaceholderArray.pop();

      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput1_new == null ) )
        endingInput1_new = this.tempLastOutputTensorPlaceholderArray.pop();

      // At most, two outputs could be handled.
      if ( this.tempLastOutputTensorPlaceholderArray.length != 0 )
        throw Error( `Operation.TwinArray.operation_append(): `
          + `The appended operations have too many output TensorPlaceholders. There are not enough .endingInputX could be used.`
        );
    }

    // 3.3 Confirm the new endingInputX.
    TwinArray.set_endingInput0_endingInput1.call( this, endingInput0_new, endingInput1_new );
  }

  get endingInput0() {
    return this.endingDummyOperation.input0;
  }

  get endingInput1() {
    return this.endingDummyOperation.input1;
  }

  get tensorWeightCountExtracted() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountExtracted;
    }
    return sum;
  }

  get tensorWeightCountTotal() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountTotal;
    }
    return sum;
  }

  /** Re-collect TensorPlaceholders into this.alwaysKeepSet if some input tensors are requested to be kept after .apply(). */
  static alwaysKeepSet_collect( bKeepInputTensor0, bKeepInputTensor1 ) {
    let bShouldbKeepInputTensor0 = ( this.input0 && bKeepInputTensor0 );
    let bShouldbKeepInputTensor1 = ( this.input1 && bKeepInputTensor1 );
    let bShouldbKeepInputTensor = ( bShouldbKeepInputTensor0 || bShouldbKeepInputTensor1 );

    if ( bShouldbKeepInputTensor ) { // 1. Some inputs should be kept.

      // 1.1
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();
      else
        this.alwaysKeepSet = new Set(); // Create container only if it is indeed necessary.

      if ( bShouldbKeepInputTensor0 ) // 1.2
        this.alwaysKeepSet.add( this.input0 );

      if ( bShouldbKeepInputTensor1 ) // 1.3
        this.alwaysKeepSet.add( this.input1 );

    } else { // 2. No inputs should be kept.

      // 2.1 Empty the container if the container exists.
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();

      // 2.2 If the container does not exist, do nothing instead.
    }
  }

  /**
   *
   * @param {TensorPlaceholder.Base} endingInput0  The tensor placeholder to become .endingDummyOperation.input0.
   * @param {TensorPlaceholder.Base} endingInput1  The tensor placeholder to become .endingDummyOperation.input1.
   */
  static set_endingInput0_endingInput1( endingInput0, endingInput1 ) {
    TwinArray.set_inputTensorPlaceholder0_inputTensorPlaceholder1.call( this.endingDummyOperation, endingInput0, endingInput1 );
  }

  /**
   * Adjust .apply data member according to calling .apply_operationArray_endingDummyOperation().
   */
  static setup_apply_loop() {
    this.apply = TwinArray.apply_operationArray_endingDummyOperation;
  }

  /**
   * Calling every sub operations', and .endingDummyOperation's .apply()
   */
  static apply_operationArray_endingDummyOperation() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.apply();
    }
    this.endingDummyOperation.apply();
  }

}

<commit_msg>Update Operation_TwinArray.js<commit_after>export { TwinArray };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
import * as TensorPlaceholder from "../TensorPlaceholder.js";
import * as ActivationEscaping from "../ActivationEscaping.js";
import { Root } from "./Operation_Base.js";

/**
 * An array of operations. Every time appending operation, one or parallel twin operations could be appended.
 *
 * No matter how many sub operations (even no sub operation) are appended, this TwinArray's .output0 and .output1 (tensor
 * placeholder) are always .endingDummyOperation.output0 and .endingDummyOperation.output1 in fact. The .endingInput0
 * and endingInput1 are always .endingDummyOperation.input0 and .endingDummyOperation.input1 in fact. This could
 * simplify the decision of what tensor placeholders should be used as the next (appended) operation's input.
 *
 *
 * Note: The .outputTensorCount is determined when constructor is called. No matter what kind of operation is appended
 * (even if the is no operation is appended), the outputTensorCount will not be changed.
 *
 *
 *
 * @member {TensorPlaceholder.Base} endingInput0
 *   The last sub operation's output0 (also .endingDummyOperation.input0). It could be used as input of next appended sub operation.
 *
 * @member {TensorPlaceholder.Base} endingInput1
 *   The last sub operation's output1 (also .endingDummyOperation.input1). It could be used as input of next appended sub operation.
 *
 * @member {number} tensorWeightCountExtracted
 *   The sum of all sub operations' tensorWeightCountExtracted.
 *
 * @member {number} tensorWeightCountTotal
 *   The sum of all sub operations' tensorWeightCountTotal.
 *
 * @member {function} apply
 *   This is a data member pointer to a function. It processes this.input0.realTensor (and this.input1.realTensor) as inputTensors. It
 * puts to this.output0.realTensor (and this.output1.realTensor) as outputTensor. In fact, its calls .apply of every sub operation
 * and .endingDummyOperation.
 *
 * @see Operation.Root
 */
class TwinArray extends Root {

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

  /**
   *
   */
  constructor( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {

    // Note: The real output TensorPlacehoder will be created later as final operation outputs.
    super( inputTensorPlaceholder0, inputTensorPlaceholder1, 0, ...restArgs );

    TwinArray.setAsConstructor_self.call( this, inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );
  }

  /** @override */
  static setAsConstructor( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {
    super.setAsConstructor( inputTensorPlaceholder0, inputTensorPlaceholder1, 0, ...restArgs );
    TwinArray.setAsConstructor_self.call( this, inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );
    return this;
  }

  /** @override */
  static setAsConstructor_self( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {

    // In order to handle keep-input-flag correctly (even if no sub operation at all), an ending dummy operation is used.
    {
      this.endingDummyOperation = Root.Pool.get_or_create_by( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );

      // The ending dummy operation's output will be the output of this operation array.
      {
        if ( this.endingDummyOperation.output0 )
          this.output0 = this.endingDummyOperation.output0;
        if ( this.endingDummyOperation.output1 )
          this.output1 = this.endingDummyOperation.output1;
      }
    }

    this.operationArray = Recyclable.OwnerArray.Pool.get_or_create_by();

    TwinArray.setup_apply_loop.call( this );

    // For reducing memory re-allocation.
    //
    // When one or twin operations are appended, the newly appende operations' output tensor placeholders will be collected here
    // temporarily. And then they will be assigned as endingDummyOperation's input tensor placeholder.
    //
    this.tempLastOutputTensorPlaceholderArray = Recyclable.Array.Pool.get_or_create_by( 0 );
    return this;
  }

  /** @override */
  disposeResources() {

    if ( this.tempLastOutputTensorPlaceholderArray ) {
      this.tempLastOutputTensorPlaceholderArray.disposeResources_and_recycleToPool();
      this.tempLastOutputTensorPlaceholderArray = null;
    }

    // Because outputs are not created by this operation, they should not be released by this operation.
    //
    // Note: The this.output0 and this.output1 are created by .endingDummyOperation (i.e. not by this), they should be released
    // by .endingDummyOperation.
    //
    // Q: Why not just use read-only property to return .endingDummyOperation.outputX?
    // A: Because the parent class (i.e. Operation.Root) has read-write .output0 and .output1 property, they can not become
    //    read-only in here (i.e. in sub-class).
    {
      if ( this.output1 )
        this.output1 = null;

      if ( this.output0 )
        this.output0 = null;
    }

!!! ...unfinished... (2022/07/03)
// Where does .endingDummyOperation.outputX's scaleBoundsArray come from?
// What about .dispose_intermediate_ScaleBoundsArray() will do for that?

    // Because outputs are created by .endingDummyOperation, they should be released by it.
    if ( this.endingDummyOperation ) {
      this.endingDummyOperation.disposeResources_and_recycleToPool();
      this.endingDummyOperation = null;
    }

    // Release every sub operation in reverse order.
    if ( this.operationArray ) {
      this.operationArray.disposeResources_and_recycleToPool();
      this.operationArray = null;
    }

    // Because inputs are not created by this operation, they should not be released by this operation.
    {
      if ( this.input1 )
        this.input1 = null;

      if ( this.input0 )
        this.input0 = null;
    }

    super.disposeResources();
  }

  /**
   * Release all ScaleBoundsArray (inside tensor placeholder) except this.input0, this.input1, this.output0, this.output1
   *
   * This could reduce memory footprint by releasing unused scale bounds array.
   */
  dispose_intermediate_ScaleBoundsArray() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];

      if ( ( operation.input0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input0 ) ) )
        operation.input0.ScaleBoundsArray_dispose();

      if ( ( operation.input1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input1 ) ) )
        operation.input1.ScaleBoundsArray_dispose();

      if ( ( operation.output0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output0 ) ) )
        operation.output0.ScaleBoundsArray_dispose();

      if ( ( operation.output1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output1 ) ) )
        operation.output1.ScaleBoundsArray_dispose();
    }
  }

  /**
   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to bKeepInputTensor0 and bKeepInputTensor1.
   *
   * Note: After all .operation_append() are called and  before .apply() is called, this .setKeepInputTensor() should be called to
   *       configure all sub operation's .apply correctly.
   *
   * @override
   */
  setKeepInputTensor( bKeepInputTensor0, bKeepInputTensor1 ) {

    // Q: Why not recorded bKeepInputTensor0 and bKeepInputTensor1 as data members.
    // A: The operation appending is complex so that the keep-input state will be changed in complicated way. Recording
    //    them is not helpful.

    TwinArray.alwaysKeepSet_collect.call( this, bKeepInputTensor0, bKeepInputTensor1 );
    TwinArray.setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet.call( this );
  }

  /**
   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to this.alwaysKeepSet.
   */
  static setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet() {

    // 2. Every input tensors' final operation is responsible for releasing the tensor (except the input tensors which are requested
    //    to be kept (i.e. inside alwaysKeepSet)).
    //
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
    }

    // 3.
    this.endingDummyOperation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
  }

  /**
   * Append one or twin (i.e. two operation in parallel) operation(s) into this.operationArray[].
   *
   * All of the newly appended operations' .outputX TensorPlaceholders will be assigned as .endingDummyOperation.inputX (i.e.
   * .endingInputX) with some rules:
   *
   *   - If a .endingDummyOperation is no longer the final operation of .endingDummyOperation.inputX, the .endingDummyOperation.inputX
   *       will be viewed as empty solt which could be assigned by newly appended operations' .outputX.
   *
   *   - However, because there are only two slots (i.e. .endingDummyOperation.input0 and .endingDummyOperation.input1) at most,
   *       there are only two operationX.outputY could be assigned to them.
   *
   *   - If there too many operationX.outputY needs to be handled, it will be asserted failed.
   *
   *
   * Note: After all .operation_append() are called, the .setKeepInputTensor() should be called to configure correctly before
   *       .apply() is called.
   *
   *
   * @param {Operation.Base} operation0  The 1st operation object to be appended into this.operationArray[].
   * @param {Operation.Base} operation1  The 2nd operation object. If null, there will be no 2nd operation.
   */
  operation_append( operation0, operation1 ) {

    // 1. Put into queue.
    if ( operation0 ) {
      this.operationArray.push( operation0 );
    }

    if ( operation1 ) {
      this.operationArray.push( operation1 );
    }

    // 2. Determine whether give up or keep current .endingInputX
    //
    // No matter ( .endingInputX does not exist ) or ( .endingInputX exists but .endingDummyOperation is no longer its final
    // operation ), .endingInputX will become an empty slot which could handle newly generated output tensor placeholders from
    // newly appended operations.
    //
    // Q: Why .endingDummyOperation should give it up when .endingDummyOperation is no longer its input tensor placeholder's
    //    final operation (i.e. the newly created and appended operation becomes its final operation)?
    // A: So that .endingDummyOperation will not use a disposed tensor.
    //
    let endingInput0_new, endingInput1_new;
    {
      if ( this.endingDummyOperation.input0?.finalOperation == this.endingDummyOperation )
        endingInput0_new = this.endingDummyOperation.input0; // Continue to handle it Since it still is its final operation.
      else
        endingInput0_new = null;

      if ( this.endingDummyOperation.input1?.finalOperation == this.endingDummyOperation )
        endingInput1_new = this.endingDummyOperation.input1; // Continue to handle it Since it still is its final operation.
      else
        endingInput1_new = null;
    }

    // 3. Adjust .endingInputX

    // 3.1 Collect output tensor placeholders in reverse order (so that they will be popped in forward order).
    {
      this.tempLastOutputTensorPlaceholderArray.length = 0;

      if ( operation1 ) {
        if ( operation1.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output1 );
        if ( operation1.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output0 );
      }

      if ( operation0 ) {
        if ( operation0.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output1 );
        if ( operation0.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output0 );
      }
    }

    // 3.2 Assign newly generated output tensor placeholders (from newly appended operations) to empty input slot of .endingDummyOperation.
    {
      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput0_new == null ) )
        endingInput0_new = this.tempLastOutputTensorPlaceholderArray.pop();

      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput1_new == null ) )
        endingInput1_new = this.tempLastOutputTensorPlaceholderArray.pop();

      // At most, two outputs could be handled.
      if ( this.tempLastOutputTensorPlaceholderArray.length != 0 )
        throw Error( `Operation.TwinArray.operation_append(): `
          + `The appended operations have too many output TensorPlaceholders. There are not enough .endingInputX could be used.`
        );
    }

    // 3.3 Confirm the new endingInputX.
    TwinArray.set_endingInput0_endingInput1.call( this, endingInput0_new, endingInput1_new );
  }

  get endingInput0() {
    return this.endingDummyOperation.input0;
  }

  get endingInput1() {
    return this.endingDummyOperation.input1;
  }

  get tensorWeightCountExtracted() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountExtracted;
    }
    return sum;
  }

  get tensorWeightCountTotal() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountTotal;
    }
    return sum;
  }

  /** Re-collect TensorPlaceholders into this.alwaysKeepSet if some input tensors are requested to be kept after .apply(). */
  static alwaysKeepSet_collect( bKeepInputTensor0, bKeepInputTensor1 ) {
    let bShouldbKeepInputTensor0 = ( this.input0 && bKeepInputTensor0 );
    let bShouldbKeepInputTensor1 = ( this.input1 && bKeepInputTensor1 );
    let bShouldbKeepInputTensor = ( bShouldbKeepInputTensor0 || bShouldbKeepInputTensor1 );

    if ( bShouldbKeepInputTensor ) { // 1. Some inputs should be kept.

      // 1.1
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();
      else
        this.alwaysKeepSet = new Set(); // Create container only if it is indeed necessary.

      if ( bShouldbKeepInputTensor0 ) // 1.2
        this.alwaysKeepSet.add( this.input0 );

      if ( bShouldbKeepInputTensor1 ) // 1.3
        this.alwaysKeepSet.add( this.input1 );

    } else { // 2. No inputs should be kept.

      // 2.1 Empty the container if the container exists.
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();

      // 2.2 If the container does not exist, do nothing instead.
    }
  }

  /**
   *
   * @param {TensorPlaceholder.Base} endingInput0  The tensor placeholder to become .endingDummyOperation.input0.
   * @param {TensorPlaceholder.Base} endingInput1  The tensor placeholder to become .endingDummyOperation.input1.
   */
  static set_endingInput0_endingInput1( endingInput0, endingInput1 ) {
    super.set_inputTensorPlaceholder0_inputTensorPlaceholder1.call( this.endingDummyOperation, endingInput0, endingInput1 );
  }

  /**
   * Adjust .apply data member according to calling .apply_operationArray_endingDummyOperation().
   */
  static setup_apply_loop() {
    this.apply = TwinArray.apply_operationArray_endingDummyOperation;
  }

  /**
   * Calling every sub operations', and .endingDummyOperation's .apply()
   */
  static apply_operationArray_endingDummyOperation() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.apply();
    }
    this.endingDummyOperation.apply();
  }

}

<|endoftext|>


<commit_before>var Web3 = require("web3");

module.exports = {
  wrap: function(provider, options) {
    options = options || {};

    if (options.verbose || options.verboseRpc) {
      this.makeVerbose(provider, options.logger);
    }
    return provider;
  },

  makeVerbose: function(provider, logger) {
    logger = logger || console;

    // // If you want to see what web3 is sending and receiving.
    var oldAsync = provider.sendAsync;

    if (oldAsync.is_verbose) return;

    provider.sendAsync = function(options, callback) {
      logger.log("   > " + JSON.stringify(options, null, 2).split("\n").join("\n   > "));
      oldAsync.call(provider, options, function(error, result) {
        if (error == null) {
          logger.log(" <   " + JSON.stringify(result, null, 2).split("\n").join("\n <   "));
        }
        callback(error, result)
      });
    };

    provider.sendAsync.is_verbose = true;
  },

  create: function(options) {
    var provider = new Web3.providers.HttpProvider("http://" + options.host + ":" + options.port);
    return this.wrap(provider, options);
  },

  test_connection: function(provider, callback) {
    var web3 = new Web3();
    web3.setProvider(provider);
    web3.eth.getCoinbase(function(error, coinbase) {
      if (error != null) {
        error = new Error("Could not connect to your RPC client. Please check your RPC configuration.");
      }

      callback(error, coinbase)
    });
  }
};
<commit_msg>Allow a custom provider to be passed in.<commit_after>var Web3 = require("web3");

module.exports = {
  wrap: function(provider, options) {
    options = options || {};

    if (options.verbose || options.verboseRpc) {
      this.makeVerbose(provider, options.logger);
    }
    return provider;
  },

  makeVerbose: function(provider, logger) {
    logger = logger || console;

    // // If you want to see what web3 is sending and receiving.
    var oldAsync = provider.sendAsync;

    if (oldAsync.is_verbose) return;

    provider.sendAsync = function(options, callback) {
      logger.log("   > " + JSON.stringify(options, null, 2).split("\n").join("\n   > "));
      oldAsync.call(provider, options, function(error, result) {
        if (error == null) {
          logger.log(" <   " + JSON.stringify(result, null, 2).split("\n").join("\n <   "));
        }
        callback(error, result)
      });
    };

    provider.sendAsync.is_verbose = true;
  },

  create: function(options) {
    var provider;

    if (options.provider) {
      provider = options.provider;
    } else {
      provider = new Web3.providers.HttpProvider("http://" + options.host + ":" + options.port);
    }

    return this.wrap(provider, options);
  },

  test_connection: function(provider, callback) {
    var web3 = new Web3();
    web3.setProvider(provider);
    web3.eth.getCoinbase(function(error, coinbase) {
      if (error != null) {
        error = new Error("Could not connect to your RPC client. Please check your RPC configuration.");
      }

      callback(error, coinbase)
    });
  }
};
<|endoftext|>


<commit_before>var helpers = require('./helpers');
var db = helpers.db;

/* /users */
exports.getAllUsers = function(req, res) {
  helpers.getRequestingUser(req, function(err, user) {

    if ( err ) {
      res.status(500).end();
      console.log("getAllUsers:", err);
    } else {

      if ( !user ) {
        res.status(403).end();
      } else {
        if(!user.isPrivileged()) {
           res.status(403).end();
        } else {
          helpers.getAllUsers(function(err, users) {
            if ( err ) {
              res.status(500).end();
            } else {

              res.set('Content-Type', 'application/json');
              res.end(JSON.stringify({
                users: users
              }));

            }
          });
        }

      }

    }

  });
};

/* /user/:id */
exports.getUser = function(req, res) {
  helpers.getRequestingUser(req, function(err, user) {

    if ( err ) {
      res.status(500).end();
    } else {

      if ( !user ) {
        res.status(403).end();
      } else {
        var id = req.params.id;

        if ( user.isPrivileged() || user.id == id ) {
          helpers.getUser({
            id: id
          }, function(err, user) {
            if ( err ) {
              res.status(500).end();
            } else {
              if ( !user ) {
                res.status(404).end();
              } else {
                res.set('Content-Type', 'application/json');
                res.end(JSON.stringify(user));
              }
            }
          });
        } else {
          res.status(403).end();
        }
      }

    }

  });
};

/* /user/:id/cards */
exports.getCardsOfUser = function(req, res) {
  helpers.getRequestingUser(req, function(err, user) {

    if ( err ) {
      res.status(500).end();
    } else {

      if ( !user ) {
        res.status(403).end();
      } else {
        var id = req.params.id;

        if(user.isPrivileged() || user.id == id) {
          helpers.getUser({
            id: id
          }, function(err, user) {

            if ( user ) {
              user.getCards().success(function(cards) {

                if ( cards ) {
                  res.set('Content-Type', 'application/json');
                  res.end(JSON.stringify(cards));
                } else {
                  res.end(500).end();
                }

              });
            }

          });

        } else {
          res.status(403).end();
        }

      }

    }

  });
};
<commit_msg>Added verbs to comments.<commit_after>var helpers = require('./helpers');
var db = helpers.db;

/* GET /users */
exports.getAllUsers = function(req, res) {
  helpers.getRequestingUser(req, function(err, user) {

    if ( err ) {
      res.status(500).end();
      console.log("getAllUsers:", err);
    } else {

      if ( !user ) {
        res.status(403).end();
      } else {
        if(!user.isPrivileged()) {
           res.status(403).end();
        } else {
          helpers.getAllUsers(function(err, users) {
            if ( err ) {
              res.status(500).end();
            } else {

              res.set('Content-Type', 'application/json');
              res.end(JSON.stringify({
                users: users
              }));

            }
          });
        }

      }

    }

  });
};

/* GET /user/:id */
exports.getUser = function(req, res) {
  helpers.getRequestingUser(req, function(err, user) {

    if ( err ) {
      res.status(500).end();
    } else {

      if ( !user ) {
        res.status(403).end();
      } else {
        var id = req.params.id;

        if ( user.isPrivileged() || user.id == id ) {
          helpers.getUser({
            id: id
          }, function(err, user) {
            if ( err ) {
              res.status(500).end();
            } else {
              if ( !user ) {
                res.status(404).end();
              } else {
                res.set('Content-Type', 'application/json');
                res.end(JSON.stringify(user));
              }
            }
          });
        } else {
          res.status(403).end();
        }
      }

    }

  });
};

/* GET /user/:id/cards */
exports.getCardsOfUser = function(req, res) {
  helpers.getRequestingUser(req, function(err, user) {

    if ( err ) {
      res.status(500).end();
    } else {

      if ( !user ) {
        res.status(403).end();
      } else {
        var id = req.params.id;

        if(user.isPrivileged() || user.id == id) {
          helpers.getUser({
            id: id
          }, function(err, user) {

            if ( user ) {
              user.getCards().success(function(cards) {

                if ( cards ) {
                  res.set('Content-Type', 'application/json');
                  res.end(JSON.stringify(cards));
                } else {
                  res.end(500).end();
                }

              });
            }

          });

        } else {
          res.status(403).end();
        }

      }

    }

  });
};
<|endoftext|>


<commit_before>CourseController = AppController.extend({
    waitOn: function() {
        // course ID
        var courseID = this.params._id;

        // Course subscriptions
        return [
             // Wait for the course to be available
            this.subscribe("singleCourse", courseID),
            // subscribe only to lessons in this course
            this.subscribe("courseLessons", courseID)
        ];
    },
    data: function () {
        // Return the course
        return Courses.findOne();
    },
    onAfterAction: function () {
        // Get the course ID from the URL parameters
        var courseID = this.params._id;

        // TODO: uncomment the following and figure out why it is generating a browser console error

        // Get the course from the database
        //var course  = Courses.find(courseID).fetch()[0]; // select the zeroeth array item

        // Set the site title for SEO
        //Meta.setTitle(course.title);
    }
});
<commit_msg>Removed course lessons subscription.<commit_after>CourseController = AppController.extend({
    waitOn: function() {
        // course ID
        var courseID = this.params._id;

        // Course subscriptions
        return [
             // Wait for the course to be available
            this.subscribe("singleCourse", courseID),
        ];
    },
    data: function () {
        // Return the course
        return Courses.findOne();
    },
    onAfterAction: function () {
        // Get the course ID from the URL parameters
        var courseID = this.params._id;

        // TODO: uncomment the following and figure out why it is generating a browser console error

        // Get the course from the database
        //var course  = Courses.find(courseID).fetch()[0]; // select the zeroeth array item

        // Set the site title for SEO
        //Meta.setTitle(course.title);
    }
});
<|endoftext|>


<commit_before>// OAuthDataProvider for activity spam server
//
// Copyright 2011-2013 E14N https://e14n.com/
//
// 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.

require("set-immediate");

var NoSuchThingError = require("databank").NoSuchThingError,
    _ = require("underscore"),
    url = require("url"),
    Step = require("step"),
    User = require("./model/user").User,
    RequestToken = require("./model/requesttoken").RequestToken,
    AccessToken = require("./model/accesstoken").AccessToken,
    Nonce = require("./model/nonce").Nonce,
    Client = require("./model/client").Client;

var TIMELIMIT = 300; // +/- 5 min seems pretty generous
var REQUESTTOKENTIMEOUT = 600; // 10 min, also pretty generous

var Provider = function(logParent, rawClients) {

    var prov = this,
	log = (logParent) ? logParent.child({component: "oauth-provider"}) : null,
	clients = _.map(rawClients, function(client) {
	    var cl = _.clone(client);
	    _.extend(cl, {
		consumer_key: client.client_id,
		secret: client.client_secret,
		asActivityObject: function(callback) {
		    var cl = this,
			ActivityObject = require("./model/activityobject").ActivityObject,
			uuidv5 = require("./uuidv5"),
			props = {};

		    props._consumer_key = cl.consumer_key;

		    if (cl.title) {
			props.displayName = cl.title;
		    }

		    if (cl.description) {
			props.content = cl.description;
		    }

		    props.objectType = ActivityObject.APPLICATION;
		    props.id = "urn:uuid:"+uuidv5(client.client_id);

		    ActivityObject.ensureObject(props, callback);
		}
	    });
	    return cl;
	});

    prov.getClient = function(client_id, callback) {

	var client;

	// Is it in our configured array?
	if (clients) {
	    client = _.find(clients, function(cl) { return cl.client_id == client_id; });
	    if (client) {
		setImmediate(callback, [null, client]);
		return;
	    }
	}

	// Is it in our database?
	Client.get(client_id, callback);
    };

    prov.previousRequestToken = function(token, callback) {
        if (log) log.info("getting previous request token for " + token);
        AccessToken.search({request_token: token}, function(err, ats) {
            if (err) {
                callback(err, null);
            } else if (ats.length > 0) {
                callback(new Error("Token has been used"), null);
            } else {
                callback(null, token);
            }
        });
    };

    prov.tokenByConsumer = function(consumerKey, callback) {
        if (log) log.info("getting token for consumer key " + consumerKey);
        prov.getClient(consumerKey, function(err, client) {
            if (err) {
                callback(err, null);
            } else {
                RequestToken.search({consumer_key: client.consumer_key}, function(err, rts) {
                    if (rts.length > 0) {
                        callback(null, rts[0]);
                    } else {
                        callback(new Error("No RequestToken for that consumer_key"), null);
                    }
                });
            }
        });
    };

    prov.tokenByTokenAndConsumer = function(token, consumerKey, callback) {
        if (log) log.info("getting token for consumer key " + consumerKey + " and token " + token);
        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null);
            } else if (rt.consumer_key !== consumerKey) {
                callback(new Error("Consumer key mismatch"), null);
            } else {
                callback(null, rt);
            }
        });
    };

    prov.applicationByConsumerKey = function(consumerKey, callback) {
        if (log) log.info("getting application for consumer key " + consumerKey);
        prov.getClient(consumerKey, callback);
    };

    prov.fetchAuthorizationInformation = function(username, token, callback) {
        if (log) log.info("getting auth information for user "+username+" with token " + token);
        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null, null);
            } else if (!_(rt).has("username") || rt.username !== username) {
                callback(new Error("Request token not associated with username '" + username + "'"), null, null);
            } else {
                prov.getClient(rt.consumer_key, function(err, client) {
                    if (err) {
                        callback(err, null, null);
                    } else {
                        if (!_(client).has("title")) {
                            client.title = "(Unknown)";
                        }
                        if (!_(client).has("description")) {
                            client.description = "(Unknown)";
                        }
                        callback(null, client, rt);
                    }
                });
            }
        });
    };

    prov.validToken = function(accessToken, callback) {
        if (log) log.info("checking for valid token " + accessToken);
        AccessToken.get(accessToken, callback);
    };

    prov.tokenByTokenAndVerifier = function(token, verifier, callback) {
        if (log) log.info("checking for valid request token " + token + " with verifier " + verifier);
        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null);
            } else if (rt.verifier !== verifier) {
                callback(new Error("Wrong verifier"), null);
            } else {
                callback(null, rt);
            }
        });
    };

    prov.validateNotReplayClient = function(consumerKey, accessToken, timestamp, nonce, callback) {
        var now = Math.floor(Date.now()/1000),
            ts;

        if (log) log.info("checking for replay with consumer key " + consumerKey + ", token = " + accessToken);

        try {
            ts = parseInt(timestamp, 10);
        } catch (err) {
            callback(err, null);
            return;
        }

        if (Math.abs(ts - now) > TIMELIMIT) {
            callback(null, false);
            return;
        }

        Step(
            function() {
                prov.getClient(consumerKey, this);
            },
            function(err, client) {
                if (err) throw err;
                if (!accessToken) {
                    this(null, null);
                } else {
                    AccessToken.get(accessToken, this);
                }
            },
            function(err, at) {
                if (err) throw err;
                if (at && at.consumer_key !== consumerKey) {
                    throw new Error("consumerKey and accessToken don't match");
                }
                Nonce.seenBefore(consumerKey, accessToken, nonce, timestamp, this);
            },
            function(err, seen) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, !seen);
                }
            }
        );
    };

    prov.userIdByToken = function(token, callback) {
        var user, client, at;

        if (log) log.info("checking for user with token = " + token);

        Step(
            function() {
                AccessToken.get(token, this);
            },
            function(err, res) {
                if (err) throw err;
                at = res;
                prov.getClient(at.consumer_key, this);
            },
            function(err, res) {
                if (err) throw err;
                client = res;
                User.get(at.username, this);
            },
            function(err, res) {
                if (err) {
                    callback(err, null);
                } else {
                    user = res;
                    callback(null, {id: at.username, user: user, client: client});
                }
            }
        );
    };

    prov.authenticateUser = function(username, password, oauthToken, callback) {

        if (log) log.info("authenticating user with username " + username + " and token " + oauthToken);

        User.checkCredentials(username, password, function(err, user) {
            if (err) {
                callback(err, null);
                return;
            }
            if (!user) {
                callback(new Error("Bad credentials"), null);
                return;
            }
            RequestToken.get(oauthToken, function(err, rt) {
                if (err) {
                    callback(err, null);
                    return;
                }
                if (rt.username && rt.username !== username) {
                    callback(new Error("Token already associated with a different user"), null);
                    return;
                }
                rt.authenticated = true;
                rt.save(function(err, rt) {
                    if (err) {
                        callback(err, null);
                    } else {
                        callback(null, rt);
                    }
                });
            });
        });
    };

    prov.associateTokenToUser = function(username, token, callback) {

        if (log) log.info("associating username " + username + " with token " + token);

        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null);
                return;
            }
            if (rt.username && rt.username !== username) {
                callback(new Error("Token already associated"), null);
                return;
            }
            rt.update({username: username}, function(err, rt) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, rt);
                }
            });
        });
    };

    prov.generateRequestToken = function(oauthConsumerKey, oauthCallback, callback) {

        if (log) log.info("getting a request token for " + oauthConsumerKey);

        if (oauthCallback !== "oob") {
            var parts = url.parse(oauthCallback);

            if (!parts.host || !parts.protocol || (parts.protocol !== "http:" && parts.protocol !== "https:")) {
                callback(new Error("Invalid callback URL"), null);
                return;
            }
        }

        prov.getClient(oauthConsumerKey, function(err, client) {
            if (err) {
                callback(err, null);
                return;
            }
            var props = {consumer_key: oauthConsumerKey,
                         callback: oauthCallback};
            RequestToken.create(props, callback);
        });
    };

    prov.generateAccessToken = function(oauthToken, callback) {

        var rt, at;

        if (log) log.info("getting an access token for " + oauthToken);

        Step(
            function() {
                RequestToken.get(oauthToken, this);
            },
            function(err, results) {
                if (err) throw err;
                rt = results;
                if (!rt.username) {
                    throw new Error("Request token not associated");
                }
                if (rt.access_token) {
                    // XXX: search AccessToken instead...?
                    throw new Error("Request token already used");
                }
                AccessToken.search({consumer_key: rt.consumer_key,
                                    username: rt.username},
                                   this);
            },
            function(err, ats) {
                var props;
                if (err) throw err;
                if (!ats || ats.length === 0) {
                    if (log) log.info("creating a new access token for " + oauthToken);
                    props = {consumer_key: rt.consumer_key,
                             request_token: rt.token,
                             username: rt.username};
                    AccessToken.create(props, this);
                } else {
                    if (log) log.info("reusing access token " + ats[0].access_token + " for " + oauthToken);
                    // XXX: keep an array of related request tokens, not just one
                    ats[0].update({request_token: rt.token}, this);
                }
            },
            function(err, results) {
                if (err) throw err;
                at = results;
                // XXX: delete...?
                if (log) log.info("saving access token for " + oauthToken);
                rt.update({access_token: at.access_token}, this);
            },
            function(err, rt) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, at);
                }
            }
        );
    };

    prov.cleanRequestTokens = function(consumerKey, callback) {

        if (log) log.info("cleaning up request tokens for " + consumerKey);

        Step(
            function() {
                prov.getClient(consumerKey, this);
            },
            function(err, client) {
                if (err) throw err;
                RequestToken.search({consumer_key: consumerKey}, this);
            },
            function(err, rts) {
                var id, now = Date.now(), touched, group = this.group();
                if (err) throw err;
                for (id in rts) {
                    touched = Date.parse(rts[id].updated);
                    if (now - touched > (REQUESTTOKENTIMEOUT * 1000)) { // ms -> sec
                        rts[id].del(group());
                    }
                }
            },
            function(err) {
                callback(err, null);
            }
        );
    };

    prov.newTokenPair = function(client, user, callback) {

        Step(
            function() {
                prov.generateRequestToken(client.consumer_key, "oob", this);
            },
            function(err, rt) {
                if (err) throw err;
                prov.associateTokenToUser(user.nickname, rt.token, this);
            },
            function(err, rt) {
                if (err) throw err;
                prov.generateAccessToken(rt.token, this);
            },
            function(err, pair) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, pair);
                }
            }
        );
    };
};

exports.Provider = Provider;
<commit_msg>Use full syntax for setImmediate()<commit_after>// OAuthDataProvider for activity spam server
//
// Copyright 2011-2013 E14N https://e14n.com/
//
// 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.

require("set-immediate");

var NoSuchThingError = require("databank").NoSuchThingError,
    _ = require("underscore"),
    url = require("url"),
    Step = require("step"),
    User = require("./model/user").User,
    RequestToken = require("./model/requesttoken").RequestToken,
    AccessToken = require("./model/accesstoken").AccessToken,
    Nonce = require("./model/nonce").Nonce,
    Client = require("./model/client").Client;

var TIMELIMIT = 300; // +/- 5 min seems pretty generous
var REQUESTTOKENTIMEOUT = 600; // 10 min, also pretty generous

var Provider = function(logParent, rawClients) {

    var prov = this,
	log = (logParent) ? logParent.child({component: "oauth-provider"}) : null,
	clients = _.map(rawClients, function(client) {
	    var cl = _.clone(client);
	    _.extend(cl, {
		consumer_key: client.client_id,
		secret: client.client_secret,
		asActivityObject: function(callback) {
		    var cl = this,
			ActivityObject = require("./model/activityobject").ActivityObject,
			uuidv5 = require("./uuidv5"),
			props = {};

		    props._consumer_key = cl.consumer_key;

		    if (cl.title) {
			props.displayName = cl.title;
		    }

		    if (cl.description) {
			props.content = cl.description;
		    }

		    props.objectType = ActivityObject.APPLICATION;
		    props.id = "urn:uuid:"+uuidv5(client.client_id);

		    ActivityObject.ensureObject(props, callback);
		}
	    });
	    return cl;
	});

    prov.getClient = function(client_id, callback) {

	var client;

	// Is it in our configured array?
	if (clients) {
	    client = _.find(clients, function(cl) { return cl.client_id == client_id; });
	    if (client) {
                setImmediate(function() {
                    callback(null, client);
                });
		return;
	    }
	}

	// Is it in our database?
	Client.get(client_id, callback);
    };

    prov.previousRequestToken = function(token, callback) {
        if (log) log.info("getting previous request token for " + token);
        AccessToken.search({request_token: token}, function(err, ats) {
            if (err) {
                callback(err, null);
            } else if (ats.length > 0) {
                callback(new Error("Token has been used"), null);
            } else {
                callback(null, token);
            }
        });
    };

    prov.tokenByConsumer = function(consumerKey, callback) {
        if (log) log.info("getting token for consumer key " + consumerKey);
        prov.getClient(consumerKey, function(err, client) {
            if (err) {
                callback(err, null);
            } else {
                RequestToken.search({consumer_key: client.consumer_key}, function(err, rts) {
                    if (rts.length > 0) {
                        callback(null, rts[0]);
                    } else {
                        callback(new Error("No RequestToken for that consumer_key"), null);
                    }
                });
            }
        });
    };

    prov.tokenByTokenAndConsumer = function(token, consumerKey, callback) {
        if (log) log.info("getting token for consumer key " + consumerKey + " and token " + token);
        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null);
            } else if (rt.consumer_key !== consumerKey) {
                callback(new Error("Consumer key mismatch"), null);
            } else {
                callback(null, rt);
            }
        });
    };

    prov.applicationByConsumerKey = function(consumerKey, callback) {
        if (log) log.info("getting application for consumer key " + consumerKey);
        prov.getClient(consumerKey, callback);
    };

    prov.fetchAuthorizationInformation = function(username, token, callback) {
        if (log) log.info("getting auth information for user "+username+" with token " + token);
        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null, null);
            } else if (!_(rt).has("username") || rt.username !== username) {
                callback(new Error("Request token not associated with username '" + username + "'"), null, null);
            } else {
                prov.getClient(rt.consumer_key, function(err, client) {
                    if (err) {
                        callback(err, null, null);
                    } else {
                        if (!_(client).has("title")) {
                            client.title = "(Unknown)";
                        }
                        if (!_(client).has("description")) {
                            client.description = "(Unknown)";
                        }
                        callback(null, client, rt);
                    }
                });
            }
        });
    };

    prov.validToken = function(accessToken, callback) {
        if (log) log.info("checking for valid token " + accessToken);
        AccessToken.get(accessToken, callback);
    };

    prov.tokenByTokenAndVerifier = function(token, verifier, callback) {
        if (log) log.info("checking for valid request token " + token + " with verifier " + verifier);
        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null);
            } else if (rt.verifier !== verifier) {
                callback(new Error("Wrong verifier"), null);
            } else {
                callback(null, rt);
            }
        });
    };

    prov.validateNotReplayClient = function(consumerKey, accessToken, timestamp, nonce, callback) {
        var now = Math.floor(Date.now()/1000),
            ts;

        if (log) log.info("checking for replay with consumer key " + consumerKey + ", token = " + accessToken);

        try {
            ts = parseInt(timestamp, 10);
        } catch (err) {
            callback(err, null);
            return;
        }

        if (Math.abs(ts - now) > TIMELIMIT) {
            callback(null, false);
            return;
        }

        Step(
            function() {
                prov.getClient(consumerKey, this);
            },
            function(err, client) {
                if (err) throw err;
                if (!accessToken) {
                    this(null, null);
                } else {
                    AccessToken.get(accessToken, this);
                }
            },
            function(err, at) {
                if (err) throw err;
                if (at && at.consumer_key !== consumerKey) {
                    throw new Error("consumerKey and accessToken don't match");
                }
                Nonce.seenBefore(consumerKey, accessToken, nonce, timestamp, this);
            },
            function(err, seen) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, !seen);
                }
            }
        );
    };

    prov.userIdByToken = function(token, callback) {
        var user, client, at;

        if (log) log.info("checking for user with token = " + token);

        Step(
            function() {
                AccessToken.get(token, this);
            },
            function(err, res) {
                if (err) throw err;
                at = res;
                prov.getClient(at.consumer_key, this);
            },
            function(err, res) {
                if (err) throw err;
                client = res;
                User.get(at.username, this);
            },
            function(err, res) {
                if (err) {
                    callback(err, null);
                } else {
                    user = res;
                    callback(null, {id: at.username, user: user, client: client});
                }
            }
        );
    };

    prov.authenticateUser = function(username, password, oauthToken, callback) {

        if (log) log.info("authenticating user with username " + username + " and token " + oauthToken);

        User.checkCredentials(username, password, function(err, user) {
            if (err) {
                callback(err, null);
                return;
            }
            if (!user) {
                callback(new Error("Bad credentials"), null);
                return;
            }
            RequestToken.get(oauthToken, function(err, rt) {
                if (err) {
                    callback(err, null);
                    return;
                }
                if (rt.username && rt.username !== username) {
                    callback(new Error("Token already associated with a different user"), null);
                    return;
                }
                rt.authenticated = true;
                rt.save(function(err, rt) {
                    if (err) {
                        callback(err, null);
                    } else {
                        callback(null, rt);
                    }
                });
            });
        });
    };

    prov.associateTokenToUser = function(username, token, callback) {

        if (log) log.info("associating username " + username + " with token " + token);

        RequestToken.get(token, function(err, rt) {
            if (err) {
                callback(err, null);
                return;
            }
            if (rt.username && rt.username !== username) {
                callback(new Error("Token already associated"), null);
                return;
            }
            rt.update({username: username}, function(err, rt) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, rt);
                }
            });
        });
    };

    prov.generateRequestToken = function(oauthConsumerKey, oauthCallback, callback) {

        if (log) log.info("getting a request token for " + oauthConsumerKey);

        if (oauthCallback !== "oob") {
            var parts = url.parse(oauthCallback);

            if (!parts.host || !parts.protocol || (parts.protocol !== "http:" && parts.protocol !== "https:")) {
                callback(new Error("Invalid callback URL"), null);
                return;
            }
        }

        prov.getClient(oauthConsumerKey, function(err, client) {
            if (err) {
                callback(err, null);
                return;
            }
            var props = {consumer_key: oauthConsumerKey,
                         callback: oauthCallback};
            RequestToken.create(props, callback);
        });
    };

    prov.generateAccessToken = function(oauthToken, callback) {

        var rt, at;

        if (log) log.info("getting an access token for " + oauthToken);

        Step(
            function() {
                RequestToken.get(oauthToken, this);
            },
            function(err, results) {
                if (err) throw err;
                rt = results;
                if (!rt.username) {
                    throw new Error("Request token not associated");
                }
                if (rt.access_token) {
                    // XXX: search AccessToken instead...?
                    throw new Error("Request token already used");
                }
                AccessToken.search({consumer_key: rt.consumer_key,
                                    username: rt.username},
                                   this);
            },
            function(err, ats) {
                var props;
                if (err) throw err;
                if (!ats || ats.length === 0) {
                    if (log) log.info("creating a new access token for " + oauthToken);
                    props = {consumer_key: rt.consumer_key,
                             request_token: rt.token,
                             username: rt.username};
                    AccessToken.create(props, this);
                } else {
                    if (log) log.info("reusing access token " + ats[0].access_token + " for " + oauthToken);
                    // XXX: keep an array of related request tokens, not just one
                    ats[0].update({request_token: rt.token}, this);
                }
            },
            function(err, results) {
                if (err) throw err;
                at = results;
                // XXX: delete...?
                if (log) log.info("saving access token for " + oauthToken);
                rt.update({access_token: at.access_token}, this);
            },
            function(err, rt) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, at);
                }
            }
        );
    };

    prov.cleanRequestTokens = function(consumerKey, callback) {

        if (log) log.info("cleaning up request tokens for " + consumerKey);

        Step(
            function() {
                prov.getClient(consumerKey, this);
            },
            function(err, client) {
                if (err) throw err;
                RequestToken.search({consumer_key: consumerKey}, this);
            },
            function(err, rts) {
                var id, now = Date.now(), touched, group = this.group();
                if (err) throw err;
                for (id in rts) {
                    touched = Date.parse(rts[id].updated);
                    if (now - touched > (REQUESTTOKENTIMEOUT * 1000)) { // ms -> sec
                        rts[id].del(group());
                    }
                }
            },
            function(err) {
                callback(err, null);
            }
        );
    };

    prov.newTokenPair = function(client, user, callback) {

        Step(
            function() {
                prov.generateRequestToken(client.consumer_key, "oob", this);
            },
            function(err, rt) {
                if (err) throw err;
                prov.associateTokenToUser(user.nickname, rt.token, this);
            },
            function(err, rt) {
                if (err) throw err;
                prov.generateAccessToken(rt.token, this);
            },
            function(err, pair) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, pair);
                }
            }
        );
    };
};

exports.Provider = Provider;
<|endoftext|>


<commit_before><commit_msg>add amap.js<commit_after>var cordova = require('cordova');
var exec = require('cordova/exec');
module.exports = {
    //获取当前地址
    getCurrentPosition: function (successCallback, errorCallback) {
        cordova.exec(successCallback, errorCallback, "AMapPlugin", "getCurrentPosition", []);
    },
    //开启持续定位
    startUpdatePosition: function (successCallback, errorCallback) {
        cordova.exec(successCallback, errorCallback, "AMapPlugin", "startUpdatePosition", []);
    },
    //读取持续定位数据
    readUpdatePosition: function (successCallback, errorCallback) {
        cordova.exec(successCallback, errorCallback, "AMapPlugin", "readUpdatePosition", []);
    },
    //停止定位
    stopUpdatePosition: function (successCallback, errorCallback) {
        cordova.exec(successCallback, errorCallback, "AMapPlugin", "stopUpdatePosition", []);
    },
    //展示地图
    showMap: function (successCallback, errorCallback, coordinates, tips, title) {
        cordova.exec(successCallback, errorCallback, "AMapPlugin", "showMap", [coordinates, tips, title]);
    },
    //关闭展示的地图
    hideMap: function (successCallback, errorCallback) {
        cordova.exec(successCallback, errorCallback, "AMapPlugin", "hideMap", []);
    },
    //轨迹地图
    traceMap: function (successCallback, errorCallback, coordinates, title) {
        cordova.exec(successCallback, errorCallback, "AMapPlugin", "traceMap", [coordinates, title]);
    }
};<|endoftext|>


<commit_before>import serialize from 'serialize-javascript';

// html attributes deserialization
const htmlAttributes = attrs => Object.keys(attrs)
  .map(attrName => `${attrName}="${attrs[attrName]}"`)
  .join(' ');

// tags array deserialization
const insertTags = tags =>
  tags
    .map(tag => `<${tag.tag} ${htmlAttributes(tag.attributes)}>${
      (tag.tag !== 'meta' && tag.tag !== 'link') ?
      `${tag.content}</${tag.tag}>` :
      ''
    }`)
    .join(' ');

// script tag deserialization from url
const scriptTag = url => `<script type="text/javascript" src="${url}"></script>`;

export default function generate(templateParams) {
  const { config, bundleConfig, clientConfig } = templateParams.htmlWebpackPlugin.options.custom;
  const { htmlPage, webPath, devVendorDLL } = bundleConfig;

  return `
    <!DOCTYPE html>

        <title>${htmlPage.defaultTitle}</title>
        ${insertTags(htmlPage.header)}

        ${
          // Enable the polyfill io script?
          // This can't be configured within a react-helmet component as we
          // may need the polyfill's before our client bundle gets parsed.
          config.polyfillIO.enabled
            ? scriptTag(config.polyfillIO.url)
            : ''
        }
        ${
          // When we are in development mode our development server will generate a
          // vendor DLL in order to dramatically reduce our compilation times.  Therefore
          // we need to inject the path to the vendor dll bundle below.
          // @see /tools/development/ensureVendorDLLExists.js
          process.env.NODE_ENV === 'development' && devVendorDLL && devVendorDLL.enabled ?
            scriptTag(`${webPath}${devVendorDLL.name}.js`) :
            ''
        }
        ${insertTags(htmlPage.footer)}

    `;
}
<commit_msg>html page generator fixes<commit_after>import serialize from 'serialize-javascript';

// html attributes deserialization
const htmlAttributes = attrs => (
  attrs ?
  Object.keys(attrs)
    .map(attrName => `${attrName}="${attrs[attrName]}"`)
    .join(' ') :
  ''
);

// tags array deserialization
const insertTags = tags => (
  tags ?
  tags.map(tag => `<${tag.tag} ${htmlAttributes(tag.attributes)}>${
      (tag.tag !== 'meta' && tag.tag !== 'link') ?
      `${tag.content}</${tag.tag}>` :
      ''
    }`)
    .join(' ') :
  ''
);

// script tag deserialization from url
const scriptTag = url => `<script type="text/javascript" src="${url}"></script>`;

export default function generate(templateParams) {
  const { config, bundleConfig, clientConfig } = templateParams.htmlWebpackPlugin.options.custom;
  const { htmlPage, webPath, devVendorDLL } = bundleConfig;

  return `
    <!DOCTYPE html>

        <title>${htmlPage.defaultTitle}</title>
        ${insertTags(htmlPage.header)}

        ${
          // Enable the polyfill io script?
          // This can't be configured within a react-helmet component as we
          // may need the polyfill's before our client bundle gets parsed.
          config.polyfillIO.enabled
            ? scriptTag(config.polyfillIO.url)
            : ''
        }
        ${
          // When we are in development mode our development server will generate a
          // vendor DLL in order to dramatically reduce our compilation times.  Therefore
          // we need to inject the path to the vendor dll bundle below.
          // @see /tools/development/ensureVendorDLLExists.js
          process.env.NODE_ENV === 'development' && devVendorDLL && devVendorDLL.enabled ?
            scriptTag(`${webPath}${devVendorDLL.name}.js`) :
            ''
        }
        ${insertTags(htmlPage.footer)}

    `;
}
<|endoftext|>