<commit_before>export { AddTwoTensors };

import * as TensorPlaceholder from "../TensorPlaceholder.js";
import * as BoundsArraySet from "../BoundsArraySet.js";
import { Root } from "./Operation_Base.js";

/**
 * Add two tensor3d. They should have the same channel count. Their ( height x width ) should be either the same or one is ( 1 x 1 ).
 * It could destroy one or two of the input tensors.
 *
 * @member {boolean} bKeepInputTensor0
 *   If false, the first input tensor will be disposed after adding. If true, the first input tensor will be kept after adding.
 *
 * @member {boolean} bKeepInputTensor1
 *   If false, the second input tensor will be disposed after adding. If true, the second input tensor will be kept after adding.
 *
 * @member {function} apply
 *   This is a method. It processes this.input0.realTensor and this.input1.realTensor as inputTensors. It puts to this.output0.realTensor
 * as outputTensor. Both inputTensors are tf.tensor3d and represents an images ( height x width x channel ) which will be added. They
 * should have the same channel count. Their ( height x width ) should be either the same or one is ( 1 x 1 ). The outputTensor
 * (tf.tensor3d) represents the result of adding the two inputs. The inputTensors may or may not be disposed. In fact, this method
 * calls one of Add_and_keep0_keep1(), Add_and_keep0_destroy1(), Add_and_destroy0_keep1(), Add_and_destroy0_destroy1() according to
 * the parameters.
 *
 */
class AddTwoTensors extends Root {

  /**
   *
   */
  constructor(
    inputTensorPlaceholder0, inputTensorPlaceholder1,
    bKeepInputTensor0, bKeepInputTensor1
  ) {

    super( inputTensorPlaceholder0, inputTensorPlaceholder1, 1 );

    this.bKeepInputTensor0 = bKeepInputTensor0;
    this.bKeepInputTensor1 = bKeepInputTensor1;
    AddTwoTensors.adjust_pfn.call( this );
    AddTwoTensors.setup_BoundsArraySet.call( this, inputTensorPlaceholder0.scaleBoundsArray, inputTensorPlaceholder1.scaleBoundsArray );
    AddTwoTensors.setup_output0_TensorPlaceholder.call( this );
  }

  /**
   * Adjust this.apply so that this.apply() will or will not dispose its inputTensors.
   */
  setKeepInputTensor0( bKeepInputTensor0 ) {
    this.bKeepInputTensor0 = bKeepInputTensor0;
    AddTwoTensors.adjust_pfn.call( this );
  }

  /**
   * Adjust this.apply so that this.apply() will or will not dispose its inputTensors.
   */
  setKeepInputTensor1( bKeepInputTensor1 ) {
    this.bKeepInputTensor1 = bKeepInputTensor1;
    AddTwoTensors.adjust_pfn.call( this );
  }

  /**
   * Adjust this.apply so that this.apply() will or will not dispose its inputTensors.
   */
  setKeepInputTensor( bKeepInputTensor0, bKeepInputTensor1 ) {
    this.bKeepInputTensor0 = bKeepInputTensor0;
    this.bKeepInputTensor1 = bKeepInputTensor1;
    AddTwoTensors.adjust_pfn.call( this );
  }

  /** Set this.apply according to this.bKeepInputTensor0 and this.bKeepInputTensor1. */
  static adjust_pfn() {
    if ( this.bKeepInputTensor0 ) {
      if ( this.bKeepInputTensor1 ) {
        this.apply = AddTwoTensors.Add_and_keep0_keep1;
      } else {
        this.apply = AddTwoTensors.Add_and_keep0_destroy1;
      }
    } else {
      if ( this.bKeepInputTensor1 ) {
        this.apply = AddTwoTensors.Add_and_destroy0_keep1;
      } else {
        this.apply = AddTwoTensors.Add_and_destroy0_destroy1;
      }
    }
  }

  /** Create this.boundsArraySet. */
  static setup_BoundsArraySet( inputScaleBoundsArray0, inputScaleBoundsArray1 ) {

    tf.util.assert( ( inputScaleBoundsArray0.channelCount == inputScaleBoundsArray1.channelCount ),
      `AddTwoTensors.setup_BoundsArraySet(): `
        + `input0 channel count ( ${inputScaleBoundsArray0.channelCount} ) should be the same as `
        + `input1 channel count ( ${inputScaleBoundsArray1.channelCount} ).`
    );

//!!! (2022/06/22 Remarked) Use pool instead.
//    this.boundsArraySet = new BoundsArraySet.InputsOutputs( inputScaleBoundsArray0, inputScaleBoundsArray1,
    this.boundsArraySet = BoundsArraySet.InputsOutputsPool.Singleton.get_or_create_by( inputScaleBoundsArray0, inputScaleBoundsArray1,
      inputScaleBoundsArray0.channelCount
    );

    this.boundsArraySet.output0
      .set_all_byScaleBoundsArray( inputScaleBoundsArray0 )
      .add_all_byScaleBoundsArray_all( inputScaleBoundsArray1 );
  }

  /** Setup this.output0.
   * This method should be called after setup_BoundsArraySet() because it uses BoundsArrarySet.
   */
  static setup_output0_TensorPlaceholder() {

    // 1. Only same channel count adding is supported.
    if ( this.input0.channelCount == this.input1.channelCount ) {

      this.output0.channelCount = this.input0.channelCount; // Result always has the same channel count.

      // 1.1 Adding two same dimension tensors. The result dimension is the same of any one.
      if ( ( this.input0.height == this.input1.height ) && ( this.input0.width == this.input1.width ) ) {
        this.output0.height = this.input0.height;
        this.output0.width = this.input0.width;

      // 1.2 Adding by broadcasting input0 to input1. The result dimension is the same as input1 (the larger one).
      } else if ( ( this.input0.height == 1 ) && ( this.input0.width == 1 ) ) {
        this.output0.height = this.input1.height;
        this.output0.width = this.input1.width;

      // 1.3 Adding by broadcasting input1 to input0. The result dimension is the same as input0 (the larger one).
      } else if ( ( this.input1.height == 1 ) && ( this.input1.width == 1 ) ) {
        this.output0.height = this.input0.height;
        this.output0.width = this.input0.width;

      // 1.4 Unsupported adding (height and width).
      } else {
        tf.util.assert( false,
          `Operation.AddTwoTensors.setup_output0_TensorPlaceholder(): `
            + `input0 ( height, width ) = ( ${this.input0.height}, ${this.input0.width} ) and `
            + `input1 ( height, width ) = ( ${this.input1.height}, ${this.input1.width} ) `
            + `should be either the same or one is ( 1, 1 ) for broadcating.`
        );
      }

      // Only if both inputs' lower half and higher half channel count are the same, they are passed through to output.
      // Otherwise, absent them in the output.
      {
        if ( this.input0.channelCount_lowerHalf == this.input1.channelCount_lowerHalf ) {
          this.output0.channelCount_lowerHalf = this.input0.channelCount_lowerHalf;
        } else {
          this.output0.channelCount_lowerHalf = undefined;
        }

        if ( this.input0.channelCount_higherHalf == this.input1.channelCount_higherHalf ) {
          this.output0.channelCount_higherHalf = this.input0.channelCount_higherHalf;
        } else {
          this.output0.channelCount_higherHalf = undefined;
        }
      }

      this.output0.scaleBoundsArray = this.boundsArraySet.output0;

      // Release for reducing memory usage. (Since it has been inside the output tensor placeholder.)
      {
        this.boundsArraySet.output0 = null; // Because it has already been transferred to TensorPlaceholder this.output0
        BoundsArraySet.InputsOutputsPool.Singleton.recycle( this.boundsArraySet );
        this.boundsArraySet = null;
      }

    // 2. Unsupported adding (different channel count).
    } else {
      tf.util.assert( false,
        `Operation.AddTwoTensors.setup_output0_TensorPlaceholder(): `
          + `input0 channel count ( ${this.input0.channelCount} ) and `
          + `input1 channel count ( ${this.input1.channelCount} ) `
          + `should be the same.`
      );
    }
  }

  /** Add. (Both the inputTensor0 and inputTensor1 will not be disposed. */
  static Add_and_keep0_keep1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
  }

  /** Add. (The inputTensors0 will not be disposed. The inputTensor1 will be disposed. */
  static Add_and_keep0_destroy1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
    this.input1.realTensor.dispose();
  }

  /** Add. (The inputTensor0 will be disposed. The inputTensor1 will not be disposed. */
  static Add_and_destroy0_keep1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
    this.input0.realTensor.dispose();
  }

  /** Add. (Both the inputTensor0 and inputTensor1 will be disposed. */
  static Add_and_destroy0_destroy1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
    this.input0.realTensor.dispose();
    this.input1.realTensor.dispose();
  }

}
<commit_msg>Update Operation_AddTwoTensors.js<commit_after>export { AddTwoTensors };
export { AddTwoTensorsPool };

import * as TensorPlaceholder from "../TensorPlaceholder.js";
import * as BoundsArraySet from "../BoundsArraySet.js";
import { Root } from "./Operation_Base.js";

/**
 * Add two tensor3d. They should have the same channel count. Their ( height x width ) should be either the same or one is ( 1 x 1 ).
 * It could destroy one or two of the input tensors.
 *
 * @member {boolean} bKeepInputTensor0
 *   If false, the first input tensor will be disposed after adding. If true, the first input tensor will be kept after adding.
 *
 * @member {boolean} bKeepInputTensor1
 *   If false, the second input tensor will be disposed after adding. If true, the second input tensor will be kept after adding.
 *
 * @member {function} apply
 *   This is a method. It processes this.input0.realTensor and this.input1.realTensor as inputTensors. It puts to this.output0.realTensor
 * as outputTensor. Both inputTensors are tf.tensor3d and represents an images ( height x width x channel ) which will be added. They
 * should have the same channel count. Their ( height x width ) should be either the same or one is ( 1 x 1 ). The outputTensor
 * (tf.tensor3d) represents the result of adding the two inputs. The inputTensors may or may not be disposed. In fact, this method
 * calls one of Add_and_keep0_keep1(), Add_and_keep0_destroy1(), Add_and_destroy0_keep1(), Add_and_destroy0_destroy1() according to
 * the parameters.
 *
 */
class AddTwoTensors extends Root {

  /**
   *
   */
  constructor(
    inputTensorPlaceholder0, inputTensorPlaceholder1,
    bKeepInputTensor0, bKeepInputTensor1
  ) {

    super( inputTensorPlaceholder0, inputTensorPlaceholder1, 1 );

    this.setAsConstructor( inputTensorPlaceholder0, inputTensorPlaceholder1, bKeepInputTensor0, bKeepInputTensor1 );
  }

  /**
   * @return {AddTwoTensors}
   *   Return the this object.
   */
  setAsConstructor(
    inputTensorPlaceholder0, inputTensorPlaceholder1,
    bKeepInputTensor0, bKeepInputTensor1
  ) {

    super.setAsConstructor( inputTensorPlaceholder0, inputTensorPlaceholder1, 1 );

    this.bKeepInputTensor0 = bKeepInputTensor0;
    this.bKeepInputTensor1 = bKeepInputTensor1;
    AddTwoTensors.adjust_pfn.call( this );
    AddTwoTensors.setup_BoundsArraySet.call( this, inputTensorPlaceholder0.scaleBoundsArray, inputTensorPlaceholder1.scaleBoundsArray );
    AddTwoTensors.setup_output0_TensorPlaceholder.call( this );
    return this;
  }

  /**
   * After calling this method, this object should be viewed as disposed and should not be operated again.
   */
  disposeResources_and_recycleToPool() {
    this.disposeResources();
    AddTwoTensorsPool.Singleton.recycle( this );
  }

  /**
   * Adjust this.apply so that this.apply() will or will not dispose its inputTensors.
   */
  setKeepInputTensor0( bKeepInputTensor0 ) {
    this.bKeepInputTensor0 = bKeepInputTensor0;
    AddTwoTensors.adjust_pfn.call( this );
  }

  /**
   * Adjust this.apply so that this.apply() will or will not dispose its inputTensors.
   */
  setKeepInputTensor1( bKeepInputTensor1 ) {
    this.bKeepInputTensor1 = bKeepInputTensor1;
    AddTwoTensors.adjust_pfn.call( this );
  }

  /**
   * Adjust this.apply so that this.apply() will or will not dispose its inputTensors.
   */
  setKeepInputTensor( bKeepInputTensor0, bKeepInputTensor1 ) {
    this.bKeepInputTensor0 = bKeepInputTensor0;
    this.bKeepInputTensor1 = bKeepInputTensor1;
    AddTwoTensors.adjust_pfn.call( this );
  }

  /** Set this.apply according to this.bKeepInputTensor0 and this.bKeepInputTensor1. */
  static adjust_pfn() {
    if ( this.bKeepInputTensor0 ) {
      if ( this.bKeepInputTensor1 ) {
        this.apply = AddTwoTensors.Add_and_keep0_keep1;
      } else {
        this.apply = AddTwoTensors.Add_and_keep0_destroy1;
      }
    } else {
      if ( this.bKeepInputTensor1 ) {
        this.apply = AddTwoTensors.Add_and_destroy0_keep1;
      } else {
        this.apply = AddTwoTensors.Add_and_destroy0_destroy1;
      }
    }
  }

  /** Create this.boundsArraySet. */
  static setup_BoundsArraySet( inputScaleBoundsArray0, inputScaleBoundsArray1 ) {

    tf.util.assert( ( inputScaleBoundsArray0.channelCount == inputScaleBoundsArray1.channelCount ),
      `AddTwoTensors.setup_BoundsArraySet(): `
        + `input0 channel count ( ${inputScaleBoundsArray0.channelCount} ) should be the same as `
        + `input1 channel count ( ${inputScaleBoundsArray1.channelCount} ).`
    );

//!!! (2022/06/22 Remarked) Use pool instead.
//    this.boundsArraySet = new BoundsArraySet.InputsOutputs( inputScaleBoundsArray0, inputScaleBoundsArray1,
    this.boundsArraySet = BoundsArraySet.InputsOutputsPool.Singleton.get_or_create_by( inputScaleBoundsArray0, inputScaleBoundsArray1,
      inputScaleBoundsArray0.channelCount
    );

    this.boundsArraySet.output0
      .set_all_byScaleBoundsArray( inputScaleBoundsArray0 )
      .add_all_byScaleBoundsArray_all( inputScaleBoundsArray1 );
  }

  /** Setup this.output0.
   * This method should be called after setup_BoundsArraySet() because it uses BoundsArrarySet.
   */
  static setup_output0_TensorPlaceholder() {

    // 1. Only same channel count adding is supported.
    if ( this.input0.channelCount == this.input1.channelCount ) {

      this.output0.channelCount = this.input0.channelCount; // Result always has the same channel count.

      // 1.1 Adding two same dimension tensors. The result dimension is the same of any one.
      if ( ( this.input0.height == this.input1.height ) && ( this.input0.width == this.input1.width ) ) {
        this.output0.height = this.input0.height;
        this.output0.width = this.input0.width;

      // 1.2 Adding by broadcasting input0 to input1. The result dimension is the same as input1 (the larger one).
      } else if ( ( this.input0.height == 1 ) && ( this.input0.width == 1 ) ) {
        this.output0.height = this.input1.height;
        this.output0.width = this.input1.width;

      // 1.3 Adding by broadcasting input1 to input0. The result dimension is the same as input0 (the larger one).
      } else if ( ( this.input1.height == 1 ) && ( this.input1.width == 1 ) ) {
        this.output0.height = this.input0.height;
        this.output0.width = this.input0.width;

      // 1.4 Unsupported adding (height and width).
      } else {
        tf.util.assert( false,
          `Operation.AddTwoTensors.setup_output0_TensorPlaceholder(): `
            + `input0 ( height, width ) = ( ${this.input0.height}, ${this.input0.width} ) and `
            + `input1 ( height, width ) = ( ${this.input1.height}, ${this.input1.width} ) `
            + `should be either the same or one is ( 1, 1 ) for broadcating.`
        );
      }

      // Only if both inputs' lower half and higher half channel count are the same, they are passed through to output.
      // Otherwise, absent them in the output.
      {
        if ( this.input0.channelCount_lowerHalf == this.input1.channelCount_lowerHalf ) {
          this.output0.channelCount_lowerHalf = this.input0.channelCount_lowerHalf;
        } else {
          this.output0.channelCount_lowerHalf = undefined;
        }

        if ( this.input0.channelCount_higherHalf == this.input1.channelCount_higherHalf ) {
          this.output0.channelCount_higherHalf = this.input0.channelCount_higherHalf;
        } else {
          this.output0.channelCount_higherHalf = undefined;
        }
      }

      this.output0.scaleBoundsArray = this.boundsArraySet.output0;

      // Release for reducing memory usage. (Since it has been inside the output tensor placeholder.)
      {
        this.boundsArraySet.output0 = null; // Because it has already been transferred to TensorPlaceholder this.output0
        BoundsArraySet.InputsOutputsPool.Singleton.recycle( this.boundsArraySet );
        this.boundsArraySet = null;
      }

    // 2. Unsupported adding (different channel count).
    } else {
      tf.util.assert( false,
        `Operation.AddTwoTensors.setup_output0_TensorPlaceholder(): `
          + `input0 channel count ( ${this.input0.channelCount} ) and `
          + `input1 channel count ( ${this.input1.channelCount} ) `
          + `should be the same.`
      );
    }
  }

  /** Add. (Both the inputTensor0 and inputTensor1 will not be disposed. */
  static Add_and_keep0_keep1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
  }

  /** Add. (The inputTensors0 will not be disposed. The inputTensor1 will be disposed. */
  static Add_and_keep0_destroy1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
    this.input1.realTensor.dispose();
  }

  /** Add. (The inputTensor0 will be disposed. The inputTensor1 will not be disposed. */
  static Add_and_destroy0_keep1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
    this.input0.realTensor.dispose();
  }

  /** Add. (Both the inputTensor0 and inputTensor1 will be disposed. */
  static Add_and_destroy0_destroy1() {
    this.output0.realTensor = tf.add( this.input0.realTensor, this.input1.realTensor );
    this.input0.realTensor.dispose();
    this.input1.realTensor.dispose();
  }

}

/**
 * Providing Operation.AddTwoTensors
 *
 */
class AddTwoTensorsPool extends Pool.Root {

  constructor() {
    super( AddTwoTensors, AddTwoTensors.setAsConstructor );
  }

//!!! (2022/06/22 Remarked) AddTwoTensors.setAsConstructor() should be enough.
//   /**
//    * @param {AddTwoTensors} this
//    *   The Operation.AddTwoTensors object to be initialized.
//    *
//    * @return {AddTwoTensors}
//    *   Return the this object.
//    */
//   static setAsConstructor() {
//     this.setAsConstructor();
//     return this;
//   }

}

/**
 * Used as default Operation.AddTwoTensors provider.
 */
AddTwoTensorsPool.Singleton = new AddTwoTensorsPool();

<|endoftext|>


<commit_before>//-----------------------------------------------------------
//-----------------------------------------------------------
CreateArray = function( size, value )
{
  if( value !== undefined )
  {
    var array = new Array( size );
    FillArray( array, value );

    return array;
  }
  else
  {
    return new Array( size );
  }
}

//-----------------------------------------------------------
//-----------------------------------------------------------
Create2dArray = function( size0, size1, value )
{
  var array = CreateArray( size0 );

  var length = size0 - 1;
  do
  {
    array[length] = CreateArray( size1, value );
  }
  while( --length > -1 );

  return array;
}

//-----------------------------------------------------------
//-----------------------------------------------------------
FillArray = function( array, value )
{
  var length = array.length - 1;
  if( length == -1 )
  {
    return;
  }
  else
  {
    do
    {
      array[length] = value;
    }
    while( --length > -1 );
  }
}

//-----------------------------------------------------------
//-----------------------------------------------------------
Fill2dArray = function( array, value )
{
  var length = array.length - 1;

  do
  {
    FillArray( array[length], value );
  }
  while( --length > -1 );
}

//-----------------------------------------------------------
// Copy contents of arrayFrom to arrayTo up to the number
// of common elements (minimum of both array lengths).
//-----------------------------------------------------------
CopyArray = function( arrayFrom, arrayTo )
{
  var length = Math.min( arrayFrom.length, arrayTo.length ) - 1;
  if( length == -1 )
  {
    return;
  }

  do
  {
    arrayTo[length] = arrayFrom[length];
  }
  while( --length > -1 );
}

//-----------------------------------------------------------
//-----------------------------------------------------------
LimitValueToRange = function( value, low, high )
{
  if( value < low )
  {
    return low;
  }
  else
  if( value > high )
  {
    return high;
  }

  return value;
}

//-----------------------------------------------------------
// Returns a random integer.
// inputs
//  - bound0: if the only parameter used, this value is one
//            more than the integer number that will be
//            returned.
//  - bound1: (optional) if this parameter is used, bound0
//            represents the lowest possible integer while
//            it represents the highest possible integer
//            returned.
//-----------------------------------------------------------
GetRandomInteger = function( bound0, bound1 )
{
  if( bound1 === undefined )
  {
    // bound0 is high + 1.
    return Math.random() * bound0 | 0;
  }
  else
  {
    // bound0 is low.
    // bound1 is high.
    return ( Math.random() * ( bound1 + 1 - bound0 ) | 0 ) + bound0;
  }
}

//-----------------------------------------------------------
//-----------------------------------------------------------
ParseQueryString = function( queryString )
{
  var queryList = new Array();

  var parameterPropertyList;
  var parameterName;
  var parameterValue;

  var queryParameterList = queryString.split( "&" );
  for( var index in queryParameterList )
  {
    parameterPropertyList = queryParameterList[index].split( "=" );
    parameterName  = parameterPropertyList[0];
    parameterValue = parameterPropertyList[1];

    //console.log( "Parameter name: " + parameterName + ", value: " + parameterValue );
    queryList[parameterName] = parameterValue;
  }

  //console.log( queryList );
  return queryList;
}

//-----------------------------------------------------------
//-----------------------------------------------------------
GetPageParameters = function()
{
  return ParseQueryString( location.search.substring( 1 ) );
}

//-----------------------------------------------------------
//-----------------------------------------------------------
GetPageParameterValue = function( pageParameters, parameterName, defaultValue )
{
  var parameterValue = pageParameters[parameterName];
  if( parameterValue === undefined )
  {
    parameterValue = defaultValue;
  }

  //console.log( parameterValue );
  return parameterValue;
}

//-----------------------------------------------------------
GeneralUtilClass = function()
{

};

GeneralUtilClass.prototype.getPageParameters = GetPageParameters;
GeneralUtilClass.prototype.getPageParameterValue = GetPageParameterValue;

GeneralUtilClass.prototype.createArray = CreateArray;
GeneralUtilClass.prototype.create2dArray = Create2dArray;
GeneralUtilClass.prototype.fillArray = FillArray;
GeneralUtilClass.prototype.fill2dArray = Fill2dArray;
GeneralUtilClass.prototype.copyArray = CopyArray;

GeneralUtil = new GeneralUtilClass();
<commit_msg>Namespaced GeneralUtils into PuzL.<commit_after>/** @constructor */
PuzL.GeneralUtil = function()
{

};

PuzL.GeneralUtil.prototype.getPageParameters = function()
{
  return this.parseQueryString( location.search.substring( 1 ) );
};

var GeneralUtil = new PuzL.GeneralUtil();

window['GeneralUtil'] = GeneralUtil;

PuzL.GeneralUtil.prototype.getPageParameterValue = function( pageParameters, parameterName, defaultValue )
{
  var parameterValue = pageParameters[parameterName];
  if( parameterValue === undefined )
  {
    parameterValue = defaultValue;
  }

  //console.log( parameterValue );
  return parameterValue;
};

PuzL.GeneralUtil.prototype.createArray = function( size, value )
{
  if( value !== undefined )
  {
    var array = new Array( size );
    this.fillArray( array, value );

    return array;
  }
  else
  {
    return new Array( size );
  }
};

PuzL.GeneralUtil.prototype.create2dArray = function( size0, size1, value )
{
  var array = this.createArray( size0 );

  var length = size0 - 1;
  do
  {
    array[length] = this.createArray( size1, value );
  }
  while( --length > -1 );

  return array;
};

PuzL.GeneralUtil.prototype.fillArray = function( array, value )
{
  var length = array.length - 1;
  if( length == -1 )
  {
    return;
  }
  else
  {
    do
    {
      array[length] = value;
    }
    while( --length > -1 );
  }
};

PuzL.GeneralUtil.prototype.fill2dArray = function( array, value )
{
  var length = array.length - 1;

  do
  {
    this.fillArray( array[length], value );
  }
  while( --length > -1 );
};

//-----------------------------------------------------------
// Copy contents of arrayFrom to arrayTo up to the number
// of common elements (minimum of both array lengths).
//-----------------------------------------------------------
PuzL.GeneralUtil.prototype.copyArray = function( arrayFrom, arrayTo )
{
  var length = Math.min( arrayFrom.length, arrayTo.length ) - 1;
  if( length == -1 )
  {
    return;
  }

  do
  {
    arrayTo[length] = arrayFrom[length];
  }
  while( --length > -1 );
};

PuzL.GeneralUtil.prototype.limitValueToRange = function( value, low, high )
{
  if( value < low )
  {
    return low;
  }
  else
  if( value > high )
  {
    return high;
  }

  return value;
};

//-----------------------------------------------------------
// Returns a random integer.
// inputs
//  - bound0: if the only parameter used, this value is one
//            more than the integer number that will be
//            returned.
//  - bound1: (optional) if this parameter is used, bound0
//            represents the lowest possible integer while
//            it represents the highest possible integer
//            returned.
//-----------------------------------------------------------
PuzL.GeneralUtil.prototype.getRandomInteger = function( bound0, bound1 )
{
  if( bound1 === undefined )
  {
    // bound0 is high + 1.
    return Math.random() * bound0 | 0;
  }
  else
  {
    // bound0 is low.
    // bound1 is high.
    return ( Math.random() * ( bound1 + 1 - bound0 ) | 0 ) + bound0;
  }
};

PuzL.GeneralUtil.prototype.parseQueryString = function( queryString )
{
  var queryList = new Array();

  var parameterPropertyList;
  var parameterName;
  var parameterValue;

  var queryParameterList = queryString.split( "&" );
  for( var index in queryParameterList )
  {
    parameterPropertyList = queryParameterList[index].split( "=" );
    parameterName  = parameterPropertyList[0];
    parameterValue = parameterPropertyList[1];

    //console.log( "Parameter name: " + parameterName + ", value: " + parameterValue );
    queryList[parameterName] = parameterValue;
  }

  //console.log( queryList );
  return queryList;
};
<|endoftext|>


<commit_before>const https = require('https');
const Stream = require('stream').Transform;
const fs = require('fs');
const Twit = require('twit');

function lazyGuid() {
  return  Math.round(Math.random() * 100000000) + '-' + Math.round(Math.random() * 100000000);
}

const cardFinderUrl = 'https://forums.goodgamery.com/includes/mtg/mtg_helper_cardfinder_v3.php?img=true&find=';
const cardname = 'Kookus';
const imgurl = cardFinderUrl + cardname;
const outputfile = cardname.replace(/\s/g, '-').toLowerCase() + '-' + lazyGuid() + '.jpg';
const outputDir = 'logs';
const outputPath = outputDir + '/' + outputfile;

var T = new Twit(
    { consumer_key:         process.env.TWITTER_CONSUMER_KEY
    , consumer_secret:      process.env.TWITTER_CONSUMER_SECRET
    , access_token:         process.env.TWITTER_ACCESS_TOKEN
    , access_token_secret:  process.env.TWITTER_ACCESS_TOKEN_SECRET
    }
);

function uploadTwitterImage(filepath) {
   return new Promise((resolve, reject) => {
      try {
        var b64content = fs.readFileSync(filepath, { encoding: 'base64' });

        T.post('media/upload', { media_data: b64content }, function (err, data, response) {
          if (!err) {
            resolve(data);
          } else {
            reject(err);
          }
        });
      } catch(e) {
        reject(e);
      }
   });
}

function postImageTweet(filepath, altText, message) {
  return new Promise((resolve, reject) => {
    // first we must post the media to Twitter
    uploadTwitterImage(filepath)
      .then(data =>{
        // now we can assign alt text to the media, for use by screen readers and
        // other text-based presentations and interpreters
        var mediaIdStr = data.media_id_string;
        var meta_params = { media_id: mediaIdStr, alt_text: { text: altText } }

        T.post('media/metadata/create', meta_params, function (err, data, response) {
          if (!err) {
            // now we can reference the media and post a tweet (media will attach to the tweet)
            var params = { status: message, media_ids: [mediaIdStr] }

            T.post('statuses/update', params, function (err, data, response) {
              console.log(data);
              resolve();
            });
          } else {
            reject(err);
          }
        });
      });
  });
}

https.request(imgurl, function(response) {
  var data = new Stream();

  response.on('data', function(chunk) {
    data.push(chunk);
  });

  response.on('end', function() {
    fs.writeFileSync(outputPath, data.read());
    postImageTweet(outputPath, cardname, 'The card you\'re thinking of is ' +  cardname)
      .then(() => { console.log('Posted to twitter.') }, e => { console.err('Failed to post to twitter: ' + e); })
      .then(() => {
        fs.unlink(outputPath, (err) => {
        if (err) throw err;
          console.log('Deleted ' + outputPath);
        });
      });
  });

  response.on('error', function(e) {
    console.log('Failed to download image: ' + e);
  });

}).end();

<commit_msg>fully promisified example of image download,upload, and post<commit_after>const https = require('https');
const Stream = require('stream').Transform;
const fs = require('fs');
const Twit = require('twit');

function lazyGuid() {
  return  Math.round(Math.random() * 100000000) + '-' + Math.round(Math.random() * 100000000);
}

const cardFinderUrl = 'https://forums.goodgamery.com/includes/mtg/mtg_helper_cardfinder_v3.php?img=true&find=';
const cardname = 'Three Visits';
const outputfile = cardname.replace(/\s+/g, '-').toLowerCase() + '-' + lazyGuid() + '.jpg';
const outputDir = 'logs';
const outputPath = outputDir + '/' + outputfile;

var T = new Twit(
    { consumer_key:         process.env.TWITTER_CONSUMER_KEY
    , consumer_secret:      process.env.TWITTER_CONSUMER_SECRET
    , access_token:         process.env.TWITTER_ACCESS_TOKEN
    , access_token_secret:  process.env.TWITTER_ACCESS_TOKEN_SECRET
    }
);

function downloadMtgCardFinderImage(cardname, outputPath) {
  return new Promise((resolve, reject) => {
    const imgurl = cardFinderUrl + cardname;
    try {
      console.log('Downloading image data from ' + imgurl);
      https.request(imgurl, function(response) {
        var data = new Stream();

        response.on('data', function(chunk) {
          data.push(chunk);
        });

        response.on('end', function() {
          console.log('Writing image data file...');

          fs.writeFileSync(outputPath, data.read());
          console.log('Wrote image date to ' + outputPath);

          resolve(outputPath);
        });

        response.on('error', function(e) {
          reject(e);
        });
      }).end();
    } catch(e) {
      reject(e);
    }
  });
}

function uploadTwitterImage(filepath) {
   return new Promise((resolve, reject) => {
      try {
        var b64content = fs.readFileSync(filepath, { encoding: 'base64' });

        console.log('Uploading image file to twitter...');

        T.post('media/upload', { media_data: b64content }, function (err, data, response) {
          if (!err) {
            resolve(data);
          } else {
            reject(err);
          }
        });
      } catch(e) {
        reject(e);
      }
   });
}

function postImageTweet(data, altText, message) {
  return new Promise((resolve, reject) => {
    // now we can assign alt text to the media, for use by screen readers and
    // other text-based presentations and interpreters
    var mediaIdStr = data.media_id_string;
    var meta_params = { media_id: mediaIdStr, alt_text: { text: altText } }

    console.log('Setting media metadata...');

    T.post('media/metadata/create', meta_params, function (err, data, response) {
      if (!err) {
        // now we can reference the media and post a tweet (media will attach to the tweet)
        var params = { status: message, media_ids: [mediaIdStr] }

        console.log('Posting tweet...');

        T.post('statuses/update', params, function (err, data, response) {
          console.log(data);
          resolve();
        });
      } else {
        reject(err);
      }
    });
  });
}

downloadMtgCardFinderImage(cardname, outputPath)
  .then(localFilePath => uploadTwitterImage(localFilePath), e => console.error('Failed to upload image: ' + e))
  .then(twitterImage => {
    return postImageTweet(twitterImage, cardname, 'The card you\'re thinking of is ' +  cardname)
      .then(() => {
        console.log('Posted tweet.');
      }, e => console.error('Failed to post tweet: ' + e))
      .then(() => {
        return fs.unlink(outputPath, (err) => {
          if (!err) {
            console.log('Deleted ' + outputPath);
          } else {
            console.error('Unable to delete local image file: ' + err);
          }
        });
      });
  }, e => console.error('Failed to download image: ' + e));<|endoftext|>


<commit_before>/*doc
---
title: Buttons
name: button_react
categories:
 - react_base_buttons
 - react_all
---

npm install pui-react-buttons --save

## Props

Property | Required | Type | Default | Description
---------|----------|------|---------|------------
alt   | no | Boolean                                        | false     | Whether to render as 'alternate' button
flat  | no | Boolean                                        | false     | Whether to render as a 'flat' button
href  | no | String                                         |           | If specified, button clicks will redirect to this href
large | no | Boolean                                        | false     | Whether to render the button large
small | no | Boolean                                        | false     | Whether to render teh button small

## Basic usage

Import the subcomponents:

```
import {DefaultButton, PrimaryButton, DangerButton, BrandButton} from 'pui-react-buttons';
import {Icon} from 'pui-react-iconography';
```

Buttons use the button tag by default. If you'd like a link rather than a button, simply add an `href` attribute.

```react_example_table
<DefaultButton>
  Button
</DefaultButton>

<DefaultButton href="http://example.com">
  Link
</DefaultButton>
```

## Styles

There are 3 main button color schemes: Default, Primary, Danger. There is also Brand, but this should only be used for marketing.

```react_example_table
<DefaultButton>
  Default
</DefaultButton>

<PrimaryButton>
  Primary
</PrimaryButton>

<DangerButton>
  Danger
</DangerButton>

<BrandButton>
  Brand
</BrandButton>
```

For each color scheme there is the default style, an alt style (with inverted colors and a transparent background) and a flat style (alt with transparent borders).
To use the alt style, set the `alt` prop, to use the flat style, use the `flat` prop

```react_example_table
<DefaultButton alt>
  Alt
</DefaultButton>

<DefaultButton flat>
  Flat
</DefaultButton>

<PrimaryButton alt>
  Primary Alt
</PrimaryButton>
```

## Sizing

To make a button large, set the `large` property to true, to make it small, set `small` to true.

```react_example_table
<PrimaryButton large>
  Big Button
</PrimaryButton>

<PrimaryButton small>
  Small Button
</PrimaryButton>
```

## Icons

Buttons can have icons by specifying the `icon` prop and giving it a node:

```react_example_table
<PrimaryButton icon={<Icon src="add"/>}>
  Icon button
</PrimaryButton>
```
*/
<commit_msg>chore(styleguide): Remove button with icon documentation until the feature is ready<commit_after>/*doc
---
title: Buttons
name: button_react
categories:
 - react_base_buttons
 - react_all
---

npm install pui-react-buttons --save

## Props

Property | Required | Type | Default | Description
---------|----------|------|---------|------------
alt   | no | Boolean                                        | false     | Whether to render as 'alternate' button
flat  | no | Boolean                                        | false     | Whether to render as a 'flat' button
href  | no | String                                         |           | If specified, button clicks will redirect to this href
large | no | Boolean                                        | false     | Whether to render the button large
small | no | Boolean                                        | false     | Whether to render teh button small

## Basic usage

Import the subcomponents:

```
import {DefaultButton, PrimaryButton, DangerButton, BrandButton} from 'pui-react-buttons';
import {Icon} from 'pui-react-iconography';
```

Buttons use the button tag by default. If you'd like a link rather than a button, simply add an `href` attribute.

```react_example_table
<DefaultButton>
  Button
</DefaultButton>

<DefaultButton href="http://example.com">
  Link
</DefaultButton>
```

## Styles

There are 3 main button color schemes: Default, Primary, Danger. There is also Brand, but this should only be used for marketing.

```react_example_table
<DefaultButton>
  Default
</DefaultButton>

<PrimaryButton>
  Primary
</PrimaryButton>

<DangerButton>
  Danger
</DangerButton>

<BrandButton>
  Brand
</BrandButton>
```

For each color scheme there is the default style, an alt style (with inverted colors and a transparent background) and a flat style (alt with transparent borders).
To use the alt style, set the `alt` prop, to use the flat style, use the `flat` prop

```react_example_table
<DefaultButton alt>
  Alt
</DefaultButton>

<DefaultButton flat>
  Flat
</DefaultButton>

<PrimaryButton alt>
  Primary Alt
</PrimaryButton>
```

## Sizing

To make a button large, set the `large` property to true, to make it small, set `small` to true.

```react_example_table
<PrimaryButton large>
  Big Button
</PrimaryButton>

<PrimaryButton small>
  Small Button
</PrimaryButton>
```
*/
<|endoftext|>


<commit_before>'use strict';

/**
* Cauchy distribution cumulative distribution function (CDF).
*
* @module @stdlib/math/base/dist/cauchy/cdf
*
* @example
* var cdf = require( '@stdlib/math/base/dist/cauchy/cdf' );
*
* var y = cdf( 2.0, 0.0, 1.0 );
* // returns ~0.852
*
* var myCDF = cdf.factory( 1.5, 3.0 );
*
* y = myCDF( 1.0 );
* // returns ~0.447
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var cdf = require( './cdf.js' );
var factory = require( './factory.js' );

// MAIN //

setReadOnly( cdf, 'factory', factory );

// EXPORTS //

module.exports = cdf;
<commit_msg>Update example<commit_after>'use strict';

/**
* Cauchy distribution cumulative distribution function (CDF).
*
* @module @stdlib/math/base/dist/cauchy/cdf
*
* @example
* var cdf = require( '@stdlib/math/base/dist/cauchy/cdf' );
*
* var y = cdf( 2.0, 0.0, 1.0 );
* // returns ~0.852
*
* @example
* var factory = require( '@stdlib/math/base/dist/cauchy/cdf' ).factory;
*
* var cdf = factory( 1.5, 3.0 );
*
* var y = cdf( 1.0 );
* // returns ~0.447
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var cdf = require( './cdf.js' );
var factory = require( './factory.js' );

// MAIN //

setReadOnly( cdf, 'factory', factory );

// EXPORTS //

module.exports = cdf;
<|endoftext|>


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

const fs = require('fs');
const path = require('path');

const SCRIPT_NAME = path.basename(__filename);
const USAGE = `
  Usage: ${SCRIPT_NAME} [--next|<version>|--help]

    --next      generate the @next version and put it across all packages
    <version>   set a new version across all packages. See examples for format
    --help      show this help message

  Examples:
    ${SCRIPT_NAME} v1.0.0
    ${SCRIPT_NAME} v1.0.0-post
    ${SCRIPT_NAME} --next
`;

if (process.argv[2] === '--help' || process.argv[2] === '-h') {
  console.log(USAGE);
  process.exit(0);
}

if (process.argv.length !== 3) {
  console.log(`ERROR: missing version argument. Use --help for details.`);
  process.exit(1);
}

let version = process.argv[2];
if (version === '--next') {
  const packageJSON = require('../package.json');
  version = package.version;
  const dashIndex = version.indexOf('-');
  if (dashIndex === -1)
    version = version.substring(0, dashIndex);
  version += '-next.' + Date.now();
  console.log('Setting version to ' + version);
} else {
  if (!version || !version.match(/^v\d+\.\d+\.\d+(-post)?$/)) {
    console.error(`Malformed version "${version}". Use --help for details.`);
    process.exit(1);
  }
  version = version.substring(1);
}

updatePackage(path.join(__dirname, '..', 'package.json'), packageJSON => {
  packageJSON.version = version;
});

for (const packageName of ['playwright-chromium', 'playwright-firefox', 'playwright-webkit', 'playwright']) {
  updatePackage(path.join(__dirname, '..', 'packages', packageName, 'package.json'), packageJSON => {
    packageJSON.version = version;
    packageJSON.dependencies['playwright-core'] = `=${version}`;
  });
}

function updatePackage(packageJSONPath, transform) {
  console.log(`Updating ${packageJSONPath} to ${version}.`);
  const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, 'utf8'));
  transform(packageJSON);
  fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, undefined, 2) + '\n');
}
<commit_msg>devops: fix update_version.js script<commit_after>#!/usr/bin/env node
/**
 * Copyright (c) Microsoft Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const fs = require('fs');
const path = require('path');

const SCRIPT_NAME = path.basename(__filename);
const USAGE = `
  Usage: ${SCRIPT_NAME} [--next|<version>|--help]

    --next      generate the @next version and put it across all packages
    <version>   set a new version across all packages. See examples for format
    --help      show this help message

  Examples:
    ${SCRIPT_NAME} v1.0.0
    ${SCRIPT_NAME} v1.0.0-post
    ${SCRIPT_NAME} --next
`;

if (process.argv[2] === '--help' || process.argv[2] === '-h') {
  console.log(USAGE);
  process.exit(0);
}

if (process.argv.length !== 3) {
  console.log(`ERROR: missing version argument. Use --help for details.`);
  process.exit(1);
}

let version = process.argv[2];
if (version === '--next') {
  const packageJSON = require('../package.json');
  version = packageJSON.version;
  const dashIndex = version.indexOf('-');
  if (dashIndex === -1)
    version = version.substring(0, dashIndex);
  version += '-next.' + Date.now();
  console.log('Setting version to ' + version);
} else {
  if (!version || !version.match(/^v\d+\.\d+\.\d+(-post)?$/)) {
    console.error(`Malformed version "${version}". Use --help for details.`);
    process.exit(1);
  }
  version = version.substring(1);
}

updatePackage(path.join(__dirname, '..', 'package.json'), packageJSON => {
  packageJSON.version = version;
});

for (const packageName of ['playwright-chromium', 'playwright-firefox', 'playwright-webkit', 'playwright']) {
  updatePackage(path.join(__dirname, '..', 'packages', packageName, 'package.json'), packageJSON => {
    packageJSON.version = version;
    packageJSON.dependencies['playwright-core'] = `=${version}`;
  });
}

function updatePackage(packageJSONPath, transform) {
  console.log(`Updating ${packageJSONPath} to ${version}.`);
  const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, 'utf8'));
  transform(packageJSON);
  fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, undefined, 2) + '\n');
}
<|endoftext|>


<commit_before>'use strict';

// MAIN //

/**
* Computes an absolute value of a signed 32-bit integer in two's complement format.
*
* ## Method
*
* * Assume two's complement format.
* * Create a mask by applying a sign propagating right-shift. For negative integers, this results in all `1`'s. For nonnegative integers, this results in all `0`'s.
* * XOR the mask with `x`. For negative integers, this is the equivalent of a NOT. For nonnegative integers, this is a no-op.
* * Subtract the mask to recover the absolute value. For negative integers, this adds `1`, which is `-x` when using two's complement. For nonnegative integers, this subtracts `0`.
*
* @private
* @param {integer32} x - integer
* @returns {integer32} absolute value
*
* @example
* var v = abs( -10 );
* // returns 10
*/
function abs( x ) {
	var mask = ( x >> 31 );
	return ((x ^ mask) - mask)|0; // asm type annotation
} // end FUNCTION abs()

// EXPORTS //

module.exports = abs;
<commit_msg>Add type annotation<commit_after>'use strict';

// MAIN //

/**
* Computes an absolute value of a signed 32-bit integer in two's complement format.
*
* ## Method
*
* * Assume two's complement format.
* * Create a mask by applying a sign propagating right-shift. For negative integers, this results in all `1`'s. For nonnegative integers, this results in all `0`'s.
* * XOR the mask with `x`. For negative integers, this is the equivalent of a NOT. For nonnegative integers, this is a no-op.
* * Subtract the mask to recover the absolute value. For negative integers, this adds `1`, which is `-x` when using two's complement. For nonnegative integers, this subtracts `0`.
*
* @private
* @param {integer32} x - integer
* @returns {integer32} absolute value
*
* @example
* var v = abs( -10|0 );
* // returns 10
*/
function abs( x ) {
	var mask = ( x >> 31 );
	return ((x ^ mask) - mask)|0; // asm type annotation
} // end FUNCTION abs()

// EXPORTS //

module.exports = abs;
<|endoftext|>


<commit_before>// @flow
import _ from 'lodash';
import type { EventOption } from 'ical-generator';

import type { RawLesson, Module, ModuleCode, Semester } from 'types/modules';
import type {
  ModuleLessonConfigWithLessons,
  SemTimetableConfigWithLessons,
} from 'types/timetables';

import config from 'config/app-config.json';
import academicCalendar from 'config/academic-calendar.json';
import { getModuleSemesterData } from 'utils/modules';

const SG_UTC_TIME_DIFF_MS = 8 * 60 * 60 * 1000;
export const RECESS_WEEK = -1;
const NUM_WEEKS_IN_A_SEM = 14; // including reading week
const ODD_WEEKS = [1, 3, 5, 7, 9, 11, 13];
const EVEN_WEEKS = [2, 4, 6, 8, 10, 12];
const ALL_WEEKS = [...ODD_WEEKS, ...EVEN_WEEKS];
const WEEKS_WITHOUT_TUTORIALS = [1, 2, 3];
const EXAM_DURATION_MS = 2 * 60 * 60 * 1000; // 2 hours
const tutorialLessonTypes = ['Design Lecture', 'Laboratory', 'Recitation'];

function dayIndex(weekday: string) {
  return ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'].indexOf(weekday.toLowerCase());
}

// needed cos the utils method formats the date for display
function getExamDate(module: Module, semester: Semester): string {
  return _.get(getModuleSemesterData(module, semester), 'ExamDate');
}

export function daysAfter(startDate: Date, days: number): Date {
  const result = new Date(startDate.getTime());
  result.setUTCDate(result.getUTCDate() + days);
  return result;
}

export function iCalEventForExam(module: Module, semester: Semester): ?EventOption {
  const examDate = new Date(getExamDate(module, semester));
  if (isNaN(examDate.getTime())) {
    return null;
  }
  return {
    start: examDate,
    end: new Date(examDate.valueOf() + EXAM_DURATION_MS),
    summary: `${module.ModuleCode} Exam`,
    description: module.ModuleTitle,
    url: `http://www.nus.edu.sg/registrar/event/examschedule-sem${semester}.html`,
  };
}

export function isTutorial(lesson: RawLesson): boolean {
  return (
    tutorialLessonTypes.includes(lesson.LessonType) ||
    lesson.LessonType.toLowerCase().includes('tutorial'));
}

// given academic weeks in semester and a start date in week 1,
// return dates corresponding to the respective weeks
export function datesForAcademicWeeks(start: Date, week: number): Date {
  // all weeks 7 and after are bumped by 7 days because of recess week
  if (week === RECESS_WEEK) {
    return daysAfter(start, 6 * 7);
  }
  return daysAfter(
    start,
    (week <= 6 ? week - 1 : week) * 7);
}

/* Calculates the dates that should be excluded for lesson
 * 1. exclude recess week from all
 * 2. odd/even weeks get appropriate exclusions
 * 3. tutorials have week 1, 2, and 3 excluded
 * 4. if comma separated weeks specified, exclude unspecified weeks
 */
function calculateExclusion(lesson: RawLesson, start: Date) {
  let excludes = _.union(
    // always exclude recess
    [RECESS_WEEK],
    // specific exclusion for lessons (tutorials)
    isTutorial(lesson) ? WEEKS_WITHOUT_TUTORIALS : []
  );

  switch (lesson.WeekText) {
    case 'Odd Week':
      excludes = _.union(excludes, EVEN_WEEKS);
      break;
    case 'Even Week':
      excludes = _.union(excludes, ODD_WEEKS);
      break;
    case 'Every Week':
      break;
    default: { // comma-separated weeks
      const weeksWithClasses = lesson.WeekText.split(',').map(w => parseInt(w, 10));
      excludes = _.union(excludes, _.difference(ALL_WEEKS, weeksWithClasses));
      break;
    }
  }

  // sort in ascending order so we get nicer dates, recess will be the first
  excludes.sort((a, b) => a - b);
  // convert the academic weeks into dates
  return excludes.map(_.partial(datesForAcademicWeeks, start));
}

function hoursAfter(date: Date, sgHour: number) {
  const d = new Date(date);
  d.setUTCHours(d.getUTCHours() + sgHour);
  return d;
}

/* Strategy is to generate a weekly event,
 * then calculate exclusion for special cases in calculateExclusion.
 */
export function iCalEventForLesson(
  lesson: RawLesson, module: Module, semester: Semester, firstDayOfSchool: Date): EventOption {
  // set start date and time, end date and time
  const lessonDayMidnight = daysAfter(firstDayOfSchool, dayIndex(lesson.DayText));
  const start = hoursAfter(lessonDayMidnight, parseInt(lesson.StartTime.slice(0, 2), 10));
  const end = hoursAfter(lessonDayMidnight, parseInt(lesson.EndTime.slice(0, 2), 10));

  const exclude = calculateExclusion(lesson, start);

  return {
    start,
    end,
    summary: `${module.ModuleCode} ${lesson.LessonType}`,
    description: `${module.ModuleTitle}\n${lesson.LessonType} Group ${lesson.ClassNo}`,
    location: lesson.Venue,
    url: 'https://myaces.nus.edu.sg/cors/jsp/report/ModuleDetailedInfo.jsp?' +
      `acad_y=${module.AcadYear}&sem_c=${semester}&mod_c=${module.ModuleCode}`,
    repeating: {
      freq: 'WEEKLY',
      count: NUM_WEEKS_IN_A_SEM,
      byDay: [lesson.DayText.slice(0, 2)],
      exclude,
    },
  };
}

export function iCalForTimetable(
    semester: Semester,
    timetable: SemTimetableConfigWithLessons,
    moduleData: { [key: ModuleCode]: Module },
    year: string = config.academicYear): Array<EventOption> {
  const start = academicCalendar[year][semester].start;
  const firstDayOfSchool = new Date(Date.UTC(start[0], start[1], start[2]) - SG_UTC_TIME_DIFF_MS);
  const events = _.flatMap(
    timetable,
    (lessonConfig: ModuleLessonConfigWithLessons, moduleCode: ModuleCode) =>
      _.concat(
        _.flatMap(
          lessonConfig,
          lessons =>
          lessons.map(
            lesson => iCalEventForLesson(
              lesson, moduleData[moduleCode], semester, firstDayOfSchool))
        ),
        iCalEventForExam(moduleData[moduleCode], semester) || [],
      )
  );
  return events;
}
<commit_msg>Fix: tutorials start in week 3, not 4<commit_after>// @flow
import _ from 'lodash';
import type { EventOption } from 'ical-generator';

import type { RawLesson, Module, ModuleCode, Semester } from 'types/modules';
import type {
  ModuleLessonConfigWithLessons,
  SemTimetableConfigWithLessons,
} from 'types/timetables';

import config from 'config/app-config.json';
import academicCalendar from 'config/academic-calendar.json';
import { getModuleSemesterData } from 'utils/modules';

const SG_UTC_TIME_DIFF_MS = 8 * 60 * 60 * 1000;
export const RECESS_WEEK = -1;
const NUM_WEEKS_IN_A_SEM = 14; // including reading week
const ODD_WEEKS = [1, 3, 5, 7, 9, 11, 13];
const EVEN_WEEKS = [2, 4, 6, 8, 10, 12];
const ALL_WEEKS = [...ODD_WEEKS, ...EVEN_WEEKS];
const WEEKS_WITHOUT_TUTORIALS = [1, 2];
const EXAM_DURATION_MS = 2 * 60 * 60 * 1000; // 2 hours
const tutorialLessonTypes = ['Design Lecture', 'Laboratory', 'Recitation'];

function dayIndex(weekday: string) {
  return ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'].indexOf(weekday.toLowerCase());
}

// needed cos the utils method formats the date for display
function getExamDate(module: Module, semester: Semester): string {
  return _.get(getModuleSemesterData(module, semester), 'ExamDate');
}

export function daysAfter(startDate: Date, days: number): Date {
  const result = new Date(startDate.getTime());
  result.setUTCDate(result.getUTCDate() + days);
  return result;
}

export function iCalEventForExam(module: Module, semester: Semester): ?EventOption {
  const examDate = new Date(getExamDate(module, semester));
  if (isNaN(examDate.getTime())) {
    return null;
  }
  return {
    start: examDate,
    end: new Date(examDate.valueOf() + EXAM_DURATION_MS),
    summary: `${module.ModuleCode} Exam`,
    description: module.ModuleTitle,
    url: `http://www.nus.edu.sg/registrar/event/examschedule-sem${semester}.html`,
  };
}

export function isTutorial(lesson: RawLesson): boolean {
  return (
    tutorialLessonTypes.includes(lesson.LessonType) ||
    lesson.LessonType.toLowerCase().includes('tutorial'));
}

// given academic weeks in semester and a start date in week 1,
// return dates corresponding to the respective weeks
export function datesForAcademicWeeks(start: Date, week: number): Date {
  // all weeks 7 and after are bumped by 7 days because of recess week
  if (week === RECESS_WEEK) {
    return daysAfter(start, 6 * 7);
  }
  return daysAfter(
    start,
    (week <= 6 ? week - 1 : week) * 7);
}

/* Calculates the dates that should be excluded for lesson
 * 1. exclude recess week from all
 * 2. odd/even weeks get appropriate exclusions
 * 3. tutorials have week 1, 2, and 3 excluded
 * 4. if comma separated weeks specified, exclude unspecified weeks
 */
function calculateExclusion(lesson: RawLesson, start: Date) {
  let excludes = _.union(
    // always exclude recess
    [RECESS_WEEK],
    // specific exclusion for lessons (tutorials)
    isTutorial(lesson) ? WEEKS_WITHOUT_TUTORIALS : []
  );

  switch (lesson.WeekText) {
    case 'Odd Week':
      excludes = _.union(excludes, EVEN_WEEKS);
      break;
    case 'Even Week':
      excludes = _.union(excludes, ODD_WEEKS);
      break;
    case 'Every Week':
      break;
    default: { // comma-separated weeks
      const weeksWithClasses = lesson.WeekText.split(',').map(w => parseInt(w, 10));
      excludes = _.union(excludes, _.difference(ALL_WEEKS, weeksWithClasses));
      break;
    }
  }

  // sort in ascending order so we get nicer dates, recess will be the first
  excludes.sort((a, b) => a - b);
  // convert the academic weeks into dates
  return excludes.map(_.partial(datesForAcademicWeeks, start));
}

function hoursAfter(date: Date, sgHour: number) {
  const d = new Date(date);
  d.setUTCHours(d.getUTCHours() + sgHour);
  return d;
}

/* Strategy is to generate a weekly event,
 * then calculate exclusion for special cases in calculateExclusion.
 */
export function iCalEventForLesson(
  lesson: RawLesson, module: Module, semester: Semester, firstDayOfSchool: Date): EventOption {
  // set start date and time, end date and time
  const lessonDayMidnight = daysAfter(firstDayOfSchool, dayIndex(lesson.DayText));
  const start = hoursAfter(lessonDayMidnight, parseInt(lesson.StartTime.slice(0, 2), 10));
  const end = hoursAfter(lessonDayMidnight, parseInt(lesson.EndTime.slice(0, 2), 10));

  const exclude = calculateExclusion(lesson, start);

  return {
    start,
    end,
    summary: `${module.ModuleCode} ${lesson.LessonType}`,
    description: `${module.ModuleTitle}\n${lesson.LessonType} Group ${lesson.ClassNo}`,
    location: lesson.Venue,
    url: 'https://myaces.nus.edu.sg/cors/jsp/report/ModuleDetailedInfo.jsp?' +
      `acad_y=${module.AcadYear}&sem_c=${semester}&mod_c=${module.ModuleCode}`,
    repeating: {
      freq: 'WEEKLY',
      count: NUM_WEEKS_IN_A_SEM,
      byDay: [lesson.DayText.slice(0, 2)],
      exclude,
    },
  };
}

export function iCalForTimetable(
    semester: Semester,
    timetable: SemTimetableConfigWithLessons,
    moduleData: { [key: ModuleCode]: Module },
    year: string = config.academicYear): Array<EventOption> {
  const start = academicCalendar[year][semester].start;
  const firstDayOfSchool = new Date(Date.UTC(start[0], start[1], start[2]) - SG_UTC_TIME_DIFF_MS);
  const events = _.flatMap(
    timetable,
    (lessonConfig: ModuleLessonConfigWithLessons, moduleCode: ModuleCode) =>
      _.concat(
        _.flatMap(
          lessonConfig,
          lessons =>
          lessons.map(
            lesson => iCalEventForLesson(
              lesson, moduleData[moduleCode], semester, firstDayOfSchool))
        ),
        iCalEventForExam(moduleData[moduleCode], semester) || [],
      )
  );
  return events;
}
<|endoftext|>


<commit_before>
var app = module.exports = {};

global.rek = require('rekuire');
global._ = rek('lodash');

var TrackScanner = rek('TrackScanner'),
	TrackRepository = rek('TrackRepository');

process.on('uncaughtException',function(e) {
	console.log("Caught unhandled exception: " + e);
	console.log(" ---> : " + e.stack);
});

if (!_.endsWith) {
	_.endsWith = function(str, suffix) {
		return str.indexOf(suffix, str.length - suffix.length) !== -1;
	};
}

app.trackScanner = new TrackScanner();
app.trackRepository = new TrackRepository(app.trackScanner);

console.log('app.js complete')<commit_msg>made assert globally available<commit_after>
var app = module.exports = {};

global.rek = require('rekuire');
global._ = rek('lodash');
global.assert = rek('assert');

var TrackScanner = rek('TrackScanner'),
	TrackRepository = rek('TrackRepository');

process.on('uncaughtException',function(e) {
	console.log("Caught unhandled exception: " + e);
	console.log(" ---> : " + e.stack);
});

if (!_.endsWith) {
	_.endsWith = function(str, suffix) {
		return str.indexOf(suffix, str.length - suffix.length) !== -1;
	};
}

app.trackScanner = new TrackScanner();
app.trackRepository = new TrackRepository(app.trackScanner);

console.log('app.js complete')<|endoftext|>


<commit_before>
/*

  Bundler.js

*/

var utils       = require("./utils"),
    _           = require("lodash"),
    Promise     = require("bluebird"),
    path        = require("path"),
    webpack     = require("webpack"),
    readFile    = Promise.promisify(_.bind(global.fs.readFile, global.fs));

var Bundler = module.exports = function(options) {

  var self = this;

  options = options || {};
  options.compile = ("undefined" === typeof options.compile) ? true: options.compile;
  options.watch = ("undefined" === typeof options.watch) ? true: options.watch;

  // Configure
  this.config = {
    entry: options.entry,
    output: {
      path: options.path || "/scripts/",
      filename: options.filename,
    },
    module: {
      loaders: [
       { test: /.+/, loader: "superloader" }
      ]
    },
    resolve: {
      extensions: ["", ".coffee", ".js"]
    }
  };

  // Store path
  this.path = path.join(this.config.output.path, options.filename);

  // Set up bundler
  this.bundler = webpack(this.config);
  this.bundler.outputFileSystem = global.fs;

  // Bind functions
  this.get = _.bind(this.get, this);
  // Optionally compile
  if (options.compile) this.compile();

  // Set up watch (it already updates)
  if (options.watch) this.bundler.watch({}, function(err, stats) {
    global.server.reload(self.path);
  });

  return this;

}

// Modifies file
Bundler.fromFile = function(file, type) {
  file.folder = "";
  file.name = file.dir.replace(utils.makePathAbsolute(file.basePath), "").slice(1);
  return new Bundler({ entry : file.path, filename : file.name + "." + type });
}

Bundler.prototype.compile = function(next) {
  next = next || function() {};
  this.bundler.run(next);
  return this;
}

Bundler.prototype.get = function() {
  return readFile(this.path, "utf8");
}
<commit_msg>bundler: promisifies #compile<commit_after>
/*

  Bundler.js

*/

var utils       = require("./utils"),
    _           = require("lodash"),
    Promise     = require("bluebird"),
    path        = require("path"),
    webpack     = require("webpack"),
    readFile    = Promise.promisify(_.bind(global.fs.readFile, global.fs));

var Bundler = module.exports = function(options) {

  var self = this;

  options = options || {};
  options.compile = ("undefined" === typeof options.compile) ? true: options.compile;
  options.watch = ("undefined" === typeof options.watch) ? true: options.watch;

  // Configure
  this.config = {
    entry: options.entry,
    output: {
      path: options.path || "/scripts/",
      filename: options.filename,
    },
    module: {
      loaders: [
       { test: /.+/, loader: "superloader" }
      ]
    },
    resolve: {
      extensions: ["", ".coffee", ".js"]
    }
  };

  // Store path
  this.path = path.join(this.config.output.path, options.filename);

  // Set up bundler
  this.bundler = webpack(this.config);
  this.bundler.outputFileSystem = global.fs;

  // Bind functions
  this.get = _.bind(this.get, this);
  this.compile = Promise.promisify(_.bind(this.bundler.run, this.bundler));

  // Optionally compile
  if (options.compile) this.compile();

  // Set up watch (it already updates)
  if (options.watch) this.bundler.watch({}, function(err, stats) {
    global.server.reload(self.path);
  });

  return this;

}

// Modifies file
Bundler.fromFile = function(file, type) {
  file.folder = "";
  file.name = file.dir.replace(utils.makePathAbsolute(file.basePath), "").slice(1);
  return new Bundler({ entry : file.path, filename : file.name + "." + type });
}

Bundler.prototype.get = function() {
  return readFile(this.path, "utf8");
}
<|endoftext|>


<commit_before>(function($, Array) {
	if (!('indexOf' in Array.prototype)) {
		Array.prototype.indexOf= function(find, i /*opt*/) {
			if (i===undefined) i= 0;
			if (i<0) i+= this.length;
			if (i<0) i= 0;
			for (var n= this.length; i<n; i++)
				if (i in this && this[i]===find)
					return i;
			return -1;
		};
	}

	$.widget("ui.SelectMultiple", {
		options: {
			sels: {
				self:	".select_multiple",
				list:	"ul",
				item:	"li"
			},
			html: {
				wrapper:	"

",
				list:		"

",
				item:		"

"
			},
			classes: {
				active: "active"
			}
		},

		_create: function() {
			var instance = this;

			this.select = this.element;
			var width = this.element.outerWidth();
			var height = this.element.outerHeight();
			this.select.wrap(this.options.html.wrapper);
			this.element = this.select.parent();
			this.element.width(width);
			this.select.hide();
			this.all_options = this.select.find("option");
			this.element.append(this.options.html.list);

			this.list = this.element.find(this.options.sels.list);
			this.list.width(width).height(height);
			this.all_options.each(function() {
				instance.list.append(instance.options.html.item);
				var item = instance.list.find(instance.options.sels.item).last();
				item.text($(this).text());
			});
			this.all_items = this.list.find(this.options.sels.item);

			this.init();
		},

		init: function() {
			var instance = this;
			this.current_index = this.select.find("option:selected").first().index();
			this.select.find("option:selected").each(function() {
				var index = $(this).index();
				instance.all_items.eq(index).addClass(instance.options.classes.active);
			});
			this.store_active();

			var count = 0;
			this.all_items.click(function(event) {
				if(!instance.state_focus) {
					return;
				}

				count = 0;
				var index = $(this).index();
				if(event.shiftKey) {
					count = index - instance.current_index;
					instance.selection(instance.current_index, count);
					instance.scroll_list_to(instance.current_index + count);
					instance.store_active();
				} else if(event.ctrlKey) {
					instance.toggle(index);
					instance.current_index = instance.select.find("option:selected").first().index();
					instance.scroll_list_to(index);
					instance.store_active();
				} else {
					var change = false;
					instance.select.find("option:selected").each(function() {
						if(index != $(this).index()) {
							instance.deactivate($(this).index());
							change = true;
						}
					});
					change = instance.activate(index) || change;
					if(change) {
						instance._trigger_change(instance.select);
					}
					instance.current_index = index;
					instance.scroll_list_to(instance.current_index);
					instance.store_active();
				}
			}).bind("selectstart dragstart", function(event) {
				event.preventDefault();
				return false;
			});

			$(document).bind("keydown", "shift+up", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count--;
				if(instance.current_index + count >= instance.all_items.size()) {
					count = instance.all_items.size() - instance.current_index - 1;
				} else if(instance.current_index + count < 0) {
					count = - instance.current_index;
				}
				var change = instance.selection(instance.current_index, count, true);
				change = instance.restore_active() || change;
				instance.scroll_list_to(instance.current_index + count);
				if(change) {
					instance._trigger_change(instance.select);
				}
			});
			$(document).bind("keydown", "shift+down", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count++;
				if(instance.current_index + count >= instance.all_items.size()) {
					count = instance.all_items.size() - instance.current_index - 1;
				} else if(instance.current_index + count < 0) {
					count = - instance.current_index;
				}
				var change = instance.selection(instance.current_index, count, true);
				change = instance.restore_active() || change;
				instance.scroll_list_to(instance.current_index + count);
				if(change) {
					instance._trigger_change(instance.select);
				}
			});
			$(document).bind("keydown", "up", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count = 0;
				instance.current_index--;
				if(instance.current_index >= instance.all_items.size()) {
					instance.current_index = instance.all_items.size() - 1;
				} else if(instance.current_index < 0) {
					instance.current_index = 0;
				}
				instance.selection(instance.current_index, 0);
				instance.scroll_list_to(instance.current_index);
				instance.store_active();
			});
			$(document).bind("keydown", "down", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count = 0;
				instance.current_index++;
				if(instance.current_index >= instance.all_items.size()) {
					instance.current_index = instance.all_items.size() - 1;
				} else if(instance.current_index < 0) {
					instance.current_index = 0;
				}
				instance.selection(instance.current_index, 0);
				instance.scroll_list_to(instance.current_index);
				instance.store_active();
			});

			this.blur();
		},

		focus: function() {
			if(this.state_focus) {
				return;
			}
			this.state_focus = true;

			var instance = this;
			var focus_bind = function(event) {
				var element = $(event.target).closest(instance.options.sels.self);
				if(element.size() == 0 || element.get(0) != instance.element.get(0)) {
					instance.blur();
				} else {
					$("html").one("click", focus_bind);
				}
			};
			$("html").one("click", focus_bind);
			$("*").one("focus", function() {
				instance.blur();
			});
		},

		blur: function() {
			this.state_focus = false;

			var instance = this;
			this.element.one("click", function(event) {
				instance.focus();
				$(event.target).trigger("click");
			});
		},

		selection: function(index, count, store) {
			var size = this.all_items.size();
			var from = Math.min(index, index + count);
			var to = Math.max(index, index + count);
			var change = false;
			for(var i = 0; i < size; i++) {
				if(i >= from && i <= to) {
					if(this.activate(i)) {
						change = true;
					}
				} else {
					if(this.deactivate(i, store)) {
						change = true;
					}
				}
			}
			return change;
		},

		activate: function(index) {
			var option = this.all_options.eq(index);
			var li = this.all_items.eq(index);
			if(!li.hasClass(this.options.classes.active)) {
				option.attr("selected", "selected");
				li.addClass(this.options.classes.active);
				option.trigger("click");
				return true;
			}
			return false;
		},

		deactivate: function(index, store) {
			if(store && this.list_active.indexOf(index) != -1) {
				return false;
			}
			var option = this.all_options.eq(index);
			var li = this.all_items.eq(index);
			if(li.hasClass(this.options.classes.active)) {
				li.removeClass(this.options.classes.active);
				option.removeAttr("selected");
				option.trigger("click");
				return true;
			}
			return false;
		},

		toggle: function(index) {
			var option = this.all_options.eq(index);
			var li = this.all_items.eq(index);
			if(li.hasClass(this.options.classes.active)) {
				option.removeAttr("selected");
				li.removeClass(this.options.classes.active);
				this.current_index = this.select.find("option:selected").last().index();
			} else {
				option.attr("selected", "selected");
				li.addClass(this.options.classes.active);
				this.current_index = index;
			}
			option.trigger("click");
			this._trigger_change(this.select);
		},

		scroll_list_to: function(index) {
			var current = this.all_items.eq(index);
			//if current is not in visible part
			if (current.position().top < 0) {
				this.scrolled_to_index = index;
				this.list.scrollTo(this.all_items.eq(this.scrolled_to_index));
			} else if(current.position().top + current.height() > this.list.height()) {
				var instance = this;
				var index_not_founded = true;
				this.all_items.each(function(index) {
					if(index_not_founded && $(this).position().top >= 0) {
						instance.scrolled_to_index = index;
						index_not_founded = false;
					}
				});
				this.scrolled_to_index++;
				if(this.scrolled_to_index >= this.all_items.size()) {
					this.scrolled_to_index = this.all_items.size() - 1;
				}
				this.list.scrollTo(this.all_items.eq(this.scrolled_to_index));
			}
		},

		store_active: function() {
			var instance = this;
			this.list_active = [];
			this.select.find("option:selected").each(function() {
				instance.list_active.push($(this).index());
			});
		},

		restore_active: function() {
			var change = false;
			for(var i = 0; i < this.list_active.length; i++) {
				if(this.activate(this.list_active[i])) {
					change = true;
				}
			}
			return change;
		},

		_trigger_change: function(select) {
			if(window.ValidatorOnChange && $.browser.msie) {
				ValidatorOnChange({target: select.get(0)});
			} else {
				select.trigger("change");
			}
		},

		destroy: function() {
			this.element.unbind("click");
			this.list.remove();
			this.select.unwrap();
			this.select.show();
			$.Widget.prototype.destroy.call(this);
		}
	});
})(jQuery, Array);
<commit_msg>.net fix<commit_after>(function($, Array) {
	if (!('indexOf' in Array.prototype)) {
		Array.prototype.indexOf= function(find, i /*opt*/) {
			if (i===undefined) i= 0;
			if (i<0) i+= this.length;
			if (i<0) i= 0;
			for (var n= this.length; i<n; i++)
				if (i in this && this[i]===find)
					return i;
			return -1;
		};
	}

	if(window.ValidatorOnChange && $.browser.msie) {
		var indians_ValidatorHookupEvent = window.ValidatorHookupEvent;
		window.ValidatorHookupEvent = function(control, eventType, functionPrefix) {
			if(functionPrefix.indexOf("ValidatorOnChange") == -1) {
				return indians_ValidatorHookupEvent.apply(this, arguments);
			} else {
				$(control).bind("change", function() {
					ValidatorOnChange({
						target: this
					});
				});
			}
			return null;
		}
	}

	$.widget("ui.SelectMultiple", {
		options: {
			sels: {
				self:	".select_multiple",
				list:	"ul",
				item:	"li"
			},
			html: {
				wrapper:	"

",
				list:		"

",
				item:		"

"
			},
			classes: {
				active: "active"
			}
		},

		_create: function() {
			var instance = this;

			this.select = this.element;
			var width = this.element.outerWidth();
			var height = this.element.outerHeight();
			this.select.wrap(this.options.html.wrapper);
			this.element = this.select.parent();
			this.element.width(width);
			this.select.hide();
			this.all_options = this.select.find("option");
			this.element.append(this.options.html.list);

			this.list = this.element.find(this.options.sels.list);
			this.list.width(width).height(height);
			this.all_options.each(function() {
				instance.list.append(instance.options.html.item);
				var item = instance.list.find(instance.options.sels.item).last();
				item.text($(this).text());
			});
			this.all_items = this.list.find(this.options.sels.item);

			this.init();
		},

		init: function() {
			var instance = this;
			this.current_index = this.select.find("option:selected").first().index();
			this.select.find("option:selected").each(function() {
				var index = $(this).index();
				instance.all_items.eq(index).addClass(instance.options.classes.active);
			});
			this.store_active();

			var count = 0;
			this.all_items.click(function(event) {
				if(!instance.state_focus) {
					return;
				}

				count = 0;
				var index = $(this).index();
				if(event.shiftKey) {
					count = index - instance.current_index;
					instance.selection(instance.current_index, count);
					instance.scroll_list_to(instance.current_index + count);
					instance.store_active();
				} else if(event.ctrlKey) {
					instance.toggle(index);
					instance.current_index = instance.select.find("option:selected").first().index();
					instance.scroll_list_to(index);
					instance.store_active();
				} else {
					var change = false;
					instance.select.find("option:selected").each(function() {
						if(index != $(this).index()) {
							instance.deactivate($(this).index());
							change = true;
						}
					});
					change = instance.activate(index) || change;
					if(change) {
						instance.select.trigger("change");
					}
					instance.current_index = index;
					instance.scroll_list_to(instance.current_index);
					instance.store_active();
				}
			}).bind("selectstart dragstart", function(event) {
				event.preventDefault();
				return false;
			});

			$(document).bind("keydown", "shift+up", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count--;
				if(instance.current_index + count >= instance.all_items.size()) {
					count = instance.all_items.size() - instance.current_index - 1;
				} else if(instance.current_index + count < 0) {
					count = - instance.current_index;
				}
				var change = instance.selection(instance.current_index, count, true);
				change = instance.restore_active() || change;
				instance.scroll_list_to(instance.current_index + count);
				if(change) {
					instance.select.trigger("change");
				}
			});
			$(document).bind("keydown", "shift+down", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count++;
				if(instance.current_index + count >= instance.all_items.size()) {
					count = instance.all_items.size() - instance.current_index - 1;
				} else if(instance.current_index + count < 0) {
					count = - instance.current_index;
				}
				var change = instance.selection(instance.current_index, count, true);
				change = instance.restore_active() || change;
				instance.scroll_list_to(instance.current_index + count);
				if(change) {
					instance.select.trigger("change");
				}
			});
			$(document).bind("keydown", "up", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count = 0;
				instance.current_index--;
				if(instance.current_index >= instance.all_items.size()) {
					instance.current_index = instance.all_items.size() - 1;
				} else if(instance.current_index < 0) {
					instance.current_index = 0;
				}
				instance.selection(instance.current_index, 0);
				instance.scroll_list_to(instance.current_index);
				instance.store_active();
			});
			$(document).bind("keydown", "down", function(event) {
				event.preventDefault();
				if(!instance.state_focus) {
					return;
				}

				count = 0;
				instance.current_index++;
				if(instance.current_index >= instance.all_items.size()) {
					instance.current_index = instance.all_items.size() - 1;
				} else if(instance.current_index < 0) {
					instance.current_index = 0;
				}
				instance.selection(instance.current_index, 0);
				instance.scroll_list_to(instance.current_index);
				instance.store_active();
			});

			this.blur();
		},

		focus: function() {
			if(this.state_focus) {
				return;
			}
			this.state_focus = true;

			var instance = this;
			var focus_bind = function(event) {
				var element = $(event.target).closest(instance.options.sels.self);
				if(element.size() == 0 || element.get(0) != instance.element.get(0)) {
					instance.blur();
				} else {
					$("html").one("click", focus_bind);
				}
			};
			$("html").one("click", focus_bind);
			$("*").one("focus", function() {
				instance.blur();
			});
		},

		blur: function() {
			this.state_focus = false;

			var instance = this;
			this.element.one("click", function(event) {
				instance.focus();
				$(event.target).trigger("click");
			});
		},

		selection: function(index, count, store) {
			var size = this.all_items.size();
			var from = Math.min(index, index + count);
			var to = Math.max(index, index + count);
			var change = false;
			for(var i = 0; i < size; i++) {
				if(i >= from && i <= to) {
					if(this.activate(i)) {
						change = true;
					}
				} else {
					if(this.deactivate(i, store)) {
						change = true;
					}
				}
			}
			return change;
		},

		activate: function(index) {
			var option = this.all_options.eq(index);
			var li = this.all_items.eq(index);
			if(!li.hasClass(this.options.classes.active)) {
				option.attr("selected", "selected");
				li.addClass(this.options.classes.active);
				option.trigger("click");
				return true;
			}
			return false;
		},

		deactivate: function(index, store) {
			if(store && this.list_active.indexOf(index) != -1) {
				return false;
			}
			var option = this.all_options.eq(index);
			var li = this.all_items.eq(index);
			if(li.hasClass(this.options.classes.active)) {
				li.removeClass(this.options.classes.active);
				option.removeAttr("selected");
				option.trigger("click");
				return true;
			}
			return false;
		},

		toggle: function(index) {
			var option = this.all_options.eq(index);
			var li = this.all_items.eq(index);
			if(li.hasClass(this.options.classes.active)) {
				option.removeAttr("selected");
				li.removeClass(this.options.classes.active);
				this.current_index = this.select.find("option:selected").last().index();
			} else {
				option.attr("selected", "selected");
				li.addClass(this.options.classes.active);
				this.current_index = index;
			}
			option.trigger("click");
			this.select.trigger("change");
		},

		scroll_list_to: function(index) {
			var current = this.all_items.eq(index);
			//if current is not in visible part
			if (current.position().top < 0) {
				this.scrolled_to_index = index;
				this.list.scrollTo(this.all_items.eq(this.scrolled_to_index));
			} else if(current.position().top + current.height() > this.list.height()) {
				var instance = this;
				var index_not_founded = true;
				this.all_items.each(function(index) {
					if(index_not_founded && $(this).position().top >= 0) {
						instance.scrolled_to_index = index;
						index_not_founded = false;
					}
				});
				this.scrolled_to_index++;
				if(this.scrolled_to_index >= this.all_items.size()) {
					this.scrolled_to_index = this.all_items.size() - 1;
				}
				this.list.scrollTo(this.all_items.eq(this.scrolled_to_index));
			}
		},

		store_active: function() {
			var instance = this;
			this.list_active = [];
			this.select.find("option:selected").each(function() {
				instance.list_active.push($(this).index());
			});
		},

		restore_active: function() {
			var change = false;
			for(var i = 0; i < this.list_active.length; i++) {
				if(this.activate(this.list_active[i])) {
					change = true;
				}
			}
			return change;
		},

		destroy: function() {
			this.element.unbind("click");
			this.list.remove();
			this.select.unwrap();
			this.select.show();
			$.Widget.prototype.destroy.call(this);
		}
	});
})(jQuery, Array);
<|endoftext|>


<commit_before>const _ = require('underscore');
const ProvinceCard = require('../../provincecard.js');

class ShamefulDisplay extends ProvinceCard {
    setupCardAbilities() {
        this.action({
            title: 'Dishonor/Honor two characters',
            condition: () => this.game.currentConflict && this.game.currentConflict.conflictProvince === this,
            target: {
                mode: 'exactly',
                numCards: 2,
                activePromptTitle: 'Select two characters',
                source: this,
                cardType: 'character',
                cardCondition: card => card.isParticipating()
            },
            source: this,
            handler: context => {
                if(_.all(context.target, card => card.isHonored)) {
                    this.game.promptForSelect(this.controller, {
                        activePromptTitle: 'Choose a character to dishonor',
                        source: this,
                        cardCondition: card => context.target.includes(card) && card.allowGameAction('dishonor', context),
                        onSelect: (player, card) => {
                            this.resolveShamefulDisplay(_.find(context.target, c => c !== card), card);
                            return true;
                        }
                    });
                } else if(_.all(context.target, card => !card.allowGameAction('dishonor'))) {
                    this.game.promptForSelect(this.controller, {
                        activePromptTitle: 'Choose a character to honor',
                        source: this,
                        cardCondition: card => context.target.includes(card) && card.allowGameAction('honor', context),
                        onSelect: (player, card) => {
                            this.resolveShamefulDisplay(card, _.find(context.target, c => c !== card));
                            return true;
                        }
                    });
                } else {
                    let choices = ['Honor', 'Dishonor'];
                    let handlers = _.map(choices, choice => {
                        return () => this.chooseCharacter(choice, context.target, context);
                    });
                    this.game.promptWithHandlerMenu(this.controller, {
                        activePromptTitle: 'Choose a character to:',
                        source: this,
                        choices: choices,
                        handlers: handlers
                    });
                }
            }
        });
    }

    chooseCharacter(choice, cards, context) {
        let promptTitle = 'Choose a character to dishonor';
        let condition = card => cards.includes(card) && card.allowGameAction('dishonor', context);
        if(choice === 'Honor') {
            promptTitle = 'Choose a character to honor';
            condition = card => cards.includes(card) && card.allowGameAction('honor', context);
        }
        this.game.promptForSelect(this.controller, {
            activePromptTitle: promptTitle,
            source: this,
            cardCondition: condition,
            onSelect: (player, card) => {
                let otherCard = _.find(cards, c => c !== card);
                if(choice === 'Honor') {
                    this.resolveShamefulDisplay(card, otherCard);
                } else {
                    this.resolveShamefulDisplay(otherCard, card);
                }
                return true;
            }
        });
    }

    resolveShamefulDisplay(cardToHonor, cardToDishonor) {
        this.game.addMessage('{0} uses {1} to dishonor {2} and honor {3}', this.controller, this, cardToDishonor, cardToHonor);
        let honorEvent = {
            name: 'onCardHonored',
            params: { player: this.controller, card: cardToHonor, source: this },
            handler: () => cardToHonor.honor()
        };
        let dishonorEvent = {
            name: 'onCardDishonored',
            params: { player: this.controller, card: cardToDishonor, source: this },
            handler: () => cardToDishonor.dishonor()
        };
        this.game.raiseMultipleEvents([honorEvent, dishonorEvent]);
    }
}

ShamefulDisplay.id = 'shameful-display';

module.exports = ShamefulDisplay;

<commit_msg>Refactor Shameful Display<commit_after>const _ = require('underscore');
const ProvinceCard = require('../../provincecard.js');

class ShamefulDisplay extends ProvinceCard {
    setupCardAbilities() {
        this.action({
            title: 'Dishonor/Honor two characters',
            condition: () => this.game.currentConflict && this.game.currentConflict.conflictProvince === this,
            target: {
                mode: 'exactly',
                numCards: 2,
                activePromptTitle: 'Select two characters',
                source: this,
                cardType: 'character',
                cardCondition: card => card.isParticipating() && (card.allowGameAction('honor') || card.allowGameAction('dishonor'))
            },
            source: this,
            handler: context => {
                if(!context.target[0].allowGameAction('honor')) {
                    if(!context.target[1].allowGameAction('honor')) {
                        this.chooseCharacter('Dishonor', context);
                        return;
                    } else if(!context.target[1].allowGameAction('dishonor')) {
                        this.resolveShamefulDisplay(context.target[1], context.target[0]);
                        return;
                    }
                } else if(!context.target[0].allowGameAction('dishonor')) {
                    if(!context.target[1].allowGameAction('honor')) {
                        this.resolveShamefulDisplay(context.target[0], context.target[1]);
                        return;
                    } else if(!context.target[1].allowGameAction('dishonor')) {
                        this.chooseCharacter('Honor', context);
                        return;
                    }
                }
                this.promptForChoice(context);
            }
        });
    }

    promptForChoice(context) {
        this.game.promptWithHandlerMenu(this.controller, {
            activePromptTitle: 'Choose a character to:',
            source: this,
            choices: ['Honor', 'Dishonor'],
            choiceHandler: choice => this.chooseCharacter(choice, context, true)
        });
    }

    chooseCharacter(choice, context, backButton = false) {
        let buttons = backButton ? [{ text: 'Back', arg: 'back' }] : [];
        buttons.push({ text: 'Done', arg: 'done' });
        this.game.promptForSelect(this.controller, {
            activePromptTitle: 'Choose a character to ' + choice.toLowerCase(),
            source: this,
            cardCondition: card => context.target.includes(card) && card.allowGameAction(choice.toLowerCase(), context),
            buttons: buttons,
            onMenuCommand: () => {
                this.promptForChoice(context);
                return true;
            },
            onSelect: (player, card) => {
                let otherCard = _.find(context.target, c => c !== card);
                if(choice === 'Honor') {
                    this.resolveShamefulDisplay(card, otherCard);
                } else {
                    this.resolveShamefulDisplay(otherCard, card);
                }
                return true;
            }
        });
    }

    resolveShamefulDisplay(cardToHonor, cardToDishonor) {
        this.game.addMessage('{0} uses {1} to dishonor {2} and honor {3}', this.controller, this, cardToDishonor, cardToHonor);
        let honorEvent = {
            name: 'onCardHonored',
            params: { player: this.controller, card: cardToHonor, source: this },
            handler: () => cardToHonor.honor()
        };
        let dishonorEvent = {
            name: 'onCardDishonored',
            params: { player: this.controller, card: cardToDishonor, source: this },
            handler: () => cardToDishonor.dishonor()
        };
        this.game.raiseMultipleEvents([honorEvent, dishonorEvent]);
    }
}

ShamefulDisplay.id = 'shameful-display';

module.exports = ShamefulDisplay;
<|endoftext|>


<commit_before>const DrawCard = require('../../drawcard.js');

class UtakuMediatior extends DrawCard {
    setupCardAbilities(ability) { // eslint-disable-line no-unused-vars
    }
}

UtakuMediatior.id = 'utaku-mediatior'; // This is a guess at what the id might be - please check it!!!

module.exports = UtakuMediatior;
<commit_msg>implemented Utaku Mediator<commit_after>const DrawCard = require('../../drawcard.js');

class UtakuMediatior extends DrawCard {
    setupCardAbilities(ability) {
        this.persistentEffect({
            match: this,
            contition: () => this.controller.imperialFavor === ''
            effect: [
                ability.effects.ModifyMilitarySkill(1),
                ability.effects.modifyPoliticalSkill(1)
            ]
        });
    }
}

UtakuMediatior.id = 'utaku-mediatior';

module.exports = UtakuMediatior;
<|endoftext|>


<commit_before>module.exports = {
  up(queryInterface, Sequelize) {
  },

  down(queryInterface, Sequelize) {
  }
};
<commit_msg>[feature #141878503] create dummy data for the roles seeder<commit_after>const faker = require('faker');

module.exports = {
  up: (queryInterface, Sequelize) => queryInterface.bulkInsert('Roles', [
    {
      name: 'user',
      createdAt: new Date(),
      updatedAt: new Date()
    },
    {
      name: 'admin',
      createdAt: new Date(),
      updatedAt: new Date()
    },
    {
      name: 'trialUser',
      createdAt: new Date(),
      updatedAt: new Date()
    },
    {
      name: 'coolUser',
      createdAt: new Date(),
      updatedAt: new Date()
    },

  ], {}),
  down: (queryInterface, Sequelize) => {
    return queryInterface.bulkDelete('Roles', null, {});
  }
};

<|endoftext|>