<commit_before>export { NeuralNet_TestParams_Base as Base };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
import * as RandTools from "../../util/RandTools.js";
import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as NeuralNet from "../../Conv/NeuralNet.js";
import * as TestParams from "./TestParams.js";
import * as Embedding_TestParams from "./Embedding_TestParams.js";
import * as Stage_TestParams from "./Stage_TestParams.js";
import * as Block_TestParams from "./Block_TestParams.js";

/**
 *
 * This is an object { id, in, out } which has one number and two sub-objects.
 *
 *
 * @see TestParams.Base
 */
class NeuralNet_TestParams_Base extends TestParams.Base {

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

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

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

  /** @override */
  static setAsConstructor_self() {
    this.stageArray = Recyclable.OwnerArray.Pool.get_or_create_by();
    this.out = NeuralNet.ParamsBase.Pool.get_or_create_by();
  }

  /** @override */
  disposeResources() {
    this.out?.disposeResources_and_recycleToPool();
    this.out = null;

    this.blockFinal?.disposeResources_and_recycleToPool();
    this.blockFinal = null;

    this.stageArray?.disposeResources_and_recycleToPool();
    this.stageArray = null;

    this.embedding?.disposeResources_and_recycleToPool();
    this.embedding = null;

    super.disposeResources();
  }

  /**
   * Use scattered parameters to fills the following proterties:
   *   - this.in
   *   - this.in_weights
   *   - this.out
   *
   * @param {NeuralNet.ParamsBase} aParamsBase  The parameters of neural network.
   *
   * @return {Base}  Return this object self.
   */
  set_byParamsBase( aParamsBase ) {
    return this.set_byParamsScattered(
      aParamsBase.input_height, aParamsBase.input_width, aParamsBase.input_channelCount,
      aParamsBase.vocabularyChannelCount, aParamsBase.vocabularyCountPerInputChannel,
      aParamsBase.nConvStageTypeId,
      aParamsBase.blockCountTotalRequested,
      aParamsBase.output_channelCount,
      aParamsBase.bKeepInputTensor
    );
  }

  /**
   * Use scattered parameters to fills the following proterties:
   *   - this.in
   *   - this.in_weights
   *   - this.out
   *
   * @return {Base}
   *   Return this object self.
   */
  set_byParamsScattered(
    input_height, input_width, input_channelCount,
    vocabularyChannelCount, vocabularyCountPerInputChannel,
    nConvStageTypeId,
    blockCountTotalRequested,
    output_channelCount,
    bKeepInputTensor
  ) {

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

    this.out = NeuralNet.ParamsBase.Pool.get_or_create_by(
      input_height, input_width, input_channelCount,
      vocabularyChannelCount, vocabularyCountPerInputChannel,
      nConvStageTypeId,
      blockCountTotalRequested,
      output_channelCount,
      bKeepInputTensor
    );

    Object.assign( this.in, this.out ); // So that all parameters are by specified (none is by evolution).

    let weightElementOffsetBegin = 0;
    return this.set_byParamsNumberArrayObject_ParamsOut( weightElementOffsetBegin );
  }

  /**
   * Fills the following proterties:
   *   - this.in_weights
   *   - this.out.inferencedParams
   *
   * @param {object} this.in.paramsNumberArrayObject
   *   Pass in an object. The result will be put into this object. It is a map from a string name (e.g. parameter name) to a number array.
   * The name should be one of Base.paramsNameOrderArray[] elements.
   *
   * @param {NeuralNet.ParamsBase} this.out
   *   An object which will be the final result of NeuralNet.Params.
   *
   * @param {number} weightElementOffsetBegin
   *   Offset how many elements (4 bytes per element) at the beginning of the result inputWeightArray.
   * The this.in.byteOffsetBegin will be ( 4 * weightElementOffsetBegin ).
   *
   * @return {NeuralNet_TestParams_Base}
   *   Return this object self.
   */
  set_byParamsNumberArrayObject_ParamsOut( weightElementOffsetBegin = 0 ) {
    let neuralNetParams = this.out;

    this.generate_out_inferencedParams();

    this.in.paramsNumberArrayObject.length = 0;

    // 1. Embedding
    {
      this.embedding?.disposeResources_and_recycleToPool();
      this.embedding = Embedding_TestParams.Base.Pool.get_or_create_by( this.id );

      this.embedding.set_byParamsScattered(
        neuralNetParams.input_height,
        neuralNetParams.input_width,
        neuralNetParams.input_channelCount,
        neuralNetParams.vocabularyChannelCount,
        neuralNetParams.vocabularyCountPerInputChannel,
        neuralNetParams.inferencedParams.bEmbedVocabularyId,
        neuralNetParams.bKeepInputTensor
      );

      this.in.paramsNumberArrayObject.push( this.embedding.in_weights.weightArray );
    }

    // 2. Stages
    let stageParamsArray = neuralNetParams.inferencedParams.stageParamsArray;

    this.stageArray.clear();
    this.stageArray.length = stageParamsArray.length;

    for ( let i = 0; i < stageParamsArray.length; ++i ) { // Stage0, 1, 2, 3, ..., StageLast.
      let stageParams = stageParamsArray[ i ];

      let stageTestParams = Stage_TestParams.Base.Pool.get_or_create_by( this.id );
      stageTestParams.set_byParamsScattered(
        stageParams.input_height, stageParams.input_width, stageParams.input_channelCount,
        stageParams.nConvStageTypeId,
        stageParams.blockCountRequested,
        stageParams.bPointwise1,
        stageParams.depthwiseFilterHeight, stageParams.depthwiseFilterWidth,
        stageParams.nSqueezeExcitationChannelCountDivisor,
        stageParams.nActivationId,
        stageParams.bKeepInputTensor
      );

      this.stageArray[ i ] = stageTestParams;
      this.in.paramsNumberArrayObject.push( stageTestParams.in_weights.weightArray ); // Place every stage's parameters in sequence.
    }

    // 3. blockFinal
    {
      let blockFinalParams = neuralNetParams.inferencedParams.blockFinalParams;

      let blockTestParams = Block_TestParams.Base.Pool.get_or_create_by( this.id );
      blockTestParams.set_byParamsBase( blockFinalParams );

      this.blockFinal?.disposeResources_and_recycleToPool();
      this.blockFinal = blockTestParams;

      this.in.paramsNumberArrayObject.push( blockTestParams.in_weights.weightArray ); // Place final block's parameters in sequence.
    }

    // 4. Pack all parameters, look-up tables weights into a (pre-allocated and re-used) NumberArray.
    this.in_weights.set_byConcat(
      NeuralNet_TestParams_Base.paramsNameOrderArray_Basic, this.in.paramsNumberArrayObject, weightElementOffsetBegin );

    { // 5. Release temporary intermediate array for reducing memory usage.
      for ( let i = 0; i < this.stageArray.length; ++i ) {
        let stageTestParams = this.stageArray[ i ];
        stageTestParams.in_weights.weightArray.length = 0;
      }

      let blockTestParams = this.blockFinal;
      blockTestParams.in_weights.weightArray.length = 0;
    }

    return this;
  }

  /** Fill this.out.inferencedParams according to this.out */
  generate_out_inferencedParams() {
    this.out.inferencedParams_create();
  }

  /**
   * @override
   */
  onYield_isLegal() {
    return true;
  }

  /**
   * @override
   */
  onYield_before() {

    // For testing not start at the offset 0.
    let weightElementOffsetBegin = RandTools.getRandomIntInclusive( 0, 3 ); // Skip a random un-used element count.

    this.set_byParamsNumberArrayObject_ParamsOut( weightElementOffsetBegin );
  }

  /**
   * @override
   */
  onYield_after() {
    this.blockFinal?.disposeResources_and_recycleToPool();
    this.blockFinal = null;

    this.stageArray.clear();

    this.embedding?.disposeResources_and_recycleToPool();
    this.embedding = null;
  }

  /**
   * Responsible for generating testing paramters combinations.
   *
   * @yield {Base}
   *   Yield this object itself. The returned object (it is this object itself) should not be modified because it will be re-used.
   */
  * ParamsGenerator() {

    // Restrict some parameter's large kinds. Otherwise, too many combination will be generated.
    let valueOutMinMax = this.valueOutMinMax = {
      input_height: [ 3, 5 ],
      input_width: [ 3, 5 ],

      input_channelCount: [
        1, //NeuralNet.Params.input_channelCount.valueDesc.range.min,
        4
      ],

      vocabularyChannelCount: [
        1, //NeuralNet.Params.vocabularyChannelCount.valueDesc.range.min,
        3 //4
      ],

      vocabularyCountPerInputChannel: [
        256, //NeuralNet.Params.vocabularyCountPerInputChannel.valueDesc.range.min,
        256
      ],

      // (2022/08/16) Note: Mobile Moto e40 seems necessary pad=valid to work.
      //

      //!!! (2022/08/16 Temp Remarked) For mobile phone Moto e40 could pass testing.
      nConvStageTypeId: [
        NeuralNet.Params.nConvStageTypeId.valueDesc.range.min,
        NeuralNet.Params.nConvStageTypeId.valueDesc.range.max
      ],
      // nConvStageTypeId: [
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID, // (6)
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID // (6)
      // ],
      // nConvStageTypeId: [
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1, // (5)
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID, // (6)
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID // (6)
      // ],

      blockCountTotalRequested: [
        NeuralNet.Params.blockCountTotalRequested.valueDesc.range.min,
        20 //NeuralNet.Params.blockCountTotalRequested.valueDesc.range.max
      ],

      output_channelCount: [
        1, //NeuralNet.Params.output_channelCount.valueDesc.range.min,
        10
      ],

      // bKeepInputTensor: undefined,
      bKeepInputTensor: [
        NeuralNet.Params.bKeepInputTensor.valueDesc.range.min,
        NeuralNet.Params.bKeepInputTensor.valueDesc.range.max
      ],
    };

    // All the parameters to be tried.
    //
    // Note: The order of these element could be adjusted to change testing order. The last element will be tested (changed) first.
    let paramDescConfigArray = [
      new TestParams.ParamDescConfig( NeuralNet.Params.input_height,                   valueOutMinMax.input_height ),
      new TestParams.ParamDescConfig( NeuralNet.Params.input_width,                    valueOutMinMax.input_width ),
      new TestParams.ParamDescConfig( NeuralNet.Params.input_channelCount,             valueOutMinMax.input_channelCount ),

      new TestParams.ParamDescConfig( NeuralNet.Params.vocabularyChannelCount,         valueOutMinMax.vocabularyChannelCount ),
      new TestParams.ParamDescConfig( NeuralNet.Params.vocabularyCountPerInputChannel, valueOutMinMax.vocabularyCountPerInputChannel ),

      new TestParams.ParamDescConfig( NeuralNet.Params.nConvStageTypeId,               valueOutMinMax.nConvStageTypeId ),

      new TestParams.ParamDescConfig( NeuralNet.Params.blockCountTotalRequested,       valueOutMinMax.blockCountTotalRequested ),

      new TestParams.ParamDescConfig( NeuralNet.Params.output_channelCount,            valueOutMinMax.output_channelCount ),

      new TestParams.ParamDescConfig( NeuralNet.Params.bKeepInputTensor,               valueOutMinMax.bKeepInputTensor ),
    ];

    yield *NeuralNet_TestParams_Base.ParamsGenerator.call( this, paramDescConfigArray );
  }

}

/**
 * The order when generate inputWeightArray[].
 *
 * This order could not be changed arbitrarily. It must be the same as the parameter extracting order of NeuralNet.initer().
 */
NeuralNet_TestParams_Base.paramsNameOrderArray_Basic = [
  NeuralNet.Params.input_height.paramName,
  NeuralNet.Params.input_width.paramName,
  NeuralNet.Params.input_channelCount.paramName,
  NeuralNet.Params.vocabularyChannelCount.paramName,
  NeuralNet.Params.vocabularyCountPerInputChannel.paramName,
  NeuralNet.Params.nConvStageTypeId.paramName,
  NeuralNet.Params.blockCountTotalRequested.paramName,
  NeuralNet.Params.output_channelCount.paramName,
  NeuralNet.Params.bKeepInputTensor.paramName,
];
<commit_msg>blockCountTotalRequested<commit_after>export { NeuralNet_TestParams_Base as Base };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
import * as RandTools from "../../util/RandTools.js";
import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as NeuralNet from "../../Conv/NeuralNet.js";
import * as TestParams from "./TestParams.js";
import * as Embedding_TestParams from "./Embedding_TestParams.js";
import * as Stage_TestParams from "./Stage_TestParams.js";
import * as Block_TestParams from "./Block_TestParams.js";

/**
 *
 * This is an object { id, in, out } which has one number and two sub-objects.
 *
 *
 * @see TestParams.Base
 */
class NeuralNet_TestParams_Base extends TestParams.Base {

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

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

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

  /** @override */
  static setAsConstructor_self() {
    this.stageArray = Recyclable.OwnerArray.Pool.get_or_create_by();
    this.out = NeuralNet.ParamsBase.Pool.get_or_create_by();
  }

  /** @override */
  disposeResources() {
    this.out?.disposeResources_and_recycleToPool();
    this.out = null;

    this.blockFinal?.disposeResources_and_recycleToPool();
    this.blockFinal = null;

    this.stageArray?.disposeResources_and_recycleToPool();
    this.stageArray = null;

    this.embedding?.disposeResources_and_recycleToPool();
    this.embedding = null;

    super.disposeResources();
  }

  /**
   * Use scattered parameters to fills the following proterties:
   *   - this.in
   *   - this.in_weights
   *   - this.out
   *
   * @param {NeuralNet.ParamsBase} aParamsBase  The parameters of neural network.
   *
   * @return {Base}  Return this object self.
   */
  set_byParamsBase( aParamsBase ) {
    return this.set_byParamsScattered(
      aParamsBase.input_height, aParamsBase.input_width, aParamsBase.input_channelCount,
      aParamsBase.vocabularyChannelCount, aParamsBase.vocabularyCountPerInputChannel,
      aParamsBase.nConvStageTypeId,
      aParamsBase.blockCountTotalRequested,
      aParamsBase.output_channelCount,
      aParamsBase.bKeepInputTensor
    );
  }

  /**
   * Use scattered parameters to fills the following proterties:
   *   - this.in
   *   - this.in_weights
   *   - this.out
   *
   * @return {Base}
   *   Return this object self.
   */
  set_byParamsScattered(
    input_height, input_width, input_channelCount,
    vocabularyChannelCount, vocabularyCountPerInputChannel,
    nConvStageTypeId,
    blockCountTotalRequested,
    output_channelCount,
    bKeepInputTensor
  ) {

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

    this.out = NeuralNet.ParamsBase.Pool.get_or_create_by(
      input_height, input_width, input_channelCount,
      vocabularyChannelCount, vocabularyCountPerInputChannel,
      nConvStageTypeId,
      blockCountTotalRequested,
      output_channelCount,
      bKeepInputTensor
    );

    Object.assign( this.in, this.out ); // So that all parameters are by specified (none is by evolution).

    let weightElementOffsetBegin = 0;
    return this.set_byParamsNumberArrayObject_ParamsOut( weightElementOffsetBegin );
  }

  /**
   * Fills the following proterties:
   *   - this.in_weights
   *   - this.out.inferencedParams
   *
   * @param {object} this.in.paramsNumberArrayObject
   *   Pass in an object. The result will be put into this object. It is a map from a string name (e.g. parameter name) to a number array.
   * The name should be one of Base.paramsNameOrderArray[] elements.
   *
   * @param {NeuralNet.ParamsBase} this.out
   *   An object which will be the final result of NeuralNet.Params.
   *
   * @param {number} weightElementOffsetBegin
   *   Offset how many elements (4 bytes per element) at the beginning of the result inputWeightArray.
   * The this.in.byteOffsetBegin will be ( 4 * weightElementOffsetBegin ).
   *
   * @return {NeuralNet_TestParams_Base}
   *   Return this object self.
   */
  set_byParamsNumberArrayObject_ParamsOut( weightElementOffsetBegin = 0 ) {
    let neuralNetParams = this.out;

    this.generate_out_inferencedParams();

    this.in.paramsNumberArrayObject.length = 0;

    // 1. Embedding
    {
      this.embedding?.disposeResources_and_recycleToPool();
      this.embedding = Embedding_TestParams.Base.Pool.get_or_create_by( this.id );

      this.embedding.set_byParamsScattered(
        neuralNetParams.input_height,
        neuralNetParams.input_width,
        neuralNetParams.input_channelCount,
        neuralNetParams.vocabularyChannelCount,
        neuralNetParams.vocabularyCountPerInputChannel,
        neuralNetParams.inferencedParams.bEmbedVocabularyId,
        neuralNetParams.bKeepInputTensor
      );

      this.in.paramsNumberArrayObject.push( this.embedding.in_weights.weightArray );
    }

    // 2. Stages
    let stageParamsArray = neuralNetParams.inferencedParams.stageParamsArray;

    this.stageArray.clear();
    this.stageArray.length = stageParamsArray.length;

    for ( let i = 0; i < stageParamsArray.length; ++i ) { // Stage0, 1, 2, 3, ..., StageLast.
      let stageParams = stageParamsArray[ i ];

      let stageTestParams = Stage_TestParams.Base.Pool.get_or_create_by( this.id );
      stageTestParams.set_byParamsScattered(
        stageParams.input_height, stageParams.input_width, stageParams.input_channelCount,
        stageParams.nConvStageTypeId,
        stageParams.blockCountRequested,
        stageParams.bPointwise1,
        stageParams.depthwiseFilterHeight, stageParams.depthwiseFilterWidth,
        stageParams.nSqueezeExcitationChannelCountDivisor,
        stageParams.nActivationId,
        stageParams.bKeepInputTensor
      );

      this.stageArray[ i ] = stageTestParams;
      this.in.paramsNumberArrayObject.push( stageTestParams.in_weights.weightArray ); // Place every stage's parameters in sequence.
    }

    // 3. blockFinal
    {
      let blockFinalParams = neuralNetParams.inferencedParams.blockFinalParams;

      let blockTestParams = Block_TestParams.Base.Pool.get_or_create_by( this.id );
      blockTestParams.set_byParamsBase( blockFinalParams );

      this.blockFinal?.disposeResources_and_recycleToPool();
      this.blockFinal = blockTestParams;

      this.in.paramsNumberArrayObject.push( blockTestParams.in_weights.weightArray ); // Place final block's parameters in sequence.
    }

    // 4. Pack all parameters, look-up tables weights into a (pre-allocated and re-used) NumberArray.
    this.in_weights.set_byConcat(
      NeuralNet_TestParams_Base.paramsNameOrderArray_Basic, this.in.paramsNumberArrayObject, weightElementOffsetBegin );

    { // 5. Release temporary intermediate array for reducing memory usage.
      for ( let i = 0; i < this.stageArray.length; ++i ) {
        let stageTestParams = this.stageArray[ i ];
        stageTestParams.in_weights.weightArray.length = 0;
      }

      let blockTestParams = this.blockFinal;
      blockTestParams.in_weights.weightArray.length = 0;
    }

    return this;
  }

  /** Fill this.out.inferencedParams according to this.out */
  generate_out_inferencedParams() {
    this.out.inferencedParams_create();
  }

  /**
   * @override
   */
  onYield_isLegal() {
    return true;
  }

  /**
   * @override
   */
  onYield_before() {

    // For testing not start at the offset 0.
    let weightElementOffsetBegin = RandTools.getRandomIntInclusive( 0, 3 ); // Skip a random un-used element count.

    this.set_byParamsNumberArrayObject_ParamsOut( weightElementOffsetBegin );
  }

  /**
   * @override
   */
  onYield_after() {
    this.blockFinal?.disposeResources_and_recycleToPool();
    this.blockFinal = null;

    this.stageArray.clear();

    this.embedding?.disposeResources_and_recycleToPool();
    this.embedding = null;
  }

  /**
   * Responsible for generating testing paramters combinations.
   *
   * @yield {Base}
   *   Yield this object itself. The returned object (it is this object itself) should not be modified because it will be re-used.
   */
  * ParamsGenerator() {

    // Restrict some parameter's large kinds. Otherwise, too many combination will be generated.
    let valueOutMinMax = this.valueOutMinMax = {
      input_height: [ 3, 5 ],
      input_width: [ 3, 5 ],

      input_channelCount: [
        1, //NeuralNet.Params.input_channelCount.valueDesc.range.min,
        4
      ],

      vocabularyChannelCount: [
        1, //NeuralNet.Params.vocabularyChannelCount.valueDesc.range.min,
        3 //4
      ],

      vocabularyCountPerInputChannel: [
        256, //NeuralNet.Params.vocabularyCountPerInputChannel.valueDesc.range.min,
        256
      ],

      // (2022/08/16) Note: Mobile Moto e40 seems necessary pad=valid to work.
      //

      //!!! (2022/08/16 Temp Remarked) For mobile phone Moto e40 could pass testing.
      nConvStageTypeId: [
        NeuralNet.Params.nConvStageTypeId.valueDesc.range.min,
        NeuralNet.Params.nConvStageTypeId.valueDesc.range.max
      ],
      // nConvStageTypeId: [
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID, // (6)
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID // (6)
      // ],
      // nConvStageTypeId: [
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1, // (5)
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID, // (6)
      //   ValueDesc.ConvStageType.Singleton.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID // (6)
      // ],

      blockCountTotalRequested: [
        NeuralNet.Params.blockCountTotalRequested.valueDesc.range.min,
        10 //NeuralNet.Params.blockCountTotalRequested.valueDesc.range.max
      ],

      output_channelCount: [
        1, //NeuralNet.Params.output_channelCount.valueDesc.range.min,
        10
      ],

      // bKeepInputTensor: undefined,
      bKeepInputTensor: [
        NeuralNet.Params.bKeepInputTensor.valueDesc.range.min,
        NeuralNet.Params.bKeepInputTensor.valueDesc.range.max
      ],
    };

    // All the parameters to be tried.
    //
    // Note: The order of these element could be adjusted to change testing order. The last element will be tested (changed) first.
    let paramDescConfigArray = [
      new TestParams.ParamDescConfig( NeuralNet.Params.input_height,                   valueOutMinMax.input_height ),
      new TestParams.ParamDescConfig( NeuralNet.Params.input_width,                    valueOutMinMax.input_width ),
      new TestParams.ParamDescConfig( NeuralNet.Params.input_channelCount,             valueOutMinMax.input_channelCount ),

      new TestParams.ParamDescConfig( NeuralNet.Params.vocabularyChannelCount,         valueOutMinMax.vocabularyChannelCount ),
      new TestParams.ParamDescConfig( NeuralNet.Params.vocabularyCountPerInputChannel, valueOutMinMax.vocabularyCountPerInputChannel ),

      new TestParams.ParamDescConfig( NeuralNet.Params.nConvStageTypeId,               valueOutMinMax.nConvStageTypeId ),

      new TestParams.ParamDescConfig( NeuralNet.Params.blockCountTotalRequested,       valueOutMinMax.blockCountTotalRequested ),

      new TestParams.ParamDescConfig( NeuralNet.Params.output_channelCount,            valueOutMinMax.output_channelCount ),

      new TestParams.ParamDescConfig( NeuralNet.Params.bKeepInputTensor,               valueOutMinMax.bKeepInputTensor ),
    ];

    yield *NeuralNet_TestParams_Base.ParamsGenerator.call( this, paramDescConfigArray );
  }

}

/**
 * The order when generate inputWeightArray[].
 *
 * This order could not be changed arbitrarily. It must be the same as the parameter extracting order of NeuralNet.initer().
 */
NeuralNet_TestParams_Base.paramsNameOrderArray_Basic = [
  NeuralNet.Params.input_height.paramName,
  NeuralNet.Params.input_width.paramName,
  NeuralNet.Params.input_channelCount.paramName,
  NeuralNet.Params.vocabularyChannelCount.paramName,
  NeuralNet.Params.vocabularyCountPerInputChannel.paramName,
  NeuralNet.Params.nConvStageTypeId.paramName,
  NeuralNet.Params.blockCountTotalRequested.paramName,
  NeuralNet.Params.output_channelCount.paramName,
  NeuralNet.Params.bKeepInputTensor.paramName,
];
<|endoftext|>


<commit_before>'use strict';

import google from 'google';
import angular from 'angular';
import RedbaMap from 'RedbaMap';
import $ from 'jquery';
import ngMaterial from 'angular-material';
import ngAnimate from 'angular-animate';
import ngAria from 'angular-aria';
import QueryFilter from './filter';

const app = angular.module('redbaApp', [ngMaterial, ngAnimate, ngAria ]);

const {ControlPosition} = google.maps;

class AppController {
  constructor($http, $scope) {
    this.$http = $http;
    this.filter = new QueryFilter();
    this.hola = 'Hol';
    this.isDisabled = false;
    this.noCache = false;
    this.selectedItem;
    this.searchText = '';
    this.items = [];

    this.loading = true;
    this.regions = [];
    this.$scope = $scope;
  }

  $onInit() {
    let ele = document.getElementById('map_canvas');
    let ops = {
      sedeIcon: '/app/assets/dot-circle-icon.png',
      streetViewControl: false,
      mapTypeControlOptions: {
        position: ControlPosition.BOTTOM_LEFT
      },
      showSede: true
    };

    ops.regions = this.$http.get('data/regiones.json');

    ops.regions.then( response => {
      this.filter.setItems(response.data);
      this.loading = false;
    });

    ops.fetchRegion = (idRegion) => {
      return this.$http.get(`data/regiones/${idRegion}.json`);
    };

    ops.fetchDistrict = (idDistrict) => {
      return this.$http.get(`data/distritos/${idDistrict}.json`);
    };

    this.map = new RedbaMap(ele, ops);

    this.map.addListener('region.click', (region) => {
      var r = _.find(this.filter.searchs, i => {
        return i.type === 'region' && i.query.region.toString() === region.region.toString();
      });

      this.selectedItem = r;
      this.searchText = r.caption;
      this.$scope.$apply();
    });

    //this.map.addListener('sede.click', (region) => {
    //  region.sede.show()
    //});

    //this.map.addListener('region.over_change', (region, prevRegion) => {
    //  console.log('region.over_change');
    //  console.log(region, prevRegion);
    //  region.showAll();
    //  if (prevRegion){
    //    prevRegion.hideAll();
    //  }
    //});
  }

  selectedItemChange(item){
    if (item === undefined){
      return this.map.resetMap();
    }

    if (item.type === 'region'){
      var region = this.map.findRegion(item.query.region);
      region.show(true);
      region.fitBounds();
      // toggle other regions
      this.map.getRegions().forEach( r => {
        if (r.region !== parseInt(item.query.region)){
          r.hide();
        }
      });
    }

    if (item.type === 'distrito'){
      var region = this.map.findRegion(item.query.region);
      region.show();

      var dist = region.getDistrito(item.query.id);
      dist.show();

      if (dist.dataLoaded){
        dist.fitBounds();
      } else {
        dist.addListener('data_loaded', () => {
          dist.fitBounds();
        });
      }

      // toggle other regions
      this.map.getRegions().forEach( r => {
        if (r.region !== parseInt(item.query.region)){
          r.hide();
        }
      });
    }
  }

  querySearch(text){
    return this.filter.queryFilter(text);
  }
}

app.controller('AppController', AppController);

export default app;
<commit_msg>fix relative paths<commit_after>'use strict';

import google from 'google';
import angular from 'angular';
import RedbaMap from 'RedbaMap';
import $ from 'jquery';
import ngMaterial from 'angular-material';
import ngAnimate from 'angular-animate';
import ngAria from 'angular-aria';
import QueryFilter from './filter';

const app = angular.module('redbaApp', [ngMaterial, ngAnimate, ngAria ]);

const {ControlPosition} = google.maps;

class AppController {
  constructor($http, $scope) {
    this.$http = $http;
    this.filter = new QueryFilter();
    this.hola = 'Hol';
    this.isDisabled = false;
    this.noCache = false;
    this.selectedItem;
    this.searchText = '';
    this.items = [];

    this.loading = true;
    this.regions = [];
    this.$scope = $scope;
  }

  $onInit() {
    let ele = document.getElementById('map_canvas');
    let ops = {
      sedeIcon: 'app/assets/dot-circle-icon.png',
      streetViewControl: false,
      mapTypeControlOptions: {
        position: ControlPosition.BOTTOM_LEFT
      },
      showSede: true
    };

    ops.regions = this.$http.get('data/regiones.json');

    ops.regions.then( response => {
      this.filter.setItems(response.data);
      this.loading = false;
    });

    ops.fetchRegion = (idRegion) => {
      return this.$http.get(`data/regiones/${idRegion}.json`);
    };

    ops.fetchDistrict = (idDistrict) => {
      return this.$http.get(`data/distritos/${idDistrict}.json`);
    };

    this.map = new RedbaMap(ele, ops);

    this.map.addListener('region.click', (region) => {
      var r = _.find(this.filter.searchs, i => {
        return i.type === 'region' && i.query.region.toString() === region.region.toString();
      });

      this.selectedItem = r;
      this.searchText = r.caption;
      this.$scope.$apply();
    });

    //this.map.addListener('sede.click', (region) => {
    //  region.sede.show()
    //});

    //this.map.addListener('region.over_change', (region, prevRegion) => {
    //  console.log('region.over_change');
    //  console.log(region, prevRegion);
    //  region.showAll();
    //  if (prevRegion){
    //    prevRegion.hideAll();
    //  }
    //});
  }

  selectedItemChange(item){
    if (item === undefined){
      return this.map.resetMap();
    }

    if (item.type === 'region'){
      var region = this.map.findRegion(item.query.region);
      region.show(true);
      region.fitBounds();
      // toggle other regions
      this.map.getRegions().forEach( r => {
        if (r.region !== parseInt(item.query.region)){
          r.hide();
        }
      });
    }

    if (item.type === 'distrito'){
      var region = this.map.findRegion(item.query.region);
      region.show();

      var dist = region.getDistrito(item.query.id);
      dist.show();

      if (dist.dataLoaded){
        dist.fitBounds();
      } else {
        dist.addListener('data_loaded', () => {
          dist.fitBounds();
        });
      }

      // toggle other regions
      this.map.getRegions().forEach( r => {
        if (r.region !== parseInt(item.query.region)){
          r.hide();
        }
      });
    }
  }

  querySearch(text){
    return this.filter.queryFilter(text);
  }
}

app.controller('AppController', AppController);

export default app;
<|endoftext|>


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

	var templateClass = {
		options: null,
		tmpl: '',
		isRequired: false,
		requiredText: '',
		name: '',
		title: '',
		isTitle: '',
		id: '',
		help: '',
		titleTransclude: false,
		// -------------------------------------------------------------------------
		//
		// this generates the standard first bit of all form displays
		//
		// -------------------------------------------------------------------------
		new: function (options) {
			this.options         = options;
			this.help            = (options.hasOwnProperty('help')) ? options.help : null;
			this.tmpl            = (options.hasOwnProperty('tmpl')) ? options.tmpl : '';
			this.isTitle         = (options.hasOwnProperty('title'));
			this.title           = (this.isTitle) ? options.title : '';
			this.name            = options.name;
			this.titleTransclude = (options.hasOwnProperty('titleTransclude') && options.titleTransclude);
			this.isRequired      = (options.hasOwnProperty('required'));
			this.required        = (this.isRequired && typeof (options.required) === 'string') ? options.required : (this.isTitle ? this.title+' is required' : 'This field is required');
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// start and end the div
		//
		// -------------------------------------------------------------------------
		open: function () {
			this.tmpl += '
';
			return this;
		},
		close: function () {
			this.tmpl += '
';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// make a label
		//
		// -------------------------------------------------------------------------
		label: function () {
			if (this.isTitle) {
				var fieldtoggle = 'fieldtoggle'+this.name;
				this.tmpl += '' + this.title + '';
				if (this.isRequired) {
					this.tmpl += ' *';
				}
				if (this.help) {
					this.tmpl += '   ';
					this.tmpl += '
';
					this.tmpl += '
'+this.help+'
';
					this.tmpl += '
';
				}
			}
			if (this.titleTransclude) {
				this.tmpl += '';
			}
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// this generates the required message
		//
		// -------------------------------------------------------------------------
		error: function () {
			if (this.isRequired) {
				this.tmpl += '
';
				this.tmpl += '
' + this.required + '
';
				this.tmpl += '
';
			}
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// make an input box
		//
		// -------------------------------------------------------------------------
		inputControl: function (attrs) {
			this.tmpl += '<input ';
			// ----------------------------------------------------------------------------------
			if ( this.options.hasOwnProperty('type') ) {
				this.tmpl += ' type="' + this.options.type + '"';
			} else {
				this.tmpl += ' type="text"';
			}
			// ----------------------------------------------------------------------------------
			this.tmpl += ' id="' + this.options.id + '" name="' + this.options.name + '" class="form-control ';
			// ----------------------------------------------------------------------------------
			// Format as number
			if ( this.options.hasOwnProperty('number') ) {
				this.tmpl += ' format-as-number text-right';
			}
			// ----------------------------------------------------------------------------------
			this.tmpl += '" ng-model="ngModel"';
			// ----------------------------------------------------------------------------------
			// Placeholder
			if ( this.options.hasOwnProperty('placeholder') ) {
				this.tmpl += ' placeholder="' + this.options.placeholder + '"';
			}
			// Validator
			if ( attrs.hasOwnProperty('validate') ) {
				this.tmpl += ' ng-change="processValidator()"';
			} else if ( attrs.hasOwnProperty('validateOf') ) {
				this.tmpl += ' ng-change="callValidator(\'' + attrs.validateOf + '\')"';
			}
			if (attrs.hasOwnProperty ('onchange')) {
				this.tmpl += ' ng-change="'+attrs.onchange+'()"';
				console.log (this.tmpl);
			}
			// ----------------------------------------------------------------------------------
			if ( this.options.hasOwnProperty('required') ) {
				this.tmpl += ' required';
			}
			if ( this.options.hasOwnProperty('disabled') ) {
				this.tmpl += ' disabled';
			}
			this.tmpl += '/>';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// make a date control
		//
		// -------------------------------------------------------------------------
		dateControl: function () {
			var dateformat = (this.options.hasOwnProperty('format')) ? this.options.format : 'dd-MMMM-yyyy';
			this.tmpl += '
'
			this.tmpl += '<input uib-datepicker-popup="'+dateformat+'" type="text" is-open="popupDate.opened" datepicker-options="dateOptions" show-button-bar="false"';
			this.tmpl += ' id="' + this.options.id + '" name="' + this.name + '" class="form-control " ng-model="ngModel"';
			if ( this.options.hasOwnProperty('placeholder') ) {
				this.tmpl += ' placeholder="' + this.options.placeholder + '"';
			}
			if (this.isRequired) {
				this.tmpl += ' required';
			}
			this.tmpl += '/>';
			this.tmpl += '';
			this.tmpl += '<button type="button" class="btn btn-default" ng-click="openPopupDate()"></button>';
			this.tmpl += '';
			this.tmpl += '
';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// just pass through contents
		//
		// -------------------------------------------------------------------------
		transcludeControl: function () {
			this.tmpl += '

';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// just return the template
		//
		// -------------------------------------------------------------------------
		template: function () {
			return this.tmpl;
		},
		// -------------------------------------------------------------------------
		//
		// methods for actualy doing the different types
		//
		// -------------------------------------------------------------------------
		date: function (attrs) {
			return this.new (JSON.parse(attrs.options)).open().label().dateControl().error().close().template();
		},
		input: function (attrs) {
			return this.new (JSON.parse(attrs.options)).open().label().inputControl(attrs).error().close().template();
		},
		transclude: function (attrs) {
			return this.new (JSON.parse(attrs.options)).open().label().transcludeControl().error().close().template();
		}
	};
	// -------------------------------------------------------------------------
	//
	// for-input makes an input control
	//
	// -------------------------------------------------------------------------
	angular.module('core')
	.directive('formInput', function() {
		return {
			require: 'ngModel',
			replace: true,
			transclude: true,
			scope: {
				ngModel: '=',
				draw: '=?',
				disabled: '=?',
				parentForm: '=form',
				validate: '=',
				validateOf: '=',
				onchange: '@',
				options: '='
			},
			template: function(elem, attrs) {
				if (attrs.hasOwnProperty('draw') && !attrs.draw ) {
					return '';
				}
				return templateClass.input (attrs);
			},
			restrict: 'E',
			link: function($scope, elem, attrs, modelCtrl) {
				// ----------------------------------------------------------------------------------
				var options = JSON.parse(attrs.options);
				// ----------------------------------------------------------------------------------
				if ( options.hasOwnProperty('number') ) {
					var precision = 3;
					if ( options.hasOwnProperty('numberPrecision') ) {
						precision = parseInt(options.numberPrecision);
					}
					// ERROR: 'number' is not a function
					// $(elem).find('input').number(true, precision, '.', ',', true).on('focus', function () {
					// 	this.select();
					// });
				}
				// ----------------------------------------------------------------------------------
				if ( attrs.hasOwnProperty('disabled') ) {

					$scope.$watch('disabled', function (newValue, oldValue) {
						if (newValue) {
							angular.element(elem).find('input').attr('disabled', 'disabled');
						} else {
							angular.element(elem).find('input').removeAttr('disabled');
						}
					});
				}
				// ----------------------------------------------------------------------------------
				// if validation is set, run the validation to set validity of parent form
				$scope.processValidator = function() {
					$scope.validate( $scope.parentForm[options.name].$viewValue ).then( function(resp) {
						$scope.parentForm[options.name].$setValidity( options.name, resp );
						$scope.$apply();
					});
					//
				};
				// change event handler to trigger another element's validator
				$scope.callValidator = function(name) {
					$scope.$parent.$broadcast('rpc.input.validator.' + name);
				};
				// ----------------------------------------------------------------------------------
				// event handler for other elements who wants trigger this element's validator
				if (attrs.hasOwnProperty('validateOf')) {
					$scope.$on('rpc.input.validator.' + options.name, function(event, data) {
						$scope.processValidator();
					});
				}
			}
		};
	})
	// -------------------------------------------------------------------------
	//
	// form-date-input makes a date control (uib-date)
	//
	// -------------------------------------------------------------------------
	.directive('formDateInput', function() {
		return {
			require: 'ngModel',
			replace: true,
			transclude: true,
			scope: {
				ngModel: '=',
				draw: '=?',
				disabled: '=?',
				parentForm: '=form',
				options: '='
			},
			template: function(elem, attrs) {
				if (attrs.hasOwnProperty('draw') && !attrs.draw ) {
					return '';
				}
				return templateClass.date (attrs);
			},
			restrict: 'E',
			compile: function(element, attributes){
				return {
					pre: function($scope, elem, attrs){
						$scope.dateOptions = {};
						$scope.dateOptions.showWeeks = false;
					},
					post: function($scope, elem, attrs){
						// ----------------------------------------------------------------------------------
						if ( attrs.hasOwnProperty('disabled') ) {
							$scope.$watch('disabled', function (newValue, oldValue) {
								if (newValue) {
									angular.element(elem).find('input').attr('disabled', 'disabled');
								} else {
									angular.element(elem).find('input').removeAttr('disabled');
								}
							});
						}
						// ----------------------------------------------------------------------------------
						$scope.popupDate = {
							opened: false
						};
						// ----------------------------------------------------------------------------------
						$scope.openPopupDate = function() {
							$scope.popupDate.opened = true;
						};
					}
				}
			}
		};
	})
	// -------------------------------------------------------------------------
	//
	// form-display wraps whatever control you put here with label and required
	//
	// -------------------------------------------------------------------------
	.directive('formDisplay', function() {
		return {
			require: 'ngModel',
			replace: true,
			transclude: true,
			scope: {
				options: '='
			},
			template: function(elem, attrs) {
				return templateClass.transclude (attrs);
			},
			restrict: 'E'
		};
	})
	.directive('warnOnExit', function() {
		return {
			restrict: 'A',
			scope: {
				parentForm: '=name'
			},
			link: function($scope, elem, attrs) {
				window.onbeforeunload = function() {
					if ($scope.parentForm.$dirty) {
						return 'You are about to leave the page with unsaved data. Click Cancel to remain here.';
					}
				};
				var $locationChangeStartUnbind = $scope.$on('$locationChangeStart', function(event, next, current) {
					if ($scope.parentForm.$dirty) {
						if ( !confirm('You are about to leave the page with unsaved data. Click Cancel to remain here.') ) {
							// cancel to not allow.
							event.preventDefault();
							return false;
						}
					}
				});
				$scope.$on('destroy', function () {
					window.onbeforeunload = null;
					$locationChangeStartUnbind ();
				})
			}
		};
	})
	.directive('formSaveRevert', function() {
		return {
			replace: true,
			restrict: 'E',
			scope: {
				form: '=',
				revertCallback: '=',
				override: '=',
				stayPage: '='
			},
			templateUrl: '/modules/core/client/views/form-save-revert.client.view.html',
			link: function(scope, elem, attrs) {
				scope.$parent.allowCancel = false;
				// ----------------------------------------------------------------------------------
				// Revert
				// If the project has not been created, abandon and reroute to project list.
				// If the projec thas already been saved, restore the previous save.
				//
				scope.revert = function() {
					if (scope.$parent.allowCancel || scope.override) {
						scope.form.$setPristine();
					}
					scope.revertAction();
				};
				scope.revertAction = function() {
					if (scope.$parent.allowCancel || scope.override) {
						scope.$parent.allowCancel = false;
						if (scope.revertCallback) {
							scope.revertCallback();
						}
					} else {
						scope.$parent.allowCancel = true;
					}
				};
				// ----------------------------------------------------------------------------------
			}
		};
	});

}());
<commit_msg>Replace `$scope` '$locationChangeStart' listener in `warnOnExit` directive to '$stateChangeStart' instead.<commit_after>(function () {
	'use strict';

	var templateClass = {
		options: null,
		tmpl: '',
		isRequired: false,
		requiredText: '',
		name: '',
		title: '',
		isTitle: '',
		id: '',
		help: '',
		titleTransclude: false,
		// -------------------------------------------------------------------------
		//
		// this generates the standard first bit of all form displays
		//
		// -------------------------------------------------------------------------
		new: function (options) {
			this.options         = options;
			this.help            = (options.hasOwnProperty('help')) ? options.help : null;
			this.tmpl            = (options.hasOwnProperty('tmpl')) ? options.tmpl : '';
			this.isTitle         = (options.hasOwnProperty('title'));
			this.title           = (this.isTitle) ? options.title : '';
			this.name            = options.name;
			this.titleTransclude = (options.hasOwnProperty('titleTransclude') && options.titleTransclude);
			this.isRequired      = (options.hasOwnProperty('required'));
			this.required        = (this.isRequired && typeof (options.required) === 'string') ? options.required : (this.isTitle ? this.title+' is required' : 'This field is required');
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// start and end the div
		//
		// -------------------------------------------------------------------------
		open: function () {
			this.tmpl += '
';
			return this;
		},
		close: function () {
			this.tmpl += '
';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// make a label
		//
		// -------------------------------------------------------------------------
		label: function () {
			if (this.isTitle) {
				var fieldtoggle = 'fieldtoggle'+this.name;
				this.tmpl += '' + this.title + '';
				if (this.isRequired) {
					this.tmpl += ' *';
				}
				if (this.help) {
					this.tmpl += '   ';
					this.tmpl += '
';
					this.tmpl += '
'+this.help+'
';
					this.tmpl += '
';
				}
			}
			if (this.titleTransclude) {
				this.tmpl += '';
			}
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// this generates the required message
		//
		// -------------------------------------------------------------------------
		error: function () {
			if (this.isRequired) {
				this.tmpl += '
';
				this.tmpl += '
' + this.required + '
';
				this.tmpl += '
';
			}
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// make an input box
		//
		// -------------------------------------------------------------------------
		inputControl: function (attrs) {
			this.tmpl += '<input ';
			// ----------------------------------------------------------------------------------
			if ( this.options.hasOwnProperty('type') ) {
				this.tmpl += ' type="' + this.options.type + '"';
			} else {
				this.tmpl += ' type="text"';
			}
			// ----------------------------------------------------------------------------------
			this.tmpl += ' id="' + this.options.id + '" name="' + this.options.name + '" class="form-control ';
			// ----------------------------------------------------------------------------------
			// Format as number
			if ( this.options.hasOwnProperty('number') ) {
				this.tmpl += ' format-as-number text-right';
			}
			// ----------------------------------------------------------------------------------
			this.tmpl += '" ng-model="ngModel"';
			// ----------------------------------------------------------------------------------
			// Placeholder
			if ( this.options.hasOwnProperty('placeholder') ) {
				this.tmpl += ' placeholder="' + this.options.placeholder + '"';
			}
			// Validator
			if ( attrs.hasOwnProperty('validate') ) {
				this.tmpl += ' ng-change="processValidator()"';
			} else if ( attrs.hasOwnProperty('validateOf') ) {
				this.tmpl += ' ng-change="callValidator(\'' + attrs.validateOf + '\')"';
			}
			if (attrs.hasOwnProperty ('onchange')) {
				this.tmpl += ' ng-change="'+attrs.onchange+'()"';
				console.log (this.tmpl);
			}
			// ----------------------------------------------------------------------------------
			if ( this.options.hasOwnProperty('required') ) {
				this.tmpl += ' required';
			}
			if ( this.options.hasOwnProperty('disabled') ) {
				this.tmpl += ' disabled';
			}
			this.tmpl += '/>';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// make a date control
		//
		// -------------------------------------------------------------------------
		dateControl: function () {
			var dateformat = (this.options.hasOwnProperty('format')) ? this.options.format : 'dd-MMMM-yyyy';
			this.tmpl += '
'
			this.tmpl += '<input uib-datepicker-popup="'+dateformat+'" type="text" is-open="popupDate.opened" datepicker-options="dateOptions" show-button-bar="false"';
			this.tmpl += ' id="' + this.options.id + '" name="' + this.name + '" class="form-control " ng-model="ngModel"';
			if ( this.options.hasOwnProperty('placeholder') ) {
				this.tmpl += ' placeholder="' + this.options.placeholder + '"';
			}
			if (this.isRequired) {
				this.tmpl += ' required';
			}
			this.tmpl += '/>';
			this.tmpl += '';
			this.tmpl += '<button type="button" class="btn btn-default" ng-click="openPopupDate()"></button>';
			this.tmpl += '';
			this.tmpl += '
';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// just pass through contents
		//
		// -------------------------------------------------------------------------
		transcludeControl: function () {
			this.tmpl += '

';
			return this;
		},
		// -------------------------------------------------------------------------
		//
		// just return the template
		//
		// -------------------------------------------------------------------------
		template: function () {
			return this.tmpl;
		},
		// -------------------------------------------------------------------------
		//
		// methods for actualy doing the different types
		//
		// -------------------------------------------------------------------------
		date: function (attrs) {
			return this.new (JSON.parse(attrs.options)).open().label().dateControl().error().close().template();
		},
		input: function (attrs) {
			return this.new (JSON.parse(attrs.options)).open().label().inputControl(attrs).error().close().template();
		},
		transclude: function (attrs) {
			return this.new (JSON.parse(attrs.options)).open().label().transcludeControl().error().close().template();
		}
	};
	// -------------------------------------------------------------------------
	//
	// for-input makes an input control
	//
	// -------------------------------------------------------------------------
	angular.module('core')
	.directive('formInput', function() {
		return {
			require: 'ngModel',
			replace: true,
			transclude: true,
			scope: {
				ngModel: '=',
				draw: '=?',
				disabled: '=?',
				parentForm: '=form',
				validate: '=',
				validateOf: '=',
				onchange: '@',
				options: '='
			},
			template: function(elem, attrs) {
				if (attrs.hasOwnProperty('draw') && !attrs.draw ) {
					return '';
				}
				return templateClass.input (attrs);
			},
			restrict: 'E',
			link: function($scope, elem, attrs, modelCtrl) {
				// ----------------------------------------------------------------------------------
				var options = JSON.parse(attrs.options);
				// ----------------------------------------------------------------------------------
				if ( options.hasOwnProperty('number') ) {
					var precision = 3;
					if ( options.hasOwnProperty('numberPrecision') ) {
						precision = parseInt(options.numberPrecision);
					}
					// ERROR: 'number' is not a function
					// $(elem).find('input').number(true, precision, '.', ',', true).on('focus', function () {
					// 	this.select();
					// });
				}
				// ----------------------------------------------------------------------------------
				if ( attrs.hasOwnProperty('disabled') ) {

					$scope.$watch('disabled', function (newValue, oldValue) {
						if (newValue) {
							angular.element(elem).find('input').attr('disabled', 'disabled');
						} else {
							angular.element(elem).find('input').removeAttr('disabled');
						}
					});
				}
				// ----------------------------------------------------------------------------------
				// if validation is set, run the validation to set validity of parent form
				$scope.processValidator = function() {
					$scope.validate( $scope.parentForm[options.name].$viewValue ).then( function(resp) {
						$scope.parentForm[options.name].$setValidity( options.name, resp );
						$scope.$apply();
					});
					//
				};
				// change event handler to trigger another element's validator
				$scope.callValidator = function(name) {
					$scope.$parent.$broadcast('rpc.input.validator.' + name);
				};
				// ----------------------------------------------------------------------------------
				// event handler for other elements who wants trigger this element's validator
				if (attrs.hasOwnProperty('validateOf')) {
					$scope.$on('rpc.input.validator.' + options.name, function(event, data) {
						$scope.processValidator();
					});
				}
			}
		};
	})
	// -------------------------------------------------------------------------
	//
	// form-date-input makes a date control (uib-date)
	//
	// -------------------------------------------------------------------------
	.directive('formDateInput', function() {
		return {
			require: 'ngModel',
			replace: true,
			transclude: true,
			scope: {
				ngModel: '=',
				draw: '=?',
				disabled: '=?',
				parentForm: '=form',
				options: '='
			},
			template: function(elem, attrs) {
				if (attrs.hasOwnProperty('draw') && !attrs.draw ) {
					return '';
				}
				return templateClass.date (attrs);
			},
			restrict: 'E',
			compile: function(element, attributes){
				return {
					pre: function($scope, elem, attrs){
						$scope.dateOptions = {};
						$scope.dateOptions.showWeeks = false;
					},
					post: function($scope, elem, attrs){
						// ----------------------------------------------------------------------------------
						if ( attrs.hasOwnProperty('disabled') ) {
							$scope.$watch('disabled', function (newValue, oldValue) {
								if (newValue) {
									angular.element(elem).find('input').attr('disabled', 'disabled');
								} else {
									angular.element(elem).find('input').removeAttr('disabled');
								}
							});
						}
						// ----------------------------------------------------------------------------------
						$scope.popupDate = {
							opened: false
						};
						// ----------------------------------------------------------------------------------
						$scope.openPopupDate = function() {
							$scope.popupDate.opened = true;
						};
					}
				}
			}
		};
	})
	// -------------------------------------------------------------------------
	//
	// form-display wraps whatever control you put here with label and required
	//
	// -------------------------------------------------------------------------
	.directive('formDisplay', function() {
		return {
			require: 'ngModel',
			replace: true,
			transclude: true,
			scope: {
				options: '='
			},
			template: function(elem, attrs) {
				return templateClass.transclude (attrs);
			},
			restrict: 'E'
		};
	})
	.directive('warnOnExit', function() {
		return {
			restrict: 'A',
			scope: {
				parentForm: '=name'
			},
			link: function($scope, elem, attrs) {
				window.onbeforeunload = function() {
					if ($scope.parentForm.$dirty) {
						return 'You are about to leave the page with unsaved data. Click Cancel to remain here.';
					}
				};
				var $stateChangeStartUnbind = $scope.$on('$stateChangeStart', function(event, next, current) {
					if ($scope.parentForm.$dirty) {
						if (!confirm('You are about to leave the page with unsaved data. Click Cancel to remain here.') ) {
							// Stay on current route if user cancels.
							event.preventDefault();
						}
					}
				});
				$scope.$on('destroy', function () {
					window.onbeforeunload = null;
					$stateChangeStartUnbind();
				})
			}
		};
	})
	.directive('formSaveRevert', function() {
		return {
			replace: true,
			restrict: 'E',
			scope: {
				form: '=',
				revertCallback: '=',
				override: '=',
				stayPage: '='
			},
			templateUrl: '/modules/core/client/views/form-save-revert.client.view.html',
			link: function(scope, elem, attrs) {
				scope.$parent.allowCancel = false;
				// ----------------------------------------------------------------------------------
				// Revert
				// If the project has not been created, abandon and reroute to project list.
				// If the projec thas already been saved, restore the previous save.
				//
				scope.revert = function() {
					if (scope.$parent.allowCancel || scope.override) {
						scope.form.$setPristine();
					}
					scope.revertAction();
				};
				scope.revertAction = function() {
					if (scope.$parent.allowCancel || scope.override) {
						scope.$parent.allowCancel = false;
						if (scope.revertCallback) {
							scope.revertCallback();
						}
					} else {
						scope.$parent.allowCancel = true;
					}
				};
				// ----------------------------------------------------------------------------------
			}
		};
	});

}());
<|endoftext|>


<commit_before>var $fs = require('fs');
var $path = require('path');
var $watchr = require('watchr');
var $marked = require('marked');
var $highlight = require('highlight.js');

$marked.setOptions({
    highlight: function (code) {
        return $highlight.highlightAuto(code).value;
    }
});

var $renderer = new $marked.Renderer();

$renderer.table = function(header, body){
    return '
\n'
        + '
\n'
        + header
        + '
\n'
        + '
\n'
        + body
        + '
\n'
        + '
\n'
    ;
}

var options = {
    filename: ""
};

function init(argv) {
    var fn = null;

    for (var i=0; i<argv.length; i++) {
        if (argv[i] != '-') {
            fn = argv[i];
            break;
        }
    }

    if (fn == null) {
        throw new Error("Invalid commandline arguments");
    }

    // resolve absolute path
    if (process.env.PWD) {
        fn = $path.resolve(process.env.PWD, fn);
    }

    options.filename = fn;
}

function start(callback) {
    render(options.filename, callback);
    watch(callback);
}

function watch(callback) {
    $watchr.watch({
        paths: options.filename,
        listeners: {change: function (event, filename) {
            render(filename, callback);
        }},
        catchupDelay: 250,
        interval: 500
    });
}

function render(filename, callback) {
    $fs.readFile(filename, function (err, data) {
        if (err) throw err;
        callback($marked(data.toString(), { renderer: $renderer }));
    });
}

module.exports = {
    init: init,
    start: start,
    watch: watch,
    render: render
};
<commit_msg>Fix highlight<commit_after>var $fs = require('fs');
var $path = require('path');
var $watchr = require('watchr');
var $marked = require('marked');
var $highlight = require('highlight.js');

$marked.setOptions({
    highlight: function (code, lang) {
        if (lang != null && $highlight.getLanguage(lang)) {
            return $highlight.highlight(lang, code).value;
        } else {
            return $highlight.highlightAuto(code).value;
        }
    }
});

var $renderer = new $marked.Renderer();

$renderer.table = function(header, body){
    return '
\n'
        + '
\n'
        + header
        + '
\n'
        + '
\n'
        + body
        + '
\n'
        + '
\n'
    ;
}

var options = {
    filename: ""
};

function init(argv) {
    var fn = null;

    for (var i=0; i<argv.length; i++) {
        if (argv[i] != '-') {
            fn = argv[i];
            break;
        }
    }

    if (fn == null) {
        throw new Error("Invalid commandline arguments");
    }

    // resolve absolute path
    if (process.env.PWD) {
        fn = $path.resolve(process.env.PWD, fn);
    }

    options.filename = fn;
}

function start(callback) {
    render(options.filename, callback);
    watch(callback);
}

function watch(callback) {
    $watchr.watch({
        paths: options.filename,
        listeners: {change: function (event, filename) {
            render(filename, callback);
        }},
        catchupDelay: 250,
        interval: 500
    });
}

function render(filename, callback) {
    $fs.readFile(filename, function (err, data) {
        if (err) throw err;
        callback($marked(data.toString(), { renderer: $renderer }));
    });
}

module.exports = {
    init: init,
    start: start,
    watch: watch,
    render: render
};
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mailin = require('mailin');
var fs = require('fs');
var nodemailer = require('nodemailer');
var ses = require('nodemailer-ses-transport');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/cha');

var User = require('./types/user');

var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
  console.log('Now connected to database');
});

var routes = require('./routes/index');
var users = require('./routes/users');

var accessKey = fs.readFileSync('/home/ubuntu/accessKey.txt').toString().trim();
var secretKey = fs.readFileSync('/home/ubuntu/secretKey.txt').toString().trim();

console.log(accessKey);
console.log(secretKey);

// create reusable transporter object using SMTP transport
var transporter = nodemailer.createTransport(ses({
        accessKeyId: accessKey,
        secretAccessKey: secretKey,
        region: 'us-west-2'
    })
);

// NB! No need to recreate the transporter object. You can use
// the same transporter object for all e-mails

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

mailin.start({
  port: 25,
  disableWebhook: true // Disable the webhook posting.
});

/* Access simplesmtp server instance. */
mailin.on('authorizeUser', function(connection, username, password, done) {
  /*
  if (username == "johnsmith" && password == "mysecret") {
    done(null, true);
  } else {
    done(new Error("Unauthorized!"), false);
  }
  */

  //TODO
});

/* Event emitted when a connection with the Mailin smtp server is initiated. */
mailin.on('startMessage', function (connection) {
  /* connection = {
      from: 'sender@somedomain.com',
      to: 'someaddress@yourdomain.com',
      id: 't84h5ugf',
      authentication: { username: null, authenticated: false, status: 'NORMAL' }
  }
  }; */
  console.log(connection);
});

/* Event emitted after a message was received and parsed. */
mailin.on('message', function (connection, data, content) {
  console.log(data);
  console.log(data.text.length);
  console.log(data.from[0].address);
  console.log(data.to[0].address);
  console.log(data.text);

  User.find({ internalEmail : data.to[0].address }, function(err, recipient) {
    var mailOptions;
    if(err) {
      //Send email not found error
      console.log("Error : ");
      console.log(err);
      console.log("Recipient : ");
      console.log(recipient);
      mailOptions = {
        from: 'postmaster@gocha.io',
        to: data.from[0].address,
        subject: "Address Error",
        html: "Terribly sorry, but that email doesn't exist.

Regards,
The Management"
      };
    } else if(data.text.length > 141){
      //Send email too long error
      console.log("Email length too long");
      mailOptions = {
        from: 'postmaster@gocha.io',
        to: data.from[0].address,
        subject: "Length Error",
        html: "Character count for your email was too long.  Current count is: " + data.text.length + "

Regards,
The Management"
      };
    } else {
      //Check if sender exists
      User.find({ externalEmail : data.from[0].address }, function(err, sender) {
        if(err || !sender.length){
          //User does not exist, so we need to make an email for them
          var newUser = new User({
            externalEmail: data.from[0].address
          });
          newUser.generateEmail(function(res, success){
            if(!success){
              console.log("Failed to generate email");
              //possibly send email saying all emails have been taken
            } else {
              console.log("Added new user");
              newUser.save(function(err){
                if(err) {
                  console.log("Unable to save new user");
                  throw err;
                } else {
                  console.log("New user saved");
                  //Now, we can pass along the message
                  mailOptions = {
                    from: newUser.internalEmail,
                    to: recipient.externalEmail,
                    subject: data.subject,
                    text: data.text
                  }
                }
              });
            }
          })
        } else {
          //Sender already exists, pass along the message just fine
          console.log("Sender exists");
          console.log(sender);
          mailOptions = {
            from: sender.internalEmail,
            to: recipient.externalEmail,
            subject: data.subject,
            text: data.text
          };
        }
      });
    }

    //MailOptions have been set, transmit the message
    transporter.sendMail(mailOptions, function(error, info){
      if(error){
          console.log(mailOptions);
          console.log(error);
      } else {
          console.log('Message sent: ' + info.response);
      }
    });
  });
});

app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

/*
var testUser = new User({
  externalEmail : 'vanhooser@ou.edu',
  internalEmail : 'gloriousLeader@gocha.io'
});

testUser.save(function(err){
  if(err) {
    throw err;
  } else {
    console.log("Added test user");
  }
});
*/

module.exports = app;

app.listen(80);<commit_msg>Fixed unpacking problem<commit_after>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mailin = require('mailin');
var fs = require('fs');
var nodemailer = require('nodemailer');
var ses = require('nodemailer-ses-transport');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/cha');

var User = require('./types/user');

var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
  console.log('Now connected to database');
});

var routes = require('./routes/index');
var users = require('./routes/users');

var accessKey = fs.readFileSync('/home/ubuntu/accessKey.txt').toString().trim();
var secretKey = fs.readFileSync('/home/ubuntu/secretKey.txt').toString().trim();

console.log(accessKey);
console.log(secretKey);

// create reusable transporter object using SMTP transport
var transporter = nodemailer.createTransport(ses({
        accessKeyId: accessKey,
        secretAccessKey: secretKey,
        region: 'us-west-2'
    })
);

// NB! No need to recreate the transporter object. You can use
// the same transporter object for all e-mails

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

mailin.start({
  port: 25,
  disableWebhook: true // Disable the webhook posting.
});

/* Access simplesmtp server instance. */
mailin.on('authorizeUser', function(connection, username, password, done) {
  /*
  if (username == "johnsmith" && password == "mysecret") {
    done(null, true);
  } else {
    done(new Error("Unauthorized!"), false);
  }
  */

  //TODO
});

/* Event emitted when a connection with the Mailin smtp server is initiated. */
mailin.on('startMessage', function (connection) {
  /* connection = {
      from: 'sender@somedomain.com',
      to: 'someaddress@yourdomain.com',
      id: 't84h5ugf',
      authentication: { username: null, authenticated: false, status: 'NORMAL' }
  }
  }; */
  console.log(connection);
});

/* Event emitted after a message was received and parsed. */
mailin.on('message', function (connection, data, content) {
  console.log(data);
  console.log(data.text.length);
  console.log(data.from[0].address);
  console.log(data.to[0].address);
  console.log(data.text);

  User.find({ internalEmail : data.to[0].address }, function(err, recipient) {
    var mailOptions;
    if(err) {
      //Send email not found error
      console.log("Error : ");
      console.log(err);
      console.log("Recipient : ");
      console.log(recipient);
      mailOptions = {
        from: 'postmaster@gocha.io',
        to: data.from[0].address,
        subject: "Address Error",
        html: "Terribly sorry, but that email doesn't exist.

Regards,
The Management"
      };
    } else if(data.text.length > 141){
      //Send email too long error
      console.log("Email length too long");
      mailOptions = {
        from: 'postmaster@gocha.io',
        to: data.from[0].address,
        subject: "Length Error",
        html: "Character count for your email was too long.  Current count is: " + data.text.length + "

Regards,
The Management"
      };
    } else {
      //Check if sender exists
      User.find({ externalEmail : data.from[0].address }, function(err, sender) {
        if(err || !sender.length){
          //User does not exist, so we need to make an email for them
          var newUser = new User({
            externalEmail: data.from[0].address
          });
          newUser.generateEmail(function(res, success){
            if(!success){
              console.log("Failed to generate email");
              //possibly send email saying all emails have been taken
            } else {
              console.log("Added new user");
              newUser.save(function(err){
                if(err) {
                  console.log("Unable to save new user");
                  throw err;
                } else {
                  console.log("New user saved");
                  //Now, we can pass along the message
                  mailOptions = {
                    from: newUser.internalEmail,
                    to: recipient.externalEmail,
                    subject: data.subject,
                    text: data.text
                  }
                }
              });
            }
          })
        } else {
          //Sender already exists, pass along the message just fine
          console.log("Sender : ");
          console.log(sender);
          console.log("Recipient : ");
        console.log(recipient);
          mailOptions = {
            from: sender[0].internalEmail,
            to: recipient[0].externalEmail,
            subject: data.subject,
            text: data.text
          };
        }
      });
    }

    //MailOptions have been set, transmit the message
    transporter.sendMail(mailOptions, function(error, info){
      if(error){
          console.log(mailOptions);
          console.log(error);
      } else {
          console.log('Message sent: ' + info.response);
      }
    });
  });
});

app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

/*
var testUser = new User({
  externalEmail : 'vanhooser@ou.edu',
  internalEmail : 'gloriousLeader@gocha.io'
});

testUser.save(function(err){
  if(err) {
    throw err;
  } else {
    console.log("Added test user");
  }
});
*/

module.exports = app;

app.listen(80);<|endoftext|>


<commit_before>/**
 * A Route describes a route and its parameters.
 *
 * @memberOf Jymfony.Component.Routing
 */
class Route {
    /**
     * Constructor.
     *
     * @param {string} path
     * @param {Object<string, *>} defaults
     * @param {Object<string, string>} requirements
     * @param {Object<string, *>} options
     * @param {[string]} host
     * @param {[string]} schemes
     * @param {[string]} methods
     * @param {string} condition
     */
    __construct(path, defaults = {}, requirements = {}, options = {}, host = undefined, schemes = [], methods = [ 'GET', 'POST' ], condition = undefined) {
        this
            .setPath(path)
            .setHost(host)
            .setSchemes(schemes)
            .setMethods(methods)
            .setOptions(options)
            .setDefaults(defaults)
            .setCondition(condition)
            .setRequirements(requirements)
        ;
    }

    /**
     * Gets the pattern for the path.
     *
     * @returns {string}
     */
    get path() {
        return this._path;
    }

    /**
     * Sets the pattern for the path.
     *
     * @param {string} path
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setPath(path) {
        this._path = '/'+__jymfony.ltrim(__jymfony.trim(path), '/');
        this._compiled = undefined;

        return this;
    }

    /**
     * Gets the pattern for the host.
     *
     * @returns {string}
     */
    get host() {
        return this._host;
    }

    /**
     * Sets the pattern for the host.
     *
     * @param {string} host
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setHost(host) {
        this._host = host;
        this._compiled = undefined;

        return this;
    }

    /**
     * Returns the lowercased schemes this route is restricted to.
     * So an empty array means that any scheme is allowed.
     *
     * @returns {[string]}
     */
    get schemes() {
        return this._schemes;
    }

    /**
     * Sets the schemes (e.g. 'https') this route is restricted to.
     * So an empty array means that any scheme is allowed.
     *
     * @param {[string]} schemes
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setSchemes(schemes) {
        this._schemes = schemes.map(s => s.toLowerCase());
        this._compiled = undefined;

        return this;
    }

    /**
     * Checks if a scheme requirement has been set.
     *
     * @param {string} scheme
     *
     * @returns {boolean}
     */
    hasScheme(scheme) {
        return -1 !== this._schemes.indexOf(scheme.toLowerCase());
    }

    /**
     * Returns the uppercased HTTP methods this route is restricted to.
     *
     * @returns {[string]}
     */
    get methods() {
        return this._methods;
    }

    /**
     * Sets the methods (e.g. 'POST') this route is restricted to.
     * An empty array is not allowed.
     *
     * @param {[string]} methods
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setMethods(methods) {
        if (0 === methods.length) {
            throw InvalidArgumentException('At least one method must be set for a route');
        }

        this._methods = methods.map(s => s.toUpperCase());
        this._compiled = undefined;

        return this;
    }

    /**
     * Returns the options.
     *
     * @returns {Object<string, *>}
     */
    get options() {
        return this._options;
    }

    /**
     * Sets the options.
     *
     * @param {Object<string, *>} options
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setOptions(options) {
        this._options = {
            compiler_class: 'Jymfony.Component.Routing.RouteCompiler',
        };

        return this.addOptions(options);
    }

    /**
     * Adds options.
     *
     * @param {Object<string, *>} options
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    addOptions(options) {
        for (const [ name, option ] of __jymfony.getEntries(options)) {
            this._options[name] = option;
        }

        this._compiled = undefined;

        return this;
    }

    /**
     * Sets an option value.
     *
     * @param {string} name
     * @param {*} value
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setOption(name, value) {
        this._options[name] = value;
        this._compiled = undefined;

        return this;
    }

    /**
     * Gets an option value.
     *
     * @param {string} name
     *
     * @returns {*}
     */
    getOption(name) {
        return this._options[name];
    }

    /**
     * Checks if an option has been set.
     *
     * @param {string} name
     *
     * @return {boolean}
     */
    hasOption(name) {
        return this._options.hasOwnProperty(name);
    }

    /**
     * Returns the defaults.
     *
     * @returns {Object<string, *>}
     */
    get defaults() {
        return this._defaults;
    }

    /**
     * Sets the defaults.
     *
     * @param {Object<string, *>} defaults
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setDefaults(defaults) {
        this._defaults = {};

        return this.addDefaults(defaults);
    }

    /**
     * Adds defaults.
     *
     * @param {Object<string, *>} defaults
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    addDefaults(defaults) {
        for (const [ name, def ] of __jymfony.getEntries(defaults)) {
            this._defaults[name] = def;
        }

        this._compiled = undefined;

        return this;
    }

    /**
     * Sets a default value.
     *
     * @param {string} name
     * @param {*} value
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setDefault(name, value) {
        this._defaults[name] = value;
        this._compiled = undefined;

        return this;
    }

    /**
     * Gets a default value.
     *
     * @param {string} name
     *
     * @returns {*}
     */
    getDefault(name) {
        return this._defaults[name];
    }

    /**
     * Checks if a default value has been set.
     *
     * @param {string} name
     *
     * @return {boolean}
     */
    hasDefault(name) {
        return this._defaults.hasOwnProperty(name);
    }

    /**
     * Sets the route condition.
     */
    setCondition(/* condition */) {
        // @todo

        return this;
    }

    /**
     * Gets the requirements.
     *
     * @return {Object<string, RegExp>}
     */
    get requirements() {
        return this._requirements;
    }

    /**
     * Sets the requirements-
     *
     * @param {Object<string, string|RegExp>|[string|RegExp]} requirements
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setRequirements(requirements) {
        this._requirements = {};

        return this.addRequirements(requirements);
    }

    /**
     * Add requirements.
     *
     * @param {Object<string, string|RegExp>|[string|RegExp]} requirements
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    addRequirements(requirements) {
        for (const [ key, regex ] of __jymfony.getEntries(requirements)) {
            this._requirements[key] = this._sanitizeRequirement(key, regex);
        }

        this._compiled = undefined;

        return this;
    }

    /**
     * Gets a requirement by key.
     *
     * @param key
     *
     * @return {RegExp|undefined}
     */
    getRequirement(key) {
        return this._requirements[key];
    }

    /**
     * Checks if a requirement for key has been set.
     *
     * @param key
     *
     * @return {boolean}
     */
    hasRequirement(key) {
        return this._requirements.hasOwnProperty(key);
    }

    /**
     * Sets a requirement.
     *
     * @param {string} key
     * @param {string|RegExp} regex
     *
     * @return {Jymfony.Component.Routing.Route}
     */
    setRequirement(key, regex) {
        this._requirements[key] = this._sanitizeRequirement(key, regex);
        this._compiled = undefined;

        return this;
    }

    /**
     * Compiles the route.
     *
     * @returns
     */
    compile() {
        if (undefined !== this._compiled) {
            return this._compiled;
        }

        const class_ = ReflectionClass.getClass(this.getOption('compiler_class'));
        return this._compiled = class_['compile'](this);
    }

    /**
     * Sanitize a requirement.
     *
     * @param {string} key
     * @param {string|RegExp} regex
     *
     * @returns {RegExp}
     *
     * @private
     */
    _sanitizeRequirement(key, regex) {
        if (regex instanceof RegExp) {
            regex = regex.source;
        }

        if (! isString(regex)) {
            throw new InvalidArgumentException(__jymfony.sprintf('Routing requirement for "%s" must be a string or a RegExp object.', key));
        }

        if ('' !== regex && '^' === regex.charAt(0)) {
            regex = regex.substr(1);
        }

        if ('$' !== regex.substr(-1)) {
            regex = regex.substr(0, -1);
        }

        if ('' === regex) {
            throw new InvalidArgumentException(__jymfony.sprintf('Routing requirement for "%s" cannot be empty.', key));
        }

        return new RegExp(regex);
    }
}

module.exports = Route;
<commit_msg>add missing new<commit_after>/**
 * A Route describes a route and its parameters.
 *
 * @memberOf Jymfony.Component.Routing
 */
class Route {
    /**
     * Constructor.
     *
     * @param {string} path
     * @param {Object<string, *>} defaults
     * @param {Object<string, string>} requirements
     * @param {Object<string, *>} options
     * @param {[string]} host
     * @param {[string]} schemes
     * @param {[string]} methods
     * @param {string} condition
     */
    __construct(path, defaults = {}, requirements = {}, options = {}, host = undefined, schemes = [], methods = [ 'GET', 'POST' ], condition = undefined) {
        this
            .setPath(path)
            .setHost(host)
            .setSchemes(schemes)
            .setMethods(methods)
            .setOptions(options)
            .setDefaults(defaults)
            .setCondition(condition)
            .setRequirements(requirements)
        ;
    }

    /**
     * Gets the pattern for the path.
     *
     * @returns {string}
     */
    get path() {
        return this._path;
    }

    /**
     * Sets the pattern for the path.
     *
     * @param {string} path
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setPath(path) {
        this._path = '/'+__jymfony.ltrim(__jymfony.trim(path), '/');
        this._compiled = undefined;

        return this;
    }

    /**
     * Gets the pattern for the host.
     *
     * @returns {string}
     */
    get host() {
        return this._host;
    }

    /**
     * Sets the pattern for the host.
     *
     * @param {string} host
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setHost(host) {
        this._host = host;
        this._compiled = undefined;

        return this;
    }

    /**
     * Returns the lowercased schemes this route is restricted to.
     * So an empty array means that any scheme is allowed.
     *
     * @returns {[string]}
     */
    get schemes() {
        return this._schemes;
    }

    /**
     * Sets the schemes (e.g. 'https') this route is restricted to.
     * So an empty array means that any scheme is allowed.
     *
     * @param {[string]} schemes
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setSchemes(schemes) {
        this._schemes = schemes.map(s => s.toLowerCase());
        this._compiled = undefined;

        return this;
    }

    /**
     * Checks if a scheme requirement has been set.
     *
     * @param {string} scheme
     *
     * @returns {boolean}
     */
    hasScheme(scheme) {
        return -1 !== this._schemes.indexOf(scheme.toLowerCase());
    }

    /**
     * Returns the uppercased HTTP methods this route is restricted to.
     *
     * @returns {[string]}
     */
    get methods() {
        return this._methods;
    }

    /**
     * Sets the methods (e.g. 'POST') this route is restricted to.
     * An empty array is not allowed.
     *
     * @param {[string]} methods
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setMethods(methods) {
        if (0 === methods.length) {
            throw new InvalidArgumentException('At least one method must be set for a route');
        }

        this._methods = methods.map(s => s.toUpperCase());
        this._compiled = undefined;

        return this;
    }

    /**
     * Returns the options.
     *
     * @returns {Object<string, *>}
     */
    get options() {
        return this._options;
    }

    /**
     * Sets the options.
     *
     * @param {Object<string, *>} options
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setOptions(options) {
        this._options = {
            compiler_class: 'Jymfony.Component.Routing.RouteCompiler',
        };

        return this.addOptions(options);
    }

    /**
     * Adds options.
     *
     * @param {Object<string, *>} options
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    addOptions(options) {
        for (const [ name, option ] of __jymfony.getEntries(options)) {
            this._options[name] = option;
        }

        this._compiled = undefined;

        return this;
    }

    /**
     * Sets an option value.
     *
     * @param {string} name
     * @param {*} value
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setOption(name, value) {
        this._options[name] = value;
        this._compiled = undefined;

        return this;
    }

    /**
     * Gets an option value.
     *
     * @param {string} name
     *
     * @returns {*}
     */
    getOption(name) {
        return this._options[name];
    }

    /**
     * Checks if an option has been set.
     *
     * @param {string} name
     *
     * @return {boolean}
     */
    hasOption(name) {
        return this._options.hasOwnProperty(name);
    }

    /**
     * Returns the defaults.
     *
     * @returns {Object<string, *>}
     */
    get defaults() {
        return this._defaults;
    }

    /**
     * Sets the defaults.
     *
     * @param {Object<string, *>} defaults
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setDefaults(defaults) {
        this._defaults = {};

        return this.addDefaults(defaults);
    }

    /**
     * Adds defaults.
     *
     * @param {Object<string, *>} defaults
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    addDefaults(defaults) {
        for (const [ name, def ] of __jymfony.getEntries(defaults)) {
            this._defaults[name] = def;
        }

        this._compiled = undefined;

        return this;
    }

    /**
     * Sets a default value.
     *
     * @param {string} name
     * @param {*} value
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setDefault(name, value) {
        this._defaults[name] = value;
        this._compiled = undefined;

        return this;
    }

    /**
     * Gets a default value.
     *
     * @param {string} name
     *
     * @returns {*}
     */
    getDefault(name) {
        return this._defaults[name];
    }

    /**
     * Checks if a default value has been set.
     *
     * @param {string} name
     *
     * @return {boolean}
     */
    hasDefault(name) {
        return this._defaults.hasOwnProperty(name);
    }

    /**
     * Sets the route condition.
     */
    setCondition(/* condition */) {
        // @todo

        return this;
    }

    /**
     * Gets the requirements.
     *
     * @return {Object<string, RegExp>}
     */
    get requirements() {
        return this._requirements;
    }

    /**
     * Sets the requirements-
     *
     * @param {Object<string, string|RegExp>|[string|RegExp]} requirements
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    setRequirements(requirements) {
        this._requirements = {};

        return this.addRequirements(requirements);
    }

    /**
     * Add requirements.
     *
     * @param {Object<string, string|RegExp>|[string|RegExp]} requirements
     *
     * @returns {Jymfony.Component.Routing.Route}
     */
    addRequirements(requirements) {
        for (const [ key, regex ] of __jymfony.getEntries(requirements)) {
            this._requirements[key] = this._sanitizeRequirement(key, regex);
        }

        this._compiled = undefined;

        return this;
    }

    /**
     * Gets a requirement by key.
     *
     * @param key
     *
     * @return {RegExp|undefined}
     */
    getRequirement(key) {
        return this._requirements[key];
    }

    /**
     * Checks if a requirement for key has been set.
     *
     * @param key
     *
     * @return {boolean}
     */
    hasRequirement(key) {
        return this._requirements.hasOwnProperty(key);
    }

    /**
     * Sets a requirement.
     *
     * @param {string} key
     * @param {string|RegExp} regex
     *
     * @return {Jymfony.Component.Routing.Route}
     */
    setRequirement(key, regex) {
        this._requirements[key] = this._sanitizeRequirement(key, regex);
        this._compiled = undefined;

        return this;
    }

    /**
     * Compiles the route.
     *
     * @returns
     */
    compile() {
        if (undefined !== this._compiled) {
            return this._compiled;
        }

        const class_ = ReflectionClass.getClass(this.getOption('compiler_class'));
        return this._compiled = class_['compile'](this);
    }

    /**
     * Sanitize a requirement.
     *
     * @param {string} key
     * @param {string|RegExp} regex
     *
     * @returns {RegExp}
     *
     * @private
     */
    _sanitizeRequirement(key, regex) {
        if (regex instanceof RegExp) {
            regex = regex.source;
        }

        if (! isString(regex)) {
            throw new InvalidArgumentException(__jymfony.sprintf('Routing requirement for "%s" must be a string or a RegExp object.', key));
        }

        if ('' !== regex && '^' === regex.charAt(0)) {
            regex = regex.substr(1);
        }

        if ('$' !== regex.substr(-1)) {
            regex = regex.substr(0, -1);
        }

        if ('' === regex) {
            throw new InvalidArgumentException(__jymfony.sprintf('Routing requirement for "%s" cannot be empty.', key));
        }

        return new RegExp(regex);
    }
}

module.exports = Route;
<|endoftext|>