<commit_before>/** @module formulas */
/*jslint node: true */
"use strict";

// ===========================================
//      Equal Temperament 12 semi-tones pool
// ===========================================
var ET12POOL = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"];

// ===========================================
//              Scale Formulas
// ===========================================

// Formulas for pentatonic scales
exports.MINOR_PENTATONIC = [3, 2, 2, 3, 2];  // minor pentatonic
exports.MAJOR_PENTATONIC = [2, 2, 3, 2, 3];  // major pentatonic

// Formulas for hexatonic scales
exports.MINOR_BLUES          = [3, 2, 1, 1, 3, 2];  // minor blues
exports.MAJOR_BLUES          = [2, 1, 1, 3, 2, 3];  // major blues
exports.PROMETHEUS           = [2, 2, 2, 3, 1, 2];  // prometheus - mystic
exports.ISTRIAN              = [1, 2, 1, 2, 1, 5];  // istrian
exports.WHOLE_TONE           = [2, 2, 2, 2, 2, 2];  // whole tone
exports.AUGMENTED            = [3, 1, 3, 1, 3, 1];  // augmented - symmetrical augmented
exports.TRITONE              = [1, 3, 2, 1, 3, 2];  // tritone
exports.TWO_SEMITONE_TRITONE = [1, 1, 4, 1, 1, 4];  // two semitone tritone

// Major derived formulas
exports.LYDIAN     = [2, 2, 2, 1, 2, 2, 1];  // lydian
exports.IONIAN     = [2, 2, 1, 2, 2, 2, 1];  // ionian - major
exports.MIXOLYDIAN = [2, 2, 1, 2, 2, 1, 2];  // mixolydian
exports.DORIAN     = [2, 1, 2, 2, 2, 1, 2];  // dorian
exports.AEOLIAN    = [2, 1, 2, 2, 1, 2, 2];  // aeolian - minor
exports.PHRYGIAN   = [1, 2, 2, 2, 1, 2, 2];  // phrygian
exports.LOCRIAN    = [1, 2, 2, 1, 2, 2, 2];  // locrian
exports.MAJOR      = [2, 2, 1, 2, 2, 2, 1];  // ionian alias
exports.MINOR      = [2, 1, 2, 2, 1, 2, 2];  // aeolian alias

// Melodic minor derived formulas
exports.MELODIC_MINOR     = [2, 1, 2, 2, 2, 2, 1]; // melodic minor
exports.DORIAN_FLAT9      = [1, 2, 2, 2, 2, 1, 2]; // dorian flat 9
exports.LYDIAN_AUGMENTED  = [2, 2, 2, 2, 1, 2, 1]; // lydian augmented
exports.LYDIAN_FLAT7      = [2, 2, 2, 1, 2, 1, 2]; // lydian flat 7
exports.MIXOLYDIAN_FLAT13 = [2, 2, 1, 2, 1, 2, 2]; // mixolydian flat 13
exports.SEMI_LOCRIAN      = [2, 1, 2, 1, 2, 2, 2]; // semilocrian
exports.SUPER_LOCRIAN     = [1, 2, 1, 2, 2, 2, 2]; // superlocrian

// Harmonic minor derived formulas
exports.HARMONIC_MINOR   = [2, 1, 2, 2, 1, 3, 1]; // harmonic minor
exports.LOCRIAN_SHARP7   = [1, 2, 2, 1, 3, 1, 2]; // locrian sharp 7
exports.IONIAN_AUGMENTED = [2, 2, 1, 3, 1, 2, 1]; // ionian augmented

// ===========================================
//               Chord Formulas
// ===========================================
// http://www.scales-chords.com/showchbykey.php?key=C
// http://music.stackexchange.com/questions/11659/what-determines-a-chords-name/
// https://en.wikipedia.org/wiki/Chord_names_and_symbols_%28jazz_and_pop_music%29#Seventh_chords
// https://en.wikibooks.org/wiki/Music_Theory/Complete_List_of_Chord_Patterns
// http://music.stackexchange.com/questions/3732/what-notes-are-optional-in-jazz-chords
// http://www.smithfowler.org/music/Chord_Formulas.htm

// Ted green's v-system:
// http://www.tedgreene.com/teaching/v_system.asp
// http://tedgreene.com/images/lessons/v_system/14_The_43_Four-Note_Qualities.pdf
// http://www.tedgreene.com/images/lessons/v_system/15_The_Mathematics_of_Four-Note_Chords-and-Beyond.pdf

// Array indexes:
// 0: formula
// 1: root offset for no root chords, distance from the lowest note to the root

var twoNoteChords = {
    // Indeterminate triad (no 3rd):
    "5"                      : [[7], 0],   // Indeterminate triad, power chord, five no 3rd
    "b5 no 3rd"              : [[6], 0],   // Flat five no third
    // No 5th:
    "maj no 5th"             : [[4], 0],   // Major no 5th
    "min no 5th"             : [[3], 0],   // Minor no 5th
    "sus4 no 5th"            : [[5], 0],   // Suspended fourth no 5th
    "sus2 no 5th"            : [[2], 0],   // Suspended second no 5th
    // No root:
    "maj no root"            : [[3], -4],  // Major no root
    "min no root"            : [[4], -3],  // Minor no root
    // No 3rd no 5th
    "maj7 no(3rd, 5th)"      : [[11], 0],  // Major seventh no 3rd no 5th
    "7 no(3rd, 5th)"         : [[10], 0]   // Dominant seventh no 3rd no 5th
};

var threeNoteChords = {
    // Triads:
    "maj"             : [[4, 3], 0],   // Major triad
    "min"             : [[3, 4], 0],   // Minor triad
    "aug"             : [[4, 4], 0],   // Augmented triad
    "dim"             : [[3, 3], 0],   // Diminished triad
    // Sus trichords:
    "sus4"            : [[5, 2], 0],   // Suspended fourth trichord
    "sus2"            : [[2, 5], 0],   // Suspended second trichord
    // 7th no 5th trichords:
    "maj7 no 5th"     : [[4, 7], 0],   // Major seventh no fifth
    "min7 no 5th"     : [[3, 7], 0],   // Minor seventh no fifth
    "7 no 5th"        : [[4, 6], 0],   // Dominant seventh no fifth
    "dim7 no 5th"     : [[3, 6], 0],   // Diminished seventh no fifth
    "minmaj7 no 5th"  : [[3, 8], 0],   // Minor-major seventh no fifth
    // 6th no 5th trichords:
    "maj6 no 5th"     : [[4, 5], 0],   // Major sixth no fifth
    "min6 no 5th"     : [[3, 6], 0],   // Minor sixth no fifth
    // Add no 5th trichords:
    "maj add2 no 5th" : [[4, 10], 0],  // Major added-second no fifth
    "maj add4 no 5th" : [[4, 1], 0],   // Major added-fourth no fifth
    // 7th no root chords:
    "maj7 no root"    : [[3, 4], -4],  // Major seventh no root
    "min7 no root"    : [[4, 3], -3],  // Minor seventh no root
    "7 no root"       : [[3, 3], -4],  // Dominant seventh no root
    "min7b5 no root"  : [[3, 4], -3],  // Half-diminished seventh no root
    "dim7 no root"    : [[3, 3], -3],  // Diminished seventh no root
    "minmaj7 no root" : [[4, 4], -3],  // Minor-major seventh no root
    "maj7#5 no root"  : [[4, 3], -4],  // Major seventh sharp fifth no root
    "7b5 no root"     : [[2, 4], -4],  // Dominant seventh flat fifth no root
    "7#5 no root"     : [[4, 2], -4],  // Dominant seventh sharp fifth no root
    "maj7b5 no root"  : [[2, 5], -4],  // Major seventh flat fifth
    "min7#5 no root"  : [[5, 2], -3]   // Minor seventh sharp fifth
};

var fourNoteChords = {
    // 7th chords:
    "maj7"           : [[4, 3, 4], 0],   // Major seventh
    "min7"           : [[3, 4, 3], 0],   // Minor seventh
    "7"              : [[4, 3, 3], 0],   // Dominant seventh
    "min7b5"         : [[3, 3, 4], 0],   // Half-diminished seventh
    "dim7"           : [[3, 3, 3], 0],   // Diminished seventh
    "minmaj7"        : [[3, 4, 4], 0],   // Minor-major seventh
    "maj7#5"         : [[4, 4, 3], 0],   // Augmented-major seventh
    "7b5"            : [[4, 2, 4], 0],   // Dominant seventh flat five
    "7#5"            : [[4, 4, 2], 0],   // Dominant seventh sharp five
    "maj7b5"         : [[4, 2, 5], 0],   // Major seventh flat fifth
    "min7#5"         : [[3, 5, 2], 0],   // Minor seventh sharp fifth
    // 6th chords:
    "maj6"           : [[4, 3, 2], 0],   // Major sixth
    "min6"           : [[3, 4, 2], 0],   // Minor sixth
    // Add chords:
    "maj add2"       : [[4, 3, 7,], 0],  // Major added-second
    "maj add4"       : [[4, 3, 10], 0],  // Major added-fourth
    // 9th no 5th chords:
    "maj9 no 5th"    : [[4, 7, 3], 0],   // Major ninth no fifth
    "min9 no 5th"    : [[3, 7, 4], 0],   // Minor ninth no fifth
    "9 no 5th"       : [[4, 6, 4], 0],   // Dominant ninth no fifth
    "6/9 no 5th"     : [[4, 5, 5], 0],   // Six Nine no fifth
    // 9th No root chords:
    "maj9 no root"   : [[3, 4, 3], -4],  // Major ninth no root
    "9 sus4 no root" : [[3, 4, 3], -7],  // Dominant ninth suspended fourth no root
    "9 no root"      : [[3, 3, 4], -4]   // Dominant ninth no root
};

var fiveNoteChords = {
    // Ninth chords:
    "min9"         : [[3, 4, 3, 4], 0],  // Minor ninth
    "9"            : [[4, 3, 3, 4], 0],  // Dominant ninth
    "maj9"         : [[4, 3, 4, 3], 0],  // Major ninth
    "6/9"          : [[4, 3, 2, 5], 0],  // Six nine
    // Ninth sus chords:
    "9 sus4"       : [[5, 2, 3, 4], 0]   // Dominant ninth suspended fourth

};

// Node exports:
exports.twoNoteChords   = twoNoteChords;
exports.threeNoteChords = threeNoteChords;
exports.fourNoteChords  = fourNoteChords;
exports.fiveNoteChords  = fiveNoteChords;
exports.ET12POOL        = ET12POOL;<commit_msg>jslint pimpin<commit_after>/** @module formulas */
/*jslint node: true */
"use strict";

// ===========================================
//      Equal Temperament 12 semi-tones pool
// ===========================================
var ET12POOL = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"];

// ===========================================
//              Scale Formulas
// ===========================================

// Formulas for pentatonic scales
exports.MINOR_PENTATONIC = [3, 2, 2, 3, 2];  // minor pentatonic
exports.MAJOR_PENTATONIC = [2, 2, 3, 2, 3];  // major pentatonic

// Formulas for hexatonic scales
exports.MINOR_BLUES          = [3, 2, 1, 1, 3, 2];  // minor blues
exports.MAJOR_BLUES          = [2, 1, 1, 3, 2, 3];  // major blues
exports.PROMETHEUS           = [2, 2, 2, 3, 1, 2];  // prometheus - mystic
exports.ISTRIAN              = [1, 2, 1, 2, 1, 5];  // istrian
exports.WHOLE_TONE           = [2, 2, 2, 2, 2, 2];  // whole tone
exports.AUGMENTED            = [3, 1, 3, 1, 3, 1];  // augmented - symmetrical augmented
exports.TRITONE              = [1, 3, 2, 1, 3, 2];  // tritone
exports.TWO_SEMITONE_TRITONE = [1, 1, 4, 1, 1, 4];  // two semitone tritone

// Major derived formulas
exports.LYDIAN     = [2, 2, 2, 1, 2, 2, 1];  // lydian
exports.IONIAN     = [2, 2, 1, 2, 2, 2, 1];  // ionian - major
exports.MIXOLYDIAN = [2, 2, 1, 2, 2, 1, 2];  // mixolydian
exports.DORIAN     = [2, 1, 2, 2, 2, 1, 2];  // dorian
exports.AEOLIAN    = [2, 1, 2, 2, 1, 2, 2];  // aeolian - minor
exports.PHRYGIAN   = [1, 2, 2, 2, 1, 2, 2];  // phrygian
exports.LOCRIAN    = [1, 2, 2, 1, 2, 2, 2];  // locrian
exports.MAJOR      = [2, 2, 1, 2, 2, 2, 1];  // ionian alias
exports.MINOR      = [2, 1, 2, 2, 1, 2, 2];  // aeolian alias

// Melodic minor derived formulas
exports.MELODIC_MINOR     = [2, 1, 2, 2, 2, 2, 1]; // melodic minor
exports.DORIAN_FLAT9      = [1, 2, 2, 2, 2, 1, 2]; // dorian flat 9
exports.LYDIAN_AUGMENTED  = [2, 2, 2, 2, 1, 2, 1]; // lydian augmented
exports.LYDIAN_FLAT7      = [2, 2, 2, 1, 2, 1, 2]; // lydian flat 7
exports.MIXOLYDIAN_FLAT13 = [2, 2, 1, 2, 1, 2, 2]; // mixolydian flat 13
exports.SEMI_LOCRIAN      = [2, 1, 2, 1, 2, 2, 2]; // semilocrian
exports.SUPER_LOCRIAN     = [1, 2, 1, 2, 2, 2, 2]; // superlocrian

// Harmonic minor derived formulas
exports.HARMONIC_MINOR   = [2, 1, 2, 2, 1, 3, 1]; // harmonic minor
exports.LOCRIAN_SHARP7   = [1, 2, 2, 1, 3, 1, 2]; // locrian sharp 7
exports.IONIAN_AUGMENTED = [2, 2, 1, 3, 1, 2, 1]; // ionian augmented

// ===========================================
//               Chord Formulas
// ===========================================
// http://www.scales-chords.com/showchbykey.php?key=C
// http://music.stackexchange.com/questions/11659/what-determines-a-chords-name/
// https://en.wikipedia.org/wiki/Chord_names_and_symbols_%28jazz_and_pop_music%29#Seventh_chords
// https://en.wikibooks.org/wiki/Music_Theory/Complete_List_of_Chord_Patterns
// http://music.stackexchange.com/questions/3732/what-notes-are-optional-in-jazz-chords
// http://www.smithfowler.org/music/Chord_Formulas.htm

// Ted green's v-system:
// http://www.tedgreene.com/teaching/v_system.asp
// http://tedgreene.com/images/lessons/v_system/14_The_43_Four-Note_Qualities.pdf
// http://www.tedgreene.com/images/lessons/v_system/15_The_Mathematics_of_Four-Note_Chords-and-Beyond.pdf

// Array indexes:
// 0: formula
// 1: root offset for no root chords, distance from the lowest note to the root

var twoNoteChords = {
    // Indeterminate triad (no 3rd):
    "5"                      : [[7], 0],   // Indeterminate triad, power chord, five no 3rd
    "b5 no 3rd"              : [[6], 0],   // Flat five no third
    // No 5th:
    "maj no 5th"             : [[4], 0],   // Major no 5th
    "min no 5th"             : [[3], 0],   // Minor no 5th
    "sus4 no 5th"            : [[5], 0],   // Suspended fourth no 5th
    "sus2 no 5th"            : [[2], 0],   // Suspended second no 5th
    // No root:
    "maj no root"            : [[3], -4],  // Major no root
    "min no root"            : [[4], -3],  // Minor no root
    // No 3rd no 5th
    "maj7 no(3rd, 5th)"      : [[11], 0],  // Major seventh no 3rd no 5th
    "7 no(3rd, 5th)"         : [[10], 0]   // Dominant seventh no 3rd no 5th
};

var threeNoteChords = {
    // Triads:
    "maj"             : [[4, 3], 0],   // Major triad
    "min"             : [[3, 4], 0],   // Minor triad
    "aug"             : [[4, 4], 0],   // Augmented triad
    "dim"             : [[3, 3], 0],   // Diminished triad
    // Sus trichords:
    "sus4"            : [[5, 2], 0],   // Suspended fourth trichord
    "sus2"            : [[2, 5], 0],   // Suspended second trichord
    // 7th no 5th trichords:
    "maj7 no 5th"     : [[4, 7], 0],   // Major seventh no fifth
    "min7 no 5th"     : [[3, 7], 0],   // Minor seventh no fifth
    "7 no 5th"        : [[4, 6], 0],   // Dominant seventh no fifth
    "dim7 no 5th"     : [[3, 6], 0],   // Diminished seventh no fifth
    "minmaj7 no 5th"  : [[3, 8], 0],   // Minor-major seventh no fifth
    // 6th no 5th trichords:
    "maj6 no 5th"     : [[4, 5], 0],   // Major sixth no fifth
    "min6 no 5th"     : [[3, 6], 0],   // Minor sixth no fifth
    // Add no 5th trichords:
    "maj add2 no 5th" : [[4, 10], 0],  // Major added-second no fifth
    "maj add4 no 5th" : [[4, 1], 0],   // Major added-fourth no fifth
    // 7th no root chords:
    "maj7 no root"    : [[3, 4], -4],  // Major seventh no root
    "min7 no root"    : [[4, 3], -3],  // Minor seventh no root
    "7 no root"       : [[3, 3], -4],  // Dominant seventh no root
    "min7b5 no root"  : [[3, 4], -3],  // Half-diminished seventh no root
    "dim7 no root"    : [[3, 3], -3],  // Diminished seventh no root
    "minmaj7 no root" : [[4, 4], -3],  // Minor-major seventh no root
    "maj7#5 no root"  : [[4, 3], -4],  // Major seventh sharp fifth no root
    "7b5 no root"     : [[2, 4], -4],  // Dominant seventh flat fifth no root
    "7#5 no root"     : [[4, 2], -4],  // Dominant seventh sharp fifth no root
    "maj7b5 no root"  : [[2, 5], -4],  // Major seventh flat fifth
    "min7#5 no root"  : [[5, 2], -3]   // Minor seventh sharp fifth
};

var fourNoteChords = {
    // 7th chords:
    "maj7"           : [[4, 3, 4], 0],   // Major seventh
    "min7"           : [[3, 4, 3], 0],   // Minor seventh
    "7"              : [[4, 3, 3], 0],   // Dominant seventh
    "min7b5"         : [[3, 3, 4], 0],   // Half-diminished seventh
    "dim7"           : [[3, 3, 3], 0],   // Diminished seventh
    "minmaj7"        : [[3, 4, 4], 0],   // Minor-major seventh
    "maj7#5"         : [[4, 4, 3], 0],   // Augmented-major seventh
    "7b5"            : [[4, 2, 4], 0],   // Dominant seventh flat five
    "7#5"            : [[4, 4, 2], 0],   // Dominant seventh sharp five
    "maj7b5"         : [[4, 2, 5], 0],   // Major seventh flat fifth
    "min7#5"         : [[3, 5, 2], 0],   // Minor seventh sharp fifth
    // 6th chords:
    "maj6"           : [[4, 3, 2], 0],   // Major sixth
    "min6"           : [[3, 4, 2], 0],   // Minor sixth
    // Add chords:
    "maj add2"       : [[4, 3, 7], 0],  // Major added-second
    "maj add4"       : [[4, 3, 10], 0],  // Major added-fourth
    // 9th no 5th chords:
    "maj9 no 5th"    : [[4, 7, 3], 0],   // Major ninth no fifth
    "min9 no 5th"    : [[3, 7, 4], 0],   // Minor ninth no fifth
    "9 no 5th"       : [[4, 6, 4], 0],   // Dominant ninth no fifth
    "6/9 no 5th"     : [[4, 5, 5], 0],   // Six Nine no fifth
    // 9th No root chords:
    "maj9 no root"   : [[3, 4, 3], -4],  // Major ninth no root
    "9 sus4 no root" : [[3, 4, 3], -7],  // Dominant ninth suspended fourth no root
    "9 no root"      : [[3, 3, 4], -4]   // Dominant ninth no root
};

var fiveNoteChords = {
    // Ninth chords:
    "min9"         : [[3, 4, 3, 4], 0],  // Minor ninth
    "9"            : [[4, 3, 3, 4], 0],  // Dominant ninth
    "maj9"         : [[4, 3, 4, 3], 0],  // Major ninth
    "6/9"          : [[4, 3, 2, 5], 0],  // Six nine
    // Ninth sus chords:
    "9 sus4"       : [[5, 2, 3, 4], 0]   // Dominant ninth suspended fourth

};

// Node exports:
exports.twoNoteChords   = twoNoteChords;
exports.threeNoteChords = threeNoteChords;
exports.fourNoteChords  = fourNoteChords;
exports.fiveNoteChords  = fiveNoteChords;
exports.ET12POOL        = ET12POOL;<|endoftext|>


<commit_before>import * as utils from './utils'

export const branding = state => state.branding
export const metadata = state => state.metadata
export const history = state => state.history
export const updateTime = state => {
  return 'NA' || state.metadata.updateTime || 'NA'
}

export const seasons = (state, getters) => {
  if (state.data) {
    return state.data[getters['switches/selectedRegion']].seasons.map(s => s.id)
  } else {
    return ['']
  }
}
export const regions = state => {
  if (state.data) {
    return state.data.map(d => d.subId)
  } else {
    return ['']
  }
}
export const choropleths = state => ['Actual Weighted ILI (%)', 'Relative Weighted ILI (%)']

export const timeChart = state => state.timeChart
export const choropleth = state => state.choropleth
export const distributionChart = state => state.distributionChart

/**
 * Return observed data for currently selected state
 */
export const observed = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  return regionSubset.seasons[getters['switches/selectedSeason']].actual.map(d => d.data)
}

/**
 * Return a series of time points to be referenced by all series
 */
export const timePoints = (state, getters) => {
  if (state.data) {
    let regionSubset = state.data[getters['switches/selectedRegion']]
    let seasonSubset = regionSubset.seasons[getters['switches/selectedSeason']]

    return seasonSubset.actual.map(d => {
      return {
        week: d.week % 100,
        year: Math.floor(d.week / 100)
      }
    })
  } else {
    return [{
      week: 0,
      year: 0
    }]
  }
}

/**
 * Return actual data for currently selected state
 */
export const actual = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  let seasonSubset = regionSubset.seasons[getters['switches/selectedSeason']]

  // Return just the values
  return utils.getMaxLagData(seasonSubset.actual).map(d => d.data)
}

/**
 * Return historical data for selected state
 * All data older than currently selected season
 */
export const historicalData = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  let currentSeasonId = getters['switches/selectedSeason']
  let weeksCount = regionSubset.seasons[currentSeasonId].actual.length

  let output = []

  // Add data from history store
  getters.history[regionSubset.id].forEach(h => {
    output.push({
      id: h.season,
      actual: utils.trimHistory(h.data, weeksCount)
    })
  })

  for (let i = 0; i < currentSeasonId; i++) {
    output.push({
      id: regionSubset.seasons[i].id,
      actual: utils.trimHistory(utils.getMaxLagData(regionSubset.seasons[i].actual),
                                weeksCount)
    })
  }

  return output
}

/**
 * Baseline for selected state
 */
export const baseline = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  return regionSubset.seasons[getters['switches/selectedSeason']].baseline
}

/**
 * Return data subset for chart as specified in region/season selected
 */
export const timeChartData = (state, getters) => {
  return {
    timePoints: getters.timePoints,
    observed: getters.observed,
    actual: getters.actual,
    baseline: getters.baseline,
    models: getters['models/models'],
    history: getters.historicalData
  }
}

/**
 * Return data for distribution plot
 */
export const distributionChartData = (state, getters) => {
  return {
    timePoints: getters.timePoints,
    currentIdx: getters['weeks/selectedWeekIdx'],
    models: getters['models/modelDistributions']
  }
}

/**
 * Return actual data for all regions for current selections
 */
export const choroplethData = (state, getters) => {
  let seasonId = getters['switches/selectedSeason']
  let relative = getters['switches/choroplethRelative']

  let output = {
    data: [],
    type: relative ? 'diverging' : 'sequential',
    decorator: relative ? x => x + ' % (baseline)' : x => x + ' %'
  }

  state.data.map(r => {
    let values = utils.getMaxLagData(r.seasons[seasonId].actual)

    if (relative) values = utils.baselineScale(values, r.seasons[seasonId].baseline)

    output.data.push({
      region: r.subId,
      states: r.states,
      value: values
    })
  })

  output.data = output.data.slice(1) // Remove national data

  output.range = utils.choroplethDataRange(state, getters)
  return output
}
<commit_msg>Fix updatetime getter<commit_after>import * as utils from './utils'

export const branding = state => state.branding
export const metadata = state => state.metadata
export const history = state => state.history
export const updateTime = state => {
  return state.metadata ? state.metadata.updateTime : 'NA'
}

export const seasons = (state, getters) => {
  if (state.data) {
    return state.data[getters['switches/selectedRegion']].seasons.map(s => s.id)
  } else {
    return ['']
  }
}
export const regions = state => {
  if (state.data) {
    return state.data.map(d => d.subId)
  } else {
    return ['']
  }
}
export const choropleths = state => ['Actual Weighted ILI (%)', 'Relative Weighted ILI (%)']

export const timeChart = state => state.timeChart
export const choropleth = state => state.choropleth
export const distributionChart = state => state.distributionChart

/**
 * Return observed data for currently selected state
 */
export const observed = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  return regionSubset.seasons[getters['switches/selectedSeason']].actual.map(d => d.data)
}

/**
 * Return a series of time points to be referenced by all series
 */
export const timePoints = (state, getters) => {
  if (state.data) {
    let regionSubset = state.data[getters['switches/selectedRegion']]
    let seasonSubset = regionSubset.seasons[getters['switches/selectedSeason']]

    return seasonSubset.actual.map(d => {
      return {
        week: d.week % 100,
        year: Math.floor(d.week / 100)
      }
    })
  } else {
    return [{
      week: 0,
      year: 0
    }]
  }
}

/**
 * Return actual data for currently selected state
 */
export const actual = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  let seasonSubset = regionSubset.seasons[getters['switches/selectedSeason']]

  // Return just the values
  return utils.getMaxLagData(seasonSubset.actual).map(d => d.data)
}

/**
 * Return historical data for selected state
 * All data older than currently selected season
 */
export const historicalData = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  let currentSeasonId = getters['switches/selectedSeason']
  let weeksCount = regionSubset.seasons[currentSeasonId].actual.length

  let output = []

  // Add data from history store
  getters.history[regionSubset.id].forEach(h => {
    output.push({
      id: h.season,
      actual: utils.trimHistory(h.data, weeksCount)
    })
  })

  for (let i = 0; i < currentSeasonId; i++) {
    output.push({
      id: regionSubset.seasons[i].id,
      actual: utils.trimHistory(utils.getMaxLagData(regionSubset.seasons[i].actual),
                                weeksCount)
    })
  }

  return output
}

/**
 * Baseline for selected state
 */
export const baseline = (state, getters) => {
  let regionSubset = state.data[getters['switches/selectedRegion']]
  return regionSubset.seasons[getters['switches/selectedSeason']].baseline
}

/**
 * Return data subset for chart as specified in region/season selected
 */
export const timeChartData = (state, getters) => {
  return {
    timePoints: getters.timePoints,
    observed: getters.observed,
    actual: getters.actual,
    baseline: getters.baseline,
    models: getters['models/models'],
    history: getters.historicalData
  }
}

/**
 * Return data for distribution plot
 */
export const distributionChartData = (state, getters) => {
  return {
    timePoints: getters.timePoints,
    currentIdx: getters['weeks/selectedWeekIdx'],
    models: getters['models/modelDistributions']
  }
}

/**
 * Return actual data for all regions for current selections
 */
export const choroplethData = (state, getters) => {
  let seasonId = getters['switches/selectedSeason']
  let relative = getters['switches/choroplethRelative']

  let output = {
    data: [],
    type: relative ? 'diverging' : 'sequential',
    decorator: relative ? x => x + ' % (baseline)' : x => x + ' %'
  }

  state.data.map(r => {
    let values = utils.getMaxLagData(r.seasons[seasonId].actual)

    if (relative) values = utils.baselineScale(values, r.seasons[seasonId].baseline)

    output.data.push({
      region: r.subId,
      states: r.states,
      value: values
    })
  })

  output.data = output.data.slice(1) // Remove national data

  output.range = utils.choroplethDataRange(state, getters)
  return output
}
<|endoftext|>


<commit_before>import Rx from 'rx'
const Observable= Rx.Observable
const Subject   = Rx.Subject
const merge   = Rx.Observable.merge

/* create an action that is both an observable AND
a function/callable*/
export function createAction(paramsMap){

  function action(params){
    //use rest parameters or not ? ...params
    if(paramsMap && typeof paramsMap === 'function')
    {
      params = paramsMap(params)
    }
    action.onNext(params)
  }
  //assign prototype stuff from Subject
  for (let key in Rx.Subject.prototype) {
    action[key] = Rx.Subject.prototype[key]
  }

  Rx.Subject.call( action )

  return action
}

/*From https://github.com/staltz/combineLatestObj*/
export function combineLatestObj(obj) {
  var sources = [];
  var keys = [];
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      keys.push(key.replace(/\$$/, ''));
      sources.push(obj[key]);
    }
  }
  return Rx.Observable.combineLatest(sources, function () {
    var argsLength = arguments.length;
    var combination = {};
    for (var i = argsLength - 1; i >= 0; i--) {
      combination[keys[i]] = arguments[i];
    }
    return combination;
  })
}

//From https://github.com/futurice/power-ui/blob/85d09645ecadc85bc753ba42fdd841d22d8bdd10/src/utils.js
export function replicateStream(origin$, proxy$) {
  origin$.subscribe(proxy$.asObserver())
}

/*merges an array of action objects into a single object :ie
 [{doBar$, doFoo$}, {doBaz$, doBar$}] => {doBar$, doFoo$, doBaz$}
*/
export function mergeActionsByName(actionSources, validActions){

  return actionSources.reduce(function(result, actions){
    //console.log("acions",Object.keys(actions),validActions)
    Object.keys(actions)
      .filter(key=>validActions.indexOf(key.replace('$',''))>-1)
      .map(function(key){
        const action = actions[key]
        if(key in result){
          result[key] = merge(result[key], action)
        }else{
          result[key] = action
        }
      })

    return result
  },{})

}

export function logNext( next ){
  log.info( next )
}
export function logError( err){
  log.error(err)
}
export function onDone( data) {
      log.info("DONE",data)
}

export function preventDefault(event) {
  event.preventDefault()
  return event
}

export function formatData(data, type){
  return {data, type}
}

export function isTextNotEmpty(text){
  return text !== ""
}

export function exists(input){
  return input !== null && input !== undefined
}

Observable.prototype.onlyWhen = function (observable, selector) {
  return this.withLatestFrom(observable,
    (self,other)=> { /*console.log("here in onlyWhen",self,other);*/return [self,other] })
  .filter(function(args) {
    return selector(args[1])
  })
  .map((data)=>data[0])
}

export {Observable}

//utility to run multiple ones in parallel, see here :
//https://github.com/Reactive-Extensions/RxJS/blob/master/doc/mapping/async/comparing.md#asyncparallel
function wrapArrayParallel (items) {
  //let __items = Rx.Observable.from()
  return Rx.Observable.forkJoin.apply(null, items);
}

/*TODO: implement, we need to find a way to do inverted filtering*/
function opposite(method){

}<commit_msg>feature(mergeActionsByName): added better handling of defaults<commit_after>import Rx from 'rx'
const Observable= Rx.Observable
const Subject   = Rx.Subject
const merge   = Rx.Observable.merge

/* create an action that is both an observable AND
a function/callable*/
export function createAction(paramsMap){

  function action(params){
    //use rest parameters or not ? ...params
    if(paramsMap && typeof paramsMap === 'function')
    {
      params = paramsMap(params)
    }
    action.onNext(params)
  }
  //assign prototype stuff from Subject
  for (let key in Rx.Subject.prototype) {
    action[key] = Rx.Subject.prototype[key]
  }

  Rx.Subject.call( action )

  return action
}

/*From https://github.com/staltz/combineLatestObj*/
export function combineLatestObj(obj) {
  var sources = [];
  var keys = [];
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      keys.push(key.replace(/\$$/, ''));
      sources.push(obj[key]);
    }
  }
  return Rx.Observable.combineLatest(sources, function () {
    var argsLength = arguments.length;
    var combination = {};
    for (var i = argsLength - 1; i >= 0; i--) {
      combination[keys[i]] = arguments[i];
    }
    return combination;
  })
}

//From https://github.com/futurice/power-ui/blob/85d09645ecadc85bc753ba42fdd841d22d8bdd10/src/utils.js
export function replicateStream(origin$, proxy$) {
  origin$.subscribe(proxy$.asObserver())
}

/*merges an array of action objects into a single object :ie
 [{doBar$, doFoo$}, {doBaz$, doBar$}] => {doBar$, doFoo$, doBaz$}
*/
export function mergeActionsByName(actionSources, validActions=[]){

  return actionSources.reduce(function(result, actions){
    //console.log("acions",Object.keys(actions),validActions)
    Object.keys(actions)
      .filter(key=> validActions.length === 0 || validActions.indexOf(key.replace('$',''))>-1)
      .map(function(key){
        const action = actions[key]
        if(key in result){
          result[key] = merge(result[key], action)
        }else{
          result[key] = action
        }
      })

    return result
  },{})

}

export function logNext( next ){
  log.info( next )
}
export function logError( err){
  log.error(err)
}
export function onDone( data) {
      log.info("DONE",data)
}

export function preventDefault(event) {
  event.preventDefault()
  return event
}

export function formatData(data, type){
  return {data, type}
}

export function isTextNotEmpty(text){
  return text !== ""
}

export function exists(input){
  return input !== null && input !== undefined
}

Observable.prototype.onlyWhen = function (observable, selector) {
  return this.withLatestFrom(observable,
    (self,other)=> { /*console.log("here in onlyWhen",self,other);*/return [self,other] })
  .filter(function(args) {
    return selector(args[1])
  })
  .map((data)=>data[0])
}

export {Observable}

//utility to run multiple ones in parallel, see here :
//https://github.com/Reactive-Extensions/RxJS/blob/master/doc/mapping/async/comparing.md#asyncparallel
function wrapArrayParallel (items) {
  //let __items = Rx.Observable.from()
  return Rx.Observable.forkJoin.apply(null, items);
}

/*TODO: implement, we need to find a way to do inverted filtering*/
function opposite(method){

}
<|endoftext|>


<commit_before>window.fragment = { render: null, html: 'fragment', json: 'fragment-json', jsonp: 'callback' };

(function(fragment) {
  if (fragment.render === null) {
    fragment.render = function(html, json) {
      var output = html;

      if (window.Mustache !== undefined && window.Mustache.render !== undefined) {
        output = Mustache.render(html, json);
      } else if (window.Handlebars !== undefined && window.Handlebars.compile !== undefined) {
        output = Handlebars.compile(html)(json);
      } else if (window._ !== undefined && window._.template !== undefined) {
        output = _.template(html, json);
      }

      return output;
    };
  }

  var load = function(url, callback) {
    var parser = document.createElement('a');
    parser.href = url;

    if (parser.hostname == window.location.hostname) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          callback(xhr.responseText);
        }
      }
      xhr.send();
    }
    // JSONP
    else {
      url += (parser.search == '' ? '?' : '&') + fragment.jsonp + '=JSONPCallback';
      var script = document.createElement('script');
      script.src = url;
      JSONPCallback = function(d) {
        callback(JSON.stringify(d));
      };
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  };

  var fragments = document.querySelectorAll('[data-'+fragment.html+'][data-'+fragment.json+']');
  Array.prototype.forEach.call(fragments, function(element) {
    var htmlUrl = element.getAttribute('data-fragment');
    var jsonUrl = element.getAttribute('data-fragment-json');

    load(htmlUrl, function(html) {
      load(jsonUrl, function(json) {
        element.innerHTML = window.fragment.render(html, JSON.parse(json));
      });
    });
  });

  var fragments = document.querySelectorAll('[data-'+fragment.html+']:not([data-'+fragment.json+'])');
  Array.prototype.forEach.call(fragments, function(element) {
    var htmlUrl = element.getAttribute('data-fragment');

    load(htmlUrl, function(html) {
      if (element.innerHTML == '') {
        element.innerHTML = html;
      }
      else {
        element.innerHTML = window.fragment.render(html, JSON.parse(element.innerHTML));
      }
    });
  });

  var fragments = document.querySelectorAll('[data-'+fragment.json+']:not([data-'+fragment.html+'])');
  Array.prototype.forEach.call(fragments, function(element) {
    var jsonUrl = element.getAttribute('data-fragment-json');

    load(jsonUrl, function(json) {
      element.innerHTML = window.fragment.render(element.innerHTML, JSON.parse(json));
    });
  });
})(fragment);
<commit_msg>Added a DOM ready checker Removed JSONPCallback after it's executed to prevent unwanted access Removed script element once loaded (with JSONP)<commit_after>window.fragment = { render: null, html: 'fragment', json: 'fragment-json', jsonp: 'callback' };

(function(fragment) {
  if (fragment.render === null) {
    fragment.render = function(html, json) {
      var output = html;

      if (window.Mustache !== undefined && window.Mustache.render !== undefined) {
        output = Mustache.render(html, json);
      } else if (window.Handlebars !== undefined && window.Handlebars.compile !== undefined) {
        output = Handlebars.compile(html)(json);
      } else if (window._ !== undefined && window._.template !== undefined) {
        output = _.template(html, json);
      }

      return output;
    };
  }

  var load = function(url, callback) {
    var parser = document.createElement('a');
    parser.href = url;

    if (parser.hostname == window.location.hostname) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          callback(xhr.responseText);
        }
      }
      xhr.send();
    }
    // JSONP
    else {
      url += (parser.search == '' ? '?' : '&') + fragment.jsonp + '=JSONPCallback';
      var script = document.createElement('script'),
          parent;
      script.src = url;
      JSONPCallback = function(d) {
        callback(JSON.stringify(d));
        JSONPCallback = null;
        parent = script.parentNode;
        if(parent) {
          parent.removeChild(script);
        }
        script = null;
      };
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  };

  var status = false,
      stack = [];

  function ready(fn){
    if(typeof fn != "function" || Object.prototype.toString.call(fn) != "[object Function]") {
      return;
    }
    if(status) {
        setTimeout(fn, 0);
    } else {
        stack.push(fn);
    }
  }

  function updateStatus(){
    if(!/in/.test(document.readyState) && document.body) {
      status = true;
      stack.forEach(function(fn){
        setTimeout(fn, 0);
      })
      stack = [];
    }
    if(!status) {
      setTimeout(updateStatus, 10);
    }
  }

  setTimeout(updateStatus, 10);

  ready(function(){
    var fragments = document.querySelectorAll('[data-'+fragment.html+'][data-'+fragment.json+']');
    Array.prototype.forEach.call(fragments, function(element) {
      var htmlUrl = element.getAttribute('data-fragment');
      var jsonUrl = element.getAttribute('data-fragment-json');

      load(htmlUrl, function(html) {
        load(jsonUrl, function(json) {
          element.innerHTML = window.fragment.render(html, JSON.parse(json));
        });
      });
    });

    var fragments = document.querySelectorAll('[data-'+fragment.html+']:not([data-'+fragment.json+'])');
    Array.prototype.forEach.call(fragments, function(element) {
      var htmlUrl = element.getAttribute('data-fragment');

      load(htmlUrl, function(html) {
        if (element.innerHTML == '') {
          element.innerHTML = html;
        }
        else {
          element.innerHTML = window.fragment.render(html, JSON.parse(element.innerHTML));
        }
      });
    });

    var fragments = document.querySelectorAll('[data-'+fragment.json+']:not([data-'+fragment.html+'])');
    Array.prototype.forEach.call(fragments, function(element) {
      var jsonUrl = element.getAttribute('data-fragment-json');

      load(jsonUrl, function(json) {
        element.innerHTML = window.fragment.render(element.innerHTML, JSON.parse(json));
      });
    });
  });
})(fragment);
<|endoftext|>


<commit_before>var x = symbolic X initial '';
var isIn = /LOREM IPSUM DIPSUM LOREM IPSUM DIPSUM LOREM IPSUM DIPSUMLOREM IPSUM DIPSUM LOREM IPSUM DIPSUM LOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUM/.test(x);

if (isIn) {
	throw 'Reachable';
} else {
	throw 'Reachable';
}<commit_msg>Tweak long_example<commit_after>var x = symbolic X initial '';
var isIn = /^LOREM IPSUM DIPSUM LOREM IPSUM DIPSUM LOREM IPSUM DIPSUMLOREM IPSUM DIPSUM LOREM IPSUM DIPSUM LOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUMLOREM IPSUM DIPSUM$/.test(x);

if (isIn) {
	throw 'Reachable';
} else {
	throw 'Reachable';
}<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2016, Joyent, Inc.
 */

var execFile = require('child_process').execFile;

var test = require('tape');
var vasync = require('vasync');
var vmadm = require('vmadm');

var common = require('./common');
var mocks = require('./mocks');
var ZoneeventWatcher = require('../lib/watchers/zoneevent-watcher');

var createdVms = [];
var debugData = {totalEvents: 0, totalLen: 0};
var smartosImageUUID;
var watcher;
var vmEvents = {};

// "CONFIG"
var CHARS_PER_LINE = 200;  // at least this many chars in a zoneevent line
// HIGH_WATER_MARK sets the highWaterMark for the lstream in ZoneeventWatcher.
// default is 16k! takes too long to get there, so we set to a lower value to
// ensure that we're going to overrun it with events.
var HIGH_WATER_MARK = 32;
var STRAGGLER_WAIT = 5000; // wait this many ms for events after delete
var OVERHEAD_EVENTS = 15;  // events we expect for create/delete
var RESTART_EVENTS = 9;    // events we expect for each restart
var NUM_RESTARTS_PER_VM = 25;
var NUM_VMS = 10;

/*
 * This test exists to confirm that AGENT-987 is fixed.
 *
 * Basically it proves that we can successfully handle at least (NUM_VMS *
 * NUM_RESTARTS_PER_VM * 9) + (NUM_VMS * 15) events.
 *
 * To test this, we create NUM_VMS VMs and reboot them in parallel
 * NUM_RESTARTS_PER_VM times.
 *
 * This should result in that number of start + stop events for each of them
 * along with 7 other intermediate events per restart and 15 events per VM for
 * the create/destroy.
 *
 */

test('find SmartOS image', function _test(t) {
    common.testFindSmartosImage(t, function _findSmartosCb(err, latest) {
        t.ifError(err, 'find SmartOS Image');
        if (err) {
            throw new Error('Cannot continue without SmartOS Image');
        }
        smartosImageUUID = latest;
        t.end();
    });
});

test('starting ZoneeventWatcher', function _test(t) {
    function _onVmUpdate(vmUuid, updateType, updateObj) {
        if (!vmEvents.hasOwnProperty(vmUuid)) {
            vmEvents[vmUuid] = {start: 0, stop: 0, other: 0};
        }

        if (updateObj.zone_state === 'running') {
            vmEvents[vmUuid].start++;
        } else if (updateObj.zone_state === 'stopped') {
            vmEvents[vmUuid].stop++;
        } else {
            vmEvents[vmUuid].other++;
        }
    }

    watcher = new ZoneeventWatcher({
        debugEvents: true,
        highWaterMark: HIGH_WATER_MARK,
        log: mocks.Logger,
        updateVm: _onVmUpdate
    });

    watcher.start();
    t.ok(watcher, 'created ZoneeventWatcher [' + watcher.getPid() + ']');

    t.end();
});

test('create VMs', function _test(t) {
    var numVms = NUM_VMS;
    var vmsToCreate = [];

    while (numVms > 0) {
        vmsToCreate.push(numVms--);
    }

    function _createVm(idx, cb) {
        var payload = {
            alias: 'vm-agent_testvm-overflow-' + idx,
            autoboot: true,
            brand: 'joyent-minimal',
            image_uuid: smartosImageUUID,
            quota: 10
        };

        payload.log = mocks.Logger;

        vmadm.create(payload, function _vmadmCreateCb(err, info) {
            t.ifError(err, 'create VM'
                + ((!err && info) ? ': ' + info.uuid : ''));
            if (!err && info) {
                createdVms.push(info.uuid);
            }
            cb(err);
        });
    }

    vasync.forEachParallel({
        inputs: vmsToCreate,
        func: _createVm
    }, function _afterForEachParallel(err) {
        t.ifError(err, 'VMs should have been created successfully');
        t.end();
    });
});

test('restart VMs', function _test(t) {
    // restart with zoneadm because we're doing this a lot and we want maximum
    // fastness.
    function _restartVm(uuid, cb) {
        var args = ['-z', uuid, 'reboot', '-X'];
        var cmd = '/usr/sbin/zoneadm';

        execFile(cmd, args, function _onExecFile(err, stdout, stderr) {
            var starts = vmEvents[uuid] ? vmEvents[uuid].start : 0;
            var stops = vmEvents[uuid] ? vmEvents[uuid].stop : 0;
            var others = vmEvents[uuid] ? vmEvents[uuid].other : 0;

            t.ifError(err, 'reboot VM ' + uuid + ' (' + starts + '/' + stops
                + '/' + others + ')');
            if (err) {
                console.error('zoneadm: ' + stderr); // eslint-disable-line
            }
            cb(err);
        });
    }

    function _multiRestartVm(uuid, cb) {
        var restarts = NUM_RESTARTS_PER_VM;
        var vmRestarts = [];

        while (restarts > 0) {
            vmRestarts.push(uuid);
            restarts--;
        }

        vasync.forEachPipeline({
            func: _restartVm,
            inputs: vmRestarts
        }, function _afterMultiRestartVm(err) {
            cb(err);
        });
    }

    vasync.forEachParallel({
        inputs: createdVms,
        func: _multiRestartVm
    }, function _afterForEachParallel(err) {
        t.ifError(err, 'done restarting');
        t.end();
    });
});

test('delete VMs', function _test(t) {
    function _deleteVm(uuid, cb) {
        var opts = {};

        opts.log = mocks.Logger;
        opts.uuid = uuid;

        vmadm.delete(opts, function _vmadmDeleteCb(err) {
            t.ifError(err, 'delete VM ' + uuid);
            cb(err);
        });
    }

    vasync.forEachParallel({
        inputs: createdVms,
        func: _deleteVm
    }, function _afterForEachParallel(err) {
        t.ifError(err, 'done deleting');
        t.end();
    });
});

test('stop ZoneeventWatcher', function _test(t) {
    // grab the totals so we can compare to expected in final check.
    debugData = {
        ringBuffer: watcher.event_ringbuffer,
        totalEvents: watcher.totalEvents,
        totalLen: watcher.totalLen
    };

    // give stragglers a chance and then stop the watcher
    setTimeout(function _afterWaiting() {
        t.ok(true, 'stopped watcher');
        watcher.stop();
        t.end();
    }, STRAGGLER_WAIT);
});

test('check final state', function _test(t) {
    var expectedTotal = (NUM_VMS * OVERHEAD_EVENTS)
        + (NUM_VMS * NUM_RESTARTS_PER_VM * RESTART_EVENTS);
    var firstBuf;
    var lastBuf;

    // ensure the number of events we received was higher than the
    // HIGH_WATER_MARK so that we know we are actually in flowing mode.
    t.ok(debugData.totalEvents > HIGH_WATER_MARK, 'events('
        + debugData.totalEvents + ') > HIGH_WATER_MARK(' + HIGH_WATER_MARK
        + ')');

    t.ok(debugData.totalEvents >= expectedTotal, debugData.totalEvents + ' >= '
        + expectedTotal);
    // lines are > CHARS_PER_LINE characters each, so we have at least this much
    t.ok(debugData.totalLen >= (expectedTotal * CHARS_PER_LINE),
        debugData.totalLen + ' >= ' + (expectedTotal * CHARS_PER_LINE));

    // ensure the event_ringbuffer was populated with events
    t.ok(debugData.ringBuffer.length > 0, 'have ' + debugData.ringBuffer.length
        + ' elements in the ringbuffer');

    if (debugData.ringBuffer.length > 0) {
        t.ok(debugData.ringBuffer[0].hasOwnProperty('event_line'),
            'ringBuffer entries have event_line');
        t.ok(debugData.ringBuffer[0].hasOwnProperty('event_timestamp'),
            'ringBuffer entries have event_timestamp');
    }

    if (debugData.ringBuffer.length > 1) {
        // we have more than one, so make sure the first element is older than
        // the last.
        firstBuf = debugData.ringBuffer[0];
        lastBuf = debugData.ringBuffer[debugData.ringBuffer.length - 1];
        t.ok(firstBuf.event_timestamp < lastBuf.event_timestamp,
            'ringBuffer[0].event_timestamp(' + firstBuf.event_timestamp + ') < '
            + 'ringBuffer[' + (debugData.ringBuffer.length - 1)
            + '].event_timestamp(' + lastBuf.event_timestamp + ')');
    }

    t.end();
});

<commit_msg>TRITON-107 vm-agent: zoneevent overflow test doesn't work as intended on vminfod-enabled nodes Reviewed by: Josh Wilsdon <josh@wilsdon.ca> Approved by: Josh Wilsdon <josh@wilsdon.ca><commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2018, Joyent, Inc.
 */

var execFile = require('child_process').execFile;

var test = require('tape');
var vasync = require('vasync');
var vmadm = require('vmadm');

var common = require('./common');
var determineEventSource = require('../lib/event-source');
var mocks = require('./mocks');
var ZoneeventWatcher = require('../lib/watchers/zoneevent-watcher');

var createdVms = [];
var debugData = {totalEvents: 0, totalLen: 0};
var eventSource;
var smartosImageUUID;
var watcher;
var vmEvents = {};

// "CONFIG"
var CHARS_PER_LINE = 200;  // at least this many chars in a zoneevent line
// HIGH_WATER_MARK sets the highWaterMark for the lstream in ZoneeventWatcher.
// default is 16k! takes too long to get there, so we set to a lower value to
// ensure that we're going to overrun it with events.
var HIGH_WATER_MARK = 32;
var STRAGGLER_WAIT = 5000; // wait this many ms for events after delete
var OVERHEAD_EVENTS = 15;  // events we expect for create/delete
var RESTART_EVENTS = 9;    // events we expect for each restart
var NUM_RESTARTS_PER_VM = 25;
var NUM_VMS = 10;

/*
 * This test exists to confirm that AGENT-987 is fixed.
 *
 * Basically it proves that we can successfully handle at least (NUM_VMS *
 * NUM_RESTARTS_PER_VM * 9) + (NUM_VMS * 15) events.
 *
 * To test this, we create NUM_VMS VMs and reboot them in parallel
 * NUM_RESTARTS_PER_VM times.
 *
 * This should result in that number of start + stop events for each of them
 * along with 7 other intermediate events per restart and 15 events per VM for
 * the create/destroy.
 *
 */

function main() {
    test('find SmartOS image', function _test(t) {
        common.testFindSmartosImage(t, function _findSmartosCb(err, latest) {
            t.ifError(err, 'find SmartOS Image');
            if (err) {
                throw new Error('Cannot continue without SmartOS Image');
            }
            smartosImageUUID = latest;
            t.end();
        });
    });

    test('starting ZoneeventWatcher', function _test(t) {
        function _onVmUpdate(vmUuid, updateType, updateObj) {
            if (!vmEvents.hasOwnProperty(vmUuid)) {
                vmEvents[vmUuid] = {start: 0, stop: 0, other: 0};
            }

            if (updateObj.zone_state === 'running') {
                vmEvents[vmUuid].start++;
            } else if (updateObj.zone_state === 'stopped') {
                vmEvents[vmUuid].stop++;
            } else {
                vmEvents[vmUuid].other++;
            }
        }

        watcher = new ZoneeventWatcher({
            debugEvents: true,
            highWaterMark: HIGH_WATER_MARK,
            log: mocks.Logger,
            updateVm: _onVmUpdate
        });

        watcher.start();
        t.ok(watcher, 'created ZoneeventWatcher [' + watcher.getPid() + ']');

        t.end();
    });

    test('create VMs', function _test(t) {
        var numVms = NUM_VMS;
        var vmsToCreate = [];

        while (numVms > 0) {
            vmsToCreate.push(numVms--);
        }

        function _createVm(idx, cb) {
            var payload = {
                alias: 'vm-agent_testvm-overflow-' + idx,
                autoboot: true,
                brand: 'joyent-minimal',
                image_uuid: smartosImageUUID,
                quota: 10
            };

            payload.log = mocks.Logger;

            vmadm.create(payload, function _vmadmCreateCb(err, info) {
                t.ifError(err, 'create VM'
                    + ((!err && info) ? ': ' + info.uuid : ''));
                if (!err && info) {
                    createdVms.push(info.uuid);
                }
                cb(err);
            });
        }

        vasync.forEachParallel({
            inputs: vmsToCreate,
            func: _createVm
        }, function _afterForEachParallel(err) {
            t.ifError(err, 'VMs should have been created successfully');
            t.end();
        });
    });

    test('restart VMs', function _test(t) {
        // restart with zoneadm because we're doing this a lot and we want
        // maximum fastness.
        function _restartVm(uuid, cb) {
            var args = ['-z', uuid, 'reboot', '-X'];
            var cmd = '/usr/sbin/zoneadm';

            execFile(cmd, args, function _onExecFile(err, stdout, stderr) {
                var starts = vmEvents[uuid] ? vmEvents[uuid].start : 0;
                var stops = vmEvents[uuid] ? vmEvents[uuid].stop : 0;
                var others = vmEvents[uuid] ? vmEvents[uuid].other : 0;

                t.ifError(err, 'reboot VM ' + uuid + ' (' + starts + '/' + stops
                    + '/' + others + ')');
                if (err) {
                    console.error('zoneadm: ' + stderr); // eslint-disable-line
                }
                cb(err);
            });
        }

        function _multiRestartVm(uuid, cb) {
            var restarts = NUM_RESTARTS_PER_VM;
            var vmRestarts = [];

            while (restarts > 0) {
                vmRestarts.push(uuid);
                restarts--;
            }

            vasync.forEachPipeline({
                func: _restartVm,
                inputs: vmRestarts
            }, function _afterMultiRestartVm(err) {
                cb(err);
            });
        }

        vasync.forEachParallel({
            inputs: createdVms,
            func: _multiRestartVm
        }, function _afterForEachParallel(err) {
            t.ifError(err, 'done restarting');
            t.end();
        });
    });

    test('delete VMs', function _test(t) {
        function _deleteVm(uuid, cb) {
            var opts = {};

            opts.log = mocks.Logger;
            opts.uuid = uuid;

            vmadm.delete(opts, function _vmadmDeleteCb(err) {
                t.ifError(err, 'delete VM ' + uuid);
                cb(err);
            });
        }

        vasync.forEachParallel({
            inputs: createdVms,
            func: _deleteVm
        }, function _afterForEachParallel(err) {
            t.ifError(err, 'done deleting');
            t.end();
        });
    });

    test('stop ZoneeventWatcher', function _test(t) {
        // grab the totals so we can compare to expected in final check.
        debugData = {
            ringBuffer: watcher.event_ringbuffer,
            totalEvents: watcher.totalEvents,
            totalLen: watcher.totalLen
        };

        // give stragglers a chance and then stop the watcher
        setTimeout(function _afterWaiting() {
            t.ok(true, 'stopped watcher');
            watcher.stop();
            t.end();
        }, STRAGGLER_WAIT);
    });

    test('check final state', function _test(t) {
        var expectedTotal = (NUM_VMS * OVERHEAD_EVENTS)
            + (NUM_VMS * NUM_RESTARTS_PER_VM * RESTART_EVENTS);
        var firstBuf;
        var lastBuf;

        // ensure the number of events we received was higher than the
        // HIGH_WATER_MARK so that we know we are actually in flowing mode.
        t.ok(debugData.totalEvents > HIGH_WATER_MARK, 'events('
            + debugData.totalEvents + ') > HIGH_WATER_MARK(' + HIGH_WATER_MARK
            + ')');

        t.ok(debugData.totalEvents >= expectedTotal, debugData.totalEvents
            + ' >= ' + expectedTotal);
        // lines are > CHARS_PER_LINE characters each, so we have at least this
        // much
        t.ok(debugData.totalLen >= (expectedTotal * CHARS_PER_LINE),
            debugData.totalLen + ' >= ' + (expectedTotal * CHARS_PER_LINE));

        // ensure the event_ringbuffer was populated with events
        t.ok(debugData.ringBuffer.length > 0, 'have '
            + debugData.ringBuffer.length + ' elements in the ringbuffer');

        if (debugData.ringBuffer.length > 0) {
            t.ok(debugData.ringBuffer[0].hasOwnProperty('event_line'),
                'ringBuffer entries have event_line');
            t.ok(debugData.ringBuffer[0].hasOwnProperty('event_timestamp'),
                'ringBuffer entries have event_timestamp');
        }

        if (debugData.ringBuffer.length > 1) {
            // we have more than one, so make sure the first element is older
            // than the last.
            firstBuf = debugData.ringBuffer[0];
            lastBuf = debugData.ringBuffer[debugData.ringBuffer.length - 1];
            t.ok(firstBuf.event_timestamp < lastBuf.event_timestamp,
                'ringBuffer[0].event_timestamp(' + firstBuf.event_timestamp
                + ') < ringBuffer[' + (debugData.ringBuffer.length - 1)
                + '].event_timestamp(' + lastBuf.event_timestamp + ')');
        }

        t.end();
    });
}

test('determine best event source', function _test(t) {
    var opts = {
        log: mocks.Logger
    };

    determineEventSource(opts,
        function determinedEventSource(err, _eventSource) {
            t.ifError(err, 'event source err');

            eventSource = _eventSource;
            t.ok(eventSource,
                'determineEventSource eventSource: ' + eventSource);

            // Only run tests if using the default eventSource
            if (err) {
                t.ok(false, 'failed to determine event source');
                t.end();
            } else if (eventSource === 'default') {
                t.end();
                main();
            } else {
                t.ok(true, 'skipping tests: eventSource !== default');
                t.end();
            }
        }
    );
});
<|endoftext|>


<commit_before>import { moduleForComponent, test } from 'ember-qunit';
import TooltipEnabledMixin from 'sl-ember-components/mixins/sl-tooltip-enabled';
import { Theme as ThemeEnum } from 'sl-ember-components/components/sl-alert';
import sinon from 'sinon';
import globalLibraries from '../../helpers/sl/synchronous/global-libraries';
import Ember from 'ember';
import * as warn from 'sl-ember-components/utils/warn';

const Theme = {
    DANGER: 'danger',
    INFO: 'info',
    SUCCESS: 'success',
    WARNING: 'warning'
};

moduleForComponent( 'sl-alert', 'Unit | Component | sl alert', {
    unit: true
});

test( 'Expected Mixins are present', function( assert ) {
    assert.ok(
        TooltipEnabledMixin.detect( this.subject() ),
        'TooltipEnabled Mixin is present'
    );
});

test( 'Default property values are set correctly', function( assert ) {
    const component = this.subject();

    assert.strictEqual(
        component.get( 'ariaRole' ),
        'alert',
        'ariaRole: "alert"'
    );

    assert.strictEqual(
        component.get( 'dismissable' ),
        false,
        'dismissable: false'
    );

    assert.strictEqual(
        component.get( 'theme' ),
        Theme.INFO,
        `theme: "${Theme.INFO}"`
    );

    assert.deepEqual(
        ThemeEnum,
        Theme,
        'Theme enum values are correct'
    );
});

test( 'Bound "dismiss" action is triggered when dismiss action is triggered', function( assert ) {
    const component = this.subject();
    const spy = sinon.spy( component, 'sendAction' );

    component.send( 'dismiss' );

    assert.strictEqual(
        spy.args[0].join(),
        'dismiss',
        'Bound "dismiss" action is triggered when dismiss action is triggered'
    );
});

test( 'themeClassName() returns expected value', function( assert ) {
    const testThemeValue = 'testTheme';
    const component = this.subject({
        theme: testThemeValue
    });

    assert.strictEqual(
        component.get( 'themeClassName' ),
        `alert-${testThemeValue}`,
        'themeClassName() returns expected value'
    );
});

test( 'Dependent keys are correct', function( assert ) {
    const component = this.subject();

    const themeClassNameDependentKeys = [
        'theme'
    ];

    assert.deepEqual(
        component.themeClassName._dependentKeys,
        themeClassNameDependentKeys,
        'Dependent keys are correct for themeClassName()'
    );
});

test( 'There are no references to Ember.$, $ or jQuery', function( assert ) {
    globalLibraries.setupSpies();

    const component = this.subject();

    this.render();

    globalLibraries.triggerEvents( component );

    assert.notOk(
        globalLibraries.called(),
        'Global libraries are not referenced in component'
    );

    globalLibraries.restoreSpies();
});

test( 'themeClassName() returns the correct class', function( assert ) {
    const component = this.subject();

    Object.keys( Theme ).forEach( ( key ) => {
        const theme = Theme[ key ];

        Ember.run( () => component.set( 'theme',  theme ) );

        assert.strictEqual(
            component.get( 'themeClassName' ),
            `alert-${theme}`,
            'themeClassName() returns expected value'
        );
    });

    const spy = sinon.spy( warn, 'default' );

    component.set( 'theme', 'invalid value' );
    component.get( 'themeClassName' );

    assert.ok(
        spy.calledOnce,
        'warn() was called when invalid theme was set'
    );

    warn.default.restore();
});
<commit_msg>Moved dual instance test to the bottom of the file<commit_after>import { moduleForComponent, test } from 'ember-qunit';
import TooltipEnabledMixin from 'sl-ember-components/mixins/sl-tooltip-enabled';
import { Theme as ThemeEnum } from 'sl-ember-components/components/sl-alert';
import sinon from 'sinon';
import globalLibraries from '../../helpers/sl/synchronous/global-libraries';
import Ember from 'ember';
import * as warn from 'sl-ember-components/utils/warn';

const Theme = {
    DANGER: 'danger',
    INFO: 'info',
    SUCCESS: 'success',
    WARNING: 'warning'
};

moduleForComponent( 'sl-alert', 'Unit | Component | sl alert', {
    unit: true
});

test( 'Expected Mixins are present', function( assert ) {
    assert.ok(
        TooltipEnabledMixin.detect( this.subject() ),
        'TooltipEnabled Mixin is present'
    );
});

test( 'Default property values are set correctly', function( assert ) {
    const component = this.subject();

    assert.strictEqual(
        component.get( 'ariaRole' ),
        'alert',
        'ariaRole: "alert"'
    );

    assert.strictEqual(
        component.get( 'dismissable' ),
        false,
        'dismissable: false'
    );

    assert.strictEqual(
        component.get( 'theme' ),
        Theme.INFO,
        `theme: "${Theme.INFO}"`
    );

    assert.deepEqual(
        ThemeEnum,
        Theme,
        'Theme enum values are correct'
    );
});

test( 'Bound "dismiss" action is triggered when dismiss action is triggered', function( assert ) {
    const component = this.subject();
    const spy = sinon.spy( component, 'sendAction' );

    component.send( 'dismiss' );

    assert.strictEqual(
        spy.args[0].join(),
        'dismiss',
        'Bound "dismiss" action is triggered when dismiss action is triggered'
    );
});

test( 'themeClassName() returns expected value', function( assert ) {
    const testThemeValue = 'testTheme';
    const component = this.subject({
        theme: testThemeValue
    });

    assert.strictEqual(
        component.get( 'themeClassName' ),
        `alert-${testThemeValue}`,
        'themeClassName() returns expected value'
    );
});

test( 'Dependent keys are correct', function( assert ) {
    const component = this.subject();

    const themeClassNameDependentKeys = [
        'theme'
    ];

    assert.deepEqual(
        component.themeClassName._dependentKeys,
        themeClassNameDependentKeys,
        'Dependent keys are correct for themeClassName()'
    );
});

test( 'themeClassName() returns the correct class', function( assert ) {
    const component = this.subject();

    Object.keys( Theme ).forEach( ( key ) => {
        const theme = Theme[ key ];

        Ember.run( () => component.set( 'theme',  theme ) );

        assert.strictEqual(
            component.get( 'themeClassName' ),
            `alert-${theme}`,
            'themeClassName() returns expected value'
        );
    });

    const spy = sinon.spy( warn, 'default' );

    component.set( 'theme', 'invalid value' );
    component.get( 'themeClassName' );

    assert.ok(
        spy.calledOnce,
        'warn() was called when invalid theme was set'
    );

    warn.default.restore();
});

test( 'There are no references to Ember.$, $ or jQuery', function( assert ) {
    globalLibraries.setupSpies();

    const component = this.subject();

    this.render();

    globalLibraries.triggerEvents( component );

    assert.notOk(
        globalLibraries.called(),
        'Global libraries are not referenced in component'
    );

    globalLibraries.restoreSpies();
});
<|endoftext|>


<commit_before>import { module, test } from 'qunit';

import QueryBuilder from 'ember-flexberry-data/query/builder';
import FilterOperator from 'ember-flexberry-data/query/filter-operator';
import Condition from 'ember-flexberry-data/query/condition';
import { SimplePredicate, ComplexPredicate, StringPredicate } from 'ember-flexberry-data/query/predicate';
import ODataAdapter from 'ember-flexberry-data/query/odata-adapter';
import startApp from '../../helpers/start-app';

const baseUrl = 'http://services.odata.org/Northwind/Northwind.svc';
const app = startApp();
const store = app.__container__.lookup('service:store');

module('query');

test('adapter odata id', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').byId(42);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers(42)');
});

test('adapter odata simple predicate eq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Eq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name eq 'Vasya'`);
});

test('adapter odata simple predicate neq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Neq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name ne 'Vasya'`);
});

test('adapter odata simple predicate ge', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Ge, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name gt 'Vasya'`);
});

test('adapter odata simple predicate geq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Geq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name ge 'Vasya'`);
});

test('adapter odata simple predicate le', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Le, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name lt 'Vasya'`);
});

test('adapter odata simple predicate leq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Leq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name le 'Vasya'`);
});

test('adapter odata string predicate', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where(new StringPredicate('Name').contains('Vasya'));
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=contains(name,'Vasya')`);
});

test('adapter odata string predicate inside complex', function (assert) {
  let stp = new StringPredicate('Name').contains('Vasya');
  let sp = new SimplePredicate('firstName', FilterOperator.Eq, 'Vasya');
  let builder = new QueryBuilder(store, 'customer').where(stp.and(sp));
  let adapter = new ODataAdapter(baseUrl, store);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=contains(name,'Vasya') and first-name eq 'Vasya'`);
});

test('adapter odata complex predicate', function (assert) {
  let sp1 = new SimplePredicate('firstName', FilterOperator.Eq, 'Vasya');
  let sp2 = new SimplePredicate('lastName', FilterOperator.Eq, 'Ivanov');
  let sp3 = new SimplePredicate('age', FilterOperator.Eq, 10);
  let cp1 = new ComplexPredicate(Condition.Or, sp1, sp2, sp3);

  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where(cp1);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name eq 'Vasya' or last-name eq 'Ivanov' or age eq 10`);
});

test('adapter odata order', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').orderBy('firstName asc, Value desc, Third');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$orderby=firstName asc,Value desc,Third');
});

test('adapter odata skip', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').skip(10);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$skip=10');
});

test('adapter odata top', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').top(20);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$top=20');
});

test('adapter odata count', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').count();
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$count=true');
});

test('adapter odata expand', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').expand('Prop1,Prop2').expand('Prop3,Prop2');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$expand=Prop1,Prop2,Prop3');
});

test('adapter odata select', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').select('Prop1,Prop2').select('Prop3,Prop2');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$select=Prop1,Prop2,Prop3');
});
<commit_msg>test odata-adapter orderby master<commit_after>import { module, test } from 'qunit';

import QueryBuilder from 'ember-flexberry-data/query/builder';
import FilterOperator from 'ember-flexberry-data/query/filter-operator';
import Condition from 'ember-flexberry-data/query/condition';
import { SimplePredicate, ComplexPredicate, StringPredicate } from 'ember-flexberry-data/query/predicate';
import ODataAdapter from 'ember-flexberry-data/query/odata-adapter';
import startApp from '../../helpers/start-app';

const baseUrl = 'http://services.odata.org/Northwind/Northwind.svc';
const app = startApp();
const store = app.__container__.lookup('service:store');

module('query');

test('adapter odata id', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').byId(42);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers(42)');
});

test('adapter odata simple predicate eq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Eq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name eq 'Vasya'`);
});

test('adapter odata simple predicate neq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Neq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name ne 'Vasya'`);
});

test('adapter odata simple predicate ge', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Ge, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name gt 'Vasya'`);
});

test('adapter odata simple predicate geq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Geq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name ge 'Vasya'`);
});

test('adapter odata simple predicate le', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Le, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name lt 'Vasya'`);
});

test('adapter odata simple predicate leq', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where('firstName', FilterOperator.Leq, 'Vasya');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name le 'Vasya'`);
});

test('adapter odata string predicate', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where(new StringPredicate('Name').contains('Vasya'));
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=contains(name,'Vasya')`);
});

test('adapter odata string predicate inside complex', function (assert) {
  let stp = new StringPredicate('Name').contains('Vasya');
  let sp = new SimplePredicate('firstName', FilterOperator.Eq, 'Vasya');
  let builder = new QueryBuilder(store, 'customer').where(stp.and(sp));
  let adapter = new ODataAdapter(baseUrl, store);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=contains(name,'Vasya') and first-name eq 'Vasya'`);
});

test('adapter odata complex predicate', function (assert) {
  let sp1 = new SimplePredicate('firstName', FilterOperator.Eq, 'Vasya');
  let sp2 = new SimplePredicate('lastName', FilterOperator.Eq, 'Ivanov');
  let sp3 = new SimplePredicate('age', FilterOperator.Eq, 10);
  let cp1 = new ComplexPredicate(Condition.Or, sp1, sp2, sp3);

  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').where(cp1);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, `${baseUrl}/Customers?$filter=first-name eq 'Vasya' or last-name eq 'Ivanov' or age eq 10`);
});

test('adapter odata order', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').orderBy('firstName asc, Value desc, Third,address.city asc');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$orderby=first-name asc,value desc,third,address/city asc');
});

test('adapter odata skip', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').skip(10);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$skip=10');
});

test('adapter odata top', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').top(20);
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$top=20');
});

test('adapter odata count', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').count();
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$count=true');
});

test('adapter odata expand', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').expand('Prop1,Prop2').expand('Prop3,Prop2');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$expand=Prop1,Prop2,Prop3');
});

test('adapter odata select', function (assert) {
  let adapter = new ODataAdapter(baseUrl, store);
  let builder = new QueryBuilder(store, 'customer').select('Prop1,Prop2').select('Prop3,Prop2');
  let url = adapter.getODataFullUrl(builder.build());

  assert.equal(url, baseUrl + '/Customers?$select=Prop1,Prop2,Prop3');
});
<|endoftext|>


<commit_before>

(function () {
    'use strict';

    var Gameloop = function (main) {

        this.main = main;
        this.setFPS(30);
        this.timer = null;

    };

    var exports = function (main) {

        return new Gameloop(main);

    };

    var pt = exports.prototype = Gameloop.prototype;

    pt.constructor = exports;

    /**
     * Starts the game loop.
     */
    pt.start = function () {

        this.setTimer();

        return this;
    };

    /**
     * Sets a timer for next frame.
     *
     * @private
     */
    pt.setTimer = function (wait) {

        var that = this;

        this.timer = setTimeout(function () {

            that.step();

        }, wait);
    };

    /**
     * Performs the step routine.
     *
     * @private
     */
    pt.step = function () {

        this.startedAt = +new Date();

        if (typeof this.main === 'function') {

            this.main();

        }

        this.endedAt = +new Date();

        var wait = this.frame - (this.startedAt - this.endedAt);

        this.setTimer(wait);

    };

    /**
     * Stops the game loop.
     */
    pt.stop = function () {

        // This must stop the loop immediately no matter when it is called.
        clearTimeout(this.timer);

        return this;

    };

    /**
     * Sets the frame per second.
     */
    pt.setFPS = function (fps) {
        this.fps = fps;
        this.frame = 1000 / this.fps;

        return this;
    };

    if (typeof module !== 'undefined' && module.exports) {

        module.exports = exports;

    } else if (typeof window !== 'undefined') {

        window.gameloop = exports;

    }

}());
<commit_msg>Add stopped flag<commit_after>

(function () {
    'use strict';

    var Gameloop = function (main) {

        this.main = main;
        this.setFPS(30);
        this.timer = null;
        this.stopped = null;

    };

    var exports = function (main) {

        return new Gameloop(main);

    };

    var pt = exports.prototype = Gameloop.prototype;

    pt.constructor = exports;

    /**
     * Starts the game loop.
     */
    pt.start = function () {

        this.stopped = false;

        this.setTimer();

        return this;
    };

    /**
     * Sets a timer for next frame.
     *
     * @private
     */
    pt.setTimer = function (wait) {

        var that = this;

        this.timer = setTimeout(function () {

            that.step();

        }, wait);
    };

    /**
     * Performs the step routine.
     *
     * @private
     */
    pt.step = function () {

        this.startedAt = +new Date();

        if (typeof this.main === 'function') {

            this.main();

        }

        this.endedAt = +new Date();

        var wait = this.frame - (this.startedAt - this.endedAt);

        if (this.stopped) {

            return;

        }

        this.setTimer(wait);

    };

    /**
     * Stops the game loop.
     */
    pt.stop = function () {

        this.stopped = true;

        // This must stop the loop immediately no matter when it is called.
        clearTimeout(this.timer);

        return this;

    };

    /**
     * Sets the frame per second.
     */
    pt.setFPS = function (fps) {
        this.fps = fps;
        this.frame = 1000 / this.fps;

        return this;
    };

    if (typeof module !== 'undefined' && module.exports) {

        module.exports = exports;

    } else if (typeof window !== 'undefined') {

        window.gameloop = exports;

    }

}());
<|endoftext|>


<commit_before>/* eslint-disable no-new */
import EasyV from '../src/EasyVLib';

describe('Test the createInitialState method', () => {
  let schema;
  const component = { dummy: true };

  beforeEach(() => {
    schema = { title: { type: String }, name: { type: String } };
  });

  test('Should return an object with certain properties', () => {
    const state = new EasyV(component, schema).createInitialState();
    expect(state).toEqual({
      isFormOK: false,
      name: {
        status: 'normal',
        errorText: '',
        value: ''
      },
      title: {
        status: 'normal',
        errorText: '',
        value: ''
      }
    });
  });

  test('Should return an object with value equal default if there is', () => {
    schema.title.default = 'I am default';
    schema.name.default = 'albert';
    const state = new EasyV(component, schema).createInitialState();
    expect(state).toEqual({
      isFormOK: false,
      name: {
        status: 'normal',
        errorText: '',
        value: 'albert'
      },
      title: {
        status: 'normal',
        errorText: '',
        value: 'I am default'
      }
    });
  });

  test('Should return an object with user`s state', () => {
    schema.title.default = 'I am default';
    schema.name.default = 'albert';
    const userState = {
      A: 'super',
      B: {
        a: 1,
        b: 'a'
      },
      C: 1
    };
    const state = new EasyV(component, schema).createInitialState(userState);
    expect(state).toEqual({
      isFormOK: false,
      name: {
        status: 'normal',
        errorText: '',
        value: 'albert'
      },
      title: {
        status: 'normal',
        errorText: '',
        value: 'I am default'
      },
      A: 'super',
      B: {
        a: 1,
        b: 'a'
      },
      C: 1
    });
  });
});
<commit_msg>#4 Add a test case, which the user try to add their custom key into the state under the same name which used in the schema<commit_after>/* eslint-disable no-new */
import EasyV from '../src/EasyVLib';

describe('Test the createInitialState method', () => {
  let schema;
  const component = { dummy: true };

  beforeEach(() => {
    schema = { title: { type: String }, name: { type: String } };
  });

  test('Should return an object with certain properties', () => {
    const state = new EasyV(component, schema).createInitialState();
    expect(state).toEqual({
      isFormOK: false,
      name: {
        status: 'normal',
        errorText: '',
        value: ''
      },
      title: {
        status: 'normal',
        errorText: '',
        value: ''
      }
    });
  });

  test('Should return an object with value equal default if there is', () => {
    schema.title.default = 'I am default';
    schema.name.default = 'albert';
    const state = new EasyV(component, schema).createInitialState();
    expect(state).toEqual({
      isFormOK: false,
      name: {
        status: 'normal',
        errorText: '',
        value: 'albert'
      },
      title: {
        status: 'normal',
        errorText: '',
        value: 'I am default'
      }
    });
  });

  test('Should return an object with user`s state', () => {
    schema.title.default = 'I am default';
    schema.name.default = 'albert';
    const userState = {
      A: 'super',
      B: {
        a: 1,
        b: 'a'
      },
      C: 1
    };
    const state = new EasyV(component, schema).createInitialState(userState);
    expect(state).toEqual({
      isFormOK: false,
      name: {
        status: 'normal',
        errorText: '',
        value: 'albert'
      },
      title: {
        status: 'normal',
        errorText: '',
        value: 'I am default'
      },
      A: 'super',
      B: {
        a: 1,
        b: 'a'
      },
      C: 1
    });
  });

  test('Should return an object with user`s state', () => {
    schema.title.default = 'I am default';
    schema.name.default = 'albert';
    const userState = {
      name: {
        firstName: 'Albert',
        lastName: 'Gao'
      },
      title: {
        realLength: 123
      },
      A: 'super',
      B: {
        a: 1,
        b: 'a'
      },
      C: 1
    };
    const state = new EasyV(component, schema).createInitialState(userState);
    expect(state).toEqual({
      isFormOK: false,
      name: {
        status: 'normal',
        errorText: '',
        value: 'albert',
        firstName: 'Albert',
        lastName: 'Gao'
      },
      title: {
        status: 'normal',
        errorText: '',
        value: 'I am default',
        realLength: 123
      },
      A: 'super',
      B: {
        a: 1,
        b: 'a'
      },
      C: 1
    });
  });

});
<|endoftext|>


<commit_before>class NoteView extends createjs.Shape {
  constructor() {
    super()
    this.isSelected = false
    this.setBounds(0, 0, 0, 0)
  }

  setSize(width, height) {
    this.setBounds(0, 0, width, height)
    this.refresh()
  }

  refresh() {
    const b = this.getBounds()
    const color = this.isSelected ? "black" : "rgb(88, 103, 250)"
    this.graphics
      .clear()
      .beginFill(color)
      .rect(0, 0, b.width, b.height)
  }

  set selected(selected) {
    this.isSelected = selected
    this.refresh()
  }
}
<commit_msg>improve performance for drawing note<commit_after>class NoteView extends createjs.Shape {
  constructor() {
    super()
    this.isSelected = false
    this.setBounds(0, 0, 0, 0)
    this.snapToPixel = true
  }

  setSize(width, height) {
    const b = this.getBounds()
    if (b.width == width && b.height == height) return
    this.setBounds(0, 0, width, height)
    this.refresh()
  }

  refresh() {
    const b = this.getBounds()
    const color = this.isSelected ? "black" : "rgb(88, 103, 250)"
    this.graphics
      .clear()
      .beginFill(color)
      .rect(0, 0, b.width, b.height)
  }

  set selected(selected) {
    if (this.isSelected == selected) return
    this.isSelected = selected
    this.refresh()
  }
}
<|endoftext|>


<commit_before>"use strict";

/**
 * Like support for WCF
 *
 * @author	Alexander Ebert
 * @copyright	2001-2018 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 *
 * @deprecated	3.0 - please use `WoltLabSuite/Core/Ui/Like/Handler` instead
 */
WCF.Like = Class.extend({
	/**
	 * true, if users can like their own content
	 * @var	boolean
	 */
	_allowForOwnContent: false,

	/**
	 * user can like
	 * @var	boolean
	 */
	_canLike: false,

	/**
	 * list of containers
	 * @var	object
	 */
	_containers: { },

	/**
	 * container meta data
	 * @var	object
	 */
	_containerData: { },

	/**
	 * enables the dislike option
	 */
	_enableDislikes: true,

	/**
	 * prevents like/dislike until the server responded
	 * @var	boolean
	 */
	_isBusy: false,

	/**
	 * cached grouped user lists for like details
	 * @var	object
	 */
	_likeDetails: { },

	/**
	 * proxy object
	 * @var	WCF.Action.Proxy
	 */
	_proxy: null,

	/**
	 * shows the detailed summary of users who liked the object
	 * @var	boolean
	 */
	_showSummary: true,

	/**
	 * Initializes like support.
	 *
	 * @param	boolean		canLike
	 * @param	boolean		enableDislikes
	 * @param	boolean		showSummary
	 * @param	boolean		allowForOwnContent
	 */
	init: function(canLike, enableDislikes, showSummary, allowForOwnContent) {
		this._canLike = canLike;
		this._enableDislikes = enableDislikes;
		this._isBusy = false;
		this._likeDetails = { };
		this._showSummary = showSummary;
		this._allowForOwnContent = allowForOwnContent;

		var $containers = this._getContainers();
		this._initContainers($containers);

		this._proxy = new WCF.Action.Proxy({
			success: $.proxy(this._success, this)
		});

		// bind dom node inserted listener
		var $date = new Date();
		var $identifier = $date.toString().hashCode + $date.getUTCMilliseconds();
		WCF.DOMNodeInsertedHandler.addCallback('WCF.Like' + $identifier, $.proxy(this._domNodeInserted, this));
	},

	/**
	 * Initialize containers once new nodes are inserted.
	 */
	_domNodeInserted: function() {
		var $containers = this._getContainers();
		this._initContainers($containers);

	},

	/**
	 * Initializes like containers.
	 *
	 * @param	object		containers
	 */
	_initContainers: function(containers) {
		var $createdWidgets = false;
		containers.each($.proxy(function(index, container) {
			// set container
			var $container = $(container);
			var $containerID = $container.wcfIdentify();

			if (!this._containers[$containerID]) {
				this._containers[$containerID] = $container;

				// set container data
				this._containerData[$containerID] = {
					'likeButton': null,
					'badge': null,
					'dislikeButton': null,
					'likes': $container.data('like-likes'),
					'dislikes': $container.data('like-dislikes'),
					'objectType': $container.data('objectType'),
					'objectID': this._getObjectID($containerID),
					'users': eval($container.data('like-users')),
					'liked': $container.data('like-liked')
				};

				// create UI
				this._createWidget($containerID);

				$createdWidgets = true;
			}
		}, this));

		if ($createdWidgets) {
			new WCF.PeriodicalExecuter(function(pe) {
				pe.stop();

				WCF.DOMNodeInsertedHandler.execute();
			}, 250);
		}
	},

	/**
	 * Returns a list of available object containers.
	 *
	 * @return	jQuery
	 */
	_getContainers: function() { },

	/**
	 * Returns widget container for target object container.
	 *
	 * @param	string		containerID
	 * @return	jQuery
	 */
	_getWidgetContainer: function(containerID) { },

	/**
	 * Returns object id for target object container.
	 *
	 * @param	string		containerID
	 * @return	integer
	 */
	_getObjectID: function(containerID) { },

	/**
	 * Adds the like widget.
	 *
	 * @param	integer		containerID
	 * @param	jQuery		widget
	 */
	_addWidget: function(containerID, widget) {
		var $widgetContainer = this._getWidgetContainer(containerID);

		widget.appendTo($widgetContainer);
	},

	/**
	 * Builds the like widget.
	 *
	 * @param	integer		containerID
	 * @param	jQuery		likeButton
	 * @param	jQuery		dislikeButton
	 * @param	jQuery		badge
	 * @param	jQuery		summary
	 */
	_buildWidget: function(containerID, likeButton, dislikeButton, badge, summary) {
		var $widget = $('

');
		if (this._canLike) {
			likeButton.appendTo($widget.find('ul'));
			dislikeButton.appendTo($widget.find('ul'));
		}
		badge.appendTo($widget);

		this._addWidget(containerID, $widget);
	},

	/**
	 * Creates the like widget.
	 *
	 * @param	integer		containerID
	 */
	_createWidget: function(containerID) {
		var $likeButton = $('
 '+WCF.Language.get('wcf.like.button.like')+'
');
		var $dislikeButton = $('
 '+WCF.Language.get('wcf.like.button.dislike')+'
');
		if (!this._enableDislikes) $dislikeButton.hide();

		if (!this._allowForOwnContent && (WCF.User.userID == this._containers[containerID].data('userID'))) {
			$likeButton = $('');
			$dislikeButton = $('');
		}

		var $badge = $('').data('containerID', containerID).click($.proxy(this._showLikeDetails, this));

		var $summary = null;
		if (this._showSummary) {
			$summary = $('

');
			$summary.children('span').data('containerID', containerID).click($.proxy(this._showLikeDetails, this));
		}
		this._buildWidget(containerID, $likeButton, $dislikeButton, $badge, $summary);

		this._containerData[containerID].likeButton = $likeButton;
		this._containerData[containerID].dislikeButton = $dislikeButton;
		this._containerData[containerID].badge = $badge;
		this._containerData[containerID].summary = $summary;

		$likeButton.data('containerID', containerID).data('type', 'like').click($.proxy(this._click, this));
		$dislikeButton.data('containerID', containerID).data('type', 'dislike').click($.proxy(this._click, this));
		this._setActiveState($likeButton, $dislikeButton, this._containerData[containerID].liked);
		this._updateBadge(containerID);
		if (this._showSummary) this._updateSummary(containerID);
	},

	/**
	 * Displays like details for an object.
	 *
	 * @param	object		event
	 * @param	string		containerID
	 */
	_showLikeDetails: function(event, containerID) {
		var $containerID = (event === null) ? containerID : $(event.currentTarget).data('containerID');

		if (this._likeDetails[$containerID] === undefined) {
			this._likeDetails[$containerID] = new WCF.User.List('wcf\\data\\like\\LikeAction', WCF.Language.get('wcf.like.details'), {
				data: {
					containerID: $containerID,
					objectID: this._containerData[$containerID].objectID,
					objectType: this._containerData[$containerID].objectType
				}
			});
		}

		this._likeDetails[$containerID].open();
	},

	/**
	 * Handles likes and dislikes.
	 *
	 * @param	object		event
	 */
	_click: function(event) {
		event.preventDefault();
		var $button = $(event.currentTarget);
		if ($button === null) {
			console.debug("[WCF.Like] Unable to find target button, aborting.");
			return;
		}

		this._sendRequest($button.data('containerID'), $button.data('type'));
	},

	/**
	 * Sends request through proxy.
	 *
	 * @param	integer		containerID
	 * @param	string		type
	 */
	_sendRequest: function(containerID, type) {
		// ignore retards spamming clicks on the buttons
		if (this._isBusy) {
			return;
		}

		this._isBusy = true;

		this._proxy.setOption('data', {
			actionName: type,
			className: 'wcf\\data\\like\\LikeAction',
			parameters: {
				data: {
					containerID: containerID,
					objectID: this._containerData[containerID].objectID,
					objectType: this._containerData[containerID].objectType
				}
			}
		});

		this._proxy.sendRequest();
	},

	/**
	 * Updates likeable object.
	 *
	 * @param	object		data
	 * @param	string		textStatus
	 * @param	object		jqXHR
	 */
	_success: function(data, textStatus, jqXHR) {
		var $containerID = data.returnValues.containerID;

		if (!this._containers[$containerID]) {
			return;
		}

		switch (data.actionName) {
			case 'dislike':
			case 'like':
				// update container data
				this._containerData[$containerID].likes = parseInt(data.returnValues.likes);
				this._containerData[$containerID].dislikes = parseInt(data.returnValues.dislikes);
				this._containerData[$containerID].users = data.returnValues.users;
				$.each(this._containerData[$containerID].users, function(userID, userData) {
					userData.username = WCF.String.escapeHTML(userData.username);
				});

				// update label
				this._updateBadge($containerID);
				// update summary
				if (this._showSummary) this._updateSummary($containerID);

				// mark button as active
				var $likeButton = this._containerData[$containerID].likeButton;
				var $dislikeButton = this._containerData[$containerID].dislikeButton;
				var $likeStatus = 0;
				if (data.returnValues.isLiked) $likeStatus = 1;
				else if (data.returnValues.isDisliked) $likeStatus = -1;
				this._setActiveState($likeButton, $dislikeButton, $likeStatus);

				// invalidate cache for like details
				if (this._likeDetails[$containerID] !== undefined) {
					delete this._likeDetails[$containerID];
				}

				this._isBusy = false;
			break;
		}
	},

	_updateBadge: function(containerID) {
		if (!this._containerData[containerID].likes && !this._containerData[containerID].dislikes) {
			this._containerData[containerID].badge.hide();
		}
		else {
			this._containerData[containerID].badge.show();

			// update like counter
			var $cumulativeLikes = this._containerData[containerID].likes - this._containerData[containerID].dislikes;
			var $badge = this._containerData[containerID].badge;
			$badge.removeClass('green red');
			if ($cumulativeLikes > 0) {
				$badge.text('+' + WCF.String.formatNumeric($cumulativeLikes));
				$badge.addClass('green');
			}
			else if ($cumulativeLikes < 0) {
				$badge.text(WCF.String.formatNumeric($cumulativeLikes));
				$badge.addClass('red');
			}
			else {
				$badge.text('\u00B10');
			}

			// update tooltip
			var $likes = this._containerData[containerID].likes;
			var $dislikes = this._containerData[containerID].dislikes;
			$badge.attr('data-tooltip', WCF.Language.get('wcf.like.tooltip', { likes: $likes, dislikes: $dislikes }));
		}
	},

	_updateSummary: function(containerID) {
		if (!this._containerData[containerID].likes) {
			this._containerData[containerID].summary.hide();
		}
		else {
			this._containerData[containerID].summary.show();

			var $users = this._containerData[containerID].users;
			var $userArray = [];
			for (var $userID in $users) $userArray.push($users[$userID].username);
			var $others = this._containerData[containerID].likes - $userArray.length;

			this._containerData[containerID].summary.children('span').html(WCF.Language.get('wcf.like.summary', { users: $userArray, others: $others }));
		}
	},

	/**
	 * Sets button active state.
	 *
	 * @param	jquery		likeButton
	 * @param	jquery		dislikeButton
	 * @param	integer		likeStatus
	 */
	_setActiveState: function(likeButton, dislikeButton, likeStatus) {
		likeButton.removeClass('active');
		dislikeButton.removeClass('active');

		if (likeStatus == 1) {
			likeButton.addClass('active');
		}
		else if (likeStatus == -1) {
			dislikeButton.addClass('active');
		}
	}
});
<commit_msg>Remove WCF.Like JS API See #2508<commit_after>"use strict";

/**
 * Like support for WCF
 *
 * @author	Alexander Ebert
 * @copyright	2001-2018 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 *
 * @deprecated	3.0 - please use `WoltLabSuite/Core/Ui/Reaction/Handler` instead
 */
WCF.Like = Class.extend({
	init: function() {
		throw new Error("The `WCF.Like` API is obsolete and therefore no longer supported. Please use the current API `WoltLabSuite/Core/Ui/Reaction/Handler` instead.");
	},
	_domNodeInserted: function() {},
	_initContainers: function() {},
	_getContainers: function() {},
	_getWidgetContainer: function() {},
	_getObjectID: function() {},
	_addWidget: function() {},
	_buildWidget: function() {},
	_createWidget: function() {},
	_showLikeDetails: function() {},
	_click: function() {},
	_sendRequest: function() {},
	_success: function() {},
	_updateBadge: function() {},
	_updateSummary: function() {},
	_setActiveState: function() {}
});
<|endoftext|>