<commit_before>
export { Base };

/**
 * Testing Filters of multiple layers.
 *
 * @member {string} name This test filters' name.
 */
class Base {

  /**
   * @param sourceHeight      The height (and width) of the source image which will be processed by apply().
   * @param sourceDepth       The channel count of the source image.
   * @param targetHeight      The taregt image height (and width).
   * @param filterHeight      The height (and width) of each depthwise convolution.
   * @param channelMultiplier Every input channel will become so many channels.
   *
   * @param strAvgMaxConv
   *   Depthwise operation. "Avg" or "Max" or "Conv" for average pooling, max pooling, depthwise convolution.
   *
   * @param bDepthwiseBias
   *   If true, there will be a bias after depthwise convolution.
   *
   * @param depthwiseActivationName
   *   The activation function name after depthwise convolution. One of the following "", "relu", "relu6", "sigmoid", "tanh", "sin".
   *
   * @param bPointwise
   *   If true, there will be pointwise convolution after every layer of depthwise convolution.
   *
   * @param bPointwiseBias
   *   If true, there will be a bias after pointwise convolution. If ( bPointwise == false ), this will be also ignored.
   *
   * @param pointwiseActivationName
   *   The activation function name after pointwise convolution. One of the following "", "relu", "relu6", "sigmoid", "tanh", "sin".
   * If ( bPointwise == false ), this activation function will be also ignored.
   */
  init(
    sourceHeight, sourceDepth, targetHeight,
    filterHeight, channelMultiplier,
    strAvgMaxConv, bDepthwiseBias, depthwiseActivationName,
    bPointwise, bPointwiseBias, pointwiseActivationName ) {

    this.disposeTensors();

//    this.name = name;

    let differenceHeight = sourceHeight - targetHeight;
    let filterWidth = filterHeight;
    this.channelMultiplier = channelMultiplier;

    this.strAvgMaxConv = strAvgMaxConv;
    switch ( strAvgMaxConv ) {
      case "Avg":  this.bDepthwiseAvg = true;
      case "Max":  this.bDepthwiseMax = true;
      case "Conv": this.bDepthwiseConv = true;
    }

    this.bDepthwiseBias = bDepthwiseBias;

    this.depthwiseActivationName = depthwiseActivationName;
    switch ( depthwiseActivationName ) {
      case "relu":    this.depthwiseActivationFunction = tf.relu;    break;
      case "relu6":   this.depthwiseActivationFunction = tf.relu6;   break;
      case "sigmoid": this.depthwiseActivationFunction = tf.sigmoid; break;
      case "tanh":    this.depthwiseActivationFunction = tf.tanh;    break;
      case "sin":     this.depthwiseActivationFunction = tf.sin;     break;
      //default:
    }

    this.bPointwise = bPointwise;
    this.bPointwiseBias = bPointwiseBias;

    this.pointwiseActivationName = pointwiseActivationName;
    switch ( pointwiseActivationName ) {
      case "relu":    this.pointwiseActivationFunction = tf.relu;    break;
      case "relu6":   this.pointwiseActivationFunction = tf.relu6;   break;
      case "sigmoid": this.pointwiseActivationFunction = tf.sigmoid; break;
      case "tanh":    this.pointwiseActivationFunction = tf.tanh;    break;
      case "sin":     this.pointwiseActivationFunction = tf.sin;     break;
      //default:
    }

    // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
    let heightReducedPerStep = filterHeight - 1;

    // The step count for reducing sourceHeight to targetHeight by depthwise convolution filter.
    this.blockCount = Math.floor( differenceHeight / heightReducedPerStep );

    // e.g. "D24_DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1"
    this.name = `D${sourceDepth * channelMultiplier}_D${strAvgMaxConv}_${filterHeight}x${filterHeight}`
      + `${ ( this.bDepthwiseBias ) ? ( "_DBias" ) : ""}`
      + `${ ( this.depthwiseActivationFunction ) ? ( "_" + depthwiseActivationName ) : ""}`
      + `${ ( this.bPointwise ) ? "__PConv" : ""}`
      + `${ ( this.bPointwise && this.bPointwiseBias ) ? ( "_PBias" ) : ""}`
      + `${ ( this.bPointwise && this.pointwiseActivationFunction ) ? ( "_" + pointwiseActivationName ) : ""}`
      + `__Block_${this.blockCount}`
    ;

    // Depthwise Filters and Biases

    this.depthwiseFilterHeightWidth = [ filterHeight, filterWidth ];
    this.depthwiseFiltersShape = [ filterHeight, filterWidth, sourceDepth, channelMultiplier ];
    this.depthwiseBiasesShape =  [            1,           1, ( sourceDepth * channelMultiplier ) ];

    let depthwiseFiltersValueCount = tf.util.sizeFromShape( this.depthwiseFiltersShape );
    let depthwiseBiasesValueCount =  tf.util.sizeFromShape( this.depthwiseBiasesShape );

    // Every element (Tensor4d) is a depthwiseFilters for one block.
    this.depthwiseFiltersTensor4dArray
      = Base.generateTensorArray( this.blockCount, depthwiseFiltersValueCount, this.depthwiseFiltersShape, this.bDepthwiseConv );

    // Every element (Tensor3d) is a depthwiseBiases for one block.
    this.depthwiseBiasesTensor3dArray
      = Base.generateTensorArray( this.blockCount, depthwiseBiasesValueCount, this.depthwiseBiasesShape, ( this.bDepthwiseConv && bDepthwiseBias ) );

    // Pointwise Filters and Biases

    let pointwiseInputDepth =  sourceDepth;
    let pointwiseOutputDepth = sourceDepth; // Assume output depth is the same as input.

    this.pointwiseFilterHeightWidth = [ 1, 1 ];
    this.pointwiseFiltersShape = [ 1, 1, pointwiseInputDepth, pointwiseOutputDepth ];

    // Both input depth and output depth of pointwise bias are the same as pointwise convolution output.
    this.pointwiseBiasesShape =  [ 1, 1, pointwiseOutputDepth ];

    let pointwiseFiltersValueCount = tf.util.sizeFromShape( this.pointwiseFiltersShape );
    let pointwiseBiasesValueCount =  tf.util.sizeFromShape( this.pointwiseBiasesShape );

    // Every element (Tensor4d) is a pointwiseFilters for one block.
    this.pointwiseFiltersTensor4dArray
      = Base.generateTensorArray( this.blockCount, pointwiseFiltersValueCount, this.pointwiseFiltersShape, bPointwise );

    // Every element (Tensor3d) is a pointwiseBiases for one block.
    this.pointwiseBiasesTensor3dArray
      = Base.generateTensorArray( this.blockCount, pointwiseBiasesValueCount, this.pointwiseBiasesShape, ( bPointwise && bPointwiseBias ) );
  }

  /**
   * @param {number}   blockCount     The element count (i.e. length) of the returned array.
   * @param {number}   valueCount     The element count of every tensor4d (which is an element of the returned array).
   * @param {number[]} newTensorShape The tensor's shape of every element of the returned array.
   * @param {boolean}  bNullElement   If true, every element of the return array will be null.
   *
   * @return {tf.tensor4d[]|tf.tensor3d[]}
   *   Return a array whose every element is a tensor4d or tensor3d (for one block), or null (if ( bNullElement == true ) ).
   */
  static generateTensorArray( blockCount, valueCount, newTensorShape, bNullElement ) {
    return tf.tidy( () => {
      let tensorNewArray = new Array( blockCount );
      for ( let i = 0; i < blockCount; ++i ) {
        if ( bNullElement ) {
          let tensor1d = tf.range( 0, valueCount, 1 );
          let tensorNew = tensor1d.reshape( newTensorShape );
          tensorNewArray[ i ] = tensorNew;
        } else {
          tensorNewArray[ i ] = null;
        }
      }
      return tensorNewArray;
    });
  }

  disposeTensors() {
    if ( this.depthwiseFiltersTensor4dArray ) {
      tf.dispose( this.depthwiseFiltersTensor4dArray );
      this.depthwiseFiltersTensor4dArray = null;
    }

    if ( this.depthwiseBiasesTensor3dArray ) {
      tf.dispose( this.depthwiseBiasesTensor3dArray );
      this.depthwiseBiasesTensor3dArray = null;
    }

    if ( this.pointwiseFiltersTensor4dArray ) {
      tf.dispose( this.pointwiseFiltersTensor4dArray );
      this.pointwiseFiltersTensor4dArray = null;
    }

    if ( this.pointwiseBiasesTensor3dArray ) {
      tf.dispose( this.pointwiseBiasesTensor3dArray );
      this.pointwiseBiasesTensor3dArray = null;
    }
  }

  /**
   * @param  {tf.tensor4d} inputTensor  Apply this tensor with depthwise (bias and activation) and pointwise (bias and activation).
   * @param  {number}      blockIndex   Which block's depthwise and pointwise operrations.
   * @return {tf.tensor4d} Return a new tensor. All other tensors (including inputTensor) were disposed.
   */
  apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( inputTensor, blockIndex ) {
    let t = inputTensor, tNew;

    if ( this.bDepthwiseBias ) {
      tNew = t.add( this.depthwiseBiasesTensor3dArray[ blockIndex ] );
      t.dispose();                                         // Dispose all intermediate (temporary) data.
      t = tNew;
    }

    if ( this.depthwiseActivationFunction ) {
      tNew = this.depthwiseActivationFunction( t );
      t.dispose();                                         // Dispose all intermediate (temporary) data.
      t = tNew;
    }

    if ( this.bPointwise ) {
      tNew = t.conv2d( this.pointwiseFiltersTensor4dArray[ blockIndex ], 1, "valid" ); // 1x1, Stride = 1
      t.dispose();                                         // Dispose all intermediate (temporary) data.
      t = tNew;

      if ( this.bPointwiseBias ) {
        tNew = t.add( this.pointwiseBiasesTensor3dArray[ blockIndex ] );
        t.dispose();                                       // Dispose all intermediate (temporary) data.
        t = tNew;
      }

      if ( this.pointwiseActivationFunction ) {
        tNew = this.pointwiseActivationFunction( t );
        t.dispose();                                       // Dispose all intermediate (temporary) data.
        t = tNew;
      }
    }

    return t;
  }

  /**
   * @param sourceImage
   *   The image which will be processed.
   *
   * @param bReturn
   *   If true, the result convoluiotn will be returned.
   *
   * @return
   *   If ( bReturn == true ), return the convolution result (tensor). Otheriwse, reurn null.
   */
  apply( sourceImage, bReturn ) {
    return tf.tidy( () => {

      let t, tNew;

      // Layer 0
      //
      // So that every layer could dispose previous result without worry about mis-dispose source.

      if ( this.bDepthwiseAvg ) {
        t = sourceImage.pool( this.depthwiseFilterHeightWidth, "avg", "valid", 1, 1 );
      } else if ( this.bDepthwiseMax ) {
        t = sourceImage.pool( this.depthwiseFilterHeightWidth, "max", "valid", 1, 1 );
      } else if ( this.bDepthwiseConv ) {
        t = sourceImage.depthwiseConv2d( this.depthwiseFiltersTensor4dArray[ 0 ], 1, "valid" );  // Stride = 1
      }
      // NOTE: Do not dispose the original data.

      t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( t, 0 );

      // Layer 1, ...
      if ( this.bDepthwiseAvg ) {

        for ( let i = 1; i < this.blockCount; ++i ) {
          tNew = t.pool( this.depthwiseFilterHeightWidth, "avg", "valid", 1, 1 );
          t.dispose();                                           // Dispose all intermediate (temporary) data.
          t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( tNew, i );
        }

      } else if ( this.bDepthwiseMax ) {

        for ( let i = 1; i < this.blockCount; ++i ) {
          tNew = t.pool( this.depthwiseFilterHeightWidth, "max", "valid", 1, 1 );
          t.dispose();                                           // Dispose all intermediate (temporary) data.
          t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( tNew, i );
        }

      } else if ( this.bDepthwiseConv ) {

        for ( let i = 1; i < this.blockCount; ++i ) {
          tNew = t.depthwiseConv2d( this.depthwiseFiltersTensor4dArray[ i ], 1, "valid" );  // Stride = 1
          t.dispose();                                           // Dispose all intermediate (temporary) data.
          t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( tNew, i );
        }

      }

      if ( bReturn )
        return t;
    });
  }

}

<commit_msg>Update TestFilters2D.js<commit_after>
export { Base };

/**
 * Testing Filters of multiple layers.
 *
 * @member {string} name This test filters' name.
 */
class Base {

  /**
   * @param sourceHeight      The height (and width) of the source image which will be processed by apply().
   * @param sourceDepth       The channel count of the source image.
   * @param targetHeight      The taregt image height (and width).
   * @param filterHeight      The height (and width) of each depthwise convolution.
   * @param channelMultiplier Every input channel will become so many channels.
   *
   * @param strAvgMaxConv
   *   Depthwise operation. "Avg" or "Max" or "Conv" for average pooling, max pooling, depthwise convolution.
   *
   * @param bDepthwiseBias
   *   If true, there will be a bias after depthwise convolution.
   *
   * @param depthwiseActivationName
   *   The activation function name after depthwise convolution. One of the following "", "relu", "relu6", "sigmoid", "tanh", "sin".
   *
   * @param bPointwise
   *   If true, there will be pointwise convolution after every layer of depthwise convolution.
   *
   * @param bPointwiseBias
   *   If true, there will be a bias after pointwise convolution. If ( bPointwise == false ), this will be also ignored.
   *
   * @param pointwiseActivationName
   *   The activation function name after pointwise convolution. One of the following "", "relu", "relu6", "sigmoid", "tanh", "sin".
   * If ( bPointwise == false ), this activation function will be also ignored.
   */
  init(
    sourceHeight, sourceDepth, targetHeight,
    filterHeight, channelMultiplier,
    strAvgMaxConv, bDepthwiseBias, depthwiseActivationName,
    bPointwise, bPointwiseBias, pointwiseActivationName ) {

    this.disposeTensors();

//    this.name = name;

    let differenceHeight = sourceHeight - targetHeight;
    let filterWidth = filterHeight;

    this.channelMultiplier = channelMultiplier;
    this.channelCountPerStage = sourceDepth * channelMultiplier;

    this.strAvgMaxConv = strAvgMaxConv;
    switch ( strAvgMaxConv ) {
      case "Avg":  this.bDepthwiseAvg = true;
      case "Max":  this.bDepthwiseMax = true;
      case "Conv": this.bDepthwiseConv = true;
    }

    this.bDepthwiseBias = bDepthwiseBias;

    this.depthwiseActivationName = depthwiseActivationName;
    switch ( depthwiseActivationName ) {
      case "relu":    this.depthwiseActivationFunction = tf.relu;    break;
      case "relu6":   this.depthwiseActivationFunction = tf.relu6;   break;
      case "sigmoid": this.depthwiseActivationFunction = tf.sigmoid; break;
      case "tanh":    this.depthwiseActivationFunction = tf.tanh;    break;
      case "sin":     this.depthwiseActivationFunction = tf.sin;     break;
      //default:
    }

    this.bPointwise = bPointwise;
    this.bPointwiseBias = bPointwiseBias;

    this.pointwiseActivationName = pointwiseActivationName;
    switch ( pointwiseActivationName ) {
      case "relu":    this.pointwiseActivationFunction = tf.relu;    break;
      case "relu6":   this.pointwiseActivationFunction = tf.relu6;   break;
      case "sigmoid": this.pointwiseActivationFunction = tf.sigmoid; break;
      case "tanh":    this.pointwiseActivationFunction = tf.tanh;    break;
      case "sin":     this.pointwiseActivationFunction = tf.sin;     break;
      //default:
    }

    // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
    let heightReducedPerStep = filterHeight - 1;

    // The step count for reducing sourceHeight to targetHeight by depthwise convolution filter.
    this.blockCount = Math.floor( differenceHeight / heightReducedPerStep );

    // e.g. "D24_DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1"
    this.name = `D${this.channelCountPerStage}_D${strAvgMaxConv}_${filterHeight}x${filterHeight}`
      + `${ ( this.bDepthwiseBias ) ? ( "_DBias" ) : ""}`
      + `${ ( this.depthwiseActivationFunction ) ? ( "_" + depthwiseActivationName ) : ""}`
      + `${ ( this.bPointwise ) ? "__PConv" : ""}`
      + `${ ( this.bPointwise && this.bPointwiseBias ) ? ( "_PBias" ) : ""}`
      + `${ ( this.bPointwise && this.pointwiseActivationFunction ) ? ( "_" + pointwiseActivationName ) : ""}`
      + `__Block_${this.blockCount}`
    ;

    // Depthwise Filters and Biases

    this.depthwiseFilterHeightWidth = [ filterHeight, filterWidth ];

    // First stage's depthwise filters will expand channel count from sourceDepth to ( sourceDepth * channelMultiplier ).
    this.depthwiseFiltersShapeFirst = [ filterHeight, filterWidth, sourceDepth,               channelMultiplier ];
    this.depthwiseFiltersShape =      [ filterHeight, filterWidth, this.channelCountPerStage,                 1 ];
    this.depthwiseBiasesShape =       [            1,           1, this.channelCountPerStage ];

    // Every element (Tensor4d) is a depthwiseFilters for one block.
    this.depthwiseFiltersTensor4dArray
      = Base.generateTensorArray( this.blockCount, this.depthwiseFiltersShapeFirst, this.depthwiseFiltersShape, this.bDepthwiseConv );

    // Every element (Tensor3d) is a depthwiseBiases for one block.
    this.depthwiseBiasesTensor3dArray
      = Base.generateTensorArray( this.blockCount, null, this.depthwiseBiasesShape, ( this.bDepthwiseConv && bDepthwiseBias ) );

    // Pointwise Filters and Biases

    let pointwiseInputDepth =  this.channelCountPerStage;
    let pointwiseOutputDepth = this.channelCountPerStage; // Assume output depth is the same as input.

    this.pointwiseFilterHeightWidth = [ 1, 1 ];
    this.pointwiseFiltersShape = [ 1, 1, pointwiseInputDepth, pointwiseOutputDepth ];

    // Both input depth and output depth of pointwise bias are the same as pointwise convolution output.
    this.pointwiseBiasesShape =  [ 1, 1, pointwiseOutputDepth ];

    // Every element (Tensor4d) is a pointwiseFilters for one block.
    this.pointwiseFiltersTensor4dArray
      = Base.generateTensorArray( this.blockCount, null, this.pointwiseFiltersShape, bPointwise );

    // Every element (Tensor3d) is a pointwiseBiases for one block.
    this.pointwiseBiasesTensor3dArray
      = Base.generateTensorArray( this.blockCount, null, this.pointwiseBiasesShape, ( bPointwise && bPointwiseBias ) );
  }

  /**
   * @param {number}   blockCount          The element count (i.e. length) of the returned array.
   * @param {number[]} newTensorShapeFirst The tensor's shape of first element of the returned array. If null, same as newTensorShape.
   * @param {number[]} newTensorShape      The tensor's shape of every (except first) element of the returned array.
   * @param {boolean}  bNullElement        If true, every element of the return array will be null.
   *
   * @return {tf.tensor4d[]|tf.tensor3d[]}
   *   Return a array whose every element is a tensor4d or tensor3d (for one block), or null (if ( bNullElement == true ) ).
   */
  static generateTensorArray( blockCount, newTensorShapeFirst, newTensorShape, bNullElement ) {
    return tf.tidy( () => {
      if ( !newTensorShapeFirst )
        newTensorShapeFirst = newTensorShape;

      let valueCountFirst = tf.util.sizeFromShape( newTensorShape );  // first element (i.e. first stage)
      let valueCount = tf.util.sizeFromShape( newTensorShape );

      let tensor1d, tensorNew;
      let tensorNewArray = new Array( blockCount );
      for ( let i = 0; i < blockCount; ++i ) {
        if ( bNullElement ) {
          if ( 0 == i ) {
            tensor1d = tf.range( 0, valueCountFirst, 1 );
            tensorNew = tensor1d.reshape( newTensorShapeFirst );
          } else {
            tensor1d = tf.range( 0, valueCount, 1 );
            tensorNew = tensor1d.reshape( newTensorShape );
          }
          tensorNewArray[ i ] = tensorNew;
        } else {
          tensorNewArray[ i ] = null;
        }
      }
      return tensorNewArray;
    });
  }

  disposeTensors() {
    if ( this.depthwiseFiltersTensor4dArray ) {
      tf.dispose( this.depthwiseFiltersTensor4dArray );
      this.depthwiseFiltersTensor4dArray = null;
    }

    if ( this.depthwiseBiasesTensor3dArray ) {
      tf.dispose( this.depthwiseBiasesTensor3dArray );
      this.depthwiseBiasesTensor3dArray = null;
    }

    if ( this.pointwiseFiltersTensor4dArray ) {
      tf.dispose( this.pointwiseFiltersTensor4dArray );
      this.pointwiseFiltersTensor4dArray = null;
    }

    if ( this.pointwiseBiasesTensor3dArray ) {
      tf.dispose( this.pointwiseBiasesTensor3dArray );
      this.pointwiseBiasesTensor3dArray = null;
    }
  }

  /**
   * @param  {tf.tensor4d} inputTensor  Apply this tensor with depthwise (bias and activation) and pointwise (bias and activation).
   * @param  {number}      blockIndex   Which block's depthwise and pointwise operrations.
   * @return {tf.tensor4d} Return a new tensor. All other tensors (including inputTensor) were disposed.
   */
  apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( inputTensor, blockIndex ) {
    let t = inputTensor, tNew;

    if ( this.bDepthwiseBias ) {
      tNew = t.add( this.depthwiseBiasesTensor3dArray[ blockIndex ] );
      t.dispose();                                         // Dispose all intermediate (temporary) data.
      t = tNew;
    }

    if ( this.depthwiseActivationFunction ) {
      tNew = this.depthwiseActivationFunction( t );
      t.dispose();                                         // Dispose all intermediate (temporary) data.
      t = tNew;
    }

    if ( this.bPointwise ) {
      tNew = t.conv2d( this.pointwiseFiltersTensor4dArray[ blockIndex ], 1, "valid" ); // 1x1, Stride = 1
      t.dispose();                                         // Dispose all intermediate (temporary) data.
      t = tNew;

      if ( this.bPointwiseBias ) {
        tNew = t.add( this.pointwiseBiasesTensor3dArray[ blockIndex ] );
        t.dispose();                                       // Dispose all intermediate (temporary) data.
        t = tNew;
      }

      if ( this.pointwiseActivationFunction ) {
        tNew = this.pointwiseActivationFunction( t );
        t.dispose();                                       // Dispose all intermediate (temporary) data.
        t = tNew;
      }
    }

    return t;
  }

  /**
   * @param sourceImage
   *   The image which will be processed.
   *
   * @param bReturn
   *   If true, the result convoluiotn will be returned.
   *
   * @return
   *   If ( bReturn == true ), return the convolution result (tensor). Otheriwse, reurn null.
   */
  apply( sourceImage, bReturn ) {
    return tf.tidy( () => {

      let t, tNew;

      // Layer 0
      //
      // So that every layer could dispose previous result without worry about mis-dispose source.

      if ( this.bDepthwiseAvg ) {
        t = sourceImage.pool( this.depthwiseFilterHeightWidth, "avg", "valid", 1, 1 );
      } else if ( this.bDepthwiseMax ) {
        t = sourceImage.pool( this.depthwiseFilterHeightWidth, "max", "valid", 1, 1 );
      } else if ( this.bDepthwiseConv ) {
        t = sourceImage.depthwiseConv2d( this.depthwiseFiltersTensor4dArray[ 0 ], 1, "valid" );  // Stride = 1
      }
      // NOTE: Do not dispose the original data.

      t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( t, 0 );

      // Layer 1, ...
      if ( this.bDepthwiseAvg ) {

        for ( let i = 1; i < this.blockCount; ++i ) {
          tNew = t.pool( this.depthwiseFilterHeightWidth, "avg", "valid", 1, 1 );
          t.dispose();                                           // Dispose all intermediate (temporary) data.
          t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( tNew, i );
        }

      } else if ( this.bDepthwiseMax ) {

        for ( let i = 1; i < this.blockCount; ++i ) {
          tNew = t.pool( this.depthwiseFilterHeightWidth, "max", "valid", 1, 1 );
          t.dispose();                                           // Dispose all intermediate (temporary) data.
          t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( tNew, i );
        }

      } else if ( this.bDepthwiseConv ) {

        for ( let i = 1; i < this.blockCount; ++i ) {
          tNew = t.depthwiseConv2d( this.depthwiseFiltersTensor4dArray[ i ], 1, "valid" );  // Stride = 1
          t.dispose();                                           // Dispose all intermediate (temporary) data.
          t = this.apply_Depthwise_Bias_Activation_Pointwise_Bias_Activation( tNew, i );
        }

      }

      if ( bReturn )
        return t;
    });
  }

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
 * See LICENSE in the project root for license information.
 */
// The contents of the outbound email message that will be sent to the user
var emailContent = ' <meta http-equiv=\'Content-Type\' content=\'text/html; charset=us-ascii\'> <title></title>
Congratulations {{name}},

This is a message from the Office 365 Connect sample. You are well on your way to incorporating Office 365 services in your apps.

What’s next?

Check out dev.office.com to start building Office 365 apps today with all the latest tools, templates, and guidance to get started quickly.

Head over to the Microsoft Graph reference to explore the rest of the APIs.

Browse other samples on GitHub to see more of the APIs in action.

Give us feedback

If you have any trouble running this sample, please log an issue.

For general questions about the Office 365 APIs, post to Stack Overflow. Make sure that your questions or comments are tagged with [office365].

Thanks and happy coding!
Your Office 365 Development team

 See on GitHub 	 Suggest on UserVoice 	 Share on Twitter

   ';

/**
 * Returns the outbound email message content with the supplied name populated in the text
 * @param {string} name The proper noun to use when addressing the email
 * @return {string} the formatted email body
 */
function getEmailContent(name) {
  return emailContent.replace('{{name}}', name);
}

/**
 * Wraps the email's message content in the expected [soon-to-deserialized JSON] format
 * @param {string} content the message body of the email message
 * @param {string} recipient the email address to whom this message will be sent
 * @return the message object to send over the wire
 */
function wrapEmail(content, recipient) {
}

/**
 * Delegating method to wrap the formatted email message into a POST-able object
 * @param {string} name the name used to address the recipient
 * @param {string} recipient the email address to which the connect email will be sent
 */
function generateMailBody(name, recipient) {
  return wrapEmail(getEmailContent(name), recipient);
}

exports.generateMailBody = generateMailBody;
<commit_msg>update email message<commit_after>/*
 * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
 * See LICENSE in the project root for license information.
 */
// The contents of the outbound email message that will be sent to the user
var emailContent = ' <meta http-equiv=\'Content-Type\' content=\'text/html; charset=us-ascii\'> <title></title>
Congratulations {{name}},

This is a message from the Microsoft Graph Connect sample. You are well on your way to incorporating Office 365 services in your apps.

What’s next?

Check out dev.office.com to start building Office 365 apps today with all the latest tools, templates, and guidance to get started quickly.

Head over to the Microsoft Graph documentation to explore the rest of the APIs.

Use the Graph Explorer  to start your testing.

Browse other samples on GitHub to see more of the APIs in action.

Give us feedback

If you have any trouble running this sample, please log an issue.

For general questions about the Microsoft Graph API, post to Stack Overflow. Make sure that your questions or comments are tagged with [microsoftgraph].

Thanks and happy coding!
Your Microsoft Graph Development team

 See on GitHub 	 Suggest on UserVoice 	 Share on Twitter

   ';

/**
 * Returns the outbound email message content with the supplied name populated in the text
 * @param {string} name The proper noun to use when addressing the email
 * @return {string} the formatted email body
 */
function getEmailContent(name) {
  return emailContent.replace('{{name}}', name);
}

/**
 * Wraps the email's message content in the expected [soon-to-deserialized JSON] format
 * @param {string} content the message body of the email message
 * @param {string} recipient the email address to whom this message will be sent
 * @return the message object to send over the wire
 */
function wrapEmail(content, recipient) {
}

/**
 * Delegating method to wrap the formatted email message into a POST-able object
 * @param {string} name the name used to address the recipient
 * @param {string} recipient the email address to which the connect email will be sent
 */
function generateMailBody(name, recipient) {
  return wrapEmail(getEmailContent(name), recipient);
}

exports.generateMailBody = generateMailBody;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 Google LLC
 *
 * 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.
 */

/**
 * @fileoverview Integrated Development Environment for Code City.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

Code.ObjectPanel = {};

/**
 * List of parts (passed in by the URL hash).
 * @type {?Array<!Object>}
 */
Code.ObjectPanel.parts = null;

/**
 * DOM node containing the list of properties.
 * @type {?Element}
 */
Code.ObjectPanel.tableBody = null;

/**
 * Structured data from Code City.
 * @type {?Object}
 */
Code.ObjectPanel.data = null;

/**
 * Page has loaded, initialize the panel.  Called by Code City with data.
 */
Code.ObjectPanel.init = function() {
  Code.ObjectPanel.tableBody = document.getElementById('objectTableBody');
  // Clear the '...'
  Code.ObjectPanel.tableBody.innerHTML = '';
  var data = Code.ObjectPanel.data;
  if (!data) {
    // Server error.  Should not happen.
    var title = document.getElementById('objectTitle');
    title.className = 'objectFailTitle';
    var fail = document.getElementById('objectFail');
    fail.style.display = 'table-row';
    return;
  }
  if (data.roots) {
    // Print all root objects.
    for (var root of data.roots) {
      var part = {type: 'id', value: root.name};
      Code.ObjectPanel.addLink(part, root.type, false);
    }
  }
  if (data.properties) {
    Code.ObjectPanel.filterShadowed(data.properties);
    // Print all properties of this object.
    for (var i = 0; i < data.properties.length; i++) {
      var propList = data.properties[i];
      for (var j = 0; j < propList.length; j++) {
        var part = {type: 'id', value: propList[j].name};
        Code.ObjectPanel.addLink(part, propList[j].type, i && !j);
      }
    }
    var part = {type: '^'};
    Code.ObjectPanel.addLink(part, 'object', true);
  }

  // Position the type symbols, and monitor for layout changes.
  Code.ObjectPanel.positionTypes();
  window.addEventListener('scroll', Code.ObjectPanel.positionTypes, false);
  window.addEventListener('resize', Code.ObjectPanel.positionTypes, false);

  // Highlight current item, and monitor for path changes.
  Code.ObjectPanel.highlight();
  window.addEventListener('message', Code.ObjectPanel.highlight, false);
};

/**
 * Create the DOM elements to add one property link to the list.
 * @param {!Object} part Single selector part.
 * @param {string} type Type of the property value.
 * @param {boolean} section Flag indicating a new section.
 */
Code.ObjectPanel.addLink = function(part, type, section) {
  var newParts = Code.ObjectPanel.parts.concat(part);
  var selector = Code.Common.partsToSelector(newParts);
  var a = document.createElement('a');
  a.href = '/code?' + encodeURIComponent(selector);
  a.target = '_blank';
  a.setAttribute('data-link', JSON.stringify(part));
  a.addEventListener('click', Code.ObjectPanel.click);
  var text = document.createTextNode(Code.Common.partsToSelector([part]));
  a.appendChild(text);
  var td = document.createElement('td');
  if (section) {
    td.className = 'section';
  }
  var typeSymbol = Code.ObjectPanel.TYPES[type];
  if (typeSymbol) {
    var div = document.createElement('div');
    div.className = 'objectType';
    div.appendChild(document.createTextNode(typeSymbol));
    div.title = type;
    td.appendChild(div);
  }
  td.appendChild(a);
  var tr = document.createElement('tr');
  tr.appendChild(td);
  Code.ObjectPanel.tableBody.appendChild(tr);
};

/**
 * Symbols to print next to properties.
 */
Code.ObjectPanel.TYPES = {
  'object': '{}',
  'symbol': '☆',
  'function': '𝑓'
};

/**
 * When scrollbar is moved or size changes reposition the floating types.
 */
Code.ObjectPanel.positionTypes = function() {
  var left = (document.body.clientWidth + window.scrollX - 18) + 'px';
  var types = document.getElementsByClassName('objectType');
  for (var t of types) {
    t.style.left = left;
  }
};

/**
 * When a property is clicked, trigger an update.
 * @param {!Event} e Click event.
 */
Code.ObjectPanel.click = function(e) {
  var part = JSON.parse(e.currentTarget.getAttribute('data-link'));
  var newParts = Code.ObjectPanel.parts.concat(part);
  var selector = Code.Common.partsToSelector(newParts);
  // Store the new selector in sessionStorage for all frames to see.
  sessionStorage.setItem(Code.Common.SELECTOR, selector);
  // Alert the top "/code" frameset that there's been a selector change.
  window.parent.parent.postMessage('ping', '*');
  // Don't navigate to this link.
  e.preventDefault();
};

/**
 * Currently selected property, or null if none.
 * @type {?Element}
 */
Code.ObjectPanel.highlighted = null;

/**
 * Highlight the currently selected property (if any).
 * The current selection is based on a value in sessionStorage.
 */
Code.ObjectPanel.highlight = function() {
  var selector = sessionStorage.getItem(Code.Common.SELECTOR);
  var parts = Code.Common.selectorToParts(selector);
  var part = parts ? parts[Code.ObjectPanel.parts.length] : null;
  var jsonPart = JSON.stringify(part);
  var newHighlighted = null;
  for (var tr of Code.ObjectPanel.tableBody.childNodes) {
    var td = tr.firstChild;
    var link = td.firstChild;
    if (link.getAttribute('data-link') === jsonPart) {
      newHighlighted = td;
    }
  }
  if (newHighlighted !== Code.ObjectPanel.highlighted) {
    if (Code.ObjectPanel.highlighted) {
      Code.ObjectPanel.highlighted.className = '';
    }
    if (newHighlighted) {
      newHighlighted.className = 'highlighted';
      if (newHighlighted.scrollIntoView) {
        newHighlighted.scrollIntoView({block: 'nearest', inline: 'nearest'});
      }
    }
    Code.ObjectPanel.highlighted = newHighlighted;
  }
};

/**
 * Remove any properties that are shadowed by objects higher on the inheritance
 * chain.  Also sort the properties alphabetically.
 * @param {Array<!Array<!Object>>} data Property names from Code City.
 */
Code.ObjectPanel.filterShadowed = function(data) {
  if (!data || data.length < 2) {
    return;
  }
  var seen = Object.create(null);
  for (var datum of data) {
    var cursorInsert = 0;
    var cursorRead = 0;
    while (cursorRead < datum.length) {
      var prop = datum[cursorRead++];
      if (!seen[prop.name]) {
        seen[prop.name] = true;
        datum[cursorInsert++] = prop;
      }
    }
    datum.length = cursorInsert;
    datum.sort(Code.ObjectPanel.caseInsensitiveComp);
  }
};

/**
 * Comparison function to sort named objects A-Z without regard to case.
 * @param {string} a One string.
 * @param {string} b Another string.
 * @return {number} -1/0/1 comparator value.
 */
Code.ObjectPanel.caseInsensitiveComp = function(a, b) {
  return a.name.toLowerCase().localeCompare(a.name.toLowerCase());
};

if (!window.TEST) {
  (function() {
    // Load the data from Code City.
    var hash = location.hash.substring(1);
    var script = document.createElement('script');
    script.src = '/code/objectPanel?parts=' + hash;
    document.head.appendChild(script);

    // Fill in the object name.
    Code.ObjectPanel.parts = JSON.parse(decodeURIComponent(hash));
    var div = document.getElementById('objectTitle');
    var lastPart = Code.ObjectPanel.parts[Code.ObjectPanel.parts.length - 1];
    var name;
    if (!lastPart) {
      name = 'Globals';
    } else if (Code.ObjectPanel.parts.length === 1) {
      // Render as 'foo' or '[42]' or '["???"]' or '^'.
      name = Code.Common.partsToSelector([lastPart]);
    } else {
      // Render as '.foo' or '[42]' or '["???"]' or '^'.
      var mockParts = [{type: 'id', value: 'X'}, lastPart];
      name = Code.Common.partsToSelector(mockParts).substring(1);
    }
    div.innerHTML = '';
    div.appendChild(document.createTextNode(name));
  })();

  window.addEventListener('load', Code.ObjectPanel.init);
}
<commit_msg>Enable command-clicking of links in editor.<commit_after>/**
 * @license
 * Copyright 2018 Google LLC
 *
 * 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.
 */

/**
 * @fileoverview Integrated Development Environment for Code City.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

Code.ObjectPanel = {};

/**
 * List of parts (passed in by the URL hash).
 * @type {?Array<!Object>}
 */
Code.ObjectPanel.parts = null;

/**
 * DOM node containing the list of properties.
 * @type {?Element}
 */
Code.ObjectPanel.tableBody = null;

/**
 * Structured data from Code City.
 * @type {?Object}
 */
Code.ObjectPanel.data = null;

/**
 * Page has loaded, initialize the panel.  Called by Code City with data.
 */
Code.ObjectPanel.init = function() {
  Code.ObjectPanel.tableBody = document.getElementById('objectTableBody');
  // Clear the '...'
  Code.ObjectPanel.tableBody.innerHTML = '';
  var data = Code.ObjectPanel.data;
  if (!data) {
    // Server error.  Should not happen.
    var title = document.getElementById('objectTitle');
    title.className = 'objectFailTitle';
    var fail = document.getElementById('objectFail');
    fail.style.display = 'table-row';
    return;
  }
  if (data.roots) {
    // Print all root objects.
    for (var root of data.roots) {
      var part = {type: 'id', value: root.name};
      Code.ObjectPanel.addLink(part, root.type, false);
    }
  }
  if (data.properties) {
    Code.ObjectPanel.filterShadowed(data.properties);
    // Print all properties of this object.
    for (var i = 0; i < data.properties.length; i++) {
      var propList = data.properties[i];
      for (var j = 0; j < propList.length; j++) {
        var part = {type: 'id', value: propList[j].name};
        Code.ObjectPanel.addLink(part, propList[j].type, i && !j);
      }
    }
    var part = {type: '^'};
    Code.ObjectPanel.addLink(part, 'object', true);
  }

  // Position the type symbols, and monitor for layout changes.
  Code.ObjectPanel.positionTypes();
  window.addEventListener('scroll', Code.ObjectPanel.positionTypes, false);
  window.addEventListener('resize', Code.ObjectPanel.positionTypes, false);

  // Highlight current item, and monitor for path changes.
  Code.ObjectPanel.highlight();
  window.addEventListener('message', Code.ObjectPanel.highlight, false);
};

/**
 * Create the DOM elements to add one property link to the list.
 * @param {!Object} part Single selector part.
 * @param {string} type Type of the property value.
 * @param {boolean} section Flag indicating a new section.
 */
Code.ObjectPanel.addLink = function(part, type, section) {
  var newParts = Code.ObjectPanel.parts.concat(part);
  var selector = Code.Common.partsToSelector(newParts);
  var a = document.createElement('a');
  a.href = '/code?' + encodeURIComponent(selector);
  a.target = '_blank';
  a.setAttribute('data-link', JSON.stringify(part));
  a.addEventListener('click', Code.ObjectPanel.click);
  var text = document.createTextNode(Code.Common.partsToSelector([part]));
  a.appendChild(text);
  var td = document.createElement('td');
  if (section) {
    td.className = 'section';
  }
  var typeSymbol = Code.ObjectPanel.TYPES[type];
  if (typeSymbol) {
    var div = document.createElement('div');
    div.className = 'objectType';
    div.appendChild(document.createTextNode(typeSymbol));
    div.title = type;
    td.appendChild(div);
  }
  td.appendChild(a);
  var tr = document.createElement('tr');
  tr.appendChild(td);
  Code.ObjectPanel.tableBody.appendChild(tr);
};

/**
 * Symbols to print next to properties.
 */
Code.ObjectPanel.TYPES = {
  'object': '{}',
  'symbol': '☆',
  'function': '𝑓'
};

/**
 * When scrollbar is moved or size changes reposition the floating types.
 */
Code.ObjectPanel.positionTypes = function() {
  var left = (document.body.clientWidth + window.scrollX - 18) + 'px';
  var types = document.getElementsByClassName('objectType');
  for (var t of types) {
    t.style.left = left;
  }
};

/**
 * When a property is clicked, trigger an update.
 * @param {!Event} e Click event.
 */
Code.ObjectPanel.click = function(e) {
  if (e.metaKey || e.ctrlKey) {
    return;
  }
  var part = JSON.parse(e.currentTarget.getAttribute('data-link'));
  var newParts = Code.ObjectPanel.parts.concat(part);
  var selector = Code.Common.partsToSelector(newParts);
  // Store the new selector in sessionStorage for all frames to see.
  sessionStorage.setItem(Code.Common.SELECTOR, selector);
  // Alert the top "/code" frameset that there's been a selector change.
  window.parent.parent.postMessage('ping', '*');
  // Don't navigate to this link.
  e.preventDefault();
};

/**
 * Currently selected property, or null if none.
 * @type {?Element}
 */
Code.ObjectPanel.highlighted = null;

/**
 * Highlight the currently selected property (if any).
 * The current selection is based on a value in sessionStorage.
 */
Code.ObjectPanel.highlight = function() {
  var selector = sessionStorage.getItem(Code.Common.SELECTOR);
  var parts = Code.Common.selectorToParts(selector);
  var part = parts ? parts[Code.ObjectPanel.parts.length] : null;
  var jsonPart = JSON.stringify(part);
  var newHighlighted = null;
  for (var tr of Code.ObjectPanel.tableBody.childNodes) {
    var td = tr.firstChild;
    var link = td.firstChild;
    if (link.getAttribute('data-link') === jsonPart) {
      newHighlighted = td;
    }
  }
  if (newHighlighted !== Code.ObjectPanel.highlighted) {
    if (Code.ObjectPanel.highlighted) {
      Code.ObjectPanel.highlighted.className = '';
    }
    if (newHighlighted) {
      newHighlighted.className = 'highlighted';
      if (newHighlighted.scrollIntoView) {
        newHighlighted.scrollIntoView({block: 'nearest', inline: 'nearest'});
      }
    }
    Code.ObjectPanel.highlighted = newHighlighted;
  }
};

/**
 * Remove any properties that are shadowed by objects higher on the inheritance
 * chain.  Also sort the properties alphabetically.
 * @param {Array<!Array<!Object>>} data Property names from Code City.
 */
Code.ObjectPanel.filterShadowed = function(data) {
  if (!data || data.length < 2) {
    return;
  }
  var seen = Object.create(null);
  for (var datum of data) {
    var cursorInsert = 0;
    var cursorRead = 0;
    while (cursorRead < datum.length) {
      var prop = datum[cursorRead++];
      if (!seen[prop.name]) {
        seen[prop.name] = true;
        datum[cursorInsert++] = prop;
      }
    }
    datum.length = cursorInsert;
    datum.sort(Code.ObjectPanel.caseInsensitiveComp);
  }
};

/**
 * Comparison function to sort named objects A-Z without regard to case.
 * @param {string} a One string.
 * @param {string} b Another string.
 * @return {number} -1/0/1 comparator value.
 */
Code.ObjectPanel.caseInsensitiveComp = function(a, b) {
  return a.name.toLowerCase().localeCompare(a.name.toLowerCase());
};

if (!window.TEST) {
  (function() {
    // Load the data from Code City.
    var hash = location.hash.substring(1);
    var script = document.createElement('script');
    script.src = '/code/objectPanel?parts=' + hash;
    document.head.appendChild(script);

    // Fill in the object name.
    Code.ObjectPanel.parts = JSON.parse(decodeURIComponent(hash));
    var div = document.getElementById('objectTitle');
    var lastPart = Code.ObjectPanel.parts[Code.ObjectPanel.parts.length - 1];
    var name;
    if (!lastPart) {
      name = 'Globals';
    } else if (Code.ObjectPanel.parts.length === 1) {
      // Render as 'foo' or '[42]' or '["???"]' or '^'.
      name = Code.Common.partsToSelector([lastPart]);
    } else {
      // Render as '.foo' or '[42]' or '["???"]' or '^'.
      var mockParts = [{type: 'id', value: 'X'}, lastPart];
      name = Code.Common.partsToSelector(mockParts).substring(1);
    }
    div.innerHTML = '';
    div.appendChild(document.createTextNode(name));
  })();

  window.addEventListener('load', Code.ObjectPanel.init);
}
<|endoftext|>


<commit_before>import {
  initAppointmentListMock,
  createPastVAAppointments,
  mockFeatureToggles,
} from './vaos-cypress-helpers';
import Timeouts from 'platform/testing/e2e/timeouts';

describe('VAOS appointment list', () => {
  beforeEach(() => {
    initAppointmentListMock();
    mockFeatureToggles();
    cy.visit('health-care/schedule-view-va-appointments/appointments/');
    cy.injectAxe();
  });

  describe('appointments details', () => {
    beforeEach(() => {
      cy.get('h2', { timeout: Timeouts.slow })
        .should('be.visible')
        .and('contain', 'Your appointments');
      cy.get('#type-dropdown').should('exist');
    });

    it('community care appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/Community Care/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/cc');
      cy.get('[data-cy=community-care-appointment-details-header]')
        .should('exist')
        .contains('Community care');
      cy.axeCheckBestPractice();
    });

    it('va appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA CLinic/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-appointment-details-header]')
        .should('exist')
        .contains('VA appointment');
      cy.axeCheckBestPractice();
    });

    it('va phone appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/Phone call/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-appointment-details-header]')
        .should('exist')
        .contains('VA appointment over the phone');
      cy.axeCheckBestPractice();
    });

    it('va video appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA Video Connect at a VA Location/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-video-appointment-details-header]')
        .should('exist')
        .contains('VA Video Connect at VA location');
      cy.axeCheckBestPractice();
    });

    it('va video appointment at an ATLAS location', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA Video Connect at an ATLAS Location/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-video-appointment-details-header]')
        .should('exist')
        .contains('VA Video Connect at an ATLAS location');
      cy.axeCheckBestPractice();
    });

    it('va video appointment at home', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA Video Connect at home/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-video-appointment-details-header]')
        .should('exist')
        .contains('VA Video Connect at home');
      cy.axeCheckBestPractice();
    });

    it('should allow for canceling of appointments', () => {
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA CLinic/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
      cy.findByText(/Cancel appointment/i).click();
      cy.findByText(/Yes, cancel this appointment/i).click();
      cy.get('.usa-alert-success').should('exist');
      cy.findByText(/Continue/i).click();
      cy.get('#cancelAppt').should('not.exist');
      cy.get('.usa-alert-success').should('not.exist');
      cy.get('.usa-alert-error').should('exist');
    });
  });

  describe('upcoming appointments', () => {
    it('should render upcoming appointments list', () => {
      cy.get('h2', { timeout: Timeouts.slow })
        .should('be.visible')
        .and('contain', 'Your appointments');
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=upcoming-appointment-list]').should('exist');
      cy.get('#type-dropdown').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to upcoming appointment details', () => {
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
    });
  });

  describe('requested appointments', () => {
    beforeEach(() => {
      cy.get('h2', { timeout: Timeouts.slow })
        .should('be.visible')
        .and('contain', 'Your appointments');
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=upcoming-appointment-list]').should('exist');
      cy.get('#type-dropdown')
        .select('requested')
        .should('have.value', 'requested');
      cy.get('h2').contains(/Requested/i);
    });

    it('should render requested appointments list', () => {
      cy.get('[data-cy=requested-appointment-list]').should('exist');
      cy.get('[data-cy=requested-appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to requested appointment details', () => {
      cy.get('[data-cy=requested-appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .click();
      cy.findByText(/Request detail/i).should('exist');
      cy.axeCheckBestPractice();
    });
  });

  describe('past appointments', () => {
    beforeEach(() => {
      cy.route({
        method: 'GET',
        url: /.*\/v0\/appointments.*type=va$/,
        response: createPastVAAppointments(),
      });
      cy.get('#type-dropdown')
        .select('past')
        .should('have.value', 'past');
      cy.get('h2').contains(/Past appointments/i);
    });

    it('should render past appointments list', () => {
      cy.findByLabelText(/Select a date range/i).should('exist');
      cy.get('[data-cy=past-appointment-list]').should('exist');
      cy.get('[data-cy=past-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to past appointment details', () => {
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .focus()
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
      cy.axeCheckBestPractice();
    });

    it('should select an updated date range', () => {
      cy.get('select')
        .eq(1)
        .select('1')
        .should('have.value', '1');
      cy.get('button')
        .contains(/Update/i)
        .click();
      cy.get('h3').should('exist');
      cy.axeCheckBestPractice();
    });
  });

  describe('canceled appointments', () => {
    beforeEach(() => {
      cy.get('#type-dropdown')
        .select('canceled')
        .should('have.value', 'canceled');
      cy.get('h2').contains(/Canceled appointments/i);
    });
    it('should render canceled appointments list', () => {
      cy.get('[data-cy=canceled-appointment-list-header]').should('exist');
      cy.get('[data-cy=canceled-appointment-list]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to canceled appointment details', () => {
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .focus()
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
      cy.axeCheckBestPractice();
    });
  });
});
<commit_msg>Skip flaky VA phone appointment test (#19926)<commit_after>import {
  initAppointmentListMock,
  createPastVAAppointments,
  mockFeatureToggles,
} from './vaos-cypress-helpers';
import Timeouts from 'platform/testing/e2e/timeouts';

describe('VAOS appointment list', () => {
  beforeEach(() => {
    initAppointmentListMock();
    mockFeatureToggles();
    cy.visit('health-care/schedule-view-va-appointments/appointments/');
    cy.injectAxe();
  });

  describe('appointments details', () => {
    beforeEach(() => {
      cy.get('h2', { timeout: Timeouts.slow })
        .should('be.visible')
        .and('contain', 'Your appointments');
      cy.get('#type-dropdown').should('exist');
    });

    it('community care appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/Community Care/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/cc');
      cy.get('[data-cy=community-care-appointment-details-header]')
        .should('exist')
        .contains('Community care');
      cy.axeCheckBestPractice();
    });

    it('va appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA CLinic/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-appointment-details-header]')
        .should('exist')
        .contains('VA appointment');
      cy.axeCheckBestPractice();
    });

    it.skip('va phone appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/Phone call/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-appointment-details-header]')
        .should('exist')
        .contains('VA appointment over the phone');
      cy.axeCheckBestPractice();
    });

    it('va video appointment', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA Video Connect at a VA Location/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-video-appointment-details-header]')
        .should('exist')
        .contains('VA Video Connect at VA location');
      cy.axeCheckBestPractice();
    });

    it('va video appointment at an ATLAS location', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA Video Connect at an ATLAS Location/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-video-appointment-details-header]')
        .should('exist')
        .contains('VA Video Connect at an ATLAS location');
      cy.axeCheckBestPractice();
    });

    it('va video appointment at home', () => {
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA Video Connect at home/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.url().should('include', '/appointments/va');
      cy.get('[data-cy=va-video-appointment-details-header]')
        .should('exist')
        .contains('VA Video Connect at home');
      cy.axeCheckBestPractice();
    });

    it('should allow for canceling of appointments', () => {
      cy.get('[data-cy=appointment-list-item]')
        .contains(/VA CLinic/i)
        .parent()
        .findByText(/Details/i)
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
      cy.findByText(/Cancel appointment/i).click();
      cy.findByText(/Yes, cancel this appointment/i).click();
      cy.get('.usa-alert-success').should('exist');
      cy.findByText(/Continue/i).click();
      cy.get('#cancelAppt').should('not.exist');
      cy.get('.usa-alert-success').should('not.exist');
      cy.get('.usa-alert-error').should('exist');
    });
  });

  describe('upcoming appointments', () => {
    it('should render upcoming appointments list', () => {
      cy.get('h2', { timeout: Timeouts.slow })
        .should('be.visible')
        .and('contain', 'Your appointments');
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=upcoming-appointment-list]').should('exist');
      cy.get('#type-dropdown').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to upcoming appointment details', () => {
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
    });
  });

  describe('requested appointments', () => {
    beforeEach(() => {
      cy.get('h2', { timeout: Timeouts.slow })
        .should('be.visible')
        .and('contain', 'Your appointments');
      cy.get('[data-cy=upcoming-appointment-list-header]').should('exist');
      cy.get('[data-cy=upcoming-appointment-list]').should('exist');
      cy.get('#type-dropdown')
        .select('requested')
        .should('have.value', 'requested');
      cy.get('h2').contains(/Requested/i);
    });

    it('should render requested appointments list', () => {
      cy.get('[data-cy=requested-appointment-list]').should('exist');
      cy.get('[data-cy=requested-appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to requested appointment details', () => {
      cy.get('[data-cy=requested-appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .click();
      cy.findByText(/Request detail/i).should('exist');
      cy.axeCheckBestPractice();
    });
  });

  describe('past appointments', () => {
    beforeEach(() => {
      cy.route({
        method: 'GET',
        url: /.*\/v0\/appointments.*type=va$/,
        response: createPastVAAppointments(),
      });
      cy.get('#type-dropdown')
        .select('past')
        .should('have.value', 'past');
      cy.get('h2').contains(/Past appointments/i);
    });

    it('should render past appointments list', () => {
      cy.findByLabelText(/Select a date range/i).should('exist');
      cy.get('[data-cy=past-appointment-list]').should('exist');
      cy.get('[data-cy=past-appointment-list-header]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to past appointment details', () => {
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .focus()
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
      cy.axeCheckBestPractice();
    });

    it('should select an updated date range', () => {
      cy.get('select')
        .eq(1)
        .select('1')
        .should('have.value', '1');
      cy.get('button')
        .contains(/Update/i)
        .click();
      cy.get('h3').should('exist');
      cy.axeCheckBestPractice();
    });
  });

  describe('canceled appointments', () => {
    beforeEach(() => {
      cy.get('#type-dropdown')
        .select('canceled')
        .should('have.value', 'canceled');
      cy.get('h2').contains(/Canceled appointments/i);
    });
    it('should render canceled appointments list', () => {
      cy.get('[data-cy=canceled-appointment-list-header]').should('exist');
      cy.get('[data-cy=canceled-appointment-list]').should('exist');
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .should('exist');
      cy.axeCheckBestPractice();
    });

    it('should navigate to canceled appointment details', () => {
      cy.get('[data-cy=appointment-list-item]')
        .first()
        .findByText(/Details/i)
        .focus()
        .click();
      cy.findByText(/Appointment detail/i).should('exist');
      cy.axeCheckBestPractice();
    });
  });
});
<|endoftext|>


<commit_before>eveui_mode = 'modal';
var eveui_imageserver = function(image_ref) {
	if (image_ref.startsWith('Character')) {
		return eve_image(encodeURI(image_ref), 'jpg');
	}
	return eve_image(encodeURI(image_ref), 'png');
};
// fix for getting names for modules from ccp api that are in the users browser language
{
	let lang_code = document.getElementById('lang-code').getAttribute('content');

	// esi only knows en_us (maybe it accepts en_* too but lets better be sure
	if (lang_code.startsWith('en_') || lang_code == 'en') {
		lang_code = 'en_us';
	}

	$.ajaxSetup({
		beforeSend: function(xhr, settings) {
			if (settings.url.includes('/universe/types/')) {
				xhr.setRequestHeader('Accept-Language', lang_code);
			}
		}
	});
}
<commit_msg>added code to clear eve-ui cache on lang change<commit_after>eveui_mode = 'modal';
var eveui_imageserver = function(image_ref) {
	if (image_ref.startsWith('Character')) {
		return eve_image(encodeURI(image_ref), 'jpg');
	}
	return eve_image(encodeURI(image_ref), 'png');
};
// fix for getting names for modules from ccp api that are in the users browser language
{
	let lang_code = document.getElementById('lang-code').getAttribute('content');

	// esi only knows en_us (maybe it accepts en_* too but lets better be sure
	if (lang_code.startsWith('en_') || lang_code == 'en') {
		lang_code = 'en_us';
	}

	$.ajaxSetup({
		beforeSend: function(xhr, settings) {
			if (settings.url.includes('/universe/types/')) {
				xhr.setRequestHeader('Accept-Language', lang_code);
			}
		}
	});

	let last_lang = localStorage.getItem('last_lang');
	if (!last_lang || last_lang != lang_code) {
		localStorage.setItem('last_lang', lang_code);
		$.ajax(`https://esi.tech.ccp.is/v1/status/`, {
			dataType: 'json',
				cache: true,
		}).done(function (data) {
			eve_version = data.server_version;
			let open = indexedDB.open('eveui', eve_version);
			let done = false;
			open.onupgradeneeded = function (e) {
				let db = open.result;
				if (db.objectStoreNames.contains('cache')) {
					db.deleteObjectStore('cache');
				}
				db.createObjectStore('cache', { keyPath: 'path' });
				done = true;
			};
			open.onsuccess = function (event) {
				if (done) {
					return;
				}
				db = open.result;
				let tx = db.transaction('cache', 'readwrite');
				if (db.objectStoreNames.contains('cache')) {
					let store = tx.objectStore('cache');
					store.clear();
				}
			};
		});
	}
}
<|endoftext|>


<commit_before>/**
 * Created by vincentfung13 on 18/02/2016.
 */
var margin = {top: 20, right: 30, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var colour = {
    "Apple": "steelblue",
    "Amazon": "purple",
    "Tesco": "grey",
    "BMW": "black",
    "HSBC": "darkorange",
    "Heineken": "darkgreen"
};

function init_graph() {
    // Get values for the three selectors
    var entity = document.getElementById('entity-picker').value;
    var dimension = document.getElementById('dimension-picker').value;
    var graph_type = document.getElementById('graph-picker').value;

    if (dimension == 'All') {
        $.ajax({
				url : '/twitter_services/stats/' + graph_type + '/' + entity,
				success : function(data) {
					$("#graph-container").html(data);
				}
        });
    }
    else {
        $.ajax({
				url : '/twitter_services/stats_both/' + graph_type + '/' + entity + '/' + dimension,
				success : function(data) {
					$("#graph-container").html(data);
				}
        });
    }
}

/**
 * Draw a line chart regarding the reputation score of an entity
 * @param time_list
 * @param reputation_scores
 */
function draw_line_charts(entity, dimension, time_list, reputation_scores) {
    // Construct data for the axis and lines
    var arrData = [];
    for (var i = 0; i < time_list.length; i++) {
        var time_score_pair = [time_list[i], reputation_scores[i]];
        arrData.push(time_score_pair);
    }

    // Draw the axis
    var xScale = d3.time.scale()
        .domain([new Date(arrData[0][0]), d3.time.day.offset(new Date(arrData[arrData.length - 1][0]), 1)])
        .rangeRound([0, width - margin.left - margin.right]);

    var yScale = d3.scale.linear()
        .domain([
            -d3.max(arrData, function (d) {
                return Math.abs(d[1]) + 1;
            }),

            d3.max(arrData, function (d) {
                return Math.abs(d[1]) + 1;
            })
        ])
        .range([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .ticks(d3.time.days, 1)
        .tickFormat(d3.time.format('%y-%m-%d'))
        .tickSize(0)
        .tickPadding(3);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(5)
        .tickSize(5)
        .tickPadding(3);

    // Create the lines
    var score_line = d3.svg.line()
        .x(function(d) {
            return xScale(new Date(d[0]));
        })
        .y(function(d) {
            return yScale(d[1]);
        });

    var base_line = d3.svg.line()
        .x(function(d) {
            return xScale(new Date(d[0]));
        })
        .y(function(d) {
            return yScale(0);
        });

    // Append all the element to the svg
    var lineChartSVG = d3.select("#line-chart")
                        .append("svg")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                        .append("g")
                        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    lineChartSVG.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis)
                .selectAll("text")
                    .attr("y", 0)
                    .attr("x", 0)
                    .attr("dy", ".5em")
                    .attr("transform", "rotate(25)")
                    .style("text-anchor", "start")

    lineChartSVG.append("g")
                .attr("class", "y axis")
                .call(yAxis)
                .append("text")
                    .attr("transform", "rotate(-90)")
                    .attr("y", 6)
                    .attr("dy", "-3em")
                    .style("text-anchor", "end")
                    .text("Reputation Score");

    // Append dot to points
    var node = lineChartSVG.selectAll(".g")
                .data(arrData)
                .enter()
                .append("g");

    var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function (d) {
                return "Click to see tweets in " + d[0] + "";
            }
        );
    lineChartSVG.call(tip);

    node.append("circle")
        .attr("class", "dot")
        .attr("cx", function(d) { return xScale(new Date(d[0])); })
        .attr("cy", function(d) { return yScale(d[1]); })
        .attr("r", 5)
        .attr("fill", colour[entity])
        .on("mouseover", tip.show)
        .on("mouseout", tip.hide)
        .on("click", function(d) {
            if (dimension == 'None') {
                post('/twitter_services/entity/' + entity + '/',
                    {
                        entity: decodeURIComponent(entity),
                        date: d[0]
                    });
            }
            else {
                post('/twitter_services/entity_dimension/' + entity + '/' + dimension + '/',
                    {
                        entity: decodeURIComponent(entity),
                        reputation_dimension: decodeURIComponent(dimension),
                        date: d[0]
                    });
            }
        });

    node.append("text")
        .attr("transform", function(d) {
            var cx = xScale(new Date(d[0])) + 10;
            var cy = yScale(d[1]);
            return "translate(" + cx + "," + cy + ")"
        })
        .style("fill", colour[entity])
        .style("font-size", "13px")
        .text(function(d) {
            return d[1];
        });

    // Append charts
    lineChartSVG.append("path")
                .datum(arrData)
                .attr("class", "score_line")
                .attr("d", score_line)
                .attr("stroke", colour[entity])

    lineChartSVG.append("path")
                .datum(arrData)
                .attr("class", "base_line")
                .attr("d", base_line)
                .attr("stroke", "red")

    lineChartSVG.append("text")
                .attr("transform", "translate(" + width * 0.8 + "," + yScale(arrData[arrData.length - 1][1]) + ")")
                .attr("dy", ".35em")
                .attr("text-anchor", "start")
                .style("fill", colour[entity])
                .style("font-size", "13px")
                .text(entity);

	lineChartSVG.append("text")
                .attr("transform", "translate(" + width * 0.75 + "," + yScale(0) + ")")
                .attr("dy", ".35em")
                .attr("text-anchor", "start")
                .style("fill", "red")
                .style("font-size", "13px")
                .text("Neutral");
}

/**
 * Draw a stack bar chart representing the tweet count and negative count
 * @param time_list
 * @param tweet_count_list
 * @param negative_count_list
 */
function draw_bar_charts(entity, dimension, time_list, tweet_count_list, negative_count_list) {
    // Construct data for the axis and charts
    var arrData = [];
    for (var i = 0; i < time_list.length; i++) {
        var time_score_pair = [time_list[i], negative_count_list[i], tweet_count_list[i] - negative_count_list[i]];
        arrData.push(time_score_pair);
    }

    var barChartSVG = d3.select("#bar-chart")
                        .append("svg")
                        .attr("class", "chart")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

   var xScale = d3.time.scale()
        .domain([new Date(arrData[0][0]), d3.time.day.offset(new Date(arrData[arrData.length - 1][0]), 1)])
        .rangeRound([0, width - margin.left - margin.right]);

    var yScale = d3.scale.linear()
        .range([height, 0])
        .domain([
            0,
            d3.max(arrData, function (d) {
                return (d[1] + d[2]) * 1.1;
            })
        ]);

    // Append bottom
    // Initialize the tip
    var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function (d) {
                return "Click to see tweets in " + d[0] + "";
            }
        );
    barChartSVG.call(tip);

    // Append bottom rect and onclick
    barChartSVG.selectAll("g")
        .data(arrData).enter()
            .append("g")
                .attr("class", "date group")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
            .append("rect")
                .attr("class", "data negative")
                .attr("y", function(d) {
                    return yScale(+d[1]);
                })
                .attr("height", function(d) {
                    return Math.abs(yScale(+d[1]) - yScale(0));
                })
                .on("mouseover", tip.show)
                .on("mouseout", tip.hide)
                .on("click", function(d) {
                    if (dimension == 'None') {
                        post('/twitter_services/entity/' + entity + '/',
                            {
                                entity: decodeURIComponent(entity),
                                date: d[0]
                            });
                    }
                    else {
                        post('/twitter_services/entity_dimension/' + entity + '/' + dimension + '/',
                            {
                                entity: decodeURIComponent(entity),
                                reputation_dimension: decodeURIComponent(dimension),
                                date: d[0]
                            });
                    }
                });

    barChartSVG.selectAll("g")
        .data(arrData)
        .append("rect")
        .attr("class", "data positive")
        .attr("y", function(d) {
            return yScale(+d[1] + +d[2])
        })
        .attr("height", function(d){
            return Math.abs(yScale(+d[2]) - yScale(0));
        })
        .on("mouseover", tip.show)
                .on("mouseout", tip.hide)
                .on("click", function(d) {
                    if (dimension == 'None') {
                        post('/twitter_services/entity/' + entity + '/',
                            {
                                entity: decodeURIComponent(entity),
                                date: d[0]
                            });
                    }
                    else {
                        post('/twitter_services/entity_dimension/' + entity + '/' + dimension + '/',
                            {
                                entity: decodeURIComponent(entity),
                                reputation_dimension: decodeURIComponent(dimension),
                                date: d[0]
                            });
                    }
                });

    barChartSVG.selectAll("g")
        .data(arrData)
        .selectAll("rect.data")
        .attr("x", function(d){
            return xScale(new Date(d[0]));
        })
        .attr("width", 100);

    // Append text label
    var node = barChartSVG.selectAll(".g")
        .data(arrData)
        .enter()
        .append("g");

    // Negative count
    node.append("text")
        .attr("transform", function(d) {
            var cx = xScale(new Date(d[0])) + 80;
            var cy = yScale(d[1]);
            return "translate(" + cx + "," + cy + ")"
        })
        .style("font-size", "13px")
        .text(function(d) {
            if (d[1] != 0)
                return d[1];
        });

    // Total count
    node.append("text")
        .attr("transform", function(d) {
            var cx = xScale(new Date(d[0])) + 80;
            var cy = yScale(d[2] + d[1]);
            return "translate(" + cx + "," + cy + ")"
        })
        .style("font-size", "13px")
        .text(function(d) {
            if (d[2] != 0)
                return d[2] + d[1];
        });

    // Append the two axises
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .ticks(d3.time.days, 1)
        .tickFormat(d3.time.format('%y-%m-%d'))
        .tickSize(0)
        .tickPadding(8);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(5)
        .tickSize(5)
        .tickPadding(8);

    barChartSVG.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(" + 2 * margin.right + "," + (height + margin.top) + ")")
                .call(xAxis)
                .selectAll("text")
                    .attr("y", 0)
                    .attr("x", 0)
                    .attr("dy", ".5em")
                    .attr("transform", "rotate(30)")
                    .style("text-anchor", "start")

    barChartSVG.append("g")
                .attr("class", "y axis")
                .attr("transform", "translate(" + margin.right * 1.35 + "," + margin.top + ")")
                .call(yAxis)
                .append("text")
                    .attr("transform", "rotate(-90)")
                    .attr("y", 5)
                    .attr("dy", ".71em")
                    .style("text-anchor", "end")
                    .text("Count");
}<commit_msg>Remove redundant code<commit_after>/**
 * Created by vincentfung13 on 18/02/2016.
 */
var margin = {top: 20, right: 30, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var colour = {
    "Apple": "steelblue",
    "Amazon": "purple",
    "Tesco": "grey",
    "BMW": "black",
    "HSBC": "darkorange",
    "Heineken": "darkgreen"
};

function init_graph() {
    // Get values for the three selectors
    var entity = document.getElementById('entity-picker').value;
    var dimension = document.getElementById('dimension-picker').value;
    var graph_type = document.getElementById('graph-picker').value;

    if (dimension == 'All') {
        $.ajax({
				url : '/twitter_services/stats/' + graph_type + '/' + entity,
				success : function(data) {
					$("#graph-container").html(data);
				}
        });
    }
    else {
        $.ajax({
				url : '/twitter_services/stats_both/' + graph_type + '/' + entity + '/' + dimension,
				success : function(data) {
					$("#graph-container").html(data);
				}
        });
    }
}

/**
 * Draw a line chart regarding the reputation score of an entity
 * @param time_list
 * @param reputation_scores
 */
function draw_line_charts(entity, dimension, time_list, reputation_scores) {
    // Construct data for the axis and lines
    var arrData = [];
    for (var i = 0; i < time_list.length; i++) {
        var time_score_pair = [time_list[i], reputation_scores[i]];
        arrData.push(time_score_pair);
    }

    // Draw the axis
    var xScale = d3.time.scale()
        .domain([new Date(arrData[0][0]), d3.time.day.offset(new Date(arrData[arrData.length - 1][0]), 1)])
        .rangeRound([0, width - margin.left - margin.right]);

    var yScale = d3.scale.linear()
        .domain([
            -d3.max(arrData, function (d) {
                return Math.abs(d[1]) + 1;
            }),

            d3.max(arrData, function (d) {
                return Math.abs(d[1]) + 1;
            })
        ])
        .range([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .ticks(d3.time.days, 1)
        .tickFormat(d3.time.format('%y-%m-%d'))
        .tickSize(0)
        .tickPadding(3);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(5)
        .tickSize(5)
        .tickPadding(3);

    // Create the lines
    var score_line = d3.svg.line()
        .x(function(d) {
            return xScale(new Date(d[0]));
        })
        .y(function(d) {
            return yScale(d[1]);
        });

    var base_line = d3.svg.line()
        .x(function(d) {
            return xScale(new Date(d[0]));
        })
        .y(function(d) {
            return yScale(0);
        });

    // Append all the element to the svg
    var lineChartSVG = d3.select("#line-chart")
                        .append("svg")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                        .append("g")
                        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    lineChartSVG.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis)
                .selectAll("text")
                    .attr("y", 0)
                    .attr("x", 0)
                    .attr("dy", ".5em")
                    .attr("transform", "rotate(25)")
                    .style("text-anchor", "start")

    lineChartSVG.append("g")
                .attr("class", "y axis")
                .call(yAxis)
                .append("text")
                    .attr("transform", "rotate(-90)")
                    .attr("y", 6)
                    .attr("dy", "-3em")
                    .style("text-anchor", "end")
                    .text("Reputation Score");

    // Append dot to points
    var node = lineChartSVG.selectAll(".g")
                .data(arrData)
                .enter()
                .append("g");

    var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function (d) {
                return "Click to see tweets in " + d[0] + "";
            }
        );
    lineChartSVG.call(tip);

    node.append("circle")
        .attr("class", "dot")
        .attr("cx", function(d) { return xScale(new Date(d[0])); })
        .attr("cy", function(d) { return yScale(d[1]); })
        .attr("r", 5)
        .attr("fill", colour[entity])
        .on("mouseover", tip.show)
        .on("mouseout", tip.hide)
        .on("click", function(d) {
            if (dimension == 'None') {
                post('/twitter_services/entity/' + entity + '/',
                    {
                        entity: decodeURIComponent(entity),
                        date: d[0]
                    });
            }
            else {
                post('/twitter_services/entity_dimension/' + entity + '/' + dimension + '/',
                    {
                        entity: decodeURIComponent(entity),
                        reputation_dimension: decodeURIComponent(dimension),
                        date: d[0]
                    });
            }
        });

    node.append("text")
        .attr("transform", function(d) {
            var cx = xScale(new Date(d[0])) + 10;
            var cy = yScale(d[1]);
            return "translate(" + cx + "," + cy + ")"
        })
        .style("fill", colour[entity])
        .style("font-size", "13px")
        .text(function(d) {
            return d[1];
        });

    // Append charts
    lineChartSVG.append("path")
                .datum(arrData)
                .attr("class", "score_line")
                .attr("d", score_line)
                .attr("stroke", colour[entity])

    lineChartSVG.append("path")
                .datum(arrData)
                .attr("class", "base_line")
                .attr("d", base_line)
                .attr("stroke", "red")

    lineChartSVG.append("text")
                .attr("transform", "translate(" + width * 0.8 + "," + yScale(arrData[arrData.length - 1][1]) + ")")
                .attr("dy", ".35em")
                .attr("text-anchor", "start")
                .style("fill", colour[entity])
                .style("font-size", "13px")
                .text(entity);

	lineChartSVG.append("text")
                .attr("transform", "translate(" + width * 0.75 + "," + yScale(0) + ")")
                .attr("dy", ".35em")
                .attr("text-anchor", "start")
                .style("fill", "red")
                .style("font-size", "13px")
                .text("Neutral");
}

/**
 * Draw a stack bar chart representing the tweet count and negative count
 * @param time_list
 * @param tweet_count_list
 * @param negative_count_list
 */
function draw_bar_charts(entity, dimension, time_list, tweet_count_list, negative_count_list) {
    // Construct data for the axis and charts
    var arrData = [];
    for (var i = 0; i < time_list.length; i++) {
        var time_score_pair = [time_list[i], negative_count_list[i], tweet_count_list[i] - negative_count_list[i]];
        arrData.push(time_score_pair);
    }

    var barChartSVG = d3.select("#bar-chart")
                        .append("svg")
                        .attr("class", "chart")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

   var xScale = d3.time.scale()
        .domain([new Date(arrData[0][0]), d3.time.day.offset(new Date(arrData[arrData.length - 1][0]), 1)])
        .rangeRound([0, width - margin.left - margin.right]);

    var yScale = d3.scale.linear()
        .range([height, 0])
        .domain([
            0,
            d3.max(arrData, function (d) {
                return (d[1] + d[2]) * 1.1;
            })
        ]);

    // Append bottom rect
    barChartSVG.selectAll("g")
        .data(arrData).enter()
            .append("g")
                .attr("class", "date group")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
            .append("rect")
                .attr("class", "data negative")
                .attr("y", function(d) {
                    return yScale(+d[1]);
                })
                .attr("height", function(d) {
                    return Math.abs(yScale(+d[1]) - yScale(0));
                });

    // Append top rect
    barChartSVG.selectAll("g")
        .data(arrData)
        .append("rect")
        .attr("class", "data positive")
        .attr("y", function(d) {
            return yScale(+d[1] + +d[2])
        })
        .attr("height", function(d){
            return Math.abs(yScale(+d[2]) - yScale(0));
        });

    // Positioning the bars, add on-clicks and tooltips
    var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function (d) {
                return "Click to see tweets in " + d[0] + "";
            }
        );
    barChartSVG.call(tip);
    barChartSVG.selectAll("g")
        .data(arrData)
        .selectAll("rect.data")
        .attr("x", function(d){
            return xScale(new Date(d[0]));
        })
        .attr("width", 100)
        .on("mouseover", tip.show)
        .on("mouseout", tip.hide)
        .on("click", function(d) {
            if (dimension == 'None') {
                post('/twitter_services/entity/' + entity + '/',
                    {
                        entity: decodeURIComponent(entity),
                        date: d[0]
                    });
            }
            else {
                post('/twitter_services/entity_dimension/' + entity + '/' + dimension + '/',
                    {
                        entity: decodeURIComponent(entity),
                        reputation_dimension: decodeURIComponent(dimension),
                        date: d[0]
                    });
            }
        });

    // Append text label
    var node = barChartSVG.selectAll(".g")
        .data(arrData)
        .enter()
        .append("g");

    // Negative count
    node.append("text")
        .attr("transform", function(d) {
            var cx = xScale(new Date(d[0])) + 80;
            var cy = yScale(d[1]);
            return "translate(" + cx + "," + cy + ")"
        })
        .style("font-size", "13px")
        .text(function(d) {
            if (d[1] != 0)
                return d[1];
        });

    // Total count
    node.append("text")
        .attr("transform", function(d) {
            var cx = xScale(new Date(d[0])) + 80;
            var cy = yScale(d[2] + d[1]);
            return "translate(" + cx + "," + cy + ")"
        })
        .style("font-size", "13px")
        .text(function(d) {
            if (d[2] != 0)
                return d[2] + d[1];
        });

    // Append the two axises
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .ticks(d3.time.days, 1)
        .tickFormat(d3.time.format('%y-%m-%d'))
        .tickSize(0)
        .tickPadding(8);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(5)
        .tickSize(5)
        .tickPadding(8);

    barChartSVG.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(" + 2 * margin.right + "," + (height + margin.top) + ")")
                .call(xAxis)
                .selectAll("text")
                    .attr("y", 0)
                    .attr("x", 0)
                    .attr("dy", ".5em")
                    .attr("transform", "rotate(30)")
                    .style("text-anchor", "start")

    barChartSVG.append("g")
                .attr("class", "y axis")
                .attr("transform", "translate(" + margin.right * 1.35 + "," + margin.top + ")")
                .call(yAxis)
                .append("text")
                    .attr("transform", "rotate(-90)")
                    .attr("y", 5)
                    .attr("dy", ".71em")
                    .style("text-anchor", "end")
                    .text("Count");
}<|endoftext|>


<commit_before>'use strict';

goog.provide('Blockly.Python.hedgehog');

goog.require('Blockly.Python');

// set indentaion to 4 spaces
Blockly.Python.INDENT = '    ';

Blockly.Python['hedgehog_scope'] = function(block) {
    var statements = Blockly.Python.statementToCode(block, 'IN');
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'with connect(emergency=15) as hedgehog:\n' + statements;
    return code;
};

Blockly.Python['hedgehog_turn'] = function(block) {
    var port1 = block.getFieldValue('MOTOR1');
    var port2 = block.getFieldValue('MOTOR2');
    var dir = parseInt(Blockly.Python.valueToCode(block, 'DIR', Blockly.Python.ORDER_NONE));
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.move(' + port1 + ', ' + dir + ')\n';
    code += 'hedgehog.move(' + port2 + ', ' + (-1 * dir) + ')\n';
    code += 'sleep(' + time + ')\n\n';

    return code;
};

Blockly.Python['hedgehog_move2'] = function(block) {
    var port1 = block.getFieldValue('MOTOR1');
    var port2 = block.getFieldValue('MOTOR2');
    var speed = Blockly.Python.valueToCode(block, 'SPEED', Blockly.Python.ORDER_NONE);
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.move(' + port1 + ', ' + speed + ')\n';
    var code = 'hedgehog.move(' + port2 + ', ' + speed + ')\n';
    code += 'sleep(' + time + ')\n\n';
    return code;
};

Blockly.Python['hedgehog_move'] = function(block) {
    var port = block.getFieldValue('PORT');
    var speed = Blockly.Python.valueToCode(block, 'SPEED', Blockly.Python.ORDER_NONE);
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.move(' + port + ', ' + speed + ')' + '\nsleep(' + time + ')\n\n';
    return code;
};

Blockly.Python['hedgehog_speed'] = function(block) {
    var speed = block.getFieldValue('SPEED');
    return [speed, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_dir'] = function(block) {
    var speed = block.getFieldValue('DIR');
    return [speed, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_servo'] = function(block) {
    var port = block.getFieldValue('PORT');
    var angle = Blockly.Python.valueToCode(block, 'ANGLE', Blockly.Python.ORDER_NONE);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.set_servo(' + port + ', True, ' + Math.floor(parseInt(angle)*11.37) + ')\n';
    code += 'sleep(0.1)\n\n';
    return code;
};

Blockly.Python['hedgehog_degrees'] = function(block) {
    var angle = block.getFieldValue('ANGLE');

    // imports
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    if(parseInt(angle) > 180) {
        return ["180", Blockly.Python.ORDER_NONE];
    }

    return [angle, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_read_analog'] = function(block) {
    var port = block.getFieldValue('PORT');

    var code = 'hedgehog.get_analog(' + port + ')';
    return [code, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_read_digital'] = function(block) {
    var port = block.getFieldValue('PORT');

    var code = 'hedgehog.get_digital(' + port + ')';
    return [code, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_sleep'] = function(block) {
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';

    var code = 'sleep(' + time + ')\n\n';
    return code;
};
<commit_msg>rename field<commit_after>'use strict';

goog.provide('Blockly.Python.hedgehog');

goog.require('Blockly.Python');

// set indentaion to 4 spaces
Blockly.Python.INDENT = '    ';

Blockly.Python['hedgehog_scope'] = function(block) {
    var statements = Blockly.Python.statementToCode(block, 'IN');
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'with connect(emergency=15) as hedgehog:\n' + statements;
    return code;
};

Blockly.Python['hedgehog_turn'] = function(block) {
    var port1 = block.getFieldValue('PORT1');
    var port2 = block.getFieldValue('PORT2');
    var dir = parseInt(Blockly.Python.valueToCode(block, 'DIR', Blockly.Python.ORDER_NONE));
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.move(' + port1 + ', ' + dir + ')\n';
    code += 'hedgehog.move(' + port2 + ', ' + (-1 * dir) + ')\n';
    code += 'sleep(' + time + ')\n\n';

    return code;
};

Blockly.Python['hedgehog_move2'] = function(block) {
    var port1 = block.getFieldValue('PORT1');
    var port2 = block.getFieldValue('PORT2');
    var speed = Blockly.Python.valueToCode(block, 'SPEED', Blockly.Python.ORDER_NONE);
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.move(' + port1 + ', ' + speed + ')\n';
    var code = 'hedgehog.move(' + port2 + ', ' + speed + ')\n';
    code += 'sleep(' + time + ')\n\n';
    return code;
};

Blockly.Python['hedgehog_move'] = function(block) {
    var port = block.getFieldValue('PORT');
    var speed = Blockly.Python.valueToCode(block, 'SPEED', Blockly.Python.ORDER_NONE);
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.move(' + port + ', ' + speed + ')' + '\nsleep(' + time + ')\n\n';
    return code;
};

Blockly.Python['hedgehog_speed'] = function(block) {
    var speed = block.getFieldValue('SPEED');
    return [speed, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_dir'] = function(block) {
    var speed = block.getFieldValue('DIR');
    return [speed, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_servo'] = function(block) {
    var port = block.getFieldValue('PORT');
    var angle = Blockly.Python.valueToCode(block, 'ANGLE', Blockly.Python.ORDER_NONE);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    var code = 'hedgehog.set_servo(' + port + ', True, ' + Math.floor(parseInt(angle)*11.37) + ')\n';
    code += 'sleep(0.1)\n\n';
    return code;
};

Blockly.Python['hedgehog_degrees'] = function(block) {
    var angle = block.getFieldValue('ANGLE');

    // imports
    Blockly.Python.definitions_['import_hedgehog'] = 'from hedgehog.client import connect';

    if(parseInt(angle) > 180) {
        return ["180", Blockly.Python.ORDER_NONE];
    }

    return [angle, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_read_analog'] = function(block) {
    var port = block.getFieldValue('PORT');

    var code = 'hedgehog.get_analog(' + port + ')';
    return [code, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_read_digital'] = function(block) {
    var port = block.getFieldValue('PORT');

    var code = 'hedgehog.get_digital(' + port + ')';
    return [code, Blockly.Python.ORDER_NONE];
};

Blockly.Python['hedgehog_sleep'] = function(block) {
    var time = Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_ATOMIC);

    // imports
    Blockly.Python.definitions_['import_sleep'] = 'from time import sleep';

    var code = 'sleep(' + time + ')\n\n';
    return code;
};
<|endoftext|>