<commit_before>// @flow

import { moment, checkStringOrDate, hasArgs, hasNoArgs, isStringArg } from './util';
import * as miniseed from '../miniseed';

/**
* A Seismogram object.
* @param {Array} yArray array of Y sample values, ie the timeseries
* @param {number} sampleRate sample rate of the seismogram, hertz
* @param {moment} start start time of seismogrm as a momentjs moment in utc or a string that can be parsed
*/
export class Seismogram {
  /** Array of y values */
  _y: Array<number>;
  _compressed: Array<miniseed.DataRecord>;
  /** the sample rate in hertz */
  sampleRate:number;
  /** @private */
  _start:moment;
  networkCode:string;
  stationCode:string;
  locationCode:string;
  channelCode:string;
  yUnit:string;
  constructor(yArray:Array<number>, sampleRate: number, start: moment) {
    if (yArray.length > 0 && yArray[0] instanceof miniseed.DataRecord) {
      this._compressed = yArray;
      this._y = null;
    } else {
      this._compressed = null;
      this._y = yArray;
    }
    this.sampleRate = sampleRate;
    this.start = checkStringOrDate(start);
    this.yUnit = 'count';
  }
  get y() {
    if ( ! this._y && this._compressed) {
      let out = [];
      for (let i=0; i<this._compressed.length; i++) {
        out = out.concat(this._compressed[i].decompress());
      }
      this._y = out;
      this._compressed = null;
    }
    return this._y;
  }
  set y(value) {
    this._y = value;
  }
  get start() :moment {
    return this._start;
  }
  set start(value: moment | string) {
    this._start = checkStringOrDate(value);
  }
  get end() :moment {
    return this.timeOfSample(this.numPoints-1);
  }
  get numPoints() :number {
    return this.y.length;
  }
  get netCode() :string {
    return this.networkCode;
  }
  get staCode() :string {
    return this.stationCode;
  }
  get locId() :string {
    return this.locationCode;
  }
  get locCode() :string {
    return this.locationCode;
  }
  get chanCode() :string {
    return this.channelCode;
  }
  yAtIndex(i: number) :number {
    return this.y[i];
  }

  timeOfSample(i:number ) :moment {
    return moment.utc(this.start).add(i/this.sampleRate, 'seconds');
  }
  codes() :string {
    return this.networkCode+"."+this.stationCode+"."+this.locationCode+"."+this.channelCode;
  }
  seisId() :string {
   return (this.codes()+"_"+this.start.toISOString()+"_"+this.end.toISOString()).replace(/\./g,'_').replace(/:/g,'');
  }
  clone():Seismogram {
    let out = new Seismogram(this.y.slice(),
                          this.sampleRate,
                          moment.utc(this._start));
    out.networkCode = this.networkCode;
    out.stationCode = this.stationCode;
    out.locationCode = this.locationCode;
    out.channelCode = this.channelCode;
    out.yUnit = this.yUnit;
    return out;
  }
  trim(trimStart: moment, trimEnd: moment) {
    if (trimEnd.isBefore(this._start) || trimStart.isAfter(this._end)) {
      return null;
    }
    let sIndex = 0;
    if (trimStart.isAfter(this._start)) {
      let milliDiff = trimStart.diff(this._start);
      let offset = milliDiff * this.sampleRate /1000.0;
      sIndex = Math.floor(offset);
    }
    let eIndex = 0;
    if (trimEnd.isBefore(this._end)) {
      let milliDiff = moment.utc(this._end).diff(trimEnd);
      let offset = milliDiff * this.sampleRate /1000.0;
      eIndex = this.y.length - Math.floor(offset);
    }
    let newY = this.y.slice(sIndex, eIndex);

    let out = new Seismogram(newY,
                          this.sampleRate,
                          moment.utc(this._start).add(sIndex / this.sampleRate, 'seconds'));
    out.networkCode = this.networkCode;
    out.stationCode = this.stationCode;
    out.locationCode = this.locationCode;
    out.channelCode = this.channelCode;
    return out;
  }
}

/** Represents time window for a single channel that may
  * contain gaps or overlaps, but is otherwise more or less
  * continuous, or at least adjacent data from the channel.
  * Each segment within
  * the Trace will have the same units, channel identifiers
  * and sample rate, but cover different times. */<commit_msg>cache end time as it is somewhat expensive to calculate and used often<commit_after>// @flow

import { moment, checkStringOrDate, hasArgs, hasNoArgs, isStringArg } from './util';
import * as miniseed from '../miniseed';

/**
* A Seismogram object.
* @param {Array} yArray array of Y sample values, ie the timeseries
* @param {number} sampleRate sample rate of the seismogram, hertz
* @param {moment} start start time of seismogrm as a momentjs moment in utc or a string that can be parsed
*/
export class Seismogram {
  /** Array of y values */
  _y: Array<number>;
  _compressed: Array<miniseed.DataRecord>;
  /** the sample rate in hertz */
  sampleRate:number;
  /** @private */
  _start:moment;
  networkCode:string;
  stationCode:string;
  locationCode:string;
  channelCode:string;
  yUnit:string;
  constructor(yArray:Array<number>, sampleRate: number, start: moment) {
    if (yArray.length > 0 && yArray[0] instanceof miniseed.DataRecord) {
      this._compressed = yArray;
      this._y = null;
    } else {
      this._compressed = null;
      this._y = yArray;
    }
    this._sampleRate = sampleRate;
    this.start = checkStringOrDate(start);
    this.yUnit = 'count';
    // to avoid recalc of end time as it is kind of expensive
    this._end_cache = null;
    this._end_cache_numPoints = 0;
  }
  get y() {
    if ( ! this._y && this._compressed) {
      let out = [];
      for (let i=0; i<this._compressed.length; i++) {
        out = out.concat(this._compressed[i].decompress());
      }
      this._y = out;
      this._compressed = null;
    }
    return this._y;
  }
  set y(value) {
    this._y = value;
    this._invalidate_end_cache();
  }
  get start() :moment {
    return this._start;
  }
  set start(value: moment | string) {
    this._start = checkStringOrDate(value);
    this._invalidate_end_cache();
  }
  get end() :moment {
    if ( ! this._end_cache || this._end_cache_numPoints !== this.numPoints) {
      // array length modified, recalc cached end time
      this._end_cache_numPoints = this.numPoints;
      this._end_cache = this.timeOfSample(this._end_cache_numPoints-1);
    }
    return this._end_cache;
  }
  get sampleRate() {
    return this._sampleRate;
  }
  set sampleRate(value: number) {
    this._sampleRate = value;
    this._invalidate_end_cache();
  }
  get numPoints() :number {
    return this.y.length;
  }
  get netCode() :string {
    return this.networkCode;
  }
  get staCode() :string {
    return this.stationCode;
  }
  get locId() :string {
    return this.locationCode;
  }
  get locCode() :string {
    return this.locationCode;
  }
  get chanCode() :string {
    return this.channelCode;
  }
  yAtIndex(i: number) :number {
    return this.y[i];
  }

  timeOfSample(i:number ) :moment {
    return moment.utc(this.start).add(i/this.sampleRate, 'seconds');
  }
  codes() :string {
    return this.networkCode+"."+this.stationCode+"."+this.locationCode+"."+this.channelCode;
  }
  seisId() :string {
   return (this.codes()+"_"+this.start.toISOString()+"_"+this.end.toISOString()).replace(/\./g,'_').replace(/:/g,'');
  }
  clone():Seismogram {
    let out = new Seismogram(this.y.slice(),
                          this.sampleRate,
                          moment.utc(this._start));
    out.networkCode = this.networkCode;
    out.stationCode = this.stationCode;
    out.locationCode = this.locationCode;
    out.channelCode = this.channelCode;
    out.yUnit = this.yUnit;
    return out;
  }
  trim(trimStart: moment, trimEnd: moment) {
    if (trimEnd.isBefore(this._start) || trimStart.isAfter(this._end)) {
      return null;
    }
    let sIndex = 0;
    if (trimStart.isAfter(this._start)) {
      let milliDiff = trimStart.diff(this._start);
      let offset = milliDiff * this.sampleRate /1000.0;
      sIndex = Math.floor(offset);
    }
    let eIndex = 0;
    if (trimEnd.isBefore(this._end)) {
      let milliDiff = moment.utc(this._end).diff(trimEnd);
      let offset = milliDiff * this.sampleRate /1000.0;
      eIndex = this.y.length - Math.floor(offset);
    }
    let newY = this.y.slice(sIndex, eIndex);

    let out = new Seismogram(newY,
                          this.sampleRate,
                          moment.utc(this._start).add(sIndex / this.sampleRate, 'seconds'));
    out.networkCode = this.networkCode;
    out.stationCode = this.stationCode;
    out.locationCode = this.locationCode;
    out.channelCode = this.channelCode;
    return out;
  }
  _invalidate_end_cache() {
    this._end_cache = null;
    this._end_cache_numPoints = 0;
  }
}

/** Represents time window for a single channel that may
  * contain gaps or overlaps, but is otherwise more or less
  * continuous, or at least adjacent data from the channel.
  * Each segment within
  * the Trace will have the same units, channel identifiers
  * and sample rate, but cover different times. */
{'fraction_non_alphanumeric': 0.12888839335488905, 'fraction_numerical': 0.003790835098673208, 'mean_word_length': 2.8497854077253217, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1272486', 'n_tokens_mistral': 2956, 'n_tokens_neox': 2919, 'n_words': 708}