<commit_before>// use nifti-js and just parse header.???

// Slicer way to handle images
// should follow it...
 // 897   if ( (this->IndexSeriesInstanceUIDs[k] != idxSeriesInstanceUID && this->IndexSeriesInstanceUIDs[k] >= 0 && idxSeriesInstanceUID >= 0) ||
 // 898        (this->IndexContentTime[k] != idxContentTime && this->IndexContentTime[k] >= 0 && idxContentTime >= 0) ||
 // 899        (this->IndexTriggerTime[k] != idxTriggerTime && this->IndexTriggerTime[k] >= 0 && idxTriggerTime >= 0) ||
 // 900        (this->IndexEchoNumbers[k] != idxEchoNumbers && this->IndexEchoNumbers[k] >= 0 && idxEchoNumbers >= 0) ||
 // 901        (this->IndexDiffusionGradientOrientation[k] != idxDiffusionGradientOrientation  && this->IndexDiffusionGradientOrientation[k] >= 0 && idxDiffusionGradientOrientation >= 0) ||
 // 902        (this->IndexSliceLocation[k] != idxSliceLocation && this->IndexSliceLocation[k] >= 0 && idxSliceLocation >= 0) ||
 // 903        (this->IndexImageOrientationPatient[k] != idxImageOrientationPatient && this->IndexImageOrientationPatient[k] >= 0 && idxImageOrientationPatient >= 0) )
 // 904     {
 // 905       continue;
 // 906     }

//http://brainder.org/2012/09/23/the-nifti-file-format/

/*** Imports ***/
import ParsersVolume from './parsers.volume';

let NiftiReader = require('nifti-reader-js');
/**
 * @module parsers/nifti
 */
export default class ParsersNifti extends ParsersVolume {
  constructor(data, id) {

    super();

    /**
      * @member
      * @type {arraybuffer}
    */
    this._id = id;
    this._arrayBuffer = data.buffer;
    this._url = data.url;
    this._dataSet = null;
    this._niftiHeader = null;
    this._niftiImage = null;
    this._ordered = true;
    this._orderedData = null;

    if (NiftiReader.isNIFTI(this._arrayBuffer)) {
      this._dataSet = NiftiReader.readHeader(this._arrayBuffer);
      this._niftiImage = NiftiReader.readImage(this._dataSet, this._arrayBuffer);
    } else {
      throw 'parsers.nifti could not parse the file';
    }
  }

  seriesInstanceUID() {
    // use filename + timestamp..?
    return this._url;
  }

  numberOfFrames() {
    return this._dataSet.dims[3];
  }

  numberOfChannels() {
    let numberOfChannels = 1;

    // can dims[0] >= 5 and not multi channels with RGB datatypecode?

    if (this._dataSet.dims[0] >= 5) {
      numberOfChannels = this._dataSet.dims[5];
      this._ordered = false;
    } else if (this._dataSet.datatypeCode === 128) {
      numberOfChannels = 3;
    } else if (this._dataSet.datatypeCode === 2304) {
      numberOfChannels = 4;
    }

    return numberOfChannels;
  }

  sopInstanceUID(frameIndex = 0) {
    return frameIndex;
  }

  rows(frameIndex = 0) {
    return this._dataSet.dims[2];
  }

  columns(frameIndex = 0) {
    return this._dataSet.dims[1];
  }

  pixelType(frameIndex = 0) {
        // papaya.volume.nifti.NIFTI_TYPE_UINT8           = 2;
    // papaya.volume.nifti.NIFTI_TYPE_INT16           = 4;
    // papaya.volume.nifti.NIFTI_TYPE_INT32           = 8;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT32        = 16;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX64      = 32;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT64        = 64;
    // papaya.volume.nifti.NIFTI_TYPE_RGB24         = 128;
    // papaya.volume.nifti.NIFTI_TYPE_INT8          = 256;
    // papaya.volume.nifti.NIFTI_TYPE_UINT16        = 512;
    // papaya.volume.nifti.NIFTI_TYPE_UINT32        = 768;
    // papaya.volume.nifti.NIFTI_TYPE_INT64        = 1024;
    // papaya.volume.nifti.NIFTI_TYPE_UINT64       = 1280;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT128     = 1536;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX128   = 1792;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX256   = 2048;

    // 0 integer, 1 float

    let pixelType = 0;
    if(this._dataSet.datatypeCode === 16 ||
      this._dataSet.datatypeCode === 64 ||
      this._dataSet.datatypeCode === 1536){
      pixelType = 1;
    }
    return pixelType;
  }

  bitsAllocated(frameIndex = 0) {
    return this._dataSet.numBitsPerVoxel;
  }

  pixelSpacing(frameIndex = 0) {
    return [
      this._dataSet.pixDims[1],
      this._dataSet.pixDims[2],
      this._dataSet.pixDims[3]
      ];
  }

  sliceThickness() {
    // should be a string...
    return null;//this._dataSet.pixDims[3].toString();
  }

  imageOrientation(frameIndex = 0) {
    // window.console.log(this._dataSet);
    // http://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h
    // http://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1_io.c
    if(this._dataSet.qform_code > 0) {
      //https://github.com/Kitware/ITK/blob/master/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx
      var a = 0.0, b = this._dataSet.quatern_b, c = this._dataSet.quatern_c, d = this._dataSet.quatern_d;
      // compute a
      a = 1.0 - (b*b + c*c + d*d) ;
      if( a < 0.0000001 ){                   /* special case */

        a = 1.0 / Math.sqrt(b*b+c*c+d*d) ;
        b *= a ; c *= a ; d *= a ;        /* normalize (b,c,d) vector */
        a = 0.0;                       /* a = 0 ==> 180 degree rotation */

      } else {

        a = Math.sqrt(a) ;                     /* angle = 2*arccos(a) */

      }

      // let qfac = 1.0;
      // if(this._dataSet.pixdim[0] < 0.0) {
      //   qfac = -qfac;
      // }

      // window.console.log(a);
      // window.console.log(b);
      // window.console.log(c);
      // window.console.log(d);

       return [
          (a*a+b*b-c*c-d*d), // -
          2*(b*c-a*d),       // -
          2*(b*d+a*c),       // -
          2*(b*c+a*d),
          a*a+c*c-b*b-d*d,
          2*(c*d-a*b)
        ];

    }else if(this._dataSet.sform_code > 0) {

      var sx = this._dataSet.srow_x, sy = this._dataSet.srow_y, sz = this._dataSet.srow_z;
      // fill IJKToRAS
      //goog.vec.Mat4.setRowValues(IJKToRAS, 0, sx[0], sx[1], sx[2], sx[3]);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 1, sy[0], sy[1], sy[2], sy[3]);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 2, sz[0], sz[1], sz[2], sz[3]);

    }
    else if(this._dataSet.qform_code === 0) {

      // fill IJKToRAS
      //goog.vec.Mat4.setRowValues(IJKToRAS, 0, MRI.pixdim[1], 0, 0, 0);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 1, 0, MRI.pixdim[2], 0, 0);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 2, 0, 0, MRI.pixdim[3], 0);

    }
    return [1, 0, 0, 0, 1, 0];
  }

  imagePosition(frameIndex = 0) {
    // qoffset is RAS
    return [
      -this._dataSet.qoffset_x,
      -this._dataSet.qoffset_y,
      this._dataSet.qoffset_z
    ];
  }

  dimensionIndexValues(frameIndex = 0) {
    return null;
  }

  instanceNumber(frameIndex = 0) {
    return frameIndex;
  }

  windowCenter(frameIndex = 0) {
    // calc min and calc max
    return null;
  }

  windowWidth(frameIndex = 0) {
    // calc min and calc max
    return null;
  }

  rescaleSlope(frameIndex = 0) {
    return this._dataSet.scl_slope;
  }

  rescaleIntercept(frameIndex = 0) {
    return this._dataSet.scl_intercept;
  }

  minMaxPixelData(pixelData = []) {
    let minMax = [65535, -32768];
    let numPixels = pixelData.length;
    for (let index = 0; index < numPixels; index++) {
      let spv = pixelData[index];
      minMax[0] = Math.min(minMax[0], spv);
      minMax[1] = Math.max(minMax[1], spv);
    }

    return minMax;
  }

  extractPixelData(frameIndex = 0) {
    return this._decompressUncompressed(frameIndex);
    //let buffer = this._dataSet.imageData;
    // if (this._dataSet.compressed) {
    // let buffer = this._dataSet.rawData[0];
    // try {
    //   let data = pako.inflate(new Uint8Array(buffer));
    //   buffer = data.buffer;
    // } catch (err) {
    //   console.log(err);
    // }

    //window.console.log(buffer);
    // }

    // is it compressed?
    // yes/no

    //     try {
    //   var result = pako.inflate(compressed);
    // } catch (err) {
    //   console.log(err);
    // }

    // window.console.log(this);
  }

  _decompressUncompressed(frameIndex = 0) {
    // papaya.volume.nifti.NIFTI_TYPE_UINT8           = 2;
    // papaya.volume.nifti.NIFTI_TYPE_INT16           = 4;
    // papaya.volume.nifti.NIFTI_TYPE_INT32           = 8;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT32        = 16;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX64      = 32;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT64        = 64;
    // papaya.volume.nifti.NIFTI_TYPE_RGB24         = 128;
    // papaya.volume.nifti.NIFTI_TYPE_INT8          = 256;
    // papaya.volume.nifti.NIFTI_TYPE_UINT16        = 512;
    // papaya.volume.nifti.NIFTI_TYPE_UINT32        = 768;
    // papaya.volume.nifti.NIFTI_TYPE_INT64        = 1024;
    // papaya.volume.nifti.NIFTI_TYPE_UINT64       = 1280;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT128     = 1536;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX128   = 1792;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX256   = 2048;

    let numberOfChannels = this.numberOfChannels();
    let numPixels = this.rows(frameIndex) * this.columns(frameIndex) * numberOfChannels;
    let frameOffset = frameIndex * numPixels;
    let buffer = this._niftiImage;

    // use bits allocated && pixel reprensentation too

    if (!this._ordered && this._orderedData === null) {
      // order then
      this._reorderData();
    }

    if (this._orderedData !== null) {
      // just a slice...
      return this._orderedData.slice(frameOffset, frameOffset + numPixels);

    } else if (this._dataSet.datatypeCode === 2) {
      // unsigned 8 bit
      return new Uint8Array(buffer, frameOffset, numPixels);

    } else if (this._dataSet.datatypeCode === 256) {
      // signed 8 bit
      return new Int8Array(buffer, frameOffset, numPixels);

    } else if (this._dataSet.datatypeCode === 512) {
      // unsigned 16 bit
      frameOffset = frameOffset * 2;
      return new Uint16Array(buffer, frameOffset, numPixels);

    } else if (this._dataSet.datatypeCode === 4) {
      // signed 16 bit
      frameOffset = frameOffset * 2;
      return new Int16Array(buffer, frameOffset, numPixels);

    }  else if (this._dataSet.datatypeCode === 16) {

      // float 32 bit
      frameOffset = frameOffset * 4;
      return new Float32Array(buffer, frameOffset, numPixels);

    }
  }

  _reorderData() {
    window.console.log('re-order');
    let numberOfChannels = this.numberOfChannels();
    let numPixels = this.rows() * this.columns() * numberOfChannels;
    let buffer = this._niftiImage;

    let totalNumPixels = numPixels * this.numberOfFrames();
    let tmp = null;
    this._orderedData = null;

    if (this._dataSet.datatypeCode === 2) {
      // unsigned 8 bit
      tmp = new Uint8Array(buffer, 0, totalNumPixels);
      this._orderedData = new Uint8Array(tmp.length);

    } else if (this._dataSet.datatypeCode === 256) {
      // signed 8 bit
      tmp = new Int8Array(buffer, 0, totalNumPixels);
      this._orderedData = new Int8Array(tmp.length);

    } else if (this._dataSet.datatypeCode === 512) {
      tmp = new Uint16Array(buffer, 0, totalNumPixels);
      this._orderedData = new Uint16Array(tmp.length);

    } else if (this._dataSet.datatypeCode === 4) {
      tmp = new Int16Array(buffer, 0, totalNumPixels);
      this._orderedData = new Int16Array(tmp.length);

    }  else if (this._dataSet.datatypeCode === 16) {
      tmp = new Float32Array(buffer, 0, totalNumPixels);
      this._orderedData = new Float32Array(tmp.length);

    }

    // re-order pixels...
    var numPixels2 = tmp.length / 3;
    var rgbaIndex = 0;
    var rIndex = 0;
    var gIndex = numPixels2;
    var bIndex = numPixels2 * 2;
    for (var i = 0; i < numPixels2; i++) {
      this._orderedData[rgbaIndex++] = tmp[rIndex++]; // red
      this._orderedData[rgbaIndex++] = tmp[gIndex++]; // green
      this._orderedData[rgbaIndex++] = tmp[bIndex++]; // blue
    }

    this._ordered = true;
  }
}
<commit_msg>fix nifti orientation<commit_after>// use nifti-js and just parse header.???

// Slicer way to handle images
// should follow it...
 // 897   if ( (this->IndexSeriesInstanceUIDs[k] != idxSeriesInstanceUID && this->IndexSeriesInstanceUIDs[k] >= 0 && idxSeriesInstanceUID >= 0) ||
 // 898        (this->IndexContentTime[k] != idxContentTime && this->IndexContentTime[k] >= 0 && idxContentTime >= 0) ||
 // 899        (this->IndexTriggerTime[k] != idxTriggerTime && this->IndexTriggerTime[k] >= 0 && idxTriggerTime >= 0) ||
 // 900        (this->IndexEchoNumbers[k] != idxEchoNumbers && this->IndexEchoNumbers[k] >= 0 && idxEchoNumbers >= 0) ||
 // 901        (this->IndexDiffusionGradientOrientation[k] != idxDiffusionGradientOrientation  && this->IndexDiffusionGradientOrientation[k] >= 0 && idxDiffusionGradientOrientation >= 0) ||
 // 902        (this->IndexSliceLocation[k] != idxSliceLocation && this->IndexSliceLocation[k] >= 0 && idxSliceLocation >= 0) ||
 // 903        (this->IndexImageOrientationPatient[k] != idxImageOrientationPatient && this->IndexImageOrientationPatient[k] >= 0 && idxImageOrientationPatient >= 0) )
 // 904     {
 // 905       continue;
 // 906     }

//http://brainder.org/2012/09/23/the-nifti-file-format/

/*** Imports ***/
import ParsersVolume from './parsers.volume';

let NiftiReader = require('nifti-reader-js');
/**
 * @module parsers/nifti
 */
export default class ParsersNifti extends ParsersVolume {
  constructor(data, id) {

    super();

    /**
      * @member
      * @type {arraybuffer}
    */
    this._id = id;
    this._arrayBuffer = data.buffer;
    this._url = data.url;
    this._dataSet = null;
    this._niftiHeader = null;
    this._niftiImage = null;
    this._ordered = true;
    this._orderedData = null;

    //
    this._qfac = 1.0;

    if (NiftiReader.isNIFTI(this._arrayBuffer)) {
      this._dataSet = NiftiReader.readHeader(this._arrayBuffer);
      this._niftiImage = NiftiReader.readImage(this._dataSet, this._arrayBuffer);
    } else {
      throw 'parsers.nifti could not parse the file';
    }
  }

  seriesInstanceUID() {
    // use filename + timestamp..?
    return this._url;
  }

  numberOfFrames() {
    return this._dataSet.dims[3];
  }

  numberOfChannels() {
    let numberOfChannels = 1;

    // can dims[0] >= 5 and not multi channels with RGB datatypecode?

    if (this._dataSet.dims[0] >= 5) {
      numberOfChannels = this._dataSet.dims[5];
      this._ordered = false;
    } else if (this._dataSet.datatypeCode === 128) {
      numberOfChannels = 3;
    } else if (this._dataSet.datatypeCode === 2304) {
      numberOfChannels = 4;
    }

    return numberOfChannels;
  }

  sopInstanceUID(frameIndex = 0) {
    return frameIndex;
  }

  rows(frameIndex = 0) {
    return this._dataSet.dims[2];
  }

  columns(frameIndex = 0) {
    return this._dataSet.dims[1];
  }

  pixelType(frameIndex = 0) {
        // papaya.volume.nifti.NIFTI_TYPE_UINT8           = 2;
    // papaya.volume.nifti.NIFTI_TYPE_INT16           = 4;
    // papaya.volume.nifti.NIFTI_TYPE_INT32           = 8;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT32        = 16;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX64      = 32;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT64        = 64;
    // papaya.volume.nifti.NIFTI_TYPE_RGB24         = 128;
    // papaya.volume.nifti.NIFTI_TYPE_INT8          = 256;
    // papaya.volume.nifti.NIFTI_TYPE_UINT16        = 512;
    // papaya.volume.nifti.NIFTI_TYPE_UINT32        = 768;
    // papaya.volume.nifti.NIFTI_TYPE_INT64        = 1024;
    // papaya.volume.nifti.NIFTI_TYPE_UINT64       = 1280;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT128     = 1536;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX128   = 1792;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX256   = 2048;

    // 0 integer, 1 float

    let pixelType = 0;
    if(this._dataSet.datatypeCode === 16 ||
      this._dataSet.datatypeCode === 64 ||
      this._dataSet.datatypeCode === 1536){
      pixelType = 1;
    }
    return pixelType;
  }

  bitsAllocated(frameIndex = 0) {
    return this._dataSet.numBitsPerVoxel;
  }

  pixelSpacing(frameIndex = 0) {

    return [
      this._dataSet.pixDims[1],
      this._dataSet.pixDims[2],
      this._dataSet.pixDims[3]
      ];
  }

  sliceThickness() {
    // should be a string...
    return null;//this._dataSet.pixDims[3].toString();
  }

  imageOrientation(frameIndex = 0) {
    // window.console.log(this._dataSet);
    // http://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h
    // http://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1_io.c
    if(this._dataSet.qform_code > 0) {
      //https://github.com/Kitware/ITK/blob/master/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx
      var a = 0.0, b = this._dataSet.quatern_b, c = this._dataSet.quatern_c, d = this._dataSet.quatern_d;
      // compute a
      a = 1.0 - (b*b + c*c + d*d) ;
      if( a < 0.0000001 ){                   /* special case */

        a = 1.0 / Math.sqrt(b*b+c*c+d*d) ;
        b *= a ; c *= a ; d *= a ;        /* normalize (b,c,d) vector */
        a = 0.0;                       /* a = 0 ==> 180 degree rotation */

      } else {

        a = Math.sqrt(a) ;                     /* angle = 2*arccos(a) */

      }

      if(this._dataSet.pixDims[0] < 0.0) {
        this._qfac = -1.0;
      }

       return [
          -(a*a+b*b-c*c-d*d),
          -2*(b*c+a*d),
          2*(b*d-a*c),
          -2*(b*c-a*d),
          -(a*a+c*c-b*b-d*d),
          2*(c*d+a*b)
        ];

    }else if(this._dataSet.sform_code > 0) {

      console.log( 'sform > 0' );

      var sx = this._dataSet.srow_x, sy = this._dataSet.srow_y, sz = this._dataSet.srow_z;
      // fill IJKToRAS
      //goog.vec.Mat4.setRowValues(IJKToRAS, 0, sx[0], sx[1], sx[2], sx[3]);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 1, sy[0], sy[1], sy[2], sy[3]);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 2, sz[0], sz[1], sz[2], sz[3]);

    }
    else if(this._dataSet.qform_code === 0) {

            console.log( 'qform === 0' );

      // fill IJKToRAS
      //goog.vec.Mat4.setRowValues(IJKToRAS, 0, MRI.pixdim[1], 0, 0, 0);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 1, 0, MRI.pixdim[2], 0, 0);
      //goog.vec.Mat4.setRowValues(IJKToRAS, 2, 0, 0, MRI.pixdim[3], 0);

    }
    return [1, 0, 0, 0, 1, 0];
  }

  imagePosition(frameIndex = 0) {
    // qoffset is RAS
    return [
      -this._dataSet.qoffset_x,
      -this._dataSet.qoffset_y,
      this._dataSet.qoffset_z
    ];
  }

  dimensionIndexValues(frameIndex = 0) {
    return null;
  }

  instanceNumber(frameIndex = 0) {
    return frameIndex;
  }

  windowCenter(frameIndex = 0) {
    // calc min and calc max
    return null;
  }

  windowWidth(frameIndex = 0) {
    // calc min and calc max
    return null;
  }

  rescaleSlope(frameIndex = 0) {
    return this._dataSet.scl_slope;
  }

  rescaleIntercept(frameIndex = 0) {
    return this._dataSet.scl_intercept;
  }

  minMaxPixelData(pixelData = []) {
    let minMax = [65535, -32768];
    let numPixels = pixelData.length;
    for (let index = 0; index < numPixels; index++) {
      let spv = pixelData[index];
      minMax[0] = Math.min(minMax[0], spv);
      minMax[1] = Math.max(minMax[1], spv);
    }

    return minMax;
  }

  extractPixelData(frameIndex = 0) {
    return this._decompressUncompressed(frameIndex);
    //let buffer = this._dataSet.imageData;
    // if (this._dataSet.compressed) {
    // let buffer = this._dataSet.rawData[0];
    // try {
    //   let data = pako.inflate(new Uint8Array(buffer));
    //   buffer = data.buffer;
    // } catch (err) {
    //   console.log(err);
    // }

    //window.console.log(buffer);
    // }

    // is it compressed?
    // yes/no

    //     try {
    //   var result = pako.inflate(compressed);
    // } catch (err) {
    //   console.log(err);
    // }

    // window.console.log(this);
  }

  _decompressUncompressed(frameIndex = 0) {
    // papaya.volume.nifti.NIFTI_TYPE_UINT8           = 2;
    // papaya.volume.nifti.NIFTI_TYPE_INT16           = 4;
    // papaya.volume.nifti.NIFTI_TYPE_INT32           = 8;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT32        = 16;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX64      = 32;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT64        = 64;
    // papaya.volume.nifti.NIFTI_TYPE_RGB24         = 128;
    // papaya.volume.nifti.NIFTI_TYPE_INT8          = 256;
    // papaya.volume.nifti.NIFTI_TYPE_UINT16        = 512;
    // papaya.volume.nifti.NIFTI_TYPE_UINT32        = 768;
    // papaya.volume.nifti.NIFTI_TYPE_INT64        = 1024;
    // papaya.volume.nifti.NIFTI_TYPE_UINT64       = 1280;
    // papaya.volume.nifti.NIFTI_TYPE_FLOAT128     = 1536;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX128   = 1792;
    // papaya.volume.nifti.NIFTI_TYPE_COMPLEX256   = 2048;

    let numberOfChannels = this.numberOfChannels();
    let numPixels = this.rows(frameIndex) * this.columns(frameIndex) * numberOfChannels;

    // frameIndex or nb frames - index -1? maybe (probably) that is where qfac comes into play
    if( this._qfac > 0 ){
      frameIndex = this.numberOfFrames() - 1 - frameIndex;
    }
    let frameOffset = frameIndex * numPixels;
    let buffer = this._niftiImage;

    // use bits allocated && pixel reprensentation too
    if (!this._ordered && this._orderedData === null) {
      // order then
      this._reorderData();
    }

    if (this._orderedData !== null) {
      // just a slice...
      return this._orderedData.slice(frameOffset, frameOffset + numPixels);

    } else if (this._dataSet.datatypeCode === 2) {
      // unsigned 8 bit
      return new Uint8Array(buffer, frameOffset, numPixels);

    } else if (this._dataSet.datatypeCode === 256) {
      // signed 8 bit
      return new Int8Array(buffer, frameOffset, numPixels);

    } else if (this._dataSet.datatypeCode === 512) {
      // unsigned 16 bit
      frameOffset = frameOffset * 2;
      return new Uint16Array(buffer, frameOffset, numPixels);

    } else if (this._dataSet.datatypeCode === 4) {
      // signed 16 bit
      frameOffset = frameOffset * 2;
      return new Int16Array(buffer, frameOffset, numPixels);

    }  else if (this._dataSet.datatypeCode === 16) {

      // float 32 bit
      frameOffset = frameOffset * 4;
      return new Float32Array(buffer, frameOffset, numPixels);

    }
  }

  _reorderData() {
    window.console.log('re-order');
    let numberOfChannels = this.numberOfChannels();
    let numPixels = this.rows() * this.columns() * numberOfChannels;
    let buffer = this._niftiImage;

    let totalNumPixels = numPixels * this.numberOfFrames();
    let tmp = null;
    this._orderedData = null;

    if (this._dataSet.datatypeCode === 2) {
      // unsigned 8 bit
      tmp = new Uint8Array(buffer, 0, totalNumPixels);
      this._orderedData = new Uint8Array(tmp.length);

    } else if (this._dataSet.datatypeCode === 256) {
      // signed 8 bit
      tmp = new Int8Array(buffer, 0, totalNumPixels);
      this._orderedData = new Int8Array(tmp.length);

    } else if (this._dataSet.datatypeCode === 512) {
      tmp = new Uint16Array(buffer, 0, totalNumPixels);
      this._orderedData = new Uint16Array(tmp.length);

    } else if (this._dataSet.datatypeCode === 4) {
      tmp = new Int16Array(buffer, 0, totalNumPixels);
      this._orderedData = new Int16Array(tmp.length);

    }  else if (this._dataSet.datatypeCode === 16) {
      tmp = new Float32Array(buffer, 0, totalNumPixels);
      this._orderedData = new Float32Array(tmp.length);

    }

    // re-order pixels...
    var numPixels2 = tmp.length / 3;
    var rgbaIndex = 0;
    var rIndex = 0;
    var gIndex = numPixels2;
    var bIndex = numPixels2 * 2;

    for (var i = 0; i < numPixels2; i++) {

      this._orderedData[rgbaIndex++] = tmp[rIndex++]; // red
      this._orderedData[rgbaIndex++] = tmp[gIndex++]; // green
      this._orderedData[rgbaIndex++] = tmp[bIndex++]; // blue

    }

    this._ordered = true;
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
/***********************************************************
 * Author: @mervinej
 * Licence: MIT
 * Date: 12/07/2013
 ***********************************************************/

var fs      = require('fs');
var Phapper = require('phapper');
var async   = require('async');
var program = require('commander');

program
  .option('-s , --script [string]' , 'script to be run')
  .option('-r , --runs   [number]' , 'number of runs [1]', parseInt, 1)
  .option('-j , --json'            , 'output in JSON format')
  .option('--parallel'             , 'run phantom calls in parallel')
  .option('--series'               , 'run phantom calls in a series')
  .option('-m , --median'          , 'return median value');

program.on('--help', function() {
    console.log('  Examples:');
    console.log('');
    console.log('    $ ./runner.js -s timer -m -r 9 -j "http://google.com,http://github.com"');
    console.log('');
    console.log('    $ ./runner.js -s grep -r 9 ./urls.txt ./strings.txt');
    console.log('');
    console.log('    $ ./runner.js -s ./external/external.js -j ./urls.txt ./excluded.txt');
    console.log('');
    console.log('  Warning:');
    console.log('');
    console.log('  This is optimized for json output, otherwise, display for anything aside\n  from simple timer output (e.g. ready and timer) needs a lot of work.');
    console.log('');
});

program.parse(process.argv);

if (!program.script) {
    program.script = program.args.slice(0);
}

try {
    if (!fs.statSync(program.script).isFile()) {
        var s = './'+program.script+'/'+program.script+'.js';
        if (fs.statSync(s).isFile()) {
            script = s;
        }
    }
} catch(e) {
    console.error("ERROR: '%s' isn't a valid script", program.script);
    process.exit(1);
}

var args = program.args;

if (args.indexOf('--json') === -1) {
    args.push('--json');
}

var runner  = new Phapper(script, args);
var runs    = [];
var itteration = 0;
for (var i=0; i < program.runs; i++) {
    runs.push( function(callback) {
        console.log('finishing itteration: ', itteration++);
        runner.run(function(json, stdio) {
            if (stdio.error) {
                callback(stdio.error, null);
            }
            if (!json) {
                callback(new Error(stdio.stdout), null);
            }
            callback(null, json);
        });
    });
}

function asyncCallback(err, results) {
    if (err) {
        console.trace(err);
        process.exit(1);
    }
    var sets = {};
    results.forEach(function(res) {
        res.forEach(function(r) {
            var address = r.address;
            delete r.address;

            sets[address] = sets[address] || {};
            Object.keys(r).forEach(function(key) {
                sets[address][key] = sets[address][key] || [];
                sets[address][key].push(r[key]);
            });
        });
    });

    if (program.json) {
        Object.keys(sets).forEach(function(set) {
            Object.keys(sets[set]).forEach(function(metric) {
                var result = sets[set][metric];
                if (Array.isArray(result) && typeof result[0] === 'number') {
                    result = median(result);
                }
                sets[set][metric] = result;
            });
        });
        console.log(JSON.stringify(sets, null, 2));
    } else {
        Object.keys(sets).forEach(function(set) {
            console.log('Regarding %s:', set);
            Object.keys(sets[set]).forEach(function(metric) {
                var result = median(sets[set][metric]);
                if (Array.isArray(result)) {
                    console.log('\n* %s:', metric);
                    crawl(result);
                } else {
                    console.log('* %s: %s', metric, result);
                }
            });
            console.log('');
        });
    }
}

if (program.series && !program.parallel) {
    async.series(runs, asyncCallback);
} else if (program.parallel && !program.series) {
    async.parallel(runs, asyncCallback);
} else {
    async.parallelLimit(runs, require('os').cpus().length, asyncCallback);
}

// functions
function median(values) {
    if (!program.median || !Array.isArray(values) || typeof values[0] !== 'number') {
        return values;
    }
    values.sort( function(a,b) {return a - b;} );
    var half = Math.floor(values.length/2);
    return (values.length % 2) ? values[half] : (values[half-1] + values[half]) / 2.0;
}

function crawl(item, depth) {
    depth = depth || 1;
    if (Array.isArray(item)) {
        var i = 1;
        item.forEach(function(sub) {
            if (Array.isArray(sub)) {
                crawl('Run ['+(i++)+']', depth);
            }
            crawl(sub, depth+1);
        });
        return;
    }

    if (typeof item === 'object') {
        Object.keys(item).forEach(function(key) {
            if (typeof item[key] === 'string') {
                crawl(item[key], depth);
            } else if (typeof item[key] === 'boolean' ||
                       typeof item[key] === 'number') {
                crawl(key+': '+item[key], depth+1);
            } else {
                crawl(item[key], depth+1);
            }
        });
        return;
    }

    var spacer = '';
    for (var i = 0; i < (depth*2); i++) {
        spacer += ' ';
    }
    console.log('%s- %s', spacer, item);
    return;
}
<commit_msg>Adding parallel limiter / cpus overide.<commit_after>#!/usr/bin/env node
/***********************************************************
 * Author: @mervinej
 * Licence: MIT
 * Date: 12/07/2013
 ***********************************************************/

var fs      = require('fs');
var Phapper = require('phapper');
var async   = require('async');
var program = require('commander');

program
  .option('-s , --script [string]' , 'script to be run')
  .option('-r , --runs   [number]' , 'number of runs [1]', parseInt, 1)
  .option('-j , --json'            , 'output in JSON format')
  .option('-m , --median'          , 'return median value')
  .option('--parallel'             , 'force runs to be parallel')
  .option('--series'               , 'force runs to be serialized')
  .option('--limit [number]'       , 'overide using the cpu count as the limit for parallel runs', parseInt);

program.on('--help', function() {
    console.log('  Examples:');
    console.log('');
    console.log('    $ ./runner.js -s timer -m -r 9 -j "http://google.com,http://github.com"');
    console.log('');
    console.log('    $ ./runner.js -s grep -r 9 ./urls.txt ./strings.txt');
    console.log('');
    console.log('    $ ./runner.js -s ./external/external.js -j ./urls.txt ./excluded.txt');
    console.log('');
    console.log('  Warning:');
    console.log('');
    console.log('  This is optimized for json output, otherwise, display for anything aside\n  from simple timer output (e.g. ready and timer) needs a lot of work.');
    console.log('');
});

program.parse(process.argv);

if (!program.script) {
    program.script = program.args.slice(0);
}

try {
    if (!fs.statSync(program.script).isFile()) {
        var s = './'+program.script+'/'+program.script+'.js';
        if (fs.statSync(s).isFile()) {
            script = s;
        }
    }
} catch(e) {
    console.error("ERROR: '%s' isn't a valid script", program.script);
    process.exit(1);
}

var args = program.args;

if (args.indexOf('--json') === -1) {
    args.push('--json');
}

var runner  = new Phapper(script, args);
var runs    = [];
var itteration = 0;
for (var i=0; i < program.runs; i++) {
    runs.push( function(callback) {
        runner.run(function(json, stdio) {
            if (stdio.error) {
                callback(stdio.error, null);
            }
            if (!json) {
                callback(new Error(stdio.stdout), null);
            }
            callback(null, json);
        });
    });
}

function asyncCallback(err, results) {
    if (err) {
        console.trace(err);
        process.exit(1);
    }
    var sets = {};
    results.forEach(function(res) {
        res.forEach(function(r) {
            var address = r.address;
            delete r.address;

            sets[address] = sets[address] || {};
            Object.keys(r).forEach(function(key) {
                sets[address][key] = sets[address][key] || [];
                sets[address][key].push(r[key]);
            });
        });
    });

    if (program.json) {
        Object.keys(sets).forEach(function(set) {
            Object.keys(sets[set]).forEach(function(metric) {
                var result = sets[set][metric];
                if (Array.isArray(result) && typeof result[0] === 'number') {
                    result = median(result);
                }
                sets[set][metric] = result;
            });
        });
        console.log(JSON.stringify(sets, null, 2));
    } else {
        Object.keys(sets).forEach(function(set) {
            console.log('Regarding %s:', set);
            Object.keys(sets[set]).forEach(function(metric) {
                var result = median(sets[set][metric]);
                if (Array.isArray(result)) {
                    console.log('\n* %s:', metric);
                    crawl(result);
                } else {
                    console.log('* %s: %s', metric, result);
                }
            });
            console.log('');
        });
    }
}

if (program.limit) {
    async.parallelLimit(runs, program.limit, asyncCallback);
} else if (program.series && !program.parallel) {
    async.series(runs, asyncCallback);
} else if (program.parallel && !program.series) {
    async.parallel(runs, asyncCallback);
} else {
    async.parallelLimit(runs, (require('os').cpus().length+1), asyncCallback);
}

// functions
function median(values) {
    if (!program.median || !Array.isArray(values) || typeof values[0] !== 'number') {
        return values;
    }
    values.sort( function(a,b) {return a - b;} );
    var half = Math.floor(values.length/2);
    return (values.length % 2) ? values[half] : (values[half-1] + values[half]) / 2.0;
}

function crawl(item, depth) {
    depth = depth || 1;
    if (Array.isArray(item)) {
        var i = 1;
        item.forEach(function(sub) {
            if (Array.isArray(sub)) {
                crawl('Run ['+(i++)+']', depth);
            }
            crawl(sub, depth+1);
        });
        return;
    }

    if (typeof item === 'object') {
        Object.keys(item).forEach(function(key) {
            if (typeof item[key] === 'string') {
                crawl(item[key], depth);
            } else if (typeof item[key] === 'boolean' ||
                       typeof item[key] === 'number') {
                crawl(key+': '+item[key], depth+1);
            } else {
                crawl(item[key], depth+1);
            }
        });
        return;
    }

    var spacer = '';
    for (var i = 0; i < (depth*2); i++) {
        spacer += ' ';
    }
    console.log('%s- %s', spacer, item);
    return;
}
<|endoftext|>


<commit_before>// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// 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 Supplies global data types and constants for the vector math
 *     library.
 */
goog.provide('goog.vec');

/**
 * On platforms that don't have native Float32Array or Float64Array support we
 * use a javascript implementation so that this math library can be used on all
 * platforms.
 */
goog.require('goog.vec.Float32Array');
goog.require('goog.vec.Float64Array');

// All vector and matrix operations are based upon arrays of numbers using
// either Float32Array, Float64Array, or a standard Javascript Array of
// Numbers.

/** @typedef {Float32Array} */
goog.vec.Float32;

/** @typedef {Float64Array} */
goog.vec.Float64;

/** @typedef {Array.<Number>} */
goog.vec.Number;

/** @typedef {goog.vec.Float32|goog.vec.Float64|goog.vec.Number} */
goog.vec.AnyType;

/**
 * @deprecated Use AnyType.
 * @typedef {Float32Array|Array.<Number>}
 */
goog.vec.ArrayType;

/**
 * For graphics work, 6 decimal places of accuracy are typically all that is
 * required.
 *
 * @type {number}
 * @const
 */
goog.vec.EPSILON = 1e-6;
<commit_msg><commit_after>// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// 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 Supplies global data types and constants for the vector math
 *     library.
 */
goog.provide('goog.vec');

/**
 * On platforms that don't have native Float32Array or Float64Array support we
 * use a javascript implementation so that this math library can be used on all
 * platforms.
 */
goog.require('goog.vec.Float32Array');
goog.require('goog.vec.Float64Array');

// All vector and matrix operations are based upon arrays of numbers using
// either Float32Array, Float64Array, or a standard Javascript Array of
// Numbers.

/** @typedef {Float32Array} */
goog.vec.Float32;

/** @typedef {Float64Array} */
goog.vec.Float64;

/** @typedef {Array.<number>} */
goog.vec.Number;

/** @typedef {goog.vec.Float32|goog.vec.Float64|goog.vec.Number} */
goog.vec.AnyType;

/**
 * @deprecated Use AnyType.
 * @typedef {Float32Array|Array.<number>}
 */
goog.vec.ArrayType;

/**
 * For graphics work, 6 decimal places of accuracy are typically all that is
 * required.
 *
 * @type {number}
 * @const
 */
goog.vec.EPSILON = 1e-6;
<|endoftext|>


<commit_before>import React, { useEffect, useRef } from "react"
import * as d3 from "d3"
import PropTypes from "prop-types"
import Text from "react-svg-text"
import useDimensions from "react-use-dimensions"

const LikertScale = ({
  onChange,
  value,
  values,
  levels,
  width,
  height,
  readonly
}) => {
  const cursorRef = useRef(null)
  const axisRef = useRef(null)
  const [containerRef, containerBox] = useDimensions()
  const containerHeight = containerBox.height || 0
  const containerWidth = containerBox.width || 0
  const containerX = containerBox.x || 0
  const MARGIN = 5
  const scaleYPosition = containerHeight - 30

  const scale = d3
    .scaleLinear()
    .domain([0, 10])
    .range([MARGIN, containerWidth - 2 * MARGIN])
  const x = scale(Number(value !== undefined ? value : 50))

  useEffect(() => {
    if (readonly) {
      return
    }
    const handleDrag = d3.drag().on("drag", function() {
      const me = d3.select(cursorRef.current)
      const newX = Math.min(
        Math.max(d3.event.x, scale.range()[0]),
        scale.range()[1]
      )
      me.attr("transform", `translate(${newX} ${scaleYPosition})`)
      onChange(scale.invert(newX))
    })
    handleDrag(d3.select(cursorRef.current))
  }, [onChange, scale, scaleYPosition, readonly])

  useEffect(() => {
    d3.select(cursorRef.current).attr(
      "transform",
      `translate(${x} ${scaleYPosition})`
    )
  }, [x, scaleYPosition])

  useEffect(() => {
    const axis = d3.axisBottom(scale)
    d3.select(axisRef.current).call(axis)
  }, [scale])

  let activeColor = null
  let valuesStats = null
  if (values?.length) {
    valuesStats = {
      min: Math.min(...values),
      max: Math.max(...values),
      avg: values.reduce((a, b) => a + b, 0) / values.length
    }
    valuesStats.avgColor =
      valuesStats &&
      levels.find(level => level.endValue > valuesStats.avg)?.color
  }

  return (
    <svg
      height={height}
      width={width}
      xmlns="http://www.w3.org/2000/svg"
      ref={containerRef}
      onClick={e =>
        !readonly && e.clientX && onChange(scale.invert(e.clientX - containerX))}
    >
      {levels.map((level, index) => {
        const startX = scale(index === 0 ? 0 : levels[index - 1].endValue)
        const endX = scale(level.endValue)
        const active = x <= endX && (x > startX || index === 0)
        const fillColor = d3.color(level.color)
        active && (activeColor = d3.hsl(level.color))
        fillColor.opacity = active ? 0.4 : 0.15
        return (
          <React.Fragment key={`level-${index}`}>
            <rect
              style={{ fill: fillColor, stroke: "gray", strokeWidth: 1 }}
              y={0}
              x={startX}
              height={Math.max(0, containerHeight - 11)}
              width={Math.max(0, endX - startX)}
            />
            <Text
              fill={active ? "black" : "gray"}
              fontWeight={active ? "bold" : "normal"}
              x={startX + 2}
              y={2}
              style={{ pointerEvents: "none" }}
              width={endX - startX - 4}
              verticalAnchor="start"
            >
              {level.label}
            </Text>
          </React.Fragment>
        )
      })}
      {values?.map((xValue, index) => (
        <g
          transform={`translate(${scale(xValue)} ${scaleYPosition})`}
          key={`values-${index}-${xValue}`}
        >
          <path
            d="M -10,-10 L 10,10 M 10,-10 L -10,10"
            style={{
              stroke: "black",
              fill: "black",
              strokeWidth: 2
            }}
          />
        </g>
      ))}

      {values?.length > 1 && (
        <g transform={`translate(0 ${scaleYPosition})`}>
          <line
            x1={scale(valuesStats.min)}
            y1="-15"
            x2={scale(valuesStats.min)}
            y2="15"
            style={{ stroke: "black", strokeWidth: 3 }}
          />
          <line
            x1={scale(valuesStats.max)}
            y1="-15"
            x2={scale(valuesStats.max)}
            y2="15"
            style={{ stroke: "black", strokeWidth: 3 }}
          />
          <line
            x1={scale(valuesStats.min)}
            y1="0"
            x2={scale(valuesStats.max)}
            y2="0"
            style={{ stroke: "black", strokeWidth: 3 }}
          />
        </g>
      )}

      {values?.length > 0 && (
        <g transform={`translate(0 ${scaleYPosition})`}>
          <circle
            cx={scale(valuesStats.avg)}
            r="10"
            style={{
              stroke: valuesStats.avgColor,
              strokeWidth: 7
            }}
          />
          <text
            x={scale(valuesStats.avg) - 22}
            y={25}
            style={{ pointerEvents: "none" }}
          >
            avg:{" "}
            {Number(valuesStats.avg).toFixed(value < scale.domain()[1] ? 1 : 0)}
          </text>
        </g>
      )}
      <g ref={axisRef} transform={`translate(0 ${scaleYPosition})`} />

      {onChange && (
        <g ref={cursorRef}>
          <polygon
            points="0,0 13,13 13,30 -13,30 -13,13"
            style={{
              stroke: "gray",
              fill: "" + activeColor,
              strokeWidth: 1,
              cursor: readonly ? null : "pointer"
            }}
          />
          <text
            fill={activeColor?.l < 0.5 ? "white" : "black"}
            fontWeight="bold"
            x={-11}
            y={25}
            style={{ pointerEvents: "none" }}
          >
            {Number(value).toFixed(value < scale.domain()[1] ? 1 : 0)}
          </text>
        </g>
      )}
    </svg>
  )
}

LikertScale.propTypes = {
  value: PropTypes.number,
  values: PropTypes.arrayOf(PropTypes.number),
  onChange: PropTypes.func,
  levels: PropTypes.arrayOf(
    PropTypes.shape({
      color: PropTypes.string,
      endValue: PropTypes.number.isRequired,
      tooltip: PropTypes.string,
      label: PropTypes.string
    })
  ).isRequired,
  width: PropTypes.string.isRequired,
  height: PropTypes.string.isRequired,
  readonly: PropTypes.bool
}

LikertScale.defaultProps = {
  value: 0,
  levels: [
    {
      color: "red",
      endValue: 3
    },
    {
      color: "#FFBF00",
      endValue: 7
    },
    {
      color: "green",
      endValue: 10
    }
  ],
  height: "65",
  width: "100%"
}

export default LikertScale
<commit_msg>NCI-Agency/anet#2905: Fix LGTM alert about useless conditional<commit_after>import React, { useEffect, useRef } from "react"
import * as d3 from "d3"
import PropTypes from "prop-types"
import Text from "react-svg-text"
import useDimensions from "react-use-dimensions"

const LikertScale = ({
  onChange,
  value,
  values,
  levels,
  width,
  height,
  readonly
}) => {
  const cursorRef = useRef(null)
  const axisRef = useRef(null)
  const [containerRef, containerBox] = useDimensions()
  const containerHeight = containerBox.height || 0
  const containerWidth = containerBox.width || 0
  const containerX = containerBox.x || 0
  const MARGIN = 5
  const scaleYPosition = containerHeight - 30

  const scale = d3
    .scaleLinear()
    .domain([0, 10])
    .range([MARGIN, containerWidth - 2 * MARGIN])
  const x = scale(Number(value !== undefined ? value : 50))

  useEffect(() => {
    if (readonly) {
      return
    }
    const handleDrag = d3.drag().on("drag", function() {
      const me = d3.select(cursorRef.current)
      const newX = Math.min(
        Math.max(d3.event.x, scale.range()[0]),
        scale.range()[1]
      )
      me.attr("transform", `translate(${newX} ${scaleYPosition})`)
      onChange(scale.invert(newX))
    })
    handleDrag(d3.select(cursorRef.current))
  }, [onChange, scale, scaleYPosition, readonly])

  useEffect(() => {
    d3.select(cursorRef.current).attr(
      "transform",
      `translate(${x} ${scaleYPosition})`
    )
  }, [x, scaleYPosition])

  useEffect(() => {
    const axis = d3.axisBottom(scale)
    d3.select(axisRef.current).call(axis)
  }, [scale])

  let activeColor = null
  let valuesStats = null
  if (values?.length) {
    valuesStats = {
      min: Math.min(...values),
      max: Math.max(...values),
      avg: values.reduce((a, b) => a + b, 0) / values.length
    }
    valuesStats.avgColor = levels.find(
      level => level.endValue > valuesStats.avg
    )?.color
  }

  return (
    <svg
      height={height}
      width={width}
      xmlns="http://www.w3.org/2000/svg"
      ref={containerRef}
      onClick={e =>
        !readonly && e.clientX && onChange(scale.invert(e.clientX - containerX))}
    >
      {levels.map((level, index) => {
        const startX = scale(index === 0 ? 0 : levels[index - 1].endValue)
        const endX = scale(level.endValue)
        const active = x <= endX && (x > startX || index === 0)
        const fillColor = d3.color(level.color)
        active && (activeColor = d3.hsl(level.color))
        fillColor.opacity = active ? 0.4 : 0.15
        return (
          <React.Fragment key={`level-${index}`}>
            <rect
              style={{ fill: fillColor, stroke: "gray", strokeWidth: 1 }}
              y={0}
              x={startX}
              height={Math.max(0, containerHeight - 11)}
              width={Math.max(0, endX - startX)}
            />
            <Text
              fill={active ? "black" : "gray"}
              fontWeight={active ? "bold" : "normal"}
              x={startX + 2}
              y={2}
              style={{ pointerEvents: "none" }}
              width={endX - startX - 4}
              verticalAnchor="start"
            >
              {level.label}
            </Text>
          </React.Fragment>
        )
      })}
      {values?.map((xValue, index) => (
        <g
          transform={`translate(${scale(xValue)} ${scaleYPosition})`}
          key={`values-${index}-${xValue}`}
        >
          <path
            d="M -10,-10 L 10,10 M 10,-10 L -10,10"
            style={{
              stroke: "black",
              fill: "black",
              strokeWidth: 2
            }}
          />
        </g>
      ))}

      {values?.length > 1 && (
        <g transform={`translate(0 ${scaleYPosition})`}>
          <line
            x1={scale(valuesStats.min)}
            y1="-15"
            x2={scale(valuesStats.min)}
            y2="15"
            style={{ stroke: "black", strokeWidth: 3 }}
          />
          <line
            x1={scale(valuesStats.max)}
            y1="-15"
            x2={scale(valuesStats.max)}
            y2="15"
            style={{ stroke: "black", strokeWidth: 3 }}
          />
          <line
            x1={scale(valuesStats.min)}
            y1="0"
            x2={scale(valuesStats.max)}
            y2="0"
            style={{ stroke: "black", strokeWidth: 3 }}
          />
        </g>
      )}

      {values?.length > 0 && (
        <g transform={`translate(0 ${scaleYPosition})`}>
          <circle
            cx={scale(valuesStats.avg)}
            r="10"
            style={{
              stroke: valuesStats.avgColor,
              strokeWidth: 7
            }}
          />
          <text
            x={scale(valuesStats.avg) - 22}
            y={25}
            style={{ pointerEvents: "none" }}
          >
            avg:{" "}
            {Number(valuesStats.avg).toFixed(value < scale.domain()[1] ? 1 : 0)}
          </text>
        </g>
      )}
      <g ref={axisRef} transform={`translate(0 ${scaleYPosition})`} />

      {onChange && (
        <g ref={cursorRef}>
          <polygon
            points="0,0 13,13 13,30 -13,30 -13,13"
            style={{
              stroke: "gray",
              fill: "" + activeColor,
              strokeWidth: 1,
              cursor: readonly ? null : "pointer"
            }}
          />
          <text
            fill={activeColor?.l < 0.5 ? "white" : "black"}
            fontWeight="bold"
            x={-11}
            y={25}
            style={{ pointerEvents: "none" }}
          >
            {Number(value).toFixed(value < scale.domain()[1] ? 1 : 0)}
          </text>
        </g>
      )}
    </svg>
  )
}

LikertScale.propTypes = {
  value: PropTypes.number,
  values: PropTypes.arrayOf(PropTypes.number),
  onChange: PropTypes.func,
  levels: PropTypes.arrayOf(
    PropTypes.shape({
      color: PropTypes.string,
      endValue: PropTypes.number.isRequired,
      tooltip: PropTypes.string,
      label: PropTypes.string
    })
  ).isRequired,
  width: PropTypes.string.isRequired,
  height: PropTypes.string.isRequired,
  readonly: PropTypes.bool
}

LikertScale.defaultProps = {
  value: 0,
  levels: [
    {
      color: "red",
      endValue: 3
    },
    {
      color: "#FFBF00",
      endValue: 7
    },
    {
      color: "green",
      endValue: 10
    }
  ],
  height: "65",
  width: "100%"
}

export default LikertScale
<|endoftext|>


<commit_before>import { server as config } from './config';
import express from 'express';
import bodyParser from 'body-parser';
import serveStatic from 'serve-static';
import cors from 'cors';
import NotifyCondition from './lib/fiware/NotifyCondition';
import ContextBroker from './lib/fiware/ContextBroker';

// setup context broker
const contextBroker = new ContextBroker({
	url: config.brokerUrl
});

// create APP
const app = express();

// allow cors from all requests
app.use(cors());

// use json body parser
app.use(bodyParser.json());

// serve static files from apps
app.use(serveStatic('apps', {
	index: 'index.html'
}));

// provide some helpful information on default route
app.get('/', (req, res) => {
	logRequest(req);

	res.send(`

Fiware test server

Supported methods

				GET /
				- displays this help information

				GET /setup
				- setups test data for empty context broker

				PUT /update/:entity/:attribute
			- updates given entity attribute with value defined in body json "value"

				GET /info/:id
				- displays entity info

				POST /mirror
				- renders requested JSON request in response and in console

				POST /aggregate/:valueAttributeName/:historyAttributeName/:maxHistoryEntries
				- aggregates changed values to an array of last values

Examples

				GET /setup
				- creates the initial test entity or resets it if already exists

				PUT /update/lab/brightness {"value": 50}
				- updates lab brightness to 50 percent

				GET /info/lab
				- display lab information

Apps

				GET /chart
				- displays live brightness chart from FIWARE, updated by a wireless Arduino YUN device.

	`);
});

// sets up the test data
app.get('/setup', (req, res) => {
	logRequest(req);

	const id = 'lab';
	const type = 'room';
	const attributes = [{
		name: 'brightness',
		type: 'float',
		value: '0'
	}, {
		name: 'brightness-history',
		type: 'array',
		value: '[]'
	}, {
		name: 'brightness-count',
		type: 'number',
		value: '0'
	}];

	contextBroker
		.createEntity(id, type, attributes)
		.then(handleQueryResponse())

		.then(contextBroker.createSubscription({
			entities: [{
				type: type,
				isPattern: false,
				id: id
			}],
			attributes: [
				'brightness',
				'brightness-history',
				'brightness-count'
			],
			reference: 'http://localhost:1028/aggregate/brightness',
			duration: 'P1M',
			notifyConditions: [{
				type: NotifyCondition.ONCHANGE,
				condValues: ['brightness']
			}],
			throttling: 'PT5S'
		}))
		.then(handleQueryResponse(req, res))

		.catch(handleQueryError(req, res));
});

// provide test method
app.get('/info/:id', (req, res) => {
	logRequest(req);

	const id = req.params.id;

	contextBroker.fetchEntity(id)
		.then(handleQueryResponse(req, res))
		.catch(handleQueryError(req, res));
});

// update given entity attribute
app.put('/update/:entity/:attribute', (req, res) => {
	logRequest(req);

	const entity = req.params.entity;
	const attribute = req.params.attribute;
	const value = req.body.value;

	contextBroker.updateEntityAttribute(entity, attribute, value)
		.then(handleQueryResponse(req, res))
		.catch(handleQueryError(req, res));
});

// aggregates entity values
app.post('/aggregate/:valueAttributeName', (req, res) => {
	logRequest(req);

	const valueAttributeName = req.params.valueAttributeName;
	const historyAttributeName = valueAttributeName + '-history';
	const countAttributeName = valueAttributeName + '-count';
	const maxHistoryEntries = 100;

	const info = req.body;

	info.contextResponses.forEach((contextResponse) => {
		const contextElement = contextResponse.contextElement;
		const attributes = contextElement.attributes;
		const valueAttribute = findAttribute(valueAttributeName, attributes, true);
		const historyAttribute = findAttribute(historyAttributeName, attributes, true);
		const countAttribute = findAttribute(countAttributeName, attributes, true);

		// add new value
		historyAttribute.value.push(valueAttribute.value);

		// increment counter
		countAttribute.value = Number.parseInt(countAttribute.value, 10) + 1;

		// limit to last maxHistoryEntries values
		while (historyAttribute.value.length > maxHistoryEntries) {
			historyAttribute.value.shift();
		}

		// update entity attributes
		contextBroker.updateEntityAttributes(contextElement.id, {
			[historyAttributeName]: historyAttribute.value,
			[countAttributeName]: countAttribute.value
		})
			.then(handleQueryResponse(req, res))
			.catch(handleQueryError(req, res));
	});
});

// accept POST request and just mirror the data back
app.post('/mirror', (req, res) => {
	logRequest(req);

	res.send(formatJsonResponse('got request', req.body));
});

// start the server
app.listen(config.port, () => {
	console.log('server started on port ' + config.port);
});

// logs the request info to console
function logRequest(req) {
	console.log(req.method + ' ' + req.url + '\n' + JSON.stringify(req.body, null, '  ') + '\n\n');
}

// handles query response
function handleQueryResponse(req, res) {
	return (response) => {
		if (res) {
			res.json(response);
		}

		return response;
	};
}

// handles query error
function handleQueryError(req, res) {
	return (response) => {
		if (res) {
			res.json(response);
		}

		return response;
	};
}

// formats JSON response to HTML
function formatJsonResponse(name, response) {
	const responseText = JSON.stringify(response, null, '\t');

	return `

${name}

${responseText}

	`;
}

// searches for an attribute from an array of attributes by name, returns null if not found
function findAttribute(name, attributes, isRequired = false) {
	const attribute = attributes.find((item) => item.name === name);

	if (!attribute) {
		if (isRequired) {
			throw new Error('Attribute called "' + name + '" could not be found in ' + JSON.stringify(attributes));
		}

		return null;
	}

	return parseAttribute(attribute);
}

// parses attribute value by type
function parseAttribute(attribute) {
	switch (attribute.type) {
		case 'integer':
			attribute.value = Number.parseInt(attribute.value, 10);
			break;

		case 'float':
			attribute.value = Number.parseFloat(attribute.value);
			break;

		case 'array':
			attribute.value = JSON.parse(attribute.value);
			break;

		default:
			// do not change anything
	}

	return attribute;
}<commit_msg>Improved server logic.<commit_after>import { server as config } from './config';
import express from 'express';
import bodyParser from 'body-parser';
import serveStatic from 'serve-static';
import cors from 'cors';
import NotifyCondition from './lib/fiware/NotifyCondition';
import ContextBroker from './lib/fiware/ContextBroker';

// setup context broker
const contextBroker = new ContextBroker({
	url: config.brokerUrl
});

// create APP
const app = express();

// allow cors from all requests
app.use(cors());

// use json body parser
app.use(bodyParser.json());

// serve static files from apps
app.use(serveStatic('apps', {
	index: 'index.html'
}));

// provide some helpful information on default route
app.get('/', (req, res) => {
	logRequest(req);

	res.send(`

Fiware test server

Supported methods

				GET /
				- displays this help information

				GET /setup
				- setups test data for empty context broker

				PUT /update/:entity/:attribute
			- updates given entity attribute with value defined in body json "value"

				GET /info/:id
				- displays entity info

				POST /mirror
				- renders requested JSON request in response and in console

				POST /aggregate/:valueAttributeName/:historyAttributeName/:maxHistoryEntries
				- aggregates changed values to an array of last values

Examples

				GET /setup
				- creates the initial test entity or resets it if already exists

				PUT /update/lab/brightness {"value": 50}
				- updates lab brightness to 50 percent

				GET /info/lab
				- display lab information

Apps

				GET /chart
				- displays live brightness chart from FIWARE, updated by a wireless Arduino YUN device.

	`);
});

// sets up the test data
app.get('/setup', (req, res) => {
	logRequest(req);

	const id = 'lab';
	const type = 'room';
	const attributes = [{
		name: 'brightness',
		type: 'float',
		value: '0'
	}, {
		name: 'brightness-history',
		type: 'array',
		value: '[]'
	}, {
		name: 'brightness-count',
		type: 'number',
		value: '0'
	}];

	contextBroker
		.createEntity(id, type, attributes)
		.then(handleQueryResponse())

		.then(contextBroker.createSubscription({
			entities: [{
				type: type,
				isPattern: false,
				id: id
			}],
			attributes: [
				'brightness',
				'brightness-history',
				'brightness-count'
			],
			reference: 'http://localhost:1028/aggregate/brightness',
			duration: 'P1M',
			notifyConditions: [{
				type: NotifyCondition.ONCHANGE,
				condValues: ['brightness']
			}],
			throttling: 'PT5S'
		}))
		.then(handleQueryResponse(req, res))

		.catch(handleQueryError(req, res));
});

// provide test method
app.get('/info/:id', (req, res) => {
	logRequest(req);

	const id = req.params.id;

	contextBroker.fetchEntity(id)
		.then(handleQueryResponse(req, res))
		.catch(handleQueryError(req, res));
});

// update given entity attribute
app.put('/update/:entity/:attribute', (req, res) => {
	logRequest(req);

	const entity = req.params.entity;
	const attribute = req.params.attribute;
	const value = req.body.value;

	contextBroker.updateEntityAttribute(entity, attribute, value)
		.then(handleQueryResponse(req, res))
		.catch(handleQueryError(req, res));
});

// aggregates entity values
app.post('/aggregate/:valueAttributeName', (req, res) => {
	logRequest(req);

	const valueAttributeName = req.params.valueAttributeName;
	const historyAttributeName = valueAttributeName + '-history';
	const countAttributeName = valueAttributeName + '-count';
	const maxHistoryEntries = 100;

	const info = req.body;

	info.contextResponses.forEach((contextResponse) => {
		const contextElement = contextResponse.contextElement;
		const attributes = contextElement.attributes;
		const valueAttribute = findAttribute(valueAttributeName, attributes, true);
		const historyAttribute = findAttribute(historyAttributeName, attributes, true);
		const countAttribute = findAttribute(countAttributeName, attributes, true);

		console.log('aggregating', valueAttribute.value, typeof valueAttribute.value, historyAttribute.value, typeof historyAttribute.value);

		// add new value
		historyAttribute.value.push(valueAttribute.value);

		// increment counter
		countAttribute.value = Number.parseInt(countAttribute.value, 10) + 1;

		// limit to last maxHistoryEntries values
		while (historyAttribute.value.length > maxHistoryEntries) {
			historyAttribute.value.shift();
		}

		// update entity attributes
		contextBroker.updateEntityAttributes(contextElement.id, {
			[historyAttributeName]: historyAttribute.value,
			[countAttributeName]: countAttribute.value
		})
			.then(handleQueryResponse(req, res))
			.catch(handleQueryError(req, res));
	});
});

// accept POST request and just mirror the data back
app.post('/mirror', (req, res) => {
	logRequest(req);

	res.send(formatJsonResponse('got request', req.body));
});

// start the server
app.listen(config.port, () => {
	console.log('server started on port ' + config.port);
});

// logs the request info to console
function logRequest(req) {
	console.log(req.method + ' ' + req.url + '\n' + JSON.stringify(req.body, null, '  ') + '\n\n');
}

// handles query response
function handleQueryResponse(req, res) {
	return (response) => {
		if (res) {
			res.json(response);
		}

		return response;
	};
}

// handles query error
function handleQueryError(req, res) {
	return (response) => {
		if (res) {
			res.json(response);
		}

		return response;
	};
}

// formats JSON response to HTML
function formatJsonResponse(name, response) {
	const responseText = JSON.stringify(response, null, '\t');

	return `

${name}

${responseText}

	`;
}

// searches for an attribute from an array of attributes by name, returns null if not found
function findAttribute(name, attributes, isRequired = false) {
	const attribute = attributes.find((item) => item.name === name);

	if (!attribute) {
		if (isRequired) {
			throw new Error('Attribute called "' + name + '" could not be found in ' + JSON.stringify(attributes));
		}

		return null;
	}

	return parseAttribute(attribute);
}

// parses attribute value by type
function parseAttribute(attribute) {
	switch (attribute.type) {
		case 'integer':
			attribute.value = Number.parseInt(attribute.value, 10);

			if (Number.isNaN(attribute.value)) {
				console.error('parsing "' + attribute.value + '" as an integer failed, using zero');

				attribute.value = 0;
			}

			break;

		case 'float':
			attribute.value = Number.parseFloat(attribute.value);

			if (Number.isNaN(attribute.value)) {
				console.error('parsing "' + attribute.value + '" as a float failed, using zero');

				attribute.value = 0;
			}

			break;

		case 'array':
			try {
				attribute.value = JSON.parse(attribute.value);
			} catch (e) {
				console.error('parsing "' + attribute.value + '" as an array failed, using empty array');

				attribute.value = [];
			}
			break;

		default:
			// do not change anything
	}

	return attribute;
}<|endoftext|>


<commit_before>// Function to load and initiate the Analytics tracker
function gaTracker(id){
  $.getScript('//www.google-analytics.com/analytics.js'); // jQuery shortcut
  window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
  ga('create', id, 'auto');
  ga('send', 'pageview');
}

// Function to track a virtual page view
function gaTrack(path, title) {
  ga('set', { page: path, title: title });
  ga('send', 'pageview');
}

// Initiate the tracker after app has loaded
gaTracker('UA-69304119-1');

// Track a virtual page
gaTrack('/', 'Accueil');
gaTrack('/index.html', 'Accueil');
gaTrack('/legroupe.html', 'Le groupe');
gaTrack('/concerts.html', 'Concerts');
gaTrack('/albums.html', 'Albums');
gaTrack('/ateliers.html', 'Ateliers');
gaTrack('/presse.html', 'Presse');
gaTrack('/contact.html', 'Contact');
gaTrack('/404.html', '404');

// Track an event on contact button click
$('#contactbutton').click(function() {
  ga('send', 'event', 'Contact', 'click', 'contact button click');
});
<commit_msg>Add a test to configure GA event tracking<commit_after>// Function to load and initiate the Analytics tracker
function gaTracker(id){
  $.getScript('//www.google-analytics.com/analytics.js'); // jQuery shortcut
  window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
  ga('create', id, 'auto');
  ga('send', 'pageview');
}

// Function to track a virtual page view
function gaTrack(path, title) {
  ga('set', { page: path, title: title });
  ga('send', 'pageview');
}

// Initiate the tracker after app has loaded
gaTracker('UA-69304119-1');

// Track a virtual page
gaTrack('/', 'Accueil');
gaTrack('/index.html', 'Accueil');
gaTrack('/legroupe.html', 'Le groupe');
gaTrack('/concerts.html', 'Concerts');
gaTrack('/albums.html', 'Albums');
gaTrack('/ateliers.html', 'Ateliers');
gaTrack('/presse.html', 'Presse');
gaTrack('/contact.html', 'Contact');
gaTrack('/404.html', '404');

// Event tracking on contact button click
$('#contactbutton').click(function() {
  ga('send', {
    hitType: 'event',
    eventCategory: 'Contact',
    eventAction: 'click',
    eventLabel: 'contact button click'
  });
});
<|endoftext|>


<commit_before>import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import SearchInput from 'components/Texts/SearchInput';
import { connect } from 'react-redux';
import {
  clearUserSearch,
  fetchUsers,
  fetchMoreUsers,
  searchUsers
} from 'redux/actions/UserActions';
import ProfilePanel from 'components/ProfilePanel';
import LoadMoreButton from 'components/Buttons/LoadMoreButton';
import Loading from 'components/Loading';
import { addEvent, removeEvent } from 'helpers/listenerHelpers';
import { stringIsEmpty, queryStringForArray } from 'helpers/stringHelpers';
import { css } from 'emotion';
import { Color, mobileMaxWidth } from 'constants/css';

People.propTypes = {
  chatMode: PropTypes.bool.isRequired,
  clearUserSearch: PropTypes.func.isRequired,
  fetchMoreUsers: PropTypes.func.isRequired,
  fetchUsers: PropTypes.func.isRequired,
  history: PropTypes.object.isRequired,
  loadMoreButton: PropTypes.bool,
  profiles: PropTypes.array.isRequired,
  searchedProfiles: PropTypes.array.isRequired,
  searchMode: PropTypes.bool.isRequired,
  searchUsers: PropTypes.func.isRequired,
  userId: PropTypes.number
};

function People({
  chatMode,
  clearUserSearch,
  fetchUsers,
  fetchMoreUsers,
  history,
  loadMoreButton,
  profiles,
  userId,
  searchedProfiles,
  searchMode,
  searchUsers
}) {
  const [searchText, setSearchText] = useState('');
  const [loading, setLoading] = useState(false);
  const [loaded, setLoaded] = useState(false);
  const [searching, setSearching] = useState(false);

  const mounted = useRef(true);
  const BodyRef = useRef(document.scrollingElement || document.documentElement);
  const scrollHeightRef = useRef(0);
  const scrollPositionRef = useRef({ desktop: 0, mobile: 0 });
  const timerRef = useRef(null);

  useEffect(() => {
    init();
    async function init() {
      if (history.action === 'PUSH' || profiles.length === 0) {
        await fetchUsers();
        setLoaded(true);
      }
    }
  }, []);

  useEffect(() => {
    if (loading) {
      loadMoreProfiles();
    }
  }, [loading]);

  useEffect(() => {
    if (searchedProfiles.length > 0) {
      setSearching(false);
    }
  }, [searchedProfiles]);

  useEffect(() => {
    mounted.current = true;
    if (mounted.current) {
      addEvent(window, 'scroll', onScroll);
      addEvent(document.getElementById('App'), 'scroll', onScroll);
    }

    return function cleanUp() {
      mounted.current = false;
      clearUserSearch();
      removeEvent(window, 'scroll', onScroll);
      removeEvent(document.getElementById('App'), 'scroll', onScroll);
    };
  }, [chatMode, profiles, searchMode, searchText]);

  return (

      <SearchInput
        className={css`
          @media (max-width: ${mobileMaxWidth}) {
            margin-top: 1rem;
          }
        `}
        style={{ zIndex: 0 }}
        addonColor={Color.gold()}
        placeholder="Search for users"
        onChange={onPeopleSearch}
        value={searchText}
      />

        {(!loaded || (!stringIsEmpty(searchText) && searching)) && (
          <Loading text={`${searching ? 'Searching' : 'Loading'} Users...`} />
        )}
        {loaded &&
          stringIsEmpty(searchText) &&
          profiles.map(profile => (
            <ProfilePanel
              expandable
              key={profile.id}
              userId={userId}
              profile={profile}
            />
          ))}
        {!stringIsEmpty(searchText) &&
          !searching &&
          searchedProfiles.map(profile => (
            <ProfilePanel
              expandable
              key={profile.id}
              userId={userId}
              profile={profile}
            />
          ))}
        {stringIsEmpty(searchText) && loaded && loadMoreButton && (
          <LoadMoreButton
            filled
            info
            onClick={loadMoreProfiles}
            loading={loading}
          />
        )}

  );

  async function loadMoreProfiles() {
    setLoading(true);
    await fetchMoreUsers(
      queryStringForArray({
        array: profiles,
        originVar: 'id',
        destinationVar: 'shownUsers'
      })
    );
    setLoading(false);
  }

  function onPeopleSearch(text) {
    clearTimeout(timerRef.current);
    setSearchText(text);
    if (stringIsEmpty(text)) {
      return clearUserSearch();
    } else {
      setSearching(true);
    }
    timerRef.current = setTimeout(() => searchUsers(text), 300);
  }

  function onScroll() {
    if (
      document.getElementById('App').scrollHeight > scrollHeightRef.current ||
      BodyRef.current.scrollTop > scrollHeightRef.current
    ) {
      scrollHeightRef.current = Math.max(
        document.getElementById('App').scrollHeight,
        BodyRef.current.scrollTop
      );
    }
    if (
      !chatMode &&
      !searchMode &&
      profiles.length > 0 &&
      stringIsEmpty(searchText) &&
      scrollHeightRef.current !== 0
    ) {
      scrollPositionRef.current = {
        desktop: document.getElementById('App').scrollTop,
        mobile: BodyRef.current.scrollTop
      };
      if (
        (scrollPositionRef.current.desktop >=
          scrollHeightRef.current - window.innerHeight - 1000 ||
          scrollPositionRef.current.mobile >=
            scrollHeightRef.current - window.innerHeight - 1000) &&
        loadMoreButton
      ) {
        setLoading(true);
      }
    }
  }
}

export default connect(
  state => ({
    chatMode: state.ChatReducer.chatMode,
    loadMoreButton: state.UserReducer.loadMoreButton,
    profiles: state.UserReducer.profiles,
    searchMode: state.SearchReducer.searchMode,
    searchedProfiles: state.UserReducer.searchedProfiles,
    userId: state.UserReducer.userId
  }),
  {
    clearUserSearch,
    fetchUsers,
    fetchMoreUsers,
    searchUsers
  }
)(People);
<commit_msg>minor fix<commit_after>import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import SearchInput from 'components/Texts/SearchInput';
import { connect } from 'react-redux';
import {
  clearUserSearch,
  fetchUsers,
  fetchMoreUsers,
  searchUsers
} from 'redux/actions/UserActions';
import ProfilePanel from 'components/ProfilePanel';
import LoadMoreButton from 'components/Buttons/LoadMoreButton';
import Loading from 'components/Loading';
import { addEvent, removeEvent } from 'helpers/listenerHelpers';
import { stringIsEmpty, queryStringForArray } from 'helpers/stringHelpers';
import { css } from 'emotion';
import { Color, mobileMaxWidth } from 'constants/css';

People.propTypes = {
  chatMode: PropTypes.bool.isRequired,
  clearUserSearch: PropTypes.func.isRequired,
  fetchMoreUsers: PropTypes.func.isRequired,
  fetchUsers: PropTypes.func.isRequired,
  history: PropTypes.object.isRequired,
  loadMoreButton: PropTypes.bool,
  profiles: PropTypes.array.isRequired,
  searchedProfiles: PropTypes.array.isRequired,
  searchMode: PropTypes.bool.isRequired,
  searchUsers: PropTypes.func.isRequired,
  userId: PropTypes.number
};

function People({
  chatMode,
  clearUserSearch,
  fetchUsers,
  fetchMoreUsers,
  history,
  loadMoreButton,
  profiles,
  userId,
  searchedProfiles,
  searchMode,
  searchUsers
}) {
  const [searchText, setSearchText] = useState('');
  const [loading, setLoading] = useState(false);
  const [loaded, setLoaded] = useState(false);
  const [searching, setSearching] = useState(false);

  const mounted = useRef(true);
  const BodyRef = useRef(document.scrollingElement || document.documentElement);
  const scrollHeightRef = useRef(0);
  const scrollPositionRef = useRef({ desktop: 0, mobile: 0 });
  const timerRef = useRef(null);

  useEffect(() => {
    init();
    async function init() {
      if (history.action === 'PUSH' || profiles.length === 0) {
        await fetchUsers();
        setLoaded(true);
      }
    }
  }, []);

  useEffect(() => {
    if (loading) {
      loadMoreProfiles();
    }
  }, [loading]);

  useEffect(() => {
    setSearching(false);
  }, [searchedProfiles]);

  useEffect(() => {
    mounted.current = true;
    if (mounted.current) {
      addEvent(window, 'scroll', onScroll);
      addEvent(document.getElementById('App'), 'scroll', onScroll);
    }

    return function cleanUp() {
      mounted.current = false;
      clearUserSearch();
      removeEvent(window, 'scroll', onScroll);
      removeEvent(document.getElementById('App'), 'scroll', onScroll);
    };
  }, [chatMode, profiles, searchMode, searchText]);

  return (

      <SearchInput
        className={css`
          @media (max-width: ${mobileMaxWidth}) {
            margin-top: 1rem;
          }
        `}
        style={{ zIndex: 0 }}
        addonColor={Color.gold()}
        placeholder="Search for users"
        onChange={onPeopleSearch}
        value={searchText}
      />

        {(!loaded || searching) && (
          <Loading text={`${searching ? 'Searching' : 'Loading'} Users...`} />
        )}
        {loaded &&
          stringIsEmpty(searchText) &&
          profiles.map(profile => (
            <ProfilePanel
              expandable
              key={profile.id}
              userId={userId}
              profile={profile}
            />
          ))}
        {!stringIsEmpty(searchText) &&
          !searching &&
          searchedProfiles.map(profile => (
            <ProfilePanel
              expandable
              key={profile.id}
              userId={userId}
              profile={profile}
            />
          ))}
        {stringIsEmpty(searchText) && loaded && loadMoreButton && (
          <LoadMoreButton
            filled
            info
            onClick={loadMoreProfiles}
            loading={loading}
          />
        )}

  );

  async function loadMoreProfiles() {
    setLoading(true);
    await fetchMoreUsers(
      queryStringForArray({
        array: profiles,
        originVar: 'id',
        destinationVar: 'shownUsers'
      })
    );
    setLoading(false);
  }

  function onPeopleSearch(text) {
    clearTimeout(timerRef.current);
    setSearchText(text);
    if (stringIsEmpty(text)) {
      return clearUserSearch();
    } else {
      setSearching(true);
    }
    timerRef.current = setTimeout(() => searchUsers(text), 300);
  }

  function onScroll() {
    if (
      document.getElementById('App').scrollHeight > scrollHeightRef.current ||
      BodyRef.current.scrollTop > scrollHeightRef.current
    ) {
      scrollHeightRef.current = Math.max(
        document.getElementById('App').scrollHeight,
        BodyRef.current.scrollTop
      );
    }
    if (
      !chatMode &&
      !searchMode &&
      profiles.length > 0 &&
      stringIsEmpty(searchText) &&
      scrollHeightRef.current !== 0
    ) {
      scrollPositionRef.current = {
        desktop: document.getElementById('App').scrollTop,
        mobile: BodyRef.current.scrollTop
      };
      if (
        (scrollPositionRef.current.desktop >=
          scrollHeightRef.current - window.innerHeight - 1000 ||
          scrollPositionRef.current.mobile >=
            scrollHeightRef.current - window.innerHeight - 1000) &&
        loadMoreButton
      ) {
        setLoading(true);
      }
    }
  }
}

export default connect(
  state => ({
    chatMode: state.ChatReducer.chatMode,
    loadMoreButton: state.UserReducer.loadMoreButton,
    profiles: state.UserReducer.profiles,
    searchMode: state.SearchReducer.searchMode,
    searchedProfiles: state.UserReducer.searchedProfiles,
    userId: state.UserReducer.userId
  }),
  {
    clearUserSearch,
    fetchUsers,
    fetchMoreUsers,
    searchUsers
  }
)(People);
<|endoftext|>


<commit_before>/**
 *  @file   config.js
 *  @author  Victor M. Rivas Santos <vrivas@ujaen.es>
 *  @date    22-Jun-2015 , 13:47
 *  @desc    Specific server's configuration
 *
 *  -------------------------------------
 *  GeNeura Team (http://geneura.ugr.es)
 */

var GLOBALS = {
    "ipaddress": process.env.OPENSHIFT_NODEJS_IP || "150.214.178.89"
    , "keepAliveSeconds": 80 // Periodicity for KEEP ALIVE messages to be sent
    , "milliSecs": 5*1000 // Periodicity changin problem
    , "port": process.env.OPENSHIFT_NODEJS_PORT || 8080
}
<commit_msg>Setting 127.0.0.1 and 8080by default<commit_after>/**
 *  @file   config.js
 *  @author  Victor M. Rivas Santos <vrivas@ujaen.es>
 *  @date    22-Jun-2015 , 13:47
 *  @desc    Specific server's configuration
 *
 *  -------------------------------------
 *  GeNeura Team (http://geneura.ugr.es)
 */

var GLOBALS = {
    "ipaddress": "127.0.0.1" || process.env.OPENSHIFT_NODEJS_IP
    , "keepAliveSeconds": 80 // Periodicity for KEEP ALIVE messages to be sent
    , "milliSecs": 5*1000 // Periodicity changin problem
    , "port": 8080 || process.env.OPENSHIFT_NODEJS_PORT
}
<|endoftext|>


<commit_before>(function () {

var _ = Flotr._;

function getEl (el) {
  return (el && el.jquery) ? el[0] : el;
}

Flotr.DOM = {
  addClass: function(element, name){
    element = getEl(element);
    var classList = (element.className ? element.className : '');
      if (_.include(classList.split(/\s+/g), name)) return;
    element.className = (classList ? classList + ' ' : '') + name;
  },
  /**
   * Create an element.
   */
  create: function(tag){
    return document.createElement(tag);
  },
  node: function(html) {
    var div = Flotr.DOM.create('div'), n;
    div.innerHTML = html;
    n = div.children[0];
    div.innerHTML = '';
    return n;
  },
  /**
   * Remove all children.
   */
  empty: function(element){
    element = getEl(element);
    element.innerHTML = '';
    /*
    if (!element) return;
    _.each(element.childNodes, function (e) {
      Flotr.DOM.empty(e);
      element.removeChild(e);
    });
    */
  },
  hide: function(element){
    element = getEl(element);
    Flotr.DOM.setStyles(element, {display:'none'});
  },
  /**
   * Insert a child.
   * @param {Element} element
   * @param {Element|String} Element or string to be appended.
   */
  insert: function(element, child){
    element = getEl(element);
    if(_.isString(child))
      element.innerHTML += child;
    else if (_.isElement(child))
      element.appendChild(child);
  },
  // @TODO find xbrowser implementation
  opacity: function(element, opacity) {
    element = getEl(element);
    element.style.opacity = opacity;
  },
  position: function(element, p){
    element = getEl(element);
    if (!element.offsetParent)
      return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)};

    p = this.position(element.offsetParent);
    p.left  += element.offsetLeft;
    p.top   += element.offsetTop;
    return p;
  },
  removeClass: function(element, name) {
    var classList = (element.className ? element.className : '');
    element = getEl(element);
    element.className = _.filter(classList.split(/\s+/g), function (c) {
      if (c != name) return true; }
    ).join(' ');
  },
  setStyles: function(element, o) {
    element = getEl(element);
    _.each(o, function (value, key) {
      element.style[key] = value;
    });
  },
  show: function(element){
    element = getEl(element);
    Flotr.DOM.setStyles(element, {display:''});
  },
  /**
   * Return element size.
   */
  size: function(element){
    element = getEl(element);
    return {
      height : element.offsetHeight,
      width : element.offsetWidth };
  }
};

})();
<commit_msg>Added remove method to DOM library.<commit_after>(function () {

var _ = Flotr._;

function getEl (el) {
  return (el && el.jquery) ? el[0] : el;
}

Flotr.DOM = {
  addClass: function(element, name){
    element = getEl(element);
    var classList = (element.className ? element.className : '');
      if (_.include(classList.split(/\s+/g), name)) return;
    element.className = (classList ? classList + ' ' : '') + name;
  },
  /**
   * Create an element.
   */
  create: function(tag){
    return document.createElement(tag);
  },
  node: function(html) {
    var div = Flotr.DOM.create('div'), n;
    div.innerHTML = html;
    n = div.children[0];
    div.innerHTML = '';
    return n;
  },
  /**
   * Remove all children.
   */
  empty: function(element){
    element = getEl(element);
    element.innerHTML = '';
    /*
    if (!element) return;
    _.each(element.childNodes, function (e) {
      Flotr.DOM.empty(e);
      element.removeChild(e);
    });
    */
  },
  remove: function (element) {
    element = getEl(element);
    element.parentNode.removeChild(element);
  },
  hide: function(element){
    element = getEl(element);
    Flotr.DOM.setStyles(element, {display:'none'});
  },
  /**
   * Insert a child.
   * @param {Element} element
   * @param {Element|String} Element or string to be appended.
   */
  insert: function(element, child){
    element = getEl(element);
    if(_.isString(child))
      element.innerHTML += child;
    else if (_.isElement(child))
      element.appendChild(child);
  },
  // @TODO find xbrowser implementation
  opacity: function(element, opacity) {
    element = getEl(element);
    element.style.opacity = opacity;
  },
  position: function(element, p){
    element = getEl(element);
    if (!element.offsetParent)
      return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)};

    p = this.position(element.offsetParent);
    p.left  += element.offsetLeft;
    p.top   += element.offsetTop;
    return p;
  },
  removeClass: function(element, name) {
    var classList = (element.className ? element.className : '');
    element = getEl(element);
    element.className = _.filter(classList.split(/\s+/g), function (c) {
      if (c != name) return true; }
    ).join(' ');
  },
  setStyles: function(element, o) {
    element = getEl(element);
    _.each(o, function (value, key) {
      element.style[key] = value;
    });
  },
  show: function(element){
    element = getEl(element);
    Flotr.DOM.setStyles(element, {display:''});
  },
  /**
   * Return element size.
   */
  size: function(element){
    element = getEl(element);
    return {
      height : element.offsetHeight,
      width : element.offsetWidth };
  }
};

})();
<|endoftext|>


<commit_before>class SelectItemsService {
    /*@ngInject*/
    constructor($mdDialog, projectsAPI, experimentsAPI, projectFileTreeAPI, mcprojstore) {
        this.$mdDialog = $mdDialog;
        this.projectsAPI = projectsAPI;
        this.experimentsAPI = experimentsAPI;
        this.projectFileTreeAPI = projectFileTreeAPI;
        this.mcprojstore = mcprojstore;
    }

    dialog(locals, controller) {
        return this.$mdDialog.show({
            templateUrl: 'app/modals/select-items-dialog.html',
            controller: controller,
            controllerAs: '$ctrl',
            bindToController: true,
            clickOutsideToClose: true,
            multiple: true,
            locals: locals
        });
    }

    fileTree(uploadFiles = false) {
        let project = this.mcprojstore.currentProject;
        return this.projectFileTreeAPI.getProjectRoot(project.id).then(
            files => {
                project.files = files;
                return this.dialog({
                    showFileTree: true,
                    showFileTable: false,
                    uploadFiles,
                    project
                }, SelectItemsFilesServiceModalController);
            });
    }

    fileTreeForProject(projectId, uploadFiles = false) {
        return this.projectFileTreeAPI.getProjectRoot(projectId).then(
            files => {
                let project = {};
                project.files = files;
                return this.dialog({
                    showFileTree: true,
                    showFileTable: false,
                    uploadFiles,
                    project
                }, SelectItemsFilesServiceModalController);
            });
    }

    fileTable(files = [], uploadFiles = false) {
        return this.dialog({
            showFileTable: true,
            showFileTree: false,
            uploadFiles,
            files
        }, SelectItemsFilesServiceModalController);
    }

    samples(samples = [], singleSelection = false) {
        return this.dialog({samples, singleSelection}, SelectItemsSamplesServiceModalController);
    }

    samplesFromProject(projectId, showAllSamples = false, singleSelection = false) {
        let options = {
            singleSelection,
            showAllSamples
        };
        return this.projectsAPI.getProjectSamples(projectId).then(
            (samples) => this.dialog({samples, options}, SelectItemsSamplesServiceModalController)
        );
    }

    samplesFromExperiment(projectId, experimentId, singleSelection = false) {
        return this.experimentsAPI.getSamplesForExperiment(projectId, experimentId).then(
            (samples) => this.dialog({samples, singleSelection}, SelectItemsSamplesServiceModalController)
        );
    }

    processes(processes = []) {
        return this.dialog({processes}, SelectItemsProcessesServiceModalController);
    }

    processesFromProject(projectId) {
        return this.projectsAPI.getProjectProcesses(projectId).then(
            (processes) => this.dialog({processes}, SelectItemsProcessesServiceModalController)
        );
    }
}

class SelectItemsBase {
    constructor($mdDialog) {
        this.activeTab = 0;
        this.currentTab = '';
        this.tabs = [];
        this.$mdDialog = $mdDialog;
    }

    isActive(tab) {
        return this.activeTab === tab;
    }

    setActive(tabName) {
        this.activeTab = tabName;
    }

    addTab(name, icon) {
        this.tabs.push({name, icon});
        if (this.tabs.length === 1) {
            this.activeTab = this.tabs[0].name;
        }
    }

    cancel() {
        this.$mdDialog.cancel();
    }
}

class SelectItemsState {
    constructor() {
        this.uploadedFiles = [];
    }

    reset() {
        this.uploadedFiles = [];
    }
}

const selectItemsState = new SelectItemsState();

class SelectItemsSamplesServiceModalController extends SelectItemsBase {
    /*@ngInject*/
    constructor($mdDialog) {
        super($mdDialog);
        this.$onInit();
    }

    $onInit() {
        this.addTab('samples', 'fa-cubes');
    }

    ok() {
        let selectedSamples = this.samples.filter(s => {
            for (let i = 0; i < s.versions.length; i++) {
                if (s.versions[i].selected) {
                    return true;
                }
            }
            return false;
        });
        this.$mdDialog.hide({samples: selectedSamples});
    }
}

class SelectItemsProcessesServiceModalController extends SelectItemsBase {
    /*@ngInject*/
    constructor($mdDialog) {
        super($mdDialog);
        this.$onInit();
    }

    $onInit() {
        this.addTab('processes', 'fa-code-fork');
    }

    ok() {
        let selectedProcesses = this.processes.filter(p => p.input || p.output);
        this.$mdDialog.hide({processes: selectedProcesses});
    }
}

class SelectItemsFilesServiceModalController extends SelectItemsBase {
    /*@ngInject*/
    constructor($mdDialog) {
        super($mdDialog);
        this.$onInit();
    }

    $onInit() {
        selectItemsState.reset();
        if (this.showFileTable) {
            this.addTab('file table', 'fa-files-o');
        }

        if (this.showFileTree) {
            this.addTab('file tree', 'fa-files-o');
        }

        if (this.uploadFiles) {
            this.addTab('Upload Files', 'fa-upload');
        }
    }

    uploadComplete(files) {
        selectItemsState.uploadedFiles = files;
    }

    ok() {
        let selectedFiles = [];
        if (this.showFileTree) {
            selectedFiles = selectedFiles.concat(this.getFilesFromTree());
        }

        if (this.showFileTable) {
            selectedFiles = selectedFiles.concat(this.files.filter(f => f.selected));
        }

        if (this.uploadFiles) {
            selectedFiles = selectedFiles.concat(selectItemsState.uploadedFiles);
        }

        this.$mdDialog.hide({files: selectedFiles});
    }

    getFilesFromTree() {
        let filesFromTree = [];
        let projectFiles = this.project.files;
        if (projectFiles && projectFiles.length) {
            let treeModel = new TreeModel(),
                root = treeModel.parse(this.project.files[0]);
            // Walk the tree looking for selected files and adding them to the
            // list of files. Also reset the selected flag so the next time
            // the popup for files is used it doesn't show previously selected
            // items.
            root.walk({strategy: 'pre'}, function(node) {
                if (node.model.data.selected) {
                    node.model.data.selected = false;
                    if (node.model.data.otype === 'file') {
                        filesFromTree.push(node.model.data);
                    }
                }
            });
        }

        return filesFromTree;
    }
}

angular.module('materialscommons').service('selectItems', SelectItemsService);
<commit_msg>Use mcStateStore rather than mcprojstore<commit_after>class SelectItemsService {
    /*@ngInject*/
    constructor($mdDialog, projectsAPI, experimentsAPI, projectFileTreeAPI, mcStateStore) {
        this.$mdDialog = $mdDialog;
        this.projectsAPI = projectsAPI;
        this.experimentsAPI = experimentsAPI;
        this.projectFileTreeAPI = projectFileTreeAPI;
        this.mcStateStore = mcStateStore;
    }

    dialog(locals, controller) {
        return this.$mdDialog.show({
            templateUrl: 'app/modals/select-items-dialog.html',
            controller: controller,
            controllerAs: '$ctrl',
            bindToController: true,
            clickOutsideToClose: true,
            multiple: true,
            locals: locals
        });
    }

    fileTree(uploadFiles = false) {
        let project = this.mcStateStore.getState('project');
        return this.projectFileTreeAPI.getProjectRoot(project.id).then(
            files => {
                project.files = files;
                return this.dialog({
                    showFileTree: true,
                    showFileTable: false,
                    uploadFiles,
                    project
                }, SelectItemsFilesServiceModalController);
            });
    }

    fileTreeForProject(projectId, uploadFiles = false) {
        return this.projectFileTreeAPI.getProjectRoot(projectId).then(
            files => {
                let project = {};
                project.files = files;
                return this.dialog({
                    showFileTree: true,
                    showFileTable: false,
                    uploadFiles,
                    project
                }, SelectItemsFilesServiceModalController);
            });
    }

    fileTable(files = [], uploadFiles = false) {
        return this.dialog({
            showFileTable: true,
            showFileTree: false,
            uploadFiles,
            files
        }, SelectItemsFilesServiceModalController);
    }

    samples(samples = [], singleSelection = false) {
        return this.dialog({samples, singleSelection}, SelectItemsSamplesServiceModalController);
    }

    samplesFromProject(projectId, showAllSamples = false, singleSelection = false) {
        let options = {
            singleSelection,
            showAllSamples
        };
        return this.projectsAPI.getProjectSamples(projectId).then(
            (samples) => this.dialog({samples, options}, SelectItemsSamplesServiceModalController)
        );
    }

    samplesFromExperiment(projectId, experimentId, singleSelection = false) {
        return this.experimentsAPI.getSamplesForExperiment(projectId, experimentId).then(
            (samples) => this.dialog({samples, singleSelection}, SelectItemsSamplesServiceModalController)
        );
    }

    processes(processes = []) {
        return this.dialog({processes}, SelectItemsProcessesServiceModalController);
    }

    processesFromProject(projectId) {
        return this.projectsAPI.getProjectProcesses(projectId).then(
            (processes) => this.dialog({processes}, SelectItemsProcessesServiceModalController)
        );
    }
}

class SelectItemsBase {
    constructor($mdDialog) {
        this.activeTab = 0;
        this.currentTab = '';
        this.tabs = [];
        this.$mdDialog = $mdDialog;
    }

    isActive(tab) {
        return this.activeTab === tab;
    }

    setActive(tabName) {
        this.activeTab = tabName;
    }

    addTab(name, icon) {
        this.tabs.push({name, icon});
        if (this.tabs.length === 1) {
            this.activeTab = this.tabs[0].name;
        }
    }

    cancel() {
        this.$mdDialog.cancel();
    }
}

class SelectItemsState {
    constructor() {
        this.uploadedFiles = [];
    }

    reset() {
        this.uploadedFiles = [];
    }
}

const selectItemsState = new SelectItemsState();

class SelectItemsSamplesServiceModalController extends SelectItemsBase {
    /*@ngInject*/
    constructor($mdDialog) {
        super($mdDialog);
        this.$onInit();
    }

    $onInit() {
        this.addTab('samples', 'fa-cubes');
    }

    ok() {
        let selectedSamples = this.samples.filter(s => {
            for (let i = 0; i < s.versions.length; i++) {
                if (s.versions[i].selected) {
                    return true;
                }
            }
            return false;
        });
        this.$mdDialog.hide({samples: selectedSamples});
    }
}

class SelectItemsProcessesServiceModalController extends SelectItemsBase {
    /*@ngInject*/
    constructor($mdDialog) {
        super($mdDialog);
        this.$onInit();
    }

    $onInit() {
        this.addTab('processes', 'fa-code-fork');
    }

    ok() {
        let selectedProcesses = this.processes.filter(p => p.input || p.output);
        this.$mdDialog.hide({processes: selectedProcesses});
    }
}

class SelectItemsFilesServiceModalController extends SelectItemsBase {
    /*@ngInject*/
    constructor($mdDialog) {
        super($mdDialog);
        this.$onInit();
    }

    $onInit() {
        selectItemsState.reset();
        if (this.showFileTable) {
            this.addTab('file table', 'fa-files-o');
        }

        if (this.showFileTree) {
            this.addTab('file tree', 'fa-files-o');
        }

        if (this.uploadFiles) {
            this.addTab('Upload Files', 'fa-upload');
        }
    }

    uploadComplete(files) {
        selectItemsState.uploadedFiles = files;
    }

    ok() {
        let selectedFiles = [];
        if (this.showFileTree) {
            selectedFiles = selectedFiles.concat(this.getFilesFromTree());
        }

        if (this.showFileTable) {
            selectedFiles = selectedFiles.concat(this.files.filter(f => f.selected));
        }

        if (this.uploadFiles) {
            selectedFiles = selectedFiles.concat(selectItemsState.uploadedFiles);
        }

        this.$mdDialog.hide({files: selectedFiles});
    }

    getFilesFromTree() {
        let filesFromTree = [];
        let projectFiles = this.project.files;
        if (projectFiles && projectFiles.length) {
            let treeModel = new TreeModel(),
                root = treeModel.parse(this.project.files[0]);
            // Walk the tree looking for selected files and adding them to the
            // list of files. Also reset the selected flag so the next time
            // the popup for files is used it doesn't show previously selected
            // items.
            root.walk({strategy: 'pre'}, function(node) {
                if (node.model.data.selected) {
                    node.model.data.selected = false;
                    if (node.model.data.otype === 'file') {
                        filesFromTree.push(node.model.data);
                    }
                }
            });
        }

        return filesFromTree;
    }
}

angular.module('materialscommons').service('selectItems', SelectItemsService);
<|endoftext|>